🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

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

Q&A

解決済

2回答

15365閲覧

Tkinterのエラーの対処方法がわかりません

person

総合スコア224

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

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

0グッド

1クリップ

投稿2019/10/29 06:10

編集2019/11/12 06:24

#質問
Tkinterでリアルタイムで時間を表示するプログラムを作ろうと思って、Threadを用いてプログラムを作ってみました。

実際動作を確認できたので良かったと思って終了した(Tkinterのウィンドウを閉じた)ところ、エラーが出てしまいました。

発生しているエラー(RuntimeError: main thread is not in main loop)は、英語の記事にはいくつか出ていて、destroy()を使う対処法(というよりはIDLEでのエラー表示をウィンドウを閉じることで、無かったことにしようとしている?)があったのですが、ターミナル等で実行するとやはりエラーメッセージが表示されるので、適切な対処方法を教えていただきたいです。

自分は、最初はThreadが原因かと思ったのですが、Threadを用いないと時間の表示ができないのでThreadは残しておこうと思いました。

#該当のソースコード

Python3

1 2import tkinter as tk 3import datetime 4import time 5import threading 6 7#ウィンドウ作成 8win = tk.Tk() 9win.title("Tkinter Test") 10win.geometry("720x480") 11 12#現在日時を表示 13time_label = tk.Label(win,text="") 14time_label.grid() 15 16#現在日時の更新 17def print_nowtime(): 18 while True: 19 now = datetime.datetime.now() 20 time_label["text"] = "{0:%Y/%m/%d %H:%M:%S}".format(now) 21 time.sleep(1) #動作が重くなるため 22 23 24def main(): 25 26 #ボタンが押されたらテキストボックス内のの文字列を表示 27 def push(): 28 str = txtbox.get() 29 print(str) 30 31 txtbox = tk.Entry() 32 txtbox.grid() 33 btn = tk.Button(win, text="click", command=push) 34 btn.grid() 35 36 37 38if __name__ == "__main__": 39 40 #時間表示と入力文字列表示を並行 41 try: 42 thread_1 = threading.Thread(target=print_nowtime) 43 thread_2 = threading.Thread(target=main) 44 thread_1.start() 45 thread_2.start() 46 #とりあえず例外が生じたら弾く(試験的) 47 except: 48 print("except") 49 win.mainloop() 50 51

#該当のエラー

PS C:\Users\user\Desktop> & C:/Users/user/AppData/Local/Programs/Python/Python37/python.exe c:/Users/user/Desktop/test.py Exception in thread Thread-1: Traceback (most recent call last): File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\threading.py", line 926, in _bootstrap_inner self.run() File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\threading.py", line 870, in run self._target(*self._args, **self._kwargs) File "c:/Users/user/Desktop/test.py", line 19, in print_nowtime time_label["text"] = "{0:%Y/%m/%d %H:%M:%S}".format(now) File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1492, in __setitem__ self.configure({key: value}) File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1485, in configure return self._configure('configure', cnf, kw) File "C:\Users\user\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1476, in _configure self.tk.call(_flatten((self._w, cmd)) + self._options(cnf)) RuntimeError: main thread is not in main loop

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

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

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

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

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

guest

回答2

0

二点問題があります。
一点目はすでに回答が出ている終了処理問題。
二点目は別のスレッドでUIメッセージを渡すような処理を行うと、以下のメッセージが出ることです。

RuntimeError: main thread is not in main loop

対策としては、以下のURLにあるように、UI操作を別スレッドで行わないようにすることしかありません。
https://stackoverflow.com/questions/54237067/how-to-make-tkinter-gui-thread-safe

[multithread tkinter]でググるとやり方がわかると思います。

それか動作環境が限られますが、適当なモジュールを使うとか。
https://pypi.org/project/tkthread/

投稿2019/10/29 09:27

t_obara

総合スコア5488

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

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

YUMA-NAGAO

2019/10/30 04:20

2点目の問題は、僕の環境では出なかったので、参考にさせていただきます!
guest

0

ベストアンサー

問題はWindowを破棄した後も、スレッドが動作し続けるためprint_nowtime 関数内より、すでに破棄されているtime_labelに対して書き込みが行われることです。

ですので対応としては、Windowが破棄されると同時に Threadを止める処理をいれることによりエラーは解決するかと思います。

具体的な方法としては

1. print_nowtime関数を外部から終了できるように

Python

1is_valid = True 2def print_nowtime(): 3 while is_valid: 4 now = datetime.datetime.now() 5 time_label["text"] = "{0:%Y/%m/%d %H:%M:%S}".format(now) 6 time.sleep(5) #動作が重くなるため

のように修正(is_validFalseにすることによってループを抜けるようにする)

2. Windowが破棄されたときにコールバック関数(on_closing())が呼ばれるように

Python

1win.protocol("WM_DELETE_WINDOW", on_closing)

を設定

3. 上記から呼ばれるコールバック関数内を

Python

1def on_closing(): 2 global is_valid 3 is_valid = False 4 thread_1.join() 5 thread_2.join() 6 # Windowを破棄 7 win.destroy()

のように記述し、Threadを停止する処理を入れる

のようにすると良いのではないでしょうか

あと質問とは全く関係ありませんが、main()関数はスレッドにする必要がないように思います。

投稿2019/10/29 08:49

magichan

総合スコア15898

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

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

person

2019/10/30 00:55

できました。ありがとうございます。 理解しました。 main()は普通に呼び出すことにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問