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

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

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

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

Python

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

Q&A

解決済

1回答

2441閲覧

Tkinter内でのループ処理

blacktt_red

総合スコア11

Tkinter

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

Python

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

0グッド

0クリップ

投稿2020/10/21 04:31

編集2020/10/21 04:32

前提・実現したいこと

Tkinterでのアプリケーションを開発しています。
現在、チェックボタンにチェックが入ったらループ処理が開始し、
チェックボタンを解除するとループから抜ける処理を行いたいです。
しかし、一度チェックが入るとループ処理に入り、それ以降チェック
ボックスが機能しないのですが、対処方法はありませんでしょうか。

thread処理やmultiprocessingなどの並列処理以外で対処できると
助かります。

該当のソースコード

Python

1import tkinter as tk 2import os.path 3import cv2 4from PIL import Image 5import csv 6import numpy as np 7import pathlib 8import time 9 10class main(): 11 def __init__(self): 12 13 root = tk.Tk() 14 root.geometry("300x300") 15 16 Frame=tk.Frame(root) 17 Frame.place(x=0, y=0, width=300, height=300) 18 19 self.var1=tk.StringVar() 20 self.var1.set("0") 21 22 checkbutton = tk.Checkbutton(Frame, text="test", variable=self.var1, command=self.check) 23 checkbutton.place(x=150, y=150) 24 25 root.mainloop() 26 27 def test(self): 28 print("test") 29 30 31 def check(self): 32 if self.var1.get()=="1": 33 while True: 34 self.test() 35 time.sleep(1) 36 if self.var1.get()=="0": 37 break 38 39 40 41if __name__=="__main__": 42 main()

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

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

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

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

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

guest

回答1

0

ベストアンサー

thread処理やmultiprocessingなどの並列処理以外で対処できると

助かります。

他には

  • generater として実装し、タイマーで処理する
  • asyncio を使う

といった方法があります。

まず、前提としてメインスレッドで処理したい場合は、
イベントループを止めるブロッキング処理(この場合は time.sleep)
は同スレッド内で使ってはいけません。イベント処理が阻害されます。

ジェネレータを使う方法では、
time.sleep の部分を tkinterのタイマーに置き換えるアプローチを取ります。

python

1def after_timed_gen(root, gen, _stop=None): 2 # タイマーでジェネレータを一つづつ読み出し 3 # yield で返された値を遅延時間に指定する(sleep) 4 def next_gen(): 5 interval = next(gen, _stop) 6 if interval is not _stop: 7 root.after(interval, next_gen) 8 root.after_idle(next_gen) 9 10 11## イベント登録部分 12 def check(): 13 after_timed_gen(root, self.check()) 14 15 checkbutton = tk.Checkbutton(Frame, text="test", variable=self.var1, command=check) 16 17 18## イベントハンドラ time.sleep(1) -> yield 1000 (ミリ秒) 19 def check(self): 20 if self.var1.get()=="1": 21 while True: 22 self.test() 23 yield 1000 24 if self.var1.get()=="0": 25 break
  • ループ内の time.sleep(1) を yield 1000

 スリープしたい時間を返すジェネレータとして実装します。
tkinter のタイマーでは ms の為 1秒 -> 1000ミリ秒

  • after_timed_gen(root, self.check()) でジェネレーターを処理するタイマーを開始

 ここで self.check を呼び出しジェネレーターオブジェクトを得ています。
関数を登録するのではない点に注意。(after_timed_gen関数でジェネレーターを受ける為)

  • after_timed_gen 関数内では、ジェネレーターから値を一つづつ読み出します

 読みだした値を元にタイマーを設定して、次の値を読み出すまでの間隔とします
これにより time.sleep 相当のスリープを実現。

  • メインスレッドの処理自体は mainloop に返るので、

 イベント処理を阻害しません。

注意点: test() メソッド内では、時間の掛かる処理をしてはいけません。
時間が掛かる場合は、test()内では処理を開始する合図のみに留め、
時間の掛かる処理自体にはスレッドを使った解決策が適切です。


関連:
tkinter キー入力の待受の方法

質問内の私の回答で、generatorとasyncioを使った回答例を提示してます。

投稿2020/10/21 05:24

編集2020/10/21 05:30
teamikl

総合スコア8760

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問