正确的方法使用PyGObject强制刷新GTK + 3中的窗口?

时间:2014-05-22 21:12:45

标签: pygtk gtk3 pygobject

我正在使用PyGObject在Python中编写我的第一个GTK + 3应用程序。

我有一个任务,我希望用户点击“开始”按钮然后我想要更新一个带有倒计时的文本字段,显示" 3"," 2",& #34; 1"," Go!"在两者之间暂停。

如果在按钮回调方法中我在暂停之间更改文本,它只显示我学到的最后一个更改,因为窗口只在重新回到主循环时重绘。我的想法是,我需要强迫它重绘。

我发现了一些旧的PyGTK示例:

while Gtk.events_pending():
    Gtk.main_iteration()

现在它有点工作,但它不会重新拉出未按下的按钮,直到显示2并且在不同的版本中它总是错过画出3.可能事件还没有待处理?我也不确定这是不是"正确的"做我想做的事情。我实际上有一堆线性任务需要在按下按钮后需要进行屏幕更新,这只是一个简单的例子。

以下是现在的代码:

from gi.repository import Gtk, GdkPixbuf, Gdk, GLib
import Image
import os, sys
import time

class GUI:
    def __init__(self):
        self.window=Gtk.Window()
        self.window.set_title("Countdown")
        self.window.set_border_width(10)
        self.window.connect_after('destroy', self.destroy)

        # main container of projct
        self.main_box=Gtk.VBox()
        self.main_box.set_spacing(5)

        # countdown label
        self.countdown_label = Gtk.Label()

        # start button
        self.start_button=Gtk.Button("Start!")

        # add the elements to the window
        self.window.add(self.main_box)
        self.main_box.pack_start(self.countdown_label, False, False, 0)
        self.main_box.pack_start(self.start_button, False, False, 0)

        # connect buttons
        self.start_button.connect_after('clicked', self.start_clicked)

        self.window.show_all()

    def start_clicked(self, button):
        # start the countdown
        count=3
        while count > 0:
            self.countdown(count)
            count = count - 1
            while Gtk.events_pending():
                Gtk.main_iteration()
            time.sleep(2)

        self.countdown_label.set_text("Go!")

    def countdown(self, count):
        self.countdown_label.set_text(str(count))
        print count
        return

    def destroy(window, self):
        Gtk.main_quit()

def main():
    app=GUI()
    Gtk.main()

if __name__ == "__main__":
    sys.exit(main())

1 个答案:

答案 0 :(得分:2)

在GTK +编程方面,需要使用Gtk.events_pending()和Gtk.main_iteration()通常是一个红旗。修复这个特定的例子,可以使用不阻塞主循环的异步超时[1]:

def start_clicked(self, button):
    self.countdown(3)

def countdown(self, count):
    if count > 0:
        self.countdown_label.set_text(str(count))
        # Manually re-add this callback with a decremented count.
        GLib.timeout_add_seconds(2, self.countdown, count - 1)
    else:
        self.countdown_label.set_text("Go!")

    # Return False so the callback is not called repeatedly
    # as we manually re-added the callback ourselves above.
    return False

在现实世界中,正如“一堆需要进行的线性任务”所述,答案取决于任务的类型。可能阻止UI的IO绑定任务可以使用Gio库来维护UI响应[2]。对于阻止UI的CPU绑定任务,Python线程[3]可以与使用Gdk.threads_add_idle或Gdk.threads_add_timeout [4]安排的UI更新回调结合使用。

另见:

  1. http://lazka.github.io/pgi-docs/api/GLib-2.0/functions.html#GLib.timeout_add_seconds
  2. http://lazka.github.io/pgi-docs/api/Gio-2.0/
  3. https://wiki.gnome.org/Projects/PyGObject/Threading
  4. http://lazka.github.io/pgi-docs/api/Gdk-3.0/functions.html#Gdk.threads_add_idle