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

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

詳細はこちら
INSERT

INSERTとは、行を追加する、コンピュータのデータベース言語SQLにおけるデータ操作言語(DML)ステートメントの1つである

Tkinter

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

Python

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

Q&A

解決済

1回答

1660閲覧

.insertでの表示ががfor文の処理完了後に表示される

sasamata

総合スコア13

INSERT

INSERTとは、行を追加する、コンピュータのデータベース言語SQLにおけるデータ操作言語(DML)ステートメントの1つである

Tkinter

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

Python

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

0グッド

2クリップ

投稿2019/12/20 01:19

前提・実現したいこと

tkinterで表示ボックスを作りそこにメッセージなどを表示したいのですが、
for文の処理が終わってから表示されてしまいます。

コードからすると、表示が先に実行されその後for文内の処理が先に実行され、処理終了後表示がメッセージボックス内に表示されます。

何がおかしいのでしょうか?

該当のソースコード

-- coding: utf-8 --

import tkinter as tk
import time

def serial_data_recv():

box.insert(tk.END, "ループ分処理中……"+ "\n") t = 0 for t in range(10): box.insert(tk.END, t) time.sleep(0.5) print(t)

def quit_func():
root.destroy()

ウィンドウを作る

root = tk.Tk()
root.geometry("500x400")
root.title("温度計")

履歴表示のテキストボックスを作る

box = tk.Text(root, font=("MS ゴシック", 14))
box.place(x=200, y=0, width=600, height=400)

ボタンを作る

button1 = tk.Button(root, text = "測定開始", font=("MS ゴシック", 14),
command=serial_data_recv)
button1.place(x = 40, y = 26)

ボタンを作る

button2 = tk.Button(root, text = "測定終了", font=("MS ゴシック", 14),
command=quit_func)
button2.place(x = 40, y = 340)

ウィンドウを表示する

root.mainloop()

試したこと

表示用の命令を先頭に記述しましたが、変わりませんでした。

補足情報(FW/ツールのバージョンなど)

python3.7 win10

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

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

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

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

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

guest

回答1

0

ベストアンサー

serial_data_recv()内で time.sleep() の使用をやめて、after()を使用するようにすると良いかと思います。

Python

1#-*- coding: utf-8 -*- 2import tkinter as tk 3import time 4 5def serial_data_recv(): 6 7 box.insert(tk.END, "ループ分処理中……"+ "\n") 8 9 t = 0 10 def countup(): 11 nonlocal t 12 box.insert(tk.END, t) 13 t = t+1 14 if t < 10: 15 root.after(500, countup) 16 17 root.after(0, countup) 18 19def quit_func(): 20 root.destroy() 21 22# ウィンドウを作る 23root = tk.Tk() 24root.geometry("500x400") 25root.title("温度計") 26 27# 履歴表示のテキストボックスを作る 28box = tk.Text(root, font=("MS ゴシック", 14)) 29box.place(x=200, y=0, width=600, height=400) 30 31# ボタンを作る 32button1 = tk.Button(root, text = "測定開始", font=("MS ゴシック", 14), 33command=serial_data_recv) 34button1.place(x = 40, y = 26) 35 36# ボタンを作る 37button2 = tk.Button(root, text = "測定終了", font=("MS ゴシック", 14), 38command=quit_func) 39button2.place(x = 40, y = 340) 40 41# ウィンドウを表示する 42root.mainloop()

【補足】

一応簡単に説明を加えます。

コードの最後の root.mainloop() の部分ですが、この関数の内部では、

  • tk内のイベントの捕捉
  • イベントに対応した適切な処理の呼び出し
  • Windowの描画の更新処理

などを繰り返す無限ループ(イベントループなどと呼ばれる)のような実装となっております。

で、今回問題となっている、serial_data_recv()ですが、この関数も当然mainloopよりボタンを押されたイベントの処理として呼ばれております。

しかしながら、質問のコードのようにコールバック関数内で時間のかかる処理(今回の場合はsleep()を含むループ処理)を行ってしまいますと、mainloop自体が回らずに処理が滞ってしまいますので、その結果として描画が更新されない状態になってしまいます(今回の不具合の原因)。

ですので、コールバック関数内でsleep()を含むループ処理を行うのではなく、一旦処理をmainloopに戻した上で、after()を使って一定時間後に再度イベントコー ルをしてもらうような実装を行うことで、mainloop内の処理が滞ることがなくなり、スムーズに描画がされるようになるかと思います。

投稿2019/12/20 04:15

編集2019/12/20 04:41
magichan

総合スコア15898

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

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

sasamata

2019/12/20 04:32

ありがとうございます。解決できました。 for文や、while文で回すのではなく、afterとif文を組み合わせれば良いのですね。
magichan

2019/12/20 04:41

あまりにも説明が・・・だったので、補足を加えました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問