While 循环锁定应用程序

While Loop Locks Application

我已经为我正在开发的应用程序苦苦思索了一段时间。在尝试调试接口锁定并且没有其他任何事情发生的问题很多小时后,我发现这是可怕的 While 循环。请参阅下面的示例并 运行 它。当您通过单击按钮启动 while 循环时,您无法在屏幕上执行任何其他操作。在这种情况下,它只是一个需要按下的简单警报按钮。

from Tkinter import *
import tkMessageBox

root = Tk()
root.geometry("450x250+300+300")
root.title("Raspberry PI Test")

def myloop():
    count = 0
    while (count < 500):
       print 'The count is:', count
       count = count + 1

    print "Good bye!"

def mymessage():
    tkMessageBox.showinfo(title="Alert", message="Hello World!")

buttonLoop = Button(root, text="Start Loop", command=myloop)
buttonLoop.place(x=5, y=15)

buttonMessage = Button(root, text="Start Loop", command=mymessage)
buttonMessage.place(x=85, y=15)


root.mainloop()

我怎样才能有一个需要 运行 直到计数完成并且仍然能够在我的应用程序中执行其他任务的循环?我还应该注意,我已经使用 Thread 尝试过同样的事情,但这并不重要。 UI 仍在等待 While 循环结束,你才能做任何事情。

既然我更了解你想要什么(秒表),我会推荐 root.after 命令

from Tkinter import *
import tkMessageBox
import threading
import time
root = Tk()
root.geometry("450x250+300+300")
root.title("Raspberry PI Test")
print dir(root)
count = 0
def start_counter():
    global count
    count = 500
    root.after(1,update_counter)
def update_counter():
    global count
    count -= 1
    if count < 0:
        count_complete()
    else:
        root.after(1,update_counter)

def count_complete():
    print "DONE COUNTING!! ... I am now back in the main thread"
def mymessage():
    tkMessageBox.showinfo(title="Alert", message="Hello World!")

buttonLoop = Button(root, text="Start Loop", command=myloop)
buttonLoop.place(x=5, y=15)

buttonMessage = Button(root, text="Start Loop", command=mymessage)
buttonMessage.place(x=85, y=15)


root.mainloop()

(下面是原始答案)

使用线程

from Tkinter import *
import tkMessageBox
import threading
import time
root = Tk()
root.geometry("450x250+300+300")
root.title("Raspberry PI Test")
print dir(root)
def myloop():
    def run():
        count = 0
        while (count < 500) and root.wm_state():
           print 'The count is:', count
           count = count + 1
           time.sleep(1)

        root.after(1,count_complete)
    thread = threading.Thread(target=run)
    thread.start()
def count_complete():
    print "DONE COUNTING!! ... I am now back in the main thread"
def mymessage():
    tkMessageBox.showinfo(title="Alert", message="Hello World!")

buttonLoop = Button(root, text="Start Loop", command=myloop)
buttonLoop.place(x=5, y=15)

buttonMessage = Button(root, text="Start Loop", command=mymessage)
buttonMessage.place(x=85, y=15)


root.mainloop()

请注意,当您显示将在 windows api 级别阻塞的信息框时,线程计数将等到它关闭...绕过您可以更换线程我认为使用多处理

我不太了解 TKinter,但根据我的阅读,很明显您需要在 while 循环中使用一些 TKinter 方法来更新文本框。 TKinter 在事件循环上运行,因此您必须从您的代码发送信号以重新进入 TKinter 的执行。

您发现您的 while 循环阻塞 UI 更新的执行,您做得很好。因此,您无需线程化,只需暂停 counting's 执行并让 TKinter 更新 UI.

这个tutorial提供了一个很好的例子。关键在第 24 行,他调用了 root.update,我相信这会打破你的程序让 TKinter 做这件事。

这里是最后的代码,只是为了证明线程可以工作。计数在发生的同时显示在屏幕上。再次感谢乔兰!

from Tkinter import *
import tkMessageBox
import threading
import time
root = Tk()
root.geometry("450x250+300+300")
root.title("Raspberry PI Test")
showResults = StringVar()
showResults.set('0')
print dir(root)
def myloop():
    def run():
        count = 0
        while (count < 1000) and root.wm_state():
           print 'The count is:', count
           showResults.set(count)
           count = count + 1
           #time.sleep(1)

        root.after(1,count_complete)
    thread = threading.Thread(target=run)
    thread.start()
def count_complete():
    print "DONE COUNTING!! ... I am now back in the main thread"
def mymessage():
    tkMessageBox.showinfo(title="Alert", message="Hello World!")

buttonLoop = Button(root, text="Start Loop", command=myloop)
buttonLoop.place(x=5, y=15)

buttonMessage = Button(root, text="Message", command=mymessage)
buttonMessage.place(x=85, y=15)

l2 = Label(root, width=15, height=4, font=("Helvetica", 16), textvariable=showResults, background="black", fg="green")
l2.place(x=15, y=65)

root.mainloop()