1

Windows でスレッドと PyGTK に問題があります。PyGTK FAQ (および私自身の実験) によると、子スレッドから 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()

4

2 に答える 2

2

スレッドから 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 のブロッキングCallFromThread ユーティリティで、面倒な作業を代行してくれます。次のように使用できます。

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()

魔法がどのように機能するかを見たい場合は、いつでもソースを読むことができます.

于 2009-06-18T10:59:31.553 に答える