144

私の弟はプログラミングを始めたばかりで、サイエンス フェアのプロジェクトで、空を飛ぶ鳥の群れのシミュレーションを行っています。彼はほとんどのコードを書き終えており、うまく機能していますが、鳥は刻一刻と動く必要があります。

ただし、Tkinter は独自のイベント ループに時間を浪費するため、彼のコードは実行されません。実行root.mainloop()し、実行し、実行し続けます。実行されるのはイベント ハンドラーだけです。

彼のコードをメインループと並行して実行する方法はありますか (マルチスレッドを使用しないと混乱するため、単純にする必要があります)。

move()現在、彼は自分の関数をに結び付け<b1-motion>て、ボタンを押したままマウスを小刻みに動かしている限り機能するようにする、醜いハックを思いつきました。しかし、もっと良い方法があるはずです。

4

5 に答える 5

168

オブジェクトでafterメソッドを使用します。Tk

from tkinter import *

root = Tk()

def task():
    print("hello")
    root.after(2000, task)  # reschedule event in 2 seconds

root.after(2000, task)
root.mainloop()

afterメソッドの宣言とドキュメントは次のとおりです。

def after(self, ms, func=None, *args):
    """Call function once after given time.

    MS specifies the time in milliseconds. FUNC gives the
    function which shall be called. Additional parameters
    are given as parameters to the function call.  Return
    identifier to cancel scheduling with after_cancel."""
于 2009-01-19T20:55:36.543 に答える
70

Bjorn によって投稿されたソリューションにより、私のコンピューター (RedHat Enterprise 5、python 2.6.1) で「RuntimeError: Calling Tcl from different appartment」というメッセージが表示されます。Bjorn はこのメッセージを受け取っていない可能性があります。私が確認したある場所によると、Tkinter でのスレッドの誤った処理は予測不可能であり、プラットフォームに依存しているためです。

app.start()アプリにはTk要素が含まれているため、問題はTkへの参照としてカウントされるようです。app.start()これをself.start()insideに置き換えることで修正しました__init__。また、すべての Tk 参照が、呼び出す関数mainloop()内にあるか、または呼び出す関数によって呼び出される関数内にあるようにしましmainloop()た(これは、「異なるアパートメント」エラーを回避するために明らかに重要です)。

最後に、コールバックを含むプロトコル ハンドラを追加しました。これがないと、ユーザーが Tk ウィンドウを閉じたときにプログラムがエラーで終了するためです。

改訂されたコードは次のとおりです。

# Run tkinter code in another thread

import tkinter as tk
import threading

class App(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.start()

    def callback(self):
        self.root.quit()

    def run(self):
        self.root = tk.Tk()
        self.root.protocol("WM_DELETE_WINDOW", self.callback)

        label = tk.Label(self.root, text="Hello World")
        label.pack()

        self.root.mainloop()


app = App()
print('Now we can continue running code while mainloop runs!')

for i in range(100000):
    print(i)
于 2009-12-02T18:55:46.127 に答える
26

シミュレーションのように(私が推測する)独自のループを作成するときは、変更内容でウィンドウを更新updateする関数を呼び出す必要がありmainloopますが、ループ内で実行します。

def task():
   # do something
   root.update()

while 1:
   task()  
于 2011-01-29T09:35:20.837 に答える
8

もう 1 つのオプションは、tkinter を別のスレッドで実行させることです。それを行う1つの方法は次のとおりです。

import Tkinter
import threading

class MyTkApp(threading.Thread):
    def __init__(self):
        self.root=Tkinter.Tk()
        self.s = Tkinter.StringVar()
        self.s.set('Foo')
        l = Tkinter.Label(self.root,textvariable=self.s)
        l.pack()
        threading.Thread.__init__(self)

    def run(self):
        self.root.mainloop()


app = MyTkApp()
app.start()

# Now the app should be running and the value shown on the label
# can be changed by changing the member variable s.
# Like this:
# app.s.set('Bar')

ただし注意してください。マルチスレッド プログラミングは難しく、本当に簡単に自分を傷つけてしまいます。たとえば、上記のサンプル クラスのメンバー変数を変更するときは、Tkinter のイベント ループを中断しないように注意する必要があります。

于 2009-02-11T20:14:55.167 に答える