2009-07-29 36 views
5

になっているとき、ここでこのコードの作品はTkinterには、アイコンがロードされ、tk.mainloopスレッド

import Tkinter as tk 
import thread 
from time import sleep 

if __name__ == '__main__': 
    t = tk.Tk() 
    thread.start_new_thread(t.mainloop,()) 
    # t.iconbitmap('icon.ico') 

    b = tk.Button(text='test', command=exit) 
    b.grid(row=0) 

    while 1: 
     sleep(1) 

...テストケースだのPythonをロックします。 t.iconbitmap行のコメントを外し、ロックします。あなたが好きな方法でそれを再配置してください。それはロックされます。

アイコンがある場合、GILをロックするtk.mainloopを防止するにはどうすればよいですか?

対象はwin32とPython 2.6.2です。

答えて

16

メインループを別のスレッドで実行しないでください。 AFAIKでは、メインループはウィジェットを作成したのと同じスレッドで実行する必要があります。

私が慣れ親しんだGUIツールキット(Tkinter、.NET Windows Forms)はそういったものです。GUIはあるスレッドからのみ操作できます。以下の

 
self.tk.mainloop(n) 
RuntimeError: Calling Tcl from different appartment 

一つは動作します(余分なスレッド):

if __name__ == '__main__': 
    t = tk.Tk() 
    t.iconbitmap('icon.ico') 

    b = tk.Button(text='test', command=exit) 
    b.grid(row=0) 

    t.mainloop() 

余分な糸で:

def threadmain(): 
    t = tk.Tk() 
    t.iconbitmap('icon.ico') 
    b = tk.Button(text='test', command=exit) 
    b.grid(row=0) 
    t.mainloop() 


if __name__ == '__main__': 
    thread.start_new_thread(threadmain,()) 

    while 1: 
     sleep(1) 

Linuxの

は、あなたのコードは、例外を発生させます

コミュニケーションが必要な場合tkinterスレッドの外部からのtkinterで、作業のためにキューをチェックするタイマーを設定することをお勧めします。ここで

は一例です:

import Tkinter as tk 
import thread 
from time import sleep 
import Queue 

request_queue = Queue.Queue() 
result_queue = Queue.Queue() 

def submit_to_tkinter(callable, *args, **kwargs): 
    request_queue.put((callable, args, kwargs)) 
    return result_queue.get() 

t = None 
def threadmain(): 
    global t 

    def timertick(): 
     try: 
      callable, args, kwargs = request_queue.get_nowait() 
     except Queue.Empty: 
      pass 
     else: 
      print "something in queue" 
      retval = callable(*args, **kwargs) 
      result_queue.put(retval) 

     t.after(500, timertick) 

    t = tk.Tk() 
    t.configure(width=640, height=480) 
    b = tk.Button(text='test', name='button', command=exit) 
    b.place(x=0, y=0) 
    timertick() 
    t.mainloop() 

def foo(): 
    t.title("Hello world") 

def bar(button_text): 
    t.children["button"].configure(text=button_text) 

def get_button_text(): 
    return t.children["button"]["text"] 

if __name__ == '__main__': 
    thread.start_new_thread(threadmain,()) 

    trigger = 0 
    while 1: 
     trigger += 1 

     if trigger == 3: 
      submit_to_tkinter(foo) 

     if trigger == 5: 
      submit_to_tkinter(bar, "changed") 

     if trigger == 7: 
      print submit_to_tkinter(get_button_text) 

     sleep(1) 
+2

さてあなたは、それが動作...頭の上に釘を打ってきましたが、私は十分な情報を提供していないに苦しんできました。 私の推論は、whileループがどこにあるのかをtkinterに任せたいと思っています... 私はあなたの答えを受け入れて、別の、もっと冗長な質問をするべきですか? – burito

+2

こんにちは、私はこれを達成するための提案とコードの例で私の答えを更新しました。 whileループは、要求/応答キューを使用して、tkinterスレッド上でいくつかのメソッドを呼び出します。 – codeape

+2

ところで、プロダクションコードでは、Tkinterウィンドウ、スレッド、およびキューをクラスにカプセル化することをお勧めします。これは、現在のグローバルを避けるためです:request_queue、response_queue、およびt。また、callable(* args、** kwargs)に関するいくつかのエラー処理が必要です。 – codeape

関連する問題