Размер окна трека Tkinter изменяется конкретно?

Я пишу небольшую программу, которая намерена запускать метод изменения размера при изменении размера окна. по этой причине я использовал toplevel.bind("<Configure>", self.resize). Хотя это работает для изменения размера, метод вызывается сотни раз: при прокрутке, при использовании некоторых кнопок, даже если размер окна не изменяется ни при одном из этих действий. Как привязать событие, чтобы оно вызывалось только при изменении размера окна?

import tkinter as tk

def resize(event):
    print("widget", event.widget)
    print("height", event.height, "width", event.width)

parent = tk.Toplevel()
canvas = tk.Canvas(parent)
scroll_y = tk.Scrollbar(parent, orient="vertical", command=canvas.yview)
scroll_x = tk.Scrollbar(parent, orient="horizontal", command=canvas.xview)
frame = tk.Frame(canvas)

# put the frame in the canvas
canvas.create_window(0, 0, anchor='nw', window=frame)
# make sure everything is displayed before configuring the scrollregion
canvas.update_idletasks()

canvas.configure(scrollregion=canvas.bbox('all'), 
                yscrollcommand=scroll_y.set,
                xscrollcommand=scroll_x.set)

scroll_y.pack(fill='y', side='right')
scroll_x.pack(fill='x', side='bottom')
canvas.pack(fill='both', expand=True, side='left')

parent.bind("<Configure>", resize)

parent.mainloop()

Выход:

widget .!toplevel
height 200 width 200
widget .!toplevel.!scrollbar
height 286 width 17
widget .!toplevel.!scrollbar2
height 17 width 382
widget .!toplevel.!canvas
height 269 width 382
widget .!toplevel
height 286 width 399
widget .!toplevel
height 286 width 399
widget .!toplevel.!can

Несмотря на то, что в окне есть только один холст и полосы прокрутки, событие изменения размера вызывается 7 раз, прежде чем пользователь даже сможет взаимодействовать с окном. Как я могу остановить это безумие и вызывать функцию изменения размера только тогда, когда размер окна изменяется?


person Tasmotanizer    schedule 10.05.2020    source источник
comment
Объяснение в этой ссылке может быть полезным .   -  person acw1668    schedule 11.05.2020


Ответы (2)



Насколько я знаю, когда вы привязываете события ‹Configure› к корневому окну или окну верхнего уровня, оно также привязывается к каждому содержащемуся в нем виджету, и единственным обходным путем является отфильтровывание всех этих других вызовов. К счастью, это не слишком сложно. Чтобы избежать использования глобальных переменных, я определил класс для работы с грязными деталями.

import tkinter as tk


class Tracker:
    """ Toplevel windows resize event tracker. """

    def __init__(self, toplevel):
        self.toplevel = toplevel
        self.width, self.height = toplevel.winfo_width(), toplevel.winfo_height()
        self._func_id = None

    def bind_config(self):
        self._func_id = self.toplevel.bind("<Configure>", self.resize)

    def unbind_config(self):  # Untested.
        if self._func_id:
            self.toplevel.unbind("<Configure>", self._func_id)
            self._func_id = None

    def resize(self, event):
        if(event.widget == self.toplevel and
           (self.width != event.width or self.height != event.height)):
            print(f'{event.widget=}: {event.height=}, {event.width=}\n')
            self.width, self.height = event.width, event.height


root = tk.Tk()
root.withdraw()
parent = tk.Toplevel(master=root)
parent.title('parent')
canvas = tk.Canvas(parent)
scroll_y = tk.Scrollbar(parent, orient="vertical", command=canvas.yview)
scroll_x = tk.Scrollbar(parent, orient="horizontal", command=canvas.xview)
frame = tk.Frame(canvas)

# put the frame in the canvas
canvas.create_window(0, 0, anchor='nw', window=frame)
# make sure everything is displayed before configuring the scrollregion
canvas.update_idletasks()

canvas.configure(scrollregion=canvas.bbox('all'),
                 yscrollcommand=scroll_y.set,
                 xscrollcommand=scroll_x.set)

scroll_y.pack(fill='y', side='right')
scroll_x.pack(fill='x', side='bottom')
canvas.pack(fill='both', expand=True, side='left')

tracker = Tracker(parent)
tracker.bind_config()

parent.mainloop()

person martineau    schedule 03.08.2021