使用PyGtk时,GUI未从另一个线程更新

8 投票
4 回答
3906 浏览
提问于 2025-04-15 18:02

我正在用PyGTK来制作一个图形界面应用程序。我想从另一个线程更新文本视图这个小部件,但每次我尝试更新时,这个小部件并没有被更新。为了让图形界面能够可靠地更新,我该怎么做呢?

4 个回答

-1

你也可以使用 gobject.idle_add 这个方法来实现同样的效果,它的写法和上面的一样。不过你需要先导入 gobject 这个模块。

2

正如之前的回答所说,GTK并不是“线程安全”的,但它是“线程感知”的——你可以查看这个关于线程的页面:https://developer.gnome.org/gdk2/stable/gdk2-Threads.html

如果你想从另一个线程修改GTK的控件,你需要使用GTK的锁定机制。你应该在导入gtk模块后立即调用gtk.threads_init(),然后你可以像这样进行更新:

gtk.threads_enter()
# make changes...
gtk.threads_leave()

需要注意的是,上面的做法在Windows上是行不通的(请参见上面的链接)。在Windows上,你必须使用gobject.idle_add(),就像上面解释的那样,但别忘了在你的代码中导入gobject后立即调用gobject.threads_init()!idle_add()函数会在主线程中执行更新(也就是运行gtk.main()的那个线程)。

15

GTK+ 这个库本身不支持多线程,所以你不能直接从其他线程去调用更新界面的方法。你可以使用 glib.idle_add(在旧版的 PyGTK 中是 gobject.idle_add)来解决这个问题。

比如,你不应该写:

label.set_text("foo")

而是应该写:

glib.idle_add(label.set_text, "foo")

这样做会把这个函数调用放到 GTK+ 的队列中。

如果你需要执行多个语句,通常把它们放在一个函数里会更简单:

def idle():
    label1.set_text("foo")
    label2.set_text("bar")
glib.idle_add(idle)

要确保传给 idle_add 的函数不要返回 True; 否则它会再次被放入队列。

补充:正如 Daniel 提到的,你需要在程序的任何地方先调用 gtk.gdk.threads_init()

撰写回答