简体   繁体   English

Tkinter 轨道 window 专门调整大小?

[英]Tkinter track window resize specifically?

I am writing a small program, which the intention to run a resize method, when the window size is changed.我正在编写一个小程序,它打算在 window 大小发生变化时运行调整大小的方法。 for this reason, I used toplevel.bind("<Configure>", self.resize) .出于这个原因,我使用了toplevel.bind("<Configure>", self.resize) While this does work for resizing, the method gets called hundreds of times: when scrolling, when using some of the buttons, even though the window size doesn't change with any of these actions.虽然这确实适用于调整大小,但该方法会被调用数百次:滚动时,使用某些按钮时,即使 window 大小不会随这些操作中的任何一个而改变。 How can I bind the event, so that it only gets called upon changing the window size?如何绑定事件,以便仅在更改 window 大小时调用它?

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()

Output: Output:

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

Eventhough there is only one canvas plus the scrollbars on the window, the resize event gets called 7 times, before the user even has a change to interact with the window.尽管只有一个 canvas 加上 window 上的滚动条,但在用户更改与 window 交互之前,调整大小事件被调用了 7 次。 How can I stop this madness and only call the resize function, when the window does get resized?当 window 确实被调整大小时,我怎样才能停止这种疯狂并只调用调整大小 function?

In effbot DOC :effbot 文档中

<Configure> <配置>

The widget changed size (or location, on some platforms).小部件更改了大小(或位置,在某些平台上)。 The new size is provided in the width and height attributes of the event object passed to the callback.新尺寸在传递给回调的事件 object 的宽度高度属性中提供。

When you run your code, it will draw those widget in the window, so the width and the height of the window will change.当您运行代码时,它将在 window 中绘制这些小部件,因此 window 的宽度和高度将发生变化。 You could use a if statement to check whether the width and height of the Toplevel changed.您可以使用if语句来检查Toplevel的宽度和高度是否发生了变化。

Change the function resize() and initialize the global variable in your code:更改 function resize()并在代码中初始化全局变量:

def resize(event):
    global window_width, window_height
    if event.widget.widgetName == "toplevel":
        if (window_width != event.width) and (window_height != event.height):
            window_width, window_height = event.width,event.height
            print(f"The width of Toplevel is {window_width} and the height of Toplevel "
                  f"is {window_height}")

window_width, window_height = 0, 0

You could avoid the global variables by using a class (OOP).您可以通过使用 class (OOP) 来避免global变量。

As far as I know, when you bind '<Configure>' events to a root or toplevel window it also gets bound to every widget it contains — and the only workaround is to filter-out all those other calls.据我所知,当您将“<Configure>”事件绑定到根或顶级 window 时,它也会绑定到它包含的每个小部件——唯一的解决方法是过滤掉所有其他调用。 Fortunately that's not too difficult.幸运的是,这并不太难。 To avoid using global variables, I've defined a class to deal with the dirty details.为了避免使用全局变量,我定义了一个 class 来处理脏细节。

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM