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

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

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

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

Tkinter

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

Python

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

Q&A

2回答

2852閲覧

Tkinterのテキストボックス内に1秒に1回自動で文字を出力したいが、まとめて出力されてしまう

S.Nimura

総合スコア0

Python 3.x

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

Tkinter

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

Python

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

0グッド

0クリップ

投稿2020/08/23 11:23

前提・実現したいこと

・Tkinterで実行ボタン、閉じるボタン、テキストボックスから成るGUIを構成

・実行ボタンを押すと、1秒に1回リアルタイムにテキストが出力されるようにしたい
(例えばサーバから1秒に1回データを取得し、結果を表示したい)

発生している問題

・文字を出力するループ(今回の場合、while i < 3)が終了するまで文字が出力されない
→リアルタイムという条件に合わない

・文字がまとめて出力されてしまう
→1秒に1回出力という条件に合わない

該当のソースコード

Python

1# -*- coding: utf-8 -*- 2 3from tkinter import * 4import tkinter as tk 5from tkinter import ttk 6import time 7 8#テキストボックスに文字を出力する関数です 9#文字を出力->改行->自動スクロール 10def print_text(text): 11 tx.insert(END, text) 12 tx.insert(END, "\n") 13 tx.see(END) 14 15#サーバに接続する関数ですが、質問簡単化のために割愛します 16#実行は1回のみです 17def connect_server(): 18 pass 19 20#サーバから文字列を取得する関数ですが、質問簡単化のために割愛します 21#実行は繰り返し行われます 22def get_text_from_server(): 23 pass 24 25#実行ボタンを押した際に実行されます 26#処理内容は以下の通りです 27#サーバに接続->文字列を取得->特定の文字列でなければwhile内を実行(例:end以外なら実行) 28#whileの中身:文字列を表示->1秒待機 29def conductMain(): 30 connect_server() 31 i = 0 32 #実際はサーバから特定の文字列を取得した際に終了しますが、 33 #今回は簡単化のために3回実行したら終了するようにしています 34 while i < 3: 35 print_text(i) 36 time.sleep(1) 37 i += 1 38 39if __name__ == "__main__": 40 41 root = Tk() 42 root.title("サンプル") 43 44 frame3 = ttk.Frame(root, padding=10) 45 frame3.grid(row=0,column=1,sticky=W) 46 47 button1 = ttk.Button(frame3, text="実行", command=conductMain) 48 button1.pack(fill = "x", padx=30, side = "left") 49 50 button2 = ttk.Button(frame3, text=("閉じる"), command=root.quit) 51 button2.pack(fill = "x", padx=30, side = "left") 52 53 frame4 = ttk.Frame(root, padding = 10) 54 frame4.grid(row=2,column=1,sticky=E) 55 56 sc = tk.Scrollbar(frame4) 57 sc.pack(side = RIGHT, fill = "y") 58 59 tx = tk.Text(frame4, width = 48, height = 5) 60 tx.pack() 61 62 tx["yscrollcommand"] = sc.set 63 sc["command"] = tx.yview 64 65 root.mainloop()

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

環境
・Windows10(64bit Home)
・Spyder(Python 3.7)

お手数ですが、上述の質問へご回答いただければ幸いです。

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

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

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

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

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

guest

回答2

0

afterだけでなく update を挟みました

Python

1# -*- coding: utf-8 -*- 2 3from tkinter import * 4import tkinter as tk 5from tkinter import ttk 6import time 7 8 9class Window: 10 def __init__(self): 11 self.root = Tk() 12 self.root.title("サンプル") 13 14 self.frame3 = ttk.Frame(self.root, padding=10) 15 self.frame3.grid(row=0,column=1,sticky=W) 16 17 self.button1 = ttk.Button(self.frame3, text="実行", command=self.conductMain) 18 self.button1.pack(fill = "x", padx=30, side = "left") 19 20 self.button2 = ttk.Button(self.frame3, text=("閉じる"), command=self.root.quit) 21 self.button2.pack(fill = "x", padx=30, side = "left") 22 23 self.frame4 = ttk.Frame(self.root, padding = 10) 24 self.frame4.grid(row=2,column=1,sticky=E) 25 26 self.sc = tk.Scrollbar(self.frame4) 27 self.sc.pack(side = RIGHT, fill = "y") 28 29 self.tx = tk.Text(self.frame4, width = 48, height = 5) 30 self.tx.pack() 31 32 self.tx["yscrollcommand"] = self.sc.set 33 self.sc["command"] = self.tx.yview 34 35 36 #テキストボックスに文字を出力する関数です 37 #文字を出力->改行->自動スクロール 38 def print_text(self,text): 39 self.tx.insert(END, text) 40 self.tx.insert(END, "\n") 41 self.tx.see(END) 42 43 #サーバに接続する関数ですが、質問簡単化のために割愛します 44 #実行は1回のみです 45 def connect_server(self): 46 pass 47 48 #サーバから文字列を取得する関数ですが、質問簡単化のために割愛します 49 #実行は繰り返し行われます 50 def get_text_from_server(self): 51 pass 52 53 #実行ボタンを押した際に実行されます 54 #処理内容は以下の通りです 55 #サーバに接続->文字列を取得->特定の文字列でなければwhile内を実行(例:end以外なら実行) 56 #whileの中身:文字列を表示->1秒待機 57 def conductMain(self): 58 self.connect_server() 59 i = 0 60 #実際はサーバから特定の文字列を取得した際に終了しますが、 61 #今回は簡単化のために3回実行したら終了するようにしています 62 while i < 3: 63 self.root.after(1000,self.print_text(i)) 64 self.root.update() 65 i += 1 66 67if __name__ == "__main__": 68 69 w = Window() 70 w.root.mainloop()

本来の目的の実装の為には
conductMain 関数の手直しが 必要かもしれません‥‥

投稿2020/08/23 14:28

編集2020/08/23 21:43
Reach

総合スコア733

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

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

teamikl

2020/08/24 12:52 編集

self.root.after(1000,self.print_text(i)) は、2つ程問題があります。 1秒後に実行を3回登録するコードになってます。 また、self.print_text(i) ... はタイマーに登録ではなく、 この時点で関数を呼び出してしまってます。 (追記: 問題点が分かりにくいかもしれませんが、  update が呼び出されるまで他の操作ができなくなってます) 恐らく意図するコードは self.root.after((i+1)*1000, (lambda i=i: self.print_text(i))) だと思いますが、 サーバーとの接続を想定だとスレッドを使ったほうが良いかも。
teamikl

2020/08/24 13:00 編集

訂正 ~~~~1秒後に実行を3回登録するコードになってます。~~~~ スミマセン、ここは勘違いでした。 sleep の代替として使われてたのですね。
teamikl

2020/08/24 13:16

訂正2: self.root.after((i+1)*1000, (lambda i=i: self.print_text(i))) 自己レスですが、サーバからの返信を想定では適してませんでした。 フリーズの回避のみを目的として、本来の問題(サーバからの~)を見てませんでした。
guest

0

コードが動いているうちはフォームの更新はされません
なので、コードが終わってから初めて更新されます

ここは、タイマなどを使って、タイマイベントで文字出力するようにしましょう

投稿2020/08/23 11:28

y_waiwai

総合スコア87774

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問