2

イベント コールバックには次のようなコードがあります。

...
self.position.side = -self.position.side
self.update_with_board() # displays self.position graphically
ai_move = self.brain.get_move(self.position)
...

update() はすぐに呼び出されますが、行まで GUI には影響しませんai_move

しかし、私がするとき:

...
self.position.side = -self.position.side
self.update_with_board() # displays self.position graphically
raw_input()
ai_move = self.brain.get_move(self.position)
...

入力を求めるとすぐにグラフィカルに更新されます。これをどうすればいいのかわからない: ファンキーな遅延評価か、私が知らない tkinter スケジューリングか? 遅延ではなく、指定された順序で GUI を更新するにはどうすればよいですか?

編集: 申し訳ありませんが、組み込みupdate()メソッドを使用していませんでしたが、描画するように定義したメソッドを使用していました。名前を変更しましたupdate_with_board()が、同じ動作が見られます。

def update_with_board(self):
    for i in range(8):
        for j in range(8):
            color = "gray" if (i+j) % 2 else "white"
            self.canvas.create_rectangle(self.square * i, self.square * j, self.square * (i+1), self.square * (j+1), fill=color)
            if self.position.board[8 * j + i] in self.ims.keys():
                self.canvas.create_image(self.square * i + self.square/2,
                self.square * j + self.square/2, image = self.ims[self.position.board[8 * j + i]])  
4

1 に答える 1

3

もう少し調査を行うと、私のコメントは正しいと確信しています。

UI は、イベント ループのたびに必要に応じてすべてのウィジェットを更新します。呼び出しupdateは、基本的にイベントループを実行するよう強制するだけです。そのため、イベント コールバックの途中にいる場合は、再帰的にイベント ループに入ることになります。これは非常に悪いことであり、無限再帰につながる可能性があります。

TkInter Bookが言うようにupdate

保留中のすべてのイベントを処理し、イベント コールバックを呼び出し、保留中のジオメトリ管理を完了し、必要に応じてウィジェットを再描画し、保留中のすべてのアイドル タスクを呼び出します。このメソッドは注意して使用する必要があります。間違った場所 (たとえば、イベント コールバック内から、または何らかの方法でイベント コールバックから呼び出すことができる関数など) から呼び出されると、本当に厄介な競合状態につながる可能性があるためです。 .)。疑わしい場合は、代わりに update_idletasks を使用してください。

同様に、TkInter リファレンスには次のように書かれています。

このメソッドは、表示の更新を強制します。予期しない動作やループが発生する可能性があるため、何をしているのかがわかっている場合にのみ使用してください。イベント コールバックまたはイベント コールバックから呼び出される関数から呼び出すことはできません。

物事をテストしてみると、少なくとも場合によってはupdate、イベント ループ内から呼び出したときに TkInter が無視するようです。おそらく無限再帰から保護するためですが、それを確認するためにコードを調べていません。

とにかく、これはあなたが望む機能ではないので、文書化されていないことを正確に実行していない理由は問題ではありません。

イベント コールバック内から更新をトリガーする必要がある場合は、 を呼び出しますupdate_idletasks。これは、イベント コールバックを呼び出すことなく、再描画を含むすべての保留中の「アイドル」タスクを実際に呼び出します。(「次にイベント ループに入って他に何もすることがないときに更新する」ではありません。)

一方、raw_inputイベント コールバック内での呼び出しはさらに悪いことです。ターミナル入力でメイン イベント ループをブロックしています。これがデバッグ目的で行ったものでない限り、それは非常に悪い考えです。また、デバッグ目的であっても、テストするのは非常に奇妙なことであり、何が起こっても通常の動作とは無関係である可能性が非常に高いです。

背景の詳細​​については、質問TkInter: How do widgets updateを参照するか、このサイトで検索update_idletasksするか、右側の関連リンクのいくつかを参照してください (少なくとも 2 つが関連しています)。

あなたの編集に基づいて、結局のところ、あなたには逆の問題があったようです.TkInterに何もするように指示せずに物事を変更しただけなので、変更はイベントを通じて次回まで現れませんでした.ループします (つまり、この関数から戻るまでは実行されません)。しかし、答えは基本的に同じです。一方の方法は「呼び出しをに置き換えるupdateupdate_idletasksであり、もう一方の方法は「呼び出しを追加するupdate_idletasks」です。

于 2012-12-10T05:39:00.997 に答える