Создание своего рода прокручиваемой таблицы Excel с помощью tkinter

Я хочу отобразить таблицу (переменное количество строк) с помощью tkinter, где:

  • Размер окна подстраивается под содержимое
  • Вертикальная прокрутка предлагается, если строк слишком много.
  • Вертикальную прокрутку можно осуществлять колесиком мыши внутри таблицы (как в Excel)
  • Возможно копирование значения одной ячейки (щелкните правой кнопкой мыши по ячейке)

Этот пост (Добавление полосы прокрутки в группу виджетов в Tkinter) полезен для понимания прокрутки с помощью tkinter... но не соответствует всем приведенным выше требованиям.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Основные хитрости:

  • Лишь немногие объекты tkinter прокручиваются (холст прокручивается)
  • Внутри холста не используйте сетку или пакет (вы потеряете возможность прокрутки), а используйте метод, предназначенный для холста, под названием «create_window».
  • Внутри окна вашего холста создайте рамку... например, внутри вашей рамки вы вполне можете использовать методы упаковки/сетки.
  • Изменение размера холста в соответствии с содержимым... каждый раз, когда содержимое добавляется в кадр (событие <Configure>).
  • Способ перехвата события колеса мыши зависит от вашей ОС (в приведенном ниже примере управление event.delta предназначено для Windows).
  • Мы прервем любое событие колеса мыши на полосе прокрутки (чтобы не конфликтовать с запрограммированным вами событием колеса мыши)

Вот пример решения:

# Standard libraries
import tkinter as tk


class ResultWindow(tk.Tk):

    def __init__(self):

        # Initialize the GUI
        super().__init__()

        # Create the main widgets
        self.canvas = tk.Canvas(self)
        self.vsb = tk.Scrollbar(self, orient = "vertical", width=25)
        self.frame = tk.Frame(self.canvas)

        # Add them to the toplevel layout
        self.canvas.pack(side = "left", fill = "y")
        self.vsb.pack(side = "right", fill = "y")
        self.canvas.create_window((0, 0), window=self.frame, anchor = "nw")

        # Bind events to the widgets
        self.canvas.bind_all("<MouseWheel>", self.on_mousewheel)
        self.vsb.bind("<MouseWheel>", lambda event: "break")
        self.frame.bind("<Configure>", self.on_frame_configure)

        # Link Canvas scroll with Scrollbar
        self.canvas.configure(yscrollcommand=self.vsb.set)
        self.vsb.configure(command=self.canvas.yview)

        # Add the frame to define the way
        self.l_cell = None

        # Add arbitrary content (to create our table)
        self.add_content(200, 5)
        
    def add_content(self, rows, cols):
        
        # Declare functions to manage code labels highlighting
        set_color = lambda event: event.widget.config(bg = "grey")
        reset_color = lambda event: event.widget.config(bg = "SystemButtonFace")
        
        for col in range(cols):
            for row in range(rows):
                # Add the cells to the grid
                text = f"row: {row}, col: {col}"
                self.l_cell = tk.Label(self.frame, text=text, relief = "solid")
                self.l_cell.grid(row=row, column=col, sticky = "nsew")
                
                # Bind each cell to events
                self.l_cell.bind("<Enter>", set_color)
                self.l_cell.bind("<Leave>", reset_color)
                self.l_cell.bind("<Button-3>", self.on_click)
                
    def on_frame_configure(self, event):
        # Resize the canvas to fit with the content
        self.canvas.config(width=self.canvas.bbox("all")[2],
                           height=self.canvas.bbox("all")[3])

        # Adjust the scrollable scope to the new size of the canvas
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

    def on_mousewheel(self, event):
        # Update the scroll according to the mousewheel scroll size
        self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

    def on_click(self, event):
        # Clear the clipboard
        self.clipboard_clear()
        # Get the Label widget code and add it to the clipboard
        self.clipboard_append(event.widget.cget("text"))
        
app = ResultWindow()
app.mainloop()

Другие вопросы по теме