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()
这段代码将生成这个gui。
我有第二个模子,它将进行逻辑运算。
Process.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
当我执行这个操作时,操作成功了,但界面却冻结了。怎样才能做得好呢?
EDIT:
正如用户4815162342所说,我把我的代码改成这样。
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()
使用该代码,程序有时可以工作,但有时会出现这个错误。
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)
*** glibc detected *** python: free(): invalid next size (fast): 0x09c9f820 ***
Segmentation fault (core dumped)
2 个回答
0 人赞同
你实际上并没有开始 the thread, you only instantiated an object that can be used to 开始 it. A full solution requires a careful separation of responsibilities between your GUI thread and your worker thread(s). What you want to do is the following:
在单独的线程中做你的重计算,由GUI代码生成和加入。计算不应该产生自己的线程,也不需要意识到线程的存在(当然,除了是线程安全的)。
当线程完成后,使用gobject.idle_add()
来告诉GUI,进度指示器可以被撤回。(gobject.idle_add
是唯一一个可以从另一个线程安全调用的GTK函数。)
有了这样的设置,无论计算做什么,GUI都能保持完全的响应和进度条的更新,而且GUI线程保证在计算完成后能注意到。关于你目前的代码,还有两点。
Instantiate threading.Thread
instead of inheriting from it. That way you don't need to bother with implementing run()
. In both cases you have to call thread.start()
, though, to 开始 off the thread.
Don't call threads_enter()
and threads_leave()
, unless you真的知道您在做什么。只要记住,只要你从一个线程(你初始化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')