前提・実現したいこと
pythonで実行中のプログラムをtkinterなどで作成したGUIのボタン押下でキャンセルしたいのですが、GUIから他のプログラムに干渉する方法がわかりません。
試したこと
キャンセルしたいプログラムにGUIをそのまま組み込むとGUIの実行部分で止まってしまうので、並列処理をしなければならないことは分かったのですが、別々に動いてるプログラムを互いに干渉させる方法が分からなくて困っております。
version
python 3.6.8
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/03/04 01:44
退会済みユーザー
2021/03/04 01:52
回答3件
0
えっと、ものすごく変な方法で良ければ、こんなふうにかけます。
追記:...すみません質問をちゃんと読んでませんでした...無視してください.......
python3
1import tkinter 2import threading 3import time 4 5class threadingLabel(): 6 def __init__(self, master): 7 self.master = master 8 self.label = tkinter.Label(root) 9 self.num = 0 10 self.stop =0 11 self.pack = self.label.pack 12 def _thread(self): 13 if not self.stop: 14 self.num+=1 15 self.label.configure(text=str(self.num)) 16 time.sleep(1) 17 def start(self): 18 self.stop = 0 19 self.num= 0 20 self.thread=threading.Thread(target=self._thread) 21 self.start() 22 def stop(self): 23 self.stop = 1 24 25root = tkinter.Tk() 26root.title("thread_test") 27tl = threadingLabel() 28t1.pack() 29b = tkinter.Button(root, text="stop", command = t1.stop) 30b.pack() 31t1.start() 32root.mainloop()
...突貫工事ですみません....
本当は、ちゃんとlabelを継承すべきなのですが...
必要でしたら、書き直します...
投稿2021/03/07 06:01
編集2021/03/07 06:09総合スコア189
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
真剣に並列処理を勉強したいのであれば、teamiklが書かれているような勉強をしてください。
手早く実現したいのであれば、プロセスとシグナルで実行する方法よりも、スレッドを使えば、メモリを共有しているのでフラグを決めておいて親スレッドがフラグに書き込み、子スレッドがときどきフラグをチェックして終了するというのが最も簡単です。子スレッド側はフラグに書き込まないので排他制御も必要ありません。
処理が単純なループならば、以下のようにして実現することが出来ます。
python
1import tkinter as tk 2import threading 3import time 4 5app = tk.Tk() 6frame = tk.Frame(master=app) 7frame.pack() 8 9LIVE = True 10 11def hello(): 12 try: 13 while True: 14 print('Hello') 15 time.sleep(1) 16 if LIVE == False: 17 raise(Exception) 18 except: 19 print("Don't kill me!!") 20 21def stop(): 22 global LIVE 23 LIVE = False 24 app.destroy() 25 26btn_stop = tk.Button(frame) 27btn_stop["text"] = "Cut, cut, cut, blood, spurt" 28btn_stop["command"] = stop 29btn_stop.pack(side="top") 30 31thread1 = threading.Thread(target=hello) 32thread1.start() 33 34app.mainloop() 35 36thread1.join()
これを実行すると、thread1はターミナルに対して1秒ごとにHelloを表示し続けます。
親スレッドはtkinterを使ってボタンを表示します。tkinterのボタンを押すと、関数stopが呼び出されてフラグであるLIVEをFalseに変更します。
すると、次のタイミングでLIVEをチェックした子スレッドはtryに向けて大域脱出して終了します。
実際の動きは実行してみればわかるはずです。
単純なループでなければ、問題が起きそうな場所に
python
1 if LIVE == False: 2 raise(Exception)
を入れておけば、そこに来た時点で止まります。(関数化しておいて呼び出した方がわかりやすいでしょう)
投稿2021/03/04 04:52
編集2021/03/04 08:01総合スコア24670
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
期待する動作が、「キャンセル」なのか、「終了」かで変わってきますが
シグナル等で別プロセスに対して終了を通知します。
別プログラム側にも手を入れられるなら、他の手段も取れます。(プロセス間通信)
- concurrent.futures ... Future オブジェクトの cancel()
- multiprocessing.Process ... kill()/terminate()
- subprocess.Popen ... kill()/terminate()
- signal を使う、os.kill
どの方法を取るのかは状況により異なりますが、別プロセスにする場合は、
内部では大抵シグナルを用いて通知していて、終了通知を受け取ったプロセスは、
(シグナルハンドラ等で特別な対応をしない限り)処理を中断して、そのまま終了することになります。
注意点: リソースの開放等は、意図通りに行われない可能性があります。安全な操作ではありません。
※ 具体的な方法は、状況・用途により異なります。起動・終了だけで良いなら subprocess
進捗状況をGUIに表示させたい等、複雑なやりとりが必要になるなら他のプロセス間通信。
例えば、「複数のファイルのコピー」という操作を途中で「キャンセル」したい場合、
既にコピーされたファイルはそのままになる(処理を中断して終了)のか、
それとも実行前の状態に戻す(操作の取り消し)のかという違いには留意して下さい。
自動的な「操作の取り消し」は出来ないので、双方のプログラムで別途対応が必要です。
投稿2021/03/04 03:11
編集2021/03/04 06:15総合スコア8740
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。