我在Windows上遇到线程和PyGTK问题。根据{{3}}(以及我自己的实验),从子线程可靠地更新GUI的唯一方法是使用gobject.idle_add
函数。但是,调用此函数时无法保证。我怎样才能保证gobject.idle_add
之后的行在它指向的函数之后被调用?
非常简单和做作的例子:
import gtk
import gobject
from threading import Thread
class Gui(object):
def __init__(self):
self.button = gtk.Button("Click")
self.button.connect("clicked", self.onButtonClicked)
self.textEntry = gtk.Entry()
self.content = gtk.HBox()
self.content.pack_start(self.button)
self.content.pack_start(self.textEntry)
self.window = gtk.Window()
self.window.connect("destroy", self.quit)
self.window.add(self.content)
self.window.show_all()
def onButtonClicked(self, button):
Thread(target=self.startThread).start()
def startThread(self):
#I want these next 2 lines to run in order
gobject.idle_add(self.updateText)
print self.textEntry.get_text()
def updateText(self):
self.textEntry.set_text("Hello!")
def quit(self, widget):
gtk.main_quit()
gobject.threads_init()
x = Gui()
gtk.main()
答案 0 :(得分:2)
不要尝试从线程更新或访问GUI。你只是在寻找麻烦。例如,“get_text
”在线程中所有的事实几乎是偶然的。您可能可以在GTK中依赖它 - 虽然我甚至不确定 - 但您将无法在其他GUI工具包中这样做。
如果您确实需要在线程中执行操作,则应在启动线程之前从GUI 获取所需数据,然后使用{{1}从线程更新GUI },像这样:
idle_add
如果你真的,绝对需要在线程中间从GUI读取数据(这是一个非常糟糕的主意,不要这样做 - 你可以进入真正令人惊讶的死锁,特别是当程序关闭时)Twisted中有一个实用工具,blockingCallFromThread,它将为你付出艰苦的努力。您可以像这样使用它:
import time
import gtk
import gobject
from threading import Thread
w = gtk.Window()
h = gtk.HBox()
v = gtk.VBox()
addend1 = gtk.Entry()
h.add(addend1)
h.add(gtk.Label(" + "))
addend2 = gtk.Entry()
h.add(addend2)
h.add(gtk.Label(" = "))
summation = gtk.Entry()
summation.set_text("?")
summation.set_editable(False)
h.add(summation)
v.add(h)
progress = gtk.ProgressBar()
v.add(progress)
b = gtk.Button("Do It")
v.add(b)
w.add(v)
status = gtk.Statusbar()
v.add(status)
w.show_all()
def hardWork(a1, a2):
messages = ["Doing the hard work to add %s to %s..." % (a1, a2),
"Oof, I'm working so hard...",
"Almost done..."]
for index, message in enumerate(messages):
fraction = index / float(len(messages))
gobject.idle_add(progress.set_fraction, fraction)
gobject.idle_add(status.push, 4321, message)
time.sleep(1)
result = a1 + a2
gobject.idle_add(summation.set_text, str(result))
gobject.idle_add(status.push, 4321, "Done!")
gobject.idle_add(progress.set_fraction, 1.0)
def addthem(*ignored):
a1 = int(addend1.get_text())
a2 = int(addend2.get_text())
Thread(target=lambda : hardWork(a1, a2)).start()
b.connect("clicked", addthem)
gtk.gdk.threads_init()
gtk.main()
如果您想了解魔术是如何运作的,您可以随时read the source。
答案 1 :(得分:1)
您可以将这两个函数包装到另一个函数中,并在此函数上调用idle_add:
def update_and_print(self):
self.updateText()
print self.textEntry.get_text()
def startThread(self):
gobject.idle_add(self.update_and_print)