如何使函数在tkinter中持续运行? (无需事件(触发器)即可绑定。)

时间:2018-04-12 20:30:22

标签: python tkinter

我希望能够在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)

创建一个窗口,2个标签和功能,根据窗口的宽度定位标签。 (有关更简单版本的示例代码,请参阅编辑历史记录。)

我的理解是mainloop导致tkinter遍历一段代码,该代码检查是否单击了按钮,检测到鼠标移动等,具体取决于窗口中的元素。我可以这样做,以便在mainloop中,我的函数在不需要这些触发器的情况下不断调用,以便(在此示例中)标签随着用户调整窗口大小而移动吗?


到目前为止,我已经找到了代码,

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

似乎适用于该示例,但知道如何避免在配置窗口时将函数的执行限制为有用将会有所帮助。

  

我不想使用gridpack,因为我觉得我可以使用place做更多事情,这对于其他语言(可能是用于游戏开发)。


  

这是我的第一个问题,所以感谢您提出任何问题的建议。


  

是。我知道这可能不是完全你应该如何使用块引号,但它是我能找到的唯一格式化样式,它提供了一个视觉队列,一段文字是你不喜欢的评论我需要阅读以回答这个问题。

2 个答案:

答案 0 :(得分:2)

您的问题有点不清楚,但这可能是由于您对tkinter概念的不熟悉。

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

Tkinter还使您能够将事件添加到队列中。您可以添加实际事件(例如:点击和按键),但您也可以指定在特定时间后运行的功能。

例如,如果要每10ms运行一次函数,可以定义如下函数:

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

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

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

大多数情况下,使用gridpack更有效,更容易,它提供的选项告诉tkinter在窗口改变大小时如何反应,而不是使用{ {1}}。例如,小部件可以保持居中,或者可以根据需要扩展或收缩。

如果您使用place,它有一些功能可以执行类似的操作(例如,它支持相对位置和相对宽度和高度),但在许多情况下,需要更多工作才能使用{{1}而不是使用placeplace。一开始看起来似乎很容易,但是一旦你有一个复杂的GUI,即使对一个小部件稍作更改,例如更改字体或边框的粗细也会迫使你对其他每个小部件进行更改。

答案 1 :(得分:0)

您可能需要使用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()