对话框在线程中冻结整个应用程序,尽管使用了Gdk.threads_enter/leave()
我有一个应用程序,它在后台做一些事情。为了让用户知道进展,它会更新一些小部件。这部分是正常工作的。
但是,有时候在这个后台操作中会出现错误或者其他问题,这时就需要显示一个对话框来提示用户。这会导致我的整个应用程序都卡住,尽管我已经用线程锁来处理所有事情。下面是一个代码示例,正好展示了我遇到的问题:
import threading, time
from gi.repository import Gtk, Gdk
def background(label, parent):
for t in range(5):
label.set_text(str(t))
time.sleep(1)
Gdk.threads_enter()
dlg = Gtk.MessageDialog(
type=Gtk.MessageType.INFO,
buttons=Gtk.ButtonsType.OK,
message_format="Time is gone.",
title="Info")
dlg.run()
dlg.destroy()
Gdk.threads_leave()
def main():
window = Gtk.Window()
window.connect("delete-event", Gtk.main_quit)
label = Gtk.Label()
window.add(label)
window.show_all()
thread = threading.Thread(target=background, args=(label, window))
Gdk.threads_init()
Gdk.threads_enter()
thread.start()
Gtk.main()
Gdk.threads_leave()
if __name__=="__main__":
main()
1 个回答
3
在gtk3中,所有像添加、删除或更改控件的操作都必须在gtk线程中执行,也就是运行Gtk.main()
的那个线程。
修正后的代码:
import threading, time
from gi.repository import Gtk, Gdk, GLib # need GLib for GLib.PRIORITY_DEFAULT
# a short utility function that I like to use.
# makes the Gtk thread execute the given callback.
def add_mainloop_task(callback, *args):
def cb(args):
args[0](*args[1:])
return False
args= [callback]+list(args)
Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT, cb, args)
def background(label, parent):
for t in range(5):
#~ label.set_text(str(t)) # let the gtk thread do this.
add_mainloop_task(label.set_text, str(t))
time.sleep(1)
#~ Gdk.threads_enter() # don't need this.
dlg = Gtk.MessageDialog(
type=Gtk.MessageType.INFO,
buttons=Gtk.ButtonsType.OK,
message_format="Time is gone.",
title="Info")
# put these two functions calls inside a little function, and let the gtk thread execute it.
def run_dialog(dlg):
dlg.run()
dlg.destroy()
add_mainloop_task(run_dialog, dlg)
#~ Gdk.threads_leave() # don't need this.
def main():
window = Gtk.Window()
window.connect("delete-event", Gtk.main_quit)
label = Gtk.Label()
window.add(label)
window.show_all()
thread = threading.Thread(target=background, args=(label, window))
Gdk.threads_init()
#~ Gdk.threads_enter() # don't need this.
thread.start()
Gtk.main()
#~ Gdk.threads_leave() # don't need this.
if __name__=="__main__":
main()