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

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

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

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

Python

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

Q&A

1回答

1564閲覧

tkinterでボタンを押してラベルを更新した3秒後にウィンドウを閉じたい

earlgrey914

総合スコア11

Tkinter

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

Python

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

0グッド

0クリップ

投稿2021/07/17 10:38

以下のようなコードがあり、clickedのメソッドにて
「ボタンが押されたらラベルを更新して3秒後にウィンドウを閉じる」
としたいのですが、ラベルが更新されず3秒後にウィンドウを閉じてしまいます。
どう実現したらよいでしょうか?

python

1from tkinter import * 2from tkinter import ttk 3import time 4 5#クリック動作(ボタンを押したらラベルを「clicked」に更新して、3秒後にウィンドウを閉じる 6def clicked(): 7 s.set("clicked") 8 root.after(3000,root.quit()) 9 10root = Tk() 11root.attributes('-topmost', True) 12root.title('test') 13 14#フレーム 15frame1 = ttk.Frame(root, padding=(5)) 16frame1.grid() 17 18#ボタン 19button1 = ttk.Button(frame1, text="button", compound=TOP, command=clicked) 20button1.grid(row=0, column=0) 21 22# ラベル 23s = StringVar() 24label1 = ttk.Label(frame1, textvariable=s) 25label1.grid(row=1, column=0) 26 27root.mainloop() 28

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

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

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

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

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

guest

回答1

0

7/18指摘箇所修整

私は趣味でtkinterを弄っている程度ですが、
参考になればと回答させていただきます。

root.after の待機中はroot.mainloop()も停止し、描画は更新されません。
そのため、質問者様のプログラムのままですと
StringVarを変更してもroot.afterで処理が一旦停止してしまいます。
結果、そのまま3000ms後にLabelが更新されるまでもなくroot.quit()が開始されるので、
ウィンドウが閉じてしまう、といった形になっています。

コメントにてteamikiさんからご指摘があり、ここは間違いでした。
root.after待機中でもmainloopは実行されるとのことです。

mainloopとは別に連続更新が必要な際は、
threadingを使用してtkでない方の処理を別スレッドに渡してしまうのがよいかと思います。
※root.mainloop()はthreadingで別スレッドに渡すとうまく動作しないのでその点は留意しておいてください
こちらも別スレッドからのGUI操作に関しては問題があるとの指摘を受けました。
詳細はコメントをご確認ください。

また、今回tkウィンドウを閉じるということでしたので
root.quit()ではなくroot.destroy()に変更しています。
quit()ではmainloopから抜けるのみで、rootは残り続けます。
一方、destroy()はmainloopを止めるだけでなくrootごと削除するため、
今回の目的にはdestroy合致していると思われます。

これを踏まえて変更を加えたプログラムが以下になります。

python

1from tkinter import * 2from tkinter import ttk 3 4#クリック動作(ボタンを押したらラベルを「clicked」に更新して、3秒後にウィンドウを閉じる 5def clicked(): 6 s.set("clicked") 7 root.after(3000, root.destroy) 8 9~~~以下、同様~~~

投稿2021/07/17 11:52

編集2021/07/18 05:57
Mikyrri

総合スコア15

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

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

teamikl

2021/07/18 04:39

> StringVarを変更してもroot.afterで処理が一旦停止してしまいます。 root.after は、タイマーに関数を登録するのみなので、 一旦停止するようなブロッキング処理ではありません。 停止(終了?)する直接の原因は quit がその場で呼ばれている為です。 「 quit() -> quit 」 で解消するはず。destroy が目的に一致するには同意です。 別スレッドから GUIを直接操作するのは、一般的にスレッドセーフな操作では有りません。 tkinter では問題なく通ることが多いですが、 稀な場合問題になる(タイミング次第で起こる再現の難しい問題)ことがあるため、 今回のような数秒後に~~を実行みたいなケースでは、 GUIライブラリが提供するタイマー(root.after) での処理が正着です。
Mikyrri

2021/07/18 05:50

ご指摘ありがとうございます。 root.afterに関して勘違いしていました。 スレッドからのGUI操作に関しましても、普段意識していなかったもので... 勉強になります。 回答の方も、指摘箇所の修整を行わせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問