如何在tkinter的后台运行一个函数

时间:2011-02-19 00:47:30

标签: python tkinter

我是GUI编程的新手,我想用tkinter编写一个Python程序。我想要它做的就是在后台运行一个可以通过GUI影响的简单函数。

该功能从0到无穷大计数,直到按下按钮。至少这就是我想要的。但我不知道如何在后台运行此函数,因为tkinter的mainloop()始终具有控制权。如果我在无限循环中启动该函数,则无法执行mainloop()并且GUI已死。

我希望在每个循环后将控制权返回给mainloop(),但是如何在没有用户触发事件的情况下将控制从mainloop()恢复到runapp-function?

以下是一些杀死GUI的示例代码:

from Tkinter import *

class App:
    def __init__(self, master):

        frame = Frame(master)
        frame.pack()

        self.button = Button(frame, text="START", command=self.runapp)
        self.button.pack(side=LEFT)

        self.hi_there = Button(frame, text="RESTART", command=self.restart)
        self.hi_there.pack(side=LEFT)

        self.runapp()

    def restart(self):
        print "Now we are restarting..."

    def runapp(self):
        counter = 0
        while (1):
            counter =+ 1
            time.sleep(0.1)

5 个答案:

答案 0 :(得分:8)

基于事件的编程在概念上很简单。试想一下,在程序文件的末尾是一个简单的无限循环:

while <we have not been told to exit>:
    <pull an event off of the queue>
    <process the event>

所以,你需要做的就是不断地运行一些小任务,把它分解成一口大小的部分并将这些部分放在事件队列中。每次循环时,计算的下一次迭代都将自动执行。

您可以使用after方法在事件队列中放置对象。因此,创建一个递增数字的方法,然后重新安排自己在几毫秒后运行。它看起来像是:

def add_one(self):
    self.counter += 1
    self.after(1000, self.add_one)

以上将每秒更新一次计数器。当你的程序初始化时,你只需要调用一次,然后再一次又一次地调用它,等等。

此方法仅在您将大问题(在您的情况下“永远计算”)分解为小步骤(“添加一个”)时才有效。如果您正在执行类似慢速数据库查询或大量计算的操作,则此技术不一定有效。

答案 1 :(得分:4)

您将在另一个问题Tkinter locks python when Icon loaded and tk.mainloop in a thread中找到答案。

简而言之,您需要有两个线程,一个用于tkinter,另一个用于后台任务。

答案 2 :(得分:2)

我没有足够的声誉来评论Bryan Oakley的答案(我发现它在我的程序中非常有效),所以我会在这里添加我的经验。我发现,根据你的后台函数运行的时间长度,以及你想要的时间间隔精确度,最好在循环函数的开头加上self.after调用。在布莱恩的例子中,这看起来像

def add_one(self):
    self.after(1000, self.add_one)
    self.counter += 1

这样做可以确保精确地遵守时间间隔,从而消除在功能需要很长时间时可能出现的间隔漂移。

答案 3 :(得分:2)

尝试理解这个例子:在backgroud中更新时钟,并更新GUI(不需要2个线程)。

# use Tkinter to show a digital clock
# tested with Python24    vegaseat    10sep2006
from Tkinter import *
import time
root = Tk()
time1 = ''
clock = Label(root, font=('times', 20, 'bold'), bg='green')
clock.pack(fill=BOTH, expand=1)
def tick():
    global time1
    # get the current local time from the PC
    time2 = time.strftime('%H:%M:%S')
    # if time string has changed, update it
    if time2 != time1:
        time1 = time2
        clock.config(text=time2)
    # calls itself every 200 milliseconds
    # to update the time display as needed
    # could use >200 ms, but display gets jerky
    clock.after(200, tick)
tick()
root.mainloop(  )

信用:link to site

答案 4 :(得分:0)

如果您不想离开这些线程,我想为您的GUI提供一个建议- 将您的GUI的函数放在root.mainloop()语句之前。

示例-

root = tk.Tk()
.
.
graphicsfunction()     #function for triggering the graphics or any other background 
                       #function
root.mainloop()

如果愿意,请投票。