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

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

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

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

Tkinter

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

Python

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

Q&A

解決済

2回答

8316閲覧

def関数を別のdef関数から停止させたい

OkukawaRyoki

総合スコア16

Python 3.x

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

Tkinter

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

Python

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

1グッド

1クリップ

投稿2020/07/23 07:15

現在pythonのtkinterを用いてプログラムを実行停止するようなアプリを作っているのですが、
実行中のdef関数を別のdef関数から停止させることは可能ですか?

python

1def button_start(): 2 while True: 3 #各種処理 4 5def button_stop(): 6 sys.exit(0) #的な? 7 8# Startボタン 9 button2 = ttk.Button(frame2, text='Start', command=button_start) 10 button2.pack(side=LEFT) 11 12# Cancelボタン 13 button3 = ttk.Button(frame2, text='Cancel', command=button_stop) 14 button3.pack(side=LEFT)

大雑把にこんな感じで書いたのですが、予想通り止めることはできず、キャンセルボタンを押すと
tkinterのguiが応答なしになります。(pythonプログラムは実行されている)

global変数でフラグを作ってdef button_startの中にif文(フラグ判定)で終了させるようなことも試したのですが
うまくいかず、pyhtonはまだ勉強したてなので
どうかご教授を、、、

調べてもこれ!!って感じの見つからなくて質問したほうが早いかなぁ、、、なんて

よろしくお願いいたします。

teamikl👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

button_start がメインスレッド上で実行されるので、
while ループが終わるまでは他の処理は実行されません。

メインループ → button_start → メインループ →

順番に実行されるので、
button_start 内で時間の掛かる処理を行い、
メインループに処理が戻らないと応答なしになります。

GUI等のイベント駆動型プログラミングで、よくある誤解なのですが、
イベントハンドラの関数(button_start)は、
勝手に裏で同時に実行される訳ではありません。

イベントハンドラ内でループを使う場合は、
スレッドを使う等が一般的な解決策です。
他に幾つか解決案を紹介します。


  1. ウインドウが固まらないように、ループ内で定期的に update() を呼ぶ

これは本当に一時的な回避策。使える状況は限られますが、有効な場合も有。

  1. 別スレッド/プロセスを作り、ループを外部から中断できるフラグを仕込む。

y_waiwaiさん提案の方法に該当します。

  1. タイマーを使う

after や after_idle を使って、
イベントループの合間に任意の処理を実行します。
但し、1回の処理は、直ぐに終わる程度に分割が必要です。

  1. ジェネレーター(とタイマー)を使う

同上ですが、ジェネレータを使ってループ文で記述可能な方法。

  1. 非同期ライブラリ (asyncio等) を使う

1と3、4 は、ネットワークやデータベースが絡む処理、
時間の掛かる計算処理には向きません。
簡単なアニメーション等やスケジューリングの用途には使えます。

2 のスレッドは汎用的な方法ですが、別スレッドからGUIにアクセスする際は、
もうひと工夫が必要なので注意。

「各種処理」の内容次第では、適切な解決策は変わってきます。

1, 2, 3 は探せばサンプルコードは見つかると思いますので、
4 の方法のみコードを紹介します。
5 は選択肢として言及したものの、長くなるので割愛。
興味があれば、「非同期プログラミング」について調べて見て下さい。

python

1 2import tkinter as tk 3from tkinter import ttk 4 5 6def after_timed_gen(root, gen, done=None, _stop=None): 7 """ 8 ジェネレーターをTkinterのタイマーで消化する関数 9 after() に指定する 遅延ミリ秒を yield で指定できます。 10 """ 11 12 def next_gen(): 13 interval = next(gen, _stop) 14 if interval is not _stop: 15 root.after(interval, next_gen) 16 else: 17 if done: 18 done() 19 20 root.after_idle(next_gen) 21 return gen 22 23 24if __name__ == "__main__": 25 root = tk.Tk() 26 label = ttk.Label(root) 27 label.pack() 28 29 def countUp(count=0): 30 while True: 31 count += 1 32 label.config(text="Count: {}".format(count)) 33 34 # メインスレッド内で GUIの応答を止めることなく、 35 # time.sleep(1) としたい場合の代替策です。 36 yield 1*1000 37 38 gen = None 39 40 def button_start(): 41 global gen 42 gen = after_timed_gen(root, countUp()) 43 44 def button_stop(): 45 global gen 46 if gen: 47 gen.close() 48 gen = None 49 50 51 button1 = ttk.Button(root, text='Start', command=button_start) 52 button1.pack() 53 54 button2 = ttk.Button(root, text='Cancel', command=button_stop) 55 button2.pack() 56 57 root.mainloop()

スレッドを使う方法の停止・中断デモ source
※ブラウザ上で実行できます

投稿2020/07/23 14:42

編集2020/07/23 14:46
teamikl

総合スコア8760

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

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

OkukawaRyoki

2020/07/23 23:19

ご回答ありがとうございます。 GUIプログラムは初めて書くのでとっても参考になりました。 現在作っているプログラムは処理が長いのでスレッド型を採用したいと思います。 またその他の解決案も一つ一つ、実践してみようと思います。 この度は本当にありがとうございます!
guest

0

グローバル変数でbool変数を定義しておき、
ループの実行をその変数で回すようにしとけば、
もう片方の関数で、その変数をfalseにすれば、そのループを止めれますね

投稿2020/07/23 07:21

y_waiwai

総合スコア88042

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

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

OkukawaRyoki

2020/07/23 07:31

ご回答ありがとうございます。 if文のフラグ判定では止められないのなぜでしょうか? よろしければ教えていただけると嬉しいです
y_waiwai

2020/07/23 07:39

if文とはどこのはなしでしょうか 提示のコードには見当たりませんが。
OkukawaRyoki

2020/07/23 07:44

提示していませんでした、すみません。 例えになってしまいますが、for文の中でif文のフラグ判定によってプログラムを停止させるようなことをが出来ればと思ったのですが実行したところ応答なしになってしまうので何か理由があるのかなと思いまして。
y_waiwai

2020/07/23 07:55

そのコードを提示してもらわないことにはなんとも言えません。 あなたのコードが間違っている、としかいえませんよ
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問