如何使函数在tkinter中连续运行?(绑定而不需要事件(触发器)。)

2024-10-02 18:17:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我希望能够使函数在tkinter窗口中不断运行。
例如,代码

>>> import tkinter
>>> Window=tkinter.Tk()
>>> ThisCouldBeAnyObject=tkinter.Label(Window,text="Aligned right.",bg="#0000FF")
>>> thisCouldBeAnyObject=tkinter.Label(Window,text="Aligned right.",bg="#0000FF")
>>> def Function():
    ThisCouldBeAnyObject.place(x=Window.winfo_width()-128,y=24)
    ThisCouldBeAnyObject.config(text="To small!" if Window.winfo_width()<128 else "Window size: "+str(Window.winfo_width()))
    thisCouldBeAnyObject.place(x=(Window.winfo_width()-128)//128*128,y=64)

创建一个窗口、两个标签以及根据窗口宽度定位标签的函数。(有关示例代码的更简单版本,请参见编辑历史。)

我的理解是mainloop导致tkinter循环一段代码,检查是否单击了按钮,是否检测到了鼠标移动等,具体取决于窗口中的元素。我可以这样做吗,在mainloop中,我的函数不断地被调用,而不需要这些触发器,这样(在本例中)标签就会随着用户调整窗口的大小而移动?你知道吗


到目前为止,我已经知道了密码

>>> Window.bind("<Configure>",func=lambda x:Function())

对于这个示例来说似乎是可行的,但是了解如何避免将函数的执行限制在配置窗口时是很有帮助的。你知道吗

I don't want to use grid, or pack because I feel that I could do more with place and it will be good practice ready for other languages (that could be used for games development).


This is my first question, so thank you for any advice on asking questions.


Yes. I know that this might not be exactly how your supposed to use block quotes, but it was the only style of formatting I could find that provides the visual queue that a piece of text is a comment that you don't need to read to answer the question.


Tags: to函数代码textforthattkinterplace
2条回答

您可能需要使用pack()grid()来获得您想要的结果。我不会使用place()那么多,除了一些您在编程早期可能不会遇到的特定需求。你知道吗

如果你花时间回顾grid()pack(),你会发现他们几乎可以做任何你需要他们做的事情。当我第一次开始学习Python/Tkinter时,我对place()有同样的想法,但在过去的一年里,我并没有在我的程序中真正使用它。只是我不需要它。你知道吗

请看下面的代码。 我选择使用grid()来放置我的小部件,我们可以使用columnconfigure()rowconfigure()来为小部件所在的行和列添加权重。这允许扩展放置在那里的小部件。你知道吗

根据您在注释中提出的问题,weight用于决定列和/或行是否随窗口展开。默认权重为零不会随窗口展开,值为1时会均匀展开。对于展开变量,也可以将其设置为大于或小于1。你知道吗

这里有一篇关于weight的帖子,已经有了很好的答案:What does 'weight' do in tkinter?

import tkinter as tk


root=tk.Tk()
root.columnconfigure(0, weight=1) # allows widgets placed on row zero to expand left and right.
root.rowconfigure(0, weight=1) # allows widgets placed on column zero to expand up and down.

tk.Label(root, text="This label resizes with window", background="grey").grid(row=0, column=0, sticky="nsew")

root.mainloop()

如果您真的想使用place(),那么您可能想尝试使用bind()和函数来更新位置。我们可以bind()将处理根窗口大小调整的事件转换为更新标签位置的函数。你知道吗

请看下面的代码:

import tkinter as tk


root=tk.Tk()

lbl = tk.Label(root, text="This label resizes with window", background="grey")
lbl.place(x=10, y=10, width=100, height=20)

def update_label(event):
    w,h = event.width, event.height
    lbl.place(x=10, y=10, width=w, height=h)

root.bind('<Configure>', update_label)

root.mainloop()

你的问题有点不清楚,但那可能是因为你不熟悉tkinter的概念。你知道吗

GUI编程就是为队列中的事件提供服务。当事情发生时(按钮单击、窗口调整大小等),事件被添加到队列中。它们由事件循环获取(在tkinter中,这是mainloop()),并且在处理事件时执行绑定到每个事件的任何函数。例如,调整窗口大小时,会将多个事件添加到队列中。如果要在窗口调整大小时运行函数,可以将函数绑定到相应的事件。你知道吗

Tkinter还提供了向队列添加事件的功能。您可以添加实际事件(例如:单击和按键),但也可以指定在特定时间后运行的函数。你知道吗

例如,如果要每10毫秒运行一个函数,可以定义如下函数:

def run_periodically(func):
    func()
    root.after(10, run_periodically, func)

当您调用该函数一次时,它将调用传递给它的函数,然后在10毫秒后再次运行自己。例如,要每10毫秒运行foo,您需要调用run_periodically(foo)一次,然后它将每10毫秒运行一次,直到您停止它。你知道吗

如果您的目标是在调整窗口大小时调整小部件的位置,则不需要连续运行自己的函数。相反,您可以绑定到<Configure>事件,它是调整窗口大小时添加到队列中的事件之一。然后,绑定到事件的函数可以查看窗口的大小并执行适当的操作。你知道吗

大多数情况下,使用gridpack比使用place更有效、更容易,它们提供了告诉tkinter在窗口大小改变时如何反应的选项。例如,小部件可以保持居中,也可以根据需要进行扩展或收缩。你知道吗

如果您使用的是place,那么它有一些功能来做类似的事情(例如,它支持相对放置和相对宽度和高度),但是在许多情况下,使用place比使用gridpack需要更多的工作。一开始可能看起来很简单,但是一旦你有了一个复杂的GUI,即使对一个小部件做一点小小的改变,比如改变字体或边框的厚度,也会迫使你对其他小部件做一些改变。你知道吗

相关问题 更多 >