gpt4 book ai didi

python - 如何在 gtk3-python 中执行后台任务?

转载 作者:太空狗 更新时间:2023-10-30 01:09:05 25 4
gpt4 key购买 nike

我有这个主线:

界面.py

from gi.repository import Gtk, Gdk
import Process
import gobject

class gui():
def __init__(self):
self.window = Gtk.Window()
self.window.connect('delete-event', Gtk.main_quit)

self.box = Gtk.Box()
self.window.add(self.box)

self.label = Gtk.Label('idle')
self.box.pack_start(self.label, True, True, 0)

self.progressbar = Gtk.ProgressBar()
self.box.pack_start(self.progressbar, True, True, 0)

self.button = Gtk.Button(label='Start')
self.button.connect('clicked', self.on_button_clicked)
self.box.pack_start(self.button, True, True, 0)

self.window.show_all()
gobject.threads_init()

Gdk.threads_enter()
Gtk.main()
Gdk.threads_leave()

def working1():
self.label.set_text('working1')
t = Process.Heavy()
t.heavyworks1()
self.label.set_text('idle')

def on_button_clicked(self, widget):
Gdk.threads_enter()
working1()
Gdk.threads_leave()

if __name__ == '__main__':
gui = gui()

此代码将生成此图形用户界面: img

我有第二个模块来执行逻辑。

进程.py

import threading

class Heavy(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)

def heavyworks1(self):
#doing heavy works1
#return result

def heavyworks2(self, *param):
#doing heavy works2
#return result

当我执行它时,操作有效,但图形用户界面卡住了。如何做好?

编辑:

正如 user4815162342 所说,我将代码更改为:

from gi.repository import Gtk, Gdk, GLib
import Process
import gobject
import threading

class gui():
def __init__(self):
self.window = Gtk.Window()
self.window.connect('delete-event', Gtk.main_quit)

self.box = Gtk.Box()
self.window.add(self.box)

self.label = Gtk.Label('idle')
self.box.pack_start(self.label, True, True, 0)

self.progressbar = Gtk.ProgressBar()
self.box.pack_start(self.progressbar, True, True, 0)

self.button = Gtk.Button(label='Start')
self.button.connect('clicked', self.on_button_clicked)
self.box.pack_start(self.button, True, True, 0)

self.window.show_all()

gobject.threads_init()
GLib.threads_init()
Gdk.threads_init()
Gdk.threads_enter()
Gtk.main()
Gdk.threads_leave()

def init_progress(self, func, arg):
self.label.set_text('working1')
self.worker = threading.Thread(target=func, args=[arg])
self.running = True
gobject.timeout_add(200, self.update_progress)
self.worker.start()

def update_progress(self):
if self.running:
self.progressbar.pulse()
return self.running

def working(self, num):
Process.heavyworks2(num)
gobject.idle_add(self.stop_progress)

def stop_progress(self):
self.running = False
self.worker.join()
self.progressbar.set_fraction(0)
self.label.set_text('idle')

def on_button_clicked(self, widget):
self.init_progress(self.working, 100000)

if __name__ == '__main__':
gui = gui()

使用该代码,程序有时可以运行但有时会出现此错误。

1.

**
Gtk:ERROR:/build/buildd/gtk+3.0-3.4.2/./gtk/gtktextview.c:3726:gtk_text_view_validate_onscreen: assertion failed: (priv->onscreen_validated)
Aborted (core dumped)

2.

*** glibc detected *** python: free(): invalid next size (fast): 0x09c9f820 ***

3.

Segmentation fault (core dumped)

最佳答案

您实际上并没有启动线程,您只是实例化了一个可用于启动它的对象。完整的解决方案需要仔分割离 GUI 线程和工作线程之间的职责。你想要做的是:

  1. 在由 GUI 代码生成和连接的单独线程中进行繁重的计算。计算不应产生自己的线程,也不需要知道线程(当然,线程安全除外)。

  2. 线程完成后,使用gobject.idle_add() 告诉 GUI 可以撤消进度指示器。 (gobject.idle_add 是唯一可以从另一个线程安全调用的 GTK 函数。)

有了这样的设置,无论计算做什么,GUI 都保持充分的响应和进度条更新,并且 GUI 线程保证在计算完成时注意到。关于您当前代码的另外两点:

  • 实例化 threading.Thread 而不是继承它。这样你就不需要费心去实现 run() 了。不过,在这两种情况下,您都必须调用 thread.start() 来启动线程。

  • 不要调用 threads_enter()threads_leave(),除非您真的知道自己在做什么。请记住,只要您从单个线程(您初始化 GTK 的同一线程)调用所有 GTK 函数,就没问题。

这是实现上述建议的概念验证代码:

    def working1(self):
self.label.set_text('working1')
self.work_thread = threading.Thread(self.run_thread)
self.running = True
gobject.timeout_add(200, self.update_progress)
self.work_thread.start()
# the GUI thread now returns to the mainloop

# this will get periodically called in the GUI thread
def update_progress(self):
if self.running:
self.progressbar.pulse() # or set_fraction, etc.
return self.running

# this will get run in a separate thread
def run_thread(self):
Process.heavyworks1() # or however you're starting your calculation
gobject.idle_add(self.stop_progress)

# this will get run in the GUI thread when the worker thread is done
def stop_progress(self):
self.running = False
self.work_thread.join()
self.label.set_text('idle')

关于python - 如何在 gtk3-python 中执行后台任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16934087/

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