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

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

詳細はこちら
Python 3.x

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

Tkinter

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

Python

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

Q&A

解決済

1回答

1681閲覧

Tkinterのエラーの対処方法がわからない

person

総合スコア224

Python 3.x

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

Tkinter

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

Python

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

0グッド

1クリップ

投稿2019/11/12 07:51

編集2019/11/12 08:07

#質問
少し前に このページ で、Tkinterのウィンドウを閉じたときにエラーが出てしまうという質問をしました。

この時のエラーについてはベストアンサーに致しました方の回答で解決できたのですが、そのプログラム(コードはほぼ同じ)を別のプログラムに使ってみたところ、まったく同じエラーが出てしまいました。(前回はVSCodeで実行したときのエラーメッセージを貼り付けたため表記に多少違いがありますが、書いてある内容は同じです)

エラーの特徴

  • プログラム実行時(Tkinterのウィンドウが表示される直前)にエラーメッセージが出る(前の質問はウィンドウを閉じたときだが、今回は開く直前)
  • このエラーが発生すると、日時表示されない
  • たまに、このエラーが発生することなく、日時表示も正常であるときもある(できるときとできないときの違いは分からない。もちろん同じソースコードである。)
  • main()に記述した内容は、期待通りに動作する

#エラーメッセージ(IDLEで実行)

=============== RESTART: /home/pi/デスクトップ/main.py =============== Exception in thread Thread-1: Traceback (most recent call last): File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner self.run() File "/usr/lib/python3.5/threading.py", line 862, in run self._target(*self._args, **self._kwargs) File "/home/pi/デスクトップ/main.py", line 53, in print_nowtime time_label["text"] = "{0:%Y/%m/%d %H:%M:%S}".format(now) File "/usr/lib/python3.5/tkinter/__init__.py", line 1349, in __setitem__ self.configure({key: value}) File "/usr/lib/python3.5/tkinter/__init__.py", line 1342, in configure return self._configure('configure', cnf, kw) File "/usr/lib/python3.5/tkinter/__init__.py", line 1333, in _configure self.tk.call(_flatten((self._w, cmd)) + self._options(cnf)) RuntimeError: main thread is not in main loop >>>

#利用したソースコード(実際はmain()の中身が違う)

import tkinter as tk import datetime import time import threading #ウィンドウ作成 win = tk.Tk() win.title("Tkinter Test") win.geometry("720x480") #現在日時を表示 time_label = tk.Label(win,text="") time_label.grid() #現在日時の更新 is_valid = True def print_nowtime(): while is_valid: now = datetime.datetime.now() time_label["text"] = "{0:%Y/%m/%d %H:%M:%S}".format(now) time.sleep(1) #動作が重くなるため #ThreadError対策 def on_closing(): global is_valid is_valid = False thread_1.join() # Windowを破棄 win.destroy() def main(): #ボタンが押されたらテキストボックス内のの文字列を表示 def push(): str = txtbox.get() print(str) txtbox.delete(0, tk.END) txtbox = tk.Entry() txtbox.grid() btn = tk.Button(win, text="click", command=push) btn.grid() if __name__ == "__main__": #時間表示と入力文字列表示を並行 try: thread_1 = threading.Thread(target=print_nowtime) thread_1.start() main() #とりあえず例外が生じたら弾く(試験的) except: print("except") win.protocol("WM_DELETE_WINDOW", on_closing) win.mainloop()

分かる方、もしくは何らかの見当がつく方、
回答よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

考えられるのは前回と全く逆でRoot Widget(Main Window)が生成される前にThread上から Label Widgetの書き換える処理がが動作してしまうことでしょうか。

試しに

Python

1def print_nowtime(): 2 time.sleep(1) #起動を遅くしてみる 3 while is_valid: 4 #省略

のように修正すると解決するかもしれません。


が、この際『Tkinterへのアスセスをmainloopからのみ行う』ように改造したほうが今後のことを考えると安全かもしれませんね。

簡単な実現方法としては
1. print_nowtime()関数での Labelの書き換えをやめて、Queueにて時間を main thread側に送信する

Python

1import queue 2 3# Queueを生成する 4message_queue = queue.Queue() 5def print_nowtime(): 6 while is_valid: 7 now = datetime.datetime.now() 8 # ここで Labelを書き換えるのはやめて、表示したいTextをQueueに書き込む 9 message_queue.put("{0:%Y/%m/%d %H:%M:%S}".format(now)) 10 time.sleep(1) #動作が重くなるため

2. Queueを受信してメッセージが合った場合に Labelに表示する部分を実装する

Python

1def check_queue(): 2 try: 3 # メッセージ受信 4 msg = message_queue.get(0) 5 time_label['text'] = msg 6 except queue.Empty: 7 pass

3. after()を使って、 上記の受信関数を mainloop(Main Thread上)から一定時間間隔でコールするようにする

Python

1def check_queue(): 2 try: 3 msg = message_queue.get(0) 4 time_label['text'] = msg 5 except queue.Empty: 6 pass 7 8 # 10ms後に再度この関数を呼ぶ(main thread上で動作) 9 win.after(10, check_queue) 10 11# 起動時に1度 main_loopからcheck_queue関数を呼ぶように設定 12win.after(0, check_queue)

を行うとかなり安定するのではないでしょうか。

以上、まとめるとこんな感じになります。

Python

1""" 2import tkinter as tk 3import datetime 4import time 5import threading 6import queue 7 8#ウィンドウ作成 9win = tk.Tk() 10win.title("Tkinter Test") 11win.geometry("720x480") 12 13#現在日時を表示 14time_label = tk.Label(win,text="") 15time_label.grid() 16 17 # Queueを生成 18message_queue = queue.Queue() 19 20#現在日時の更新 21is_valid = True 22def print_nowtime(): 23 while is_valid: 24 now = datetime.datetime.now() 25 # ここで Labelを書き換えるのはやめて、表示したいTextをQueueに書き込む 26 message_queue.put("{0:%Y/%m/%d %H:%M:%S}".format(now)) 27 time.sleep(1) #動作が重くなるため 28 29 30#ThreadError対策 31def on_closing(): 32 global is_valid 33 is_valid = False 34 thread_1.join() 35 # Windowを破棄 36 win.destroy() 37 38#Queueを確認しLabelを更新 39def check_queue(): 40 try: 41 msg = message_queue.get(0) 42 time_label['text'] = msg 43 except queue.Empty: 44 pass 45 46 # 10ms後に再度この関数を呼ぶ(main thread上で動作) 47 # 10msが適切かどうか不明なので別途調整してください 48 win.after(10, check_queue) 49 50def main(): 51 #ボタンが押されたらテキストボックス内のの文字列を表示 52 def push(): 53 str = txtbox.get() 54 print(str) 55 txtbox.delete(0, tk.END) 56 57 txtbox = tk.Entry() 58 txtbox.grid() 59 btn = tk.Button(win, text="click", command=push) 60 btn.grid() 61 62 63 64if __name__ == "__main__": 65 66 #時間表示と入力文字列表示を並行 67 try: 68 thread_1 = threading.Thread(target=print_nowtime) 69 thread_1.start() 70 main() 71 #とりあえず例外が生じたら弾く(試験的) 72 except: 73 print("except") 74 75 # 起動後すぐにcheck_queue関数を1度呼ぶように設定 76 win.after(0, check_queue) 77 78 win.protocol("WM_DELETE_WINDOW", on_closing) 79 win.mainloop()

投稿2019/11/12 09:51

magichan

総合スコア15898

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

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

person

2019/11/13 00:20

回答にあるように対処したところ、エラーが出なくなりました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問