添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
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)
    
python
multithreading
user-interface
gtk
user2435611
user2435611
发布于 2013-06-05
2 个回答
user4815162342
user4815162342
发布于 2013-06-05
已采纳
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')