Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在gtk3 python中执行后台任务?_Python_Multithreading_User Interface_Gtk - Fatal编程技术网

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

如何在gtk3 python中执行后台任务?,python,multithreading,user-interface,gtk,Python,Multithreading,User Interface,Gtk,我有一条主线: Gui.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()

我有一条主线:

Gui.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()
此代码将生成以下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
当我执行此操作时,操作正常,但gui冻结。如何做好

编辑:

正如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()
有了这些代码,程序有时会运行,但有时会出现这种错误

一,

二,

三,


正如您所建议的,您需要为此启动另一个线程。python中的线程通常非常简单,但使用GUI时可能会变得棘手

这应该会有所帮助:

您实际上并没有启动线程,您只是实例化了一个可以用来启动它的对象。完整的解决方案需要在GUI线程和辅助线程之间仔细地划分职责。您希望执行以下操作:

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

  • 线程完成后,使用
    gobject.idle\u add()
    告诉GUI可以提取进度指示器。(
    gobject.idle\u add
    是唯一可以从另一个线程安全调用的GTK函数。)

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

    • 实例化
      threading.Thread
      ,而不是从中继承。这样,您就不必费心实现
      run()
      。在这两种情况下,您都必须调用
      thread.start()
      ,才能启动线程

    • 不要调用
      threads\u enter()
      threads\u 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')
    

    很好,我已经看到了,但是我错过的是GLib.threads\u init():D但是,既然heavyworks无法使用,如何使progressbar脉动?当我在某些东西仍在运行时单击该按钮时,为什么会出现此错误
    ***glibc检测到***python:double-free或corruption(!prev):0x09154320***
    ,还有另一个类似这样的错误
    Gtk:error:/build/buildd/Gtk+3.0-3.4.2//Gtk/gtktextview.c:3726:Gtk_text_view_-validate_-on-screen:assertion失败:(priv->-onscreen_-validated)中止(内核转储)
    谢谢,这是可行的,但有时我会出错。看看我的更新。啊,我知道我的问题。仍然有一些代码可以从我的线程访问gtk ui:p@user2435611很高兴听到。这个答案可能对其他尝试同样方法的人有用;如何正确地将PyGTK与线程一起使用还很不明显。另外,如果您的崩溃得到解决,请不要忘记回答您的问题并接受它。当我退出窗口时,您知道如何终止后台线程吗?我认为Python不支持终止线程。线程只能自动退出,因此您的工作线程需要不时检查“exit requested”标志。如果需要真正的异步终止,则需要生成一个子进程,并使用
    os.kill
    终止它。
    *** glibc detected *** python: free(): invalid next size (fast): 0x09c9f820 ***
    
    Segmentation fault (core dumped)
    
        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')