Gtk widget shows up with delay

蓝咒 提交于 2020-01-06 10:53:10

问题


Using python3 and gi.repository, I want to have a Gtk.HeaderBar with a Gtk.Button that is replaced by a Gtk.Spinner as soon as you click on it. After a calculation the button should appear again.

Here is an example of how I think it should work but the Gtk.Spinner only shows up after the calculation (in this example sleep) for a very short time. How can I achieve that the spinner shows up for the whole calculation (or sleep)?

from gi.repository import Gtk
import time

class window:
    def __init__(self):
        self.w = Gtk.Window()
        self.button = Gtk.Button('x')
        self.button.connect('clicked', self.on_button_clicked)
        self.spinner = Gtk.Spinner()
        self.hb = Gtk.HeaderBar()
        self.hb.props.show_close_button = True
        self.hb.pack_start(self.button)
        self.w.set_titlebar(self.hb)
        self.w.connect('delete-event', Gtk.main_quit)
        self.w.show_all()

    def on_button_clicked(self, widget):
        self.button.hide()
        self.hb.pack_start(self.spinner)
        self.spinner.show()
        self.spinner.start()
        time.sleep(5)
        self.spinner.stop()
        self.hb.remove(self.spinner)
        self.button.show()

if __name__ == '__main__':
    w = window()
    Gtk.main()

回答1:


GTK+ is an event driven system where the mainloop should be left free to update the UI and everything that takes time (like reading from a file, making a network connection, long calculations) should happen asynchronously.

In your case this would look something like this:

def on_button_clicked(self, widget):
    self.button.hide()
    self.spinner.show()
    self.spinner.start()
    GLib.timeout_add_seconds (5, self.processing_finished)

def processing_finished(self):
    self.spinner.stop()
    self.spinner.hide()
    self.button.show()

Note that I removed the pack and remove calls: do those in __init__(). You'll want from gi.repository import GLib in there as well.

This way the main loop is free to update the UI as often as it wants. If you really want to use a blocking call like sleep(), then you'll need to do that in another thread, but my suggestion is to use libraries that are asychronous like that timeout_add_seconds() call.




回答2:


The problem is time.sleep(): it is a blocking function.

def on_button_clicked(self, widget):
    self.button.hide()
    self.hb.pack_start(self.spinner)
    self.spinner.show()
    self.spinner.start()
    t = time.time()
    while time.time() - t < 5:
        Gtk.main_iteration()
    self.spinner.stop()
    self.hb.remove(self.spinner)
    self.button.show()

I think that's what you expect.

Edit: You may put a time.sleep(.1) inside while loop, for cpu saving, but don't forget Gtk.main_iteration(): that is the function that exit from while loop to main loop (show spinner, progress bar and so on).



来源:https://stackoverflow.com/questions/24272293/gtk-widget-shows-up-with-delay

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!