質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

5771閲覧

Python(TkInter) 関数側でカーソルの変更を行っても即座に反映しない

saya24

総合スコア247

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/05/12 13:20

Python

1# モーダルウィンドウ 2self.dialog['cursor'] = 'hand2' 3self.this = self.dialog 4 5 6 7# WebAPIアクセス 8 def webAPI(self): 9 self.this['cursor'] = 'watch' # ★関数起動後にすぐさまカーソルが変わることを期待したが... 10 # 割愛 11 # 割愛 WebAPI/DataBase データ取得で時間を要す 12 # 割愛 13 self.this['cursor'] = 'hand2'

モーダルウィンドウ上のボタン押下(CallBack)から上記関数を実行しており、関数の起動直後にカーソルを変更している認識です。
当方Windows10ですが、クルクル廻るカーソルが現れません。
時間のかかる関数の本質の部分の前後で、カーソルを変更させる配慮をしたつもりですが変化がありません。

何が悪いのでしょう?? こういうものとして 諦めるべきでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

webAPI関数はどのように呼び出してますか?self.this は何でしょう?
対象のウィジェットによっては期待通りの動作をすることも有るようですが

問題の原因は、
cursor の設定自体は設定値の変更に過ぎず、
実際に描写が変更されるのは、イベント処理で呼び出される関数の実行が終わり
処理がメインループに移った時になります。

tkinterのmainloop() のイベントループが、
マウスやボタンクリック時のイベント呼び出しや
描画の更新等を担っています。

これは単一のスレッドで順番に実行されている為、
イベント内で時間のかかる処理をすると、
一時的に他のイベントが処理されなくなり
ウィンドウが操作を受け付けなくなったり、固まった状態に陥ったりします。

一時的な回避策としては、明示的に描画の更新処理を呼び出す事です。

def webAPI(self): self.this['cursor'] = 'watch' self.update() # <-- これで明示的に描画更新できますが # 時間のかかる処理 ... この間描画は更新されない。 # ウィンドウも操作を受け付けない状態になります self.this['cursor'] = 'hand2'

時間のかかる処理は別スレッド等で行うようにすると、
ウィンドウの操作が固まる状態も解決できます。この場合であれば、

  • 解決案1) webAPI()関数自体をスレッドで呼ぶように変更
  • 解決案2) cursor変更の間の処理の身をスレッドで実行する
    この場合、終了時のカーソル変更は別の場所で行うことになります。

他に、非同期IOを使うといった方法もありますが、
tkinter での事例が少ないのでお勧めはし辛いです。


一時的な回避策

python

1import time 2import tkinter as tk 3from tkinter import ttk 4 5root = tk.Tk() 6def onClick(): 7 button['state'] = 'disable' 8 root['cursor'] = 'watch' 9 time.sleep(0.01) # <--- 少し待ってから。(これがないと複数回試したときに描画更新されないことあり) 10 root.update() # <--- 描画更新 11 12 time.sleep(5) # <--- 時間のかかる処理 13 14 button['state'] = 'normal' 15 root['cursor'] = 'hand1' 16button = ttk.Button(root, text="OK", command=onClick) 17button.pack() 18root.mainloop()

時間のかかる処理をスレッドで実行

python

1 2import time 3import tkinter as tk 4from tkinter import ttk 5from threading import Thread 6from contextlib import contextmanager 7 8DEFAULT_BUTTON_TEXT = "OK" 9 10@contextmanager 11def on_busy_task(root, button): 12 # 前準備と後始末 13 try: 14 button['state'] = 'disable' 15 button["text"] = "Running..." 16 root['cursor'] = 'watch' 17 yield 18 finally: 19 button['state'] = 'normal' 20 button["text"] = DEFAULT_BUTTON_TEXT 21 root['cursor'] = 'hand1' 22 23def heavyTask(root, button): 24 with on_busy_task(root, button): 25 time.sleep(5) # <-- 時間のかかる処理 26 27def onClick(): 28 thread = Thread(target=heavyTask, args=(root, button), daemon=True) 29 thread.start() 30 31root = tk.Tk() 32button = ttk.Button(root, text=DEFAULT_BUTTON_TEXT, command=onClick) 33button.pack() 34root.mainloop()

投稿2020/05/12 14:23

編集2020/05/12 14:24
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

saya24

2020/05/12 23:52

いつもご支援をありがとうございます。 >webAPI関数はどのように呼び出してますか?self.this は何でしょう? requestを予めインポートしておき、関数の中ではrequests.postでURLへアクセスすることを行っています。 self.thisは モーダルウィンドウを定義づける部分で self.this=selef.dialog のコードから格納してます。 超親切にご説明を頂いたのですが、self.update()  でもう大満足の結果を得られましたよ。 今後の開発に役立てられるよう 後続部分も解読しておきます.... ありがとうございました。
teamikl

2020/05/13 02:58

知りたかった部分は、webAPI関数が既にスレッドで呼ばれていたのか メインループは動いてるがカーソルが変更されないとなると別問題なので、 念の為に確認した次第でした。後続部分は余談程度に・・・ 数秒程度の待ち時間ならメインループが止まっても気になりませんが、 問題は数分規模の待ち時間が発生し、処理の中断を行いたいとなった場合、 中断の操作をしようにも、メインループが止まっているとGUIが入力を受け付けない状態なので、 マルチスレッド/プロセスや非同期といった手法が必要になってきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問