Update a Gtk.ProgressBar from another thread or process

后端 未结 2 1076
挽巷
挽巷 2021-01-03 11:11

I have a GUI with a progressbar. It should show the progress of the work a second thread does. I would like to have something like an event the thread can send to the GUIs p

相关标签:
2条回答
  • 2021-01-03 11:33

    Your implementation is correct. You are processing the threaded commands, sharing the feedback in a Queue, and updating the progressbar from the main loop via the GLib.timeout_add().

    Initially, this may seem like a complex way to do a simple progressbar update, but it is one of the only ways to spawn a child process and track the progress, all the while respecting the Gtk main loop.

    0 讨论(0)
  • 2021-01-03 11:36

    Based on the comments of my question I modified my example. Please use this with caution because it is still unclear for me if the solution is thread safe or not.

    I tried the GLib.idle_add() and removed my own timer and the queue. Attention: The docu is no correct about the signature/parameters of the methode. Originaly it is

    idle_add(function, *user_data, **kwargs)
    

    Possible solution for Threads

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

    What GLib.idle_add() does?

    I am not an expert or core developer of Gtk. In my understanding I would say you can _install__ event handler metodes into the Gtk main loop. In other words the second thread tells the Gtk main loop (which is the first thread) to call the givin methode when nothing else is todo (which is quit often in a GUI loop).

    There is no solution for Process because they run in a separate Python interpreter instance. There is no way to call GLib.idle_add() between two process.

    0 讨论(0)
提交回复
热议问题