[英]Execution order with threads and PyGTK on Windows
我在 Windows 上遇到線程和 PyGTK 問題。根據PyGTK 常見問題解答(和我自己的實驗),從子線程可靠地更新 GUI 的唯一方法是使用gobject.idle_add
function。但是,它不能'無法保證何時調用此 function。 我如何保證在它指向的 function 之后調用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()
不要嘗試從線程更新或訪問您的 GUI。 你只是在自找麻煩。 例如,“ get_text
”在一個線程中工作幾乎是一個意外。 您可能可以在 GTK 中依賴它——盡管我什至不確定——但您將無法在其他 GUI 工具包中這樣做。
如果你有真正需要在線程中做的事情,你應該在啟動線程之前從 GUI 獲取你需要的數據,然后使用idle_add
從線程更新 GUI,如下所示:
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()
如果你真的,絕對需要在線程中間從 GUI 讀取數據(這是一個非常糟糕的主意,不要這樣做 - 你可能會陷入非常令人驚訝的死鎖,特別是當程序關閉時)有Twisted 中的一個實用程序blockingCallFromThread ,它將為您完成艱苦的工作。 你可以像這樣使用它:
from twisted.internet.gtk2reactor import install
install()
from twisted.internet import reactor
from twisted.internet.threads import blockingCallFromThread
from threading import Thread
import gtk
w = gtk.Window()
v = gtk.VBox()
e = gtk.Entry()
b = gtk.Button("Get Text")
v.add(e)
v.add(b)
w.add(v)
def inThread():
print 'Getting value'
textValue = blockingCallFromThread(reactor, e.get_text)
print 'Got it!', repr(textValue)
def kickOffThread(*ignored):
Thread(target=inThread).start()
b.connect("clicked", kickOffThread)
w.show_all()
reactor.run()
如果您想了解魔法是如何運作的,您可以隨時閱讀源代碼。
您可以將這兩個函數包裝到另一個 function 中,然后在這個 function 上調用 idle_add:
def update_and_print(self):
self.updateText()
print self.textEntry.get_text()
def startThread(self):
gobject.idle_add(self.update_and_print)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.