我有一个过程需要一段时间(可能一两分钟)才能完成。当我从我的 pygtk GUI 调用它时,窗口会在大约 10 秒后锁定(变暗并阻止用户操作)。
我想阻止这种情况发生,但我不确定该怎么做。我认为多线程将是答案,但它似乎不起作用。我尝试了两种在网上找到的不同方法。首先,我修改了this FAQ采取长时间运行的功能。其次,我尝试像 this answer 中那样直接使用 threading.Thread。 ,但这也会锁定。
我的两个样本如下。我是多线程的新手,所以也许这不是我正在寻找的解决方案。我基本上只是试图防止 GUI 锁定,以便我可以使用进度条进行更新并让用户使用取消按钮。
#Sample 1
import threading
import time
import gobject
import gtk
gobject.threads_init()
class MyThread(threading.Thread):
def __init__(self, label, button):
super(MyThread, self).__init__()
self.label = label
self.button = button
self.counter = 0
button.connect("clicked", self.on_button_click)
self.quit = False
def update_label(self, counter):
self.label.set_text("Counter: %i" % counter)
time.sleep(20)
return False
def on_button_click(self, widget):
self.counter += 1
gobject.idle_add(self.update_label, self.counter)
window = gtk.Window()
label = gtk.Label()
box = gtk.VBox()
button = gtk.Button("Test")
box.pack_start(label)
box.pack_start(button)
window.add(box)
window.show_all()
window.connect("destroy", lambda _: gtk.main_quit())
thread = MyThread(label, button)
thread.start()
gtk.main()
thread.quit = True
#####################################
#Sample 2
from threading import Thread
import time
import gobject
import gtk
class Test():
def __init__(self):
self.counter = 0
self.label = gtk.Label()
button = gtk.Button("Test")
window = gtk.Window()
box = gtk.VBox()
box.pack_start(self.label)
box.pack_start(button)
window.add(box)
window.connect("destroy", lambda _: gtk.main_quit())
button.connect("clicked", self.on_button_click)
window.show_all()
def update_label(self, counter):
self.label.set_text("Counter: %i" % counter)
time.sleep(20)
return False
def on_button_click(self, widget):
self.counter += 1
thread = Thread(target=self.update_label, args=(self.counter,))
thread.start()
while thread.is_alive():
pass
thread.stop()
test = Test()
gtk.main()
最佳答案
请在下面找到适用于我的第二个示例的修改版本:
import threading
import time
import gtk, gobject, glib
gobject.threads_init()
class Test():
def __init__(self):
self.counter = 0
self.label = gtk.Label()
self.progress_bar = gtk.ProgressBar()
self.progress_bar_lock = threading.Lock()
button = gtk.Button("Test")
window = gtk.Window()
box = gtk.VBox()
box.pack_start(self.label)
box.pack_start(self.progress_bar)
box.pack_start(button)
window.add(box)
window.connect("destroy", lambda _: gtk.main_quit())
button.connect("clicked", self.on_button_click)
window.show_all()
def update_label(self, counter):
self.label.set_text("Thread started (counter: {0})"
.format(counter))
time.sleep(5)
self.label.set_text("Thread finished (counter: {0})"
.format(counter))
return False
def pulse_progress_bar(self):
print threading.active_count()
if threading.active_count() > 1:
self.progress_bar.pulse()
return True
self.progress_bar.set_fraction(0.0)
self.progress_bar_lock.release()
return False
def on_button_click(self, widget):
self.counter += 1
thread = threading.Thread(target=self.update_label,
args=(self.counter,))
thread.start()
if self.progress_bar_lock.acquire(False):
glib.timeout_add(250, self.pulse_progress_bar)
if __name__ == '__main__':
test = Test()
gtk.main()
所做的更改是:
- 避免在回调中等待线程完成,以保持主循环处理事件。
- 添加了在执行线程时显示的进度条。
- 使用
glib.timeout_add
安排一个回调,在执行某个线程时使进度条脉动。这与轮询线程具有相同的效果,但优点是主循环仍然响应其他事件。 - 使用
threading.Lock
来证明回调被安排多次,无论按钮被点击了多少次。 - 添加了此示例中缺少的
gobject.threads_init
(上一个示例中没有)。
现在,当单击按钮时,您将看到标签是如何被单击的,只要线程正在运行,进度条就会一直闪烁。
关于python - 阻止 pygtk GUI 在长时间运行的过程中锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8583975/