gpt4 book ai didi

python - 从另一个线程或进程更新 Gtk.ProgressBar

转载 作者:太空宇宙 更新时间:2023-11-04 04:13:43 27 4
gpt4 key购买 nike

我有一个带有进度条的 GUI。它应该显示第二个线程所做的工作的进度。我希望线程可以在工作的每一步立即发送到 GUI 进度条之类的事件。但我不知道如何做到这一点。

Python 本身为线程情况提供了一个Event 类。但由于 Event.wait() 方法,它会阻塞 GUI 主线程。

如果第二个线程是一个进程,它如何改变这种情况和可能的解决方案?

我这里的示例基于 PyGObject (Python Gtk),但也与所有其他 GUI 库相关。当前的解决方案有效,但 IMO 只是一种解决方法。 GUI(作为主线程)和第二个(辅助)线程通过线程安全的 queue.Queue 共享数据。 GUI 线程中有一个计时器事件,检查 **fixed intervalls* 中的 qeueu 以获取来自线程的新数据并更新进度条。

#!/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()

最佳答案

根据我的问题的评论,我修改了我的示例。请谨慎使用,因为我仍然不清楚该解决方案是否是线程安全的。

我尝试了 GLib.idle_add()并删除了我自己的计时器和队列。 注意:文档中方法的签名/参数不正确。原来是

idle_add(function, *user_data, **kwargs)

线程的可能解决方案

#!/usr/bin/env python3
import time
import threading
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib


class MyThread(threading.Thread):
def __init__(self, callback, n_tasks):
threading.Thread.__init__(self)
self._callback = callback
self._max = n_tasks

def run(self):
for i in range(self._max):
# simulate a task
time.sleep(1)
# increment/update progress
GLib.idle_add(self._callback)


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

# gui: progressbar
self._bar = Gtk.ProgressBar(show_text=True)
self.add(self._bar)
self.connect('destroy', Gtk.main_quit)

# start the thread
self._thread = MyThread(self._update_progress, self._max)
self._thread.start()

def _update_progress(self):
# increment
self._curr += 1
# update the progressbar
self._bar.set_fraction(self._curr / self._max)

# end this event handler
return False

if __name__ == '__main__':
win = MyWindow(30)
win.show_all()
Gtk.main()

GLib.idle_add() 做什么?

我不是 Gtk 的专家或核心开发人员。在我的理解中,我会说你可以将事件处理程序方法安装到 Gtk 主循环中。换句话说,第二个线程告诉 Gtk 主循环(这是第一个线程)在没有其他待办事项(在 GUI 循环中经常退出)时调用 givin 方法。

Process 没有解决方案,因为它们在单独的 Python 解释器实例中运行。无法在两个进程之间调用 GLib.idle_add()

关于python - 从另一个线程或进程更新 Gtk.ProgressBar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55868685/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com