GUI не обновляется из другого потока при использовании PyGtk
Я использую PyGTK для создания приложения с графическим интерфейсом. Я хочу обновить виджет textview из другого потока, но виджет не обновляется каждый раз, когда я пытаюсь обновить. Что я должен сделать, чтобы получить надежное обновление графического интерфейса?
4 ответа
GTK+ не является потокобезопасным, поэтому вам не следует просто вызывать методы обновления GUI из других потоков. Для этой цели можно использовать glib.idle_add (или gobject.idle_add в более старых версиях PyGTK).
Вместо того чтобы писать:
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
; в противном случае он снова будет поставлен в очередь.
Редактировать: как Дэниел указал, вам нужно позвонить gtk.gdk.threads_init()
сначала в любом месте вашей программы.
Как указывалось в предыдущих ответах, GTK не является "потокобезопасным", но он "поддерживает потоки" - см. Эту страницу в разделе "Потоки": http://library.gnome.org/devel/gdk/unstable/gdk-Threads.html.
Чтобы изменить виджеты GTK из другого потока, вы должны использовать блокировку GTK. Вызов gtk.threads_init()
сразу после импорта модуля gtk, а затем вы можете обновить его так:
gtk.threads_enter()
# make changes...
gtk.threads_leave()
Обратите внимание, что вышеописанное не будет работать в Windows (см. Ссылку выше). В Windows вы должны использовать gobject.idle_add()
как объяснено выше, но не забудьте поставить gobject.threads_init()
непосредственно после импорта gobject в ваш код! Функция idle_add() выполнит само обновление в основном потоке (потоке, выполняющем gtk.main()).
То же самое может быть достигнуто с помощью метода gobject.idle_add, синтаксис которого такой же, как и выше, вы должны импортировать модуль gobject
То, что сказал Йоханнес, верно, однако, поскольку GTK является оберткой для вещей glib и gobject, вы на самом деле захотите использовать gtk.idle_add(). Нет необходимости в ненужном импорте.