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

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

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

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

Tkinter

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

Q&A

解決済

2回答

1464閲覧

並列処理の止め方(ラベルを使用して、簡易的な秒数をカウント)

MATLIB

総合スコア27

Python 3.x

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

Tkinter

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

0グッド

1クリップ

投稿2021/04/11 12:52

編集2021/04/12 05:11

ラベルを使用して簡易的な秒数をカウントするプログラムを作成しています。
1のボタンを押下すると、カウントが開始されて、2のボタンを押すとカウントが終了されて
初期のラベルの状態に戻したいのですが、カウントがとまりません。

どなたか、対処方法をご教授ください。

# -*- coding: utf-8 -*- import tkinter import tkinter as tk import tkinter.font as font from enum import Enum,auto import multiprocessing as mp import time import threading class WindowType(Enum): itiran=auto() kaiseki=auto() mente=auto() toroku=auto() class menu(tkinter.Frame): def __init__(self,master): super().__init__(master) self.pack() self.master.geometry("800x480") self.master.title("メニュー画面") self.create_widgets() def click1(self): thread = threading.Thread(target=self.changeLabelText) thread.start() def click2(self):     #2のボタン押下 def create_widgets(self): # Button font1 = font.Font(size=12) menu_btn1 = tkinter.Button(text='1', bg="#e6e6fa", font=font1, height=11, width=25,command=self.click1) menu_btn1.place(x=30, y=30) menu_btn2 = tkinter.Button(text='2', bg="#e6e6fa", font=font1, height=11, width=25,command=self.click2) menu_btn2.place(x=330, y=30) self.master.label = tk.Label(self.master) self.master.label["font"] = ("Helvetica", 50) self.master.label["bg"] = "green" self.master.label["fg"] = "white" self.master.label.place(x=30, y=250) def changeLabelText(self): i = 0 while True: i += 1 self.master.label["text"] = i time.sleep(1) def main(): root = tk.Tk() app = menu(master=root) app.mainloop() if __name__ == "__main__": main()

#追記 while文 フラグ変数版

# -*- coding: utf-8 -*- import tkinter import tkinter as tk import tkinter.font as font from enum import Enum,auto import time import threading flag = True class WindowType(Enum): itiran=auto() kaiseki=auto() mente=auto() toroku=auto() class menu(tkinter.Frame): def __init__(self,master): super().__init__(master) self.pack() self.master.geometry("800x480") self.master.title("メニュー画面") self.create_widgets() def click1(self): thread = threading.Thread(target=self.changeLabelText) thread.start() def click2(self): flag = False print('aaa',flag) def create_widgets(self): # Button font1 = font.Font(size=12) menu_btn1 = tkinter.Button(text='1', bg="#e6e6fa", font=font1, height=11, width=25,command=self.click1) menu_btn1.place(x=30, y=30) menu_btn2 = tkinter.Button(text='2', bg="#e6e6fa", font=font1, height=11, width=25,command=self.click2) menu_btn2.place(x=330, y=30) self.master.label = tk.Label(self.master) self.master.label["font"] = ("Helvetica", 50) self.master.label["bg"] = "green" self.master.label["fg"] = "white" self.master.label.place(x=30, y=250) def changeLabelText(self): i = 0 while flag is True: i += 1 self.master.label["text"] = i time.sleep(1) if flag is False: break def main(): root = tk.Tk() app = menu(master=root) app.mainloop() if __name__ == "__main__": main()

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

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

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

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

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

guest

回答2

0

なにかフラグを用意して、click2でそのフラグを立たせるようにして、
カウントのところのループでそのフラグをチェックし、そのフラグが立っていたらカウント行わないようにすればよろしい

投稿2021/04/11 13:48

y_waiwai

総合スコア88042

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

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

0

ベストアンサー

「秒数をカウントする」用途であれば、tkinterの提供するタイマー (after関数) を使った方が良いです。

Backend主な用途注意点
ProcessCPU Bound な処理プロセス間通信。(キューや共有メモリ)
ThreadI/O Bound な処理等スレッドセーフ。サブスレッドから直接GUI操作は行わない事
asyncio非同期 I/Oイベントループの統合・分離により、使い方が複数有り
tkinter (after)GUI アニメーションイベントループ内でtime.sleep 等の時間のかかる処理は行わない事

Thread 内で何か他の時間のかかる処理を行う予定が有る場合は、
y_waiwai さんの回答が正着で、具体的には、while True: の部分をフラグの変数にして、
ボタンを押したときにそのフラグをオフにします。


質問とは外れますが、スレッドを利用する場合

python

1# サブスレッドで実行されるchangeLabelText メソッド 2self.master.label["text"] = i

tkinter ではエラーなく実行できますが、お勧めはしません。
理由:

  • 別スレッドからの割り込みになるので、

 実際のラベルの表示の更新はメインスレッドのイベントループの描画タイミング、
タイミング次第で発症する問題が起こる等、再現が難しい問題の原因になりやすい。

  • tkitnerが終了しているが、サブスレッドが生き残っている場合、

 破棄済みの tkinter へのアクセスになってしまいます。
主に、アプリケーション終了時に後始末の方法次第でエラーに。

スレッドを跨ぐリソースの利用は問題が起こりやすいため、
安全な設計にするためには、スレッドの役割を分離したほうが良いです。

  • サブスレッド (時間のかかるタスク等。GUI操作は行わない )
  • メインスレッド (GUIイベントの処理。時間のかかる処理は行わない

→ イベントループが止まりGUIが応答なしになる為)

双方を両立したい場合、例えば時間のかかる処理の進捗をGUIに表示したい場合等は、
別スレッドからは通知のみを行い、コードの実行は担当のスレッド側で行う、といった手法を取ります。


タイマーを利用する場合、同一スレッド上での順番に実行されるため、
マルチスレッドの様な問題は有りません。

但し、大量のデータの分析といった処理の場合は
パフォーマンスが課題になります。(どの方法が適切かは用途次第)

tkinterのタイマーを利用する場合のコード例: 外部ライブラリ gentimer を利用

ジェネレータを tkinter のタイマーで実行する仕組みで、
time.sleep(1) -> yield 1 と置き換えてジェネレータとして実装。

python

1# NOTE: pip install gentimer でインストールしておく。 2import gentimer 3 4 5def __init__(self, ...): 6 ... 7 8 self.cancel_timer = None 9 10 11def click1(self): 12 if not self.cancel_timer: # NOTE: 多重起動防止 13 self.cancel_timer = gentimer.tk(self, self.changeLabelText()) 14 15def click2(self): 16 if self.cancel_timer: 17 self.cancel_timer() 18 self.cancel_timer = None 19 20def changeLabelText(self): 21 i = 0 22 while True: 23 i += 1 24 self.master.label["text"] = i 25 yield 1 # NOTE: sleep 1 sec time.sleep(1) を置き換え

投稿2021/04/12 02:10

teamikl

総合スコア8760

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

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

MATLIB

2021/04/12 03:19

詳細に記載していただきありがとうございます。 すごく勉強になりました。 スレッドの使用はやめて、タイマーでの実装にします。
MATLIB

2021/04/12 05:12 編集

ちなみにスレッドを使う場合で、while True:の部分をフラグでやってたのですが(初心者なのでやり方が間違っていると思いますがご了承ください)処理が終了しません。 flag = Falseになるのですが、 if flag is False: break の中に入っていきません。 ご教授お願い致します。
teamikl

2021/04/12 06:08 編集

現状の問題点は、click2 内の flag はローカル変数への代入となる為、 ループ側で参照しているグローバル変数に影響がありません。 グローバル変数への代入の際は、 関数内で global flag と宣言が必要になります。 ですが、クラスで使う場合は新たな課題が有り、 インスタンスを複数作る際は、すべてのインスタンスで グローバル変数を共有してしまいます。 (複数作る想定はないかもしれませんが、 例えばインスタンス menu1, menu2 を造ったとき、 menu1 の click2 の呼出で menu2 のカウントも止まってしまいます。 一般的に、グローバル変数利用→ 再利用性が低い設計になってしまう) クラスを使う場合は、インスタンス変数としたほうが良いでしょう。 - __init__ 内で self.flag = False - 実行時に self.flag = True - 停止時に self.flag = False - ループでは while self.flag:
MATLIB

2021/04/12 07:21

ありがとうございます。 できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問