我有一个带有progressbar的GUI。它应该显示第二个线程所做的工作的进度。我想要一个类似事件的东西,线程可以在工作的每一步立即发送到GUIs progressbar。但我不明白这是怎么做到的。在
Python本身为线程情况提供了一个Event
类。但是由于Event.wait()
方法,它会阻塞GUI主线程。在
如果第二个线程是一个进程,它如何改变情况和可能的解决方案?在
我这里的示例基于PyGObject(Pythons Gtk),但也与所有其他GUI库相关。
目前的解决方案可行,但在我看来,这只是一个变通办法。GUI(作为主线程)和第二个(工作线程)线程通过线程安全queue.Queue
共享数据。GUI线程中有一个计时器事件,它在**fixed intervalls*中检查queu,以获取线程中的新数据,并更新progressbar。在
#!/usr/bin/env python3
import time
import threading
import queue
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib
class MyThread(threading.Thread):
def __init__(self, queue, n_tasks):
threading.Thread.__init__(self)
self._queue = queue
self._max = n_tasks
def run(self):
for i in range(self._max):
# simulate a task
time.sleep(1)
# put something in the data queue
self._queue.put(1)
class MyWindow(Gtk.Window):
def __init__(self, n_tasks):
Gtk.Window.__init__(self)
# max and current number of tasks
self._max = n_tasks
self._curr = 0
# queue to share data between threads
self._queue = queue.Queue()
# gui: progressbar
self._bar = Gtk.ProgressBar(show_text=True)
self.add(self._bar)
self.connect('destroy', Gtk.main_quit)
# install timer event to check the queue for new data from the thread
GLib.timeout_add(interval=250, function=self._on_timer)
# start the thread
self._thread = MyThread(self._queue, self._max)
self._thread.start()
def _on_timer(self):
# if the thread is dead and no more data available...
if not self._thread.is_alive() and self._queue.empty():
# ...end the timer
return False
# if data available
while not self._queue.empty():
# read data from the thread
self._curr += self._queue.get()
# update the progressbar
self._bar.set_fraction(self._curr / self._max)
# keep the timer alive
return True
if __name__ == '__main__':
win = MyWindow(30)
win.show_all()
Gtk.main()
根据我对问题的评论,我修改了我的例子。请谨慎使用,因为我仍然不清楚解决方案是否是线程安全的。在
我尝试了^{} ,并删除了我自己的计时器和队列。注意:docu对方法的签名/参数不正确。最初是这样的
螺纹的可能解决方案
^{pr2}$GLib.idle_add()
做什么?在我不是Gtk的专家或核心开发人员。在我的理解中,我会说您可以将事件处理程序metodes安装到Gtk主循环中。换句话说,第二个线程告诉Gtk主循环(它是第一个线程)在没有其他任务时调用givin方法(在GUI循环中通常是退出的)。在
对于进程,没有解决方案,因为它们运行在单独的Python解释器实例中。无法在两个进程之间调用
GLib.idle_add()
。在你的实现是正确的。您正在处理线程化命令,在队列中共享反馈,并通过
GLib.timeout_add()
从主循环更新progressbar。在最初,这看起来像是一种复杂的方法来进行简单的progressbar更新,但这是生成子进程并跟踪进度的唯一方法之一,同时还要考虑Gtk主循环。在
相关问题 更多 >
编程相关推荐