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

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

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

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

Q&A

解決済

2回答

7346閲覧

Pysimpleguiのデバックウインドウやプログレスメーターのボタンで処理を中断できるようにしたい

sugar_p

総合スコア2

Python

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

0グッド

0クリップ

投稿2020/05/28 01:08

前提・実現したいこと

こんにちは。Python学習2か月目のプログラミング初心者です。
質問に答えていただけると幸いです。

現在、CSVファイルを読み込み、1ファイル毎にある処理を行っているプログラムを作成しています。
ファイル処理中にPysimpleguiのDebug WindowかProgress Meterを用いて処理状況を
画面に表示させているのですが、ウインドウの何らかのボタンが押された場合、
処理を中断するような仕様にしたいです。

該当のソースコード

Python

1 2#files_pathに各CSVファイルのパスがリストで入っている 3 4# プログレスメーターの場合 5i = 1 6for file_path in files_path:    # ファイル毎に処理 7 # プログレスメーター 8 sg.one_line_progress_meter('ファイル処理中', i+1, ful = len(files_path), key = 'pbar', orientation="v",) 9 10  (ファイル処理部) 11 12 i = i + 1 13 14 15# デバッグウインドウの場合 16for file_path in files_path:    # ファイル毎に処理 17 sg.Print(ファイル名 + "処理中")    # デバッグウインドウ 18 19  (ファイル処理部) 20 21 sg.Print(ファイル名 + "処理完了") 22

試したこと

event , values = window.read()
を使うとボタンが押されるとそれに応じた何らかの値が返ってきますが、
その場合ボタンを押さないと次の処理に進まないため、
(ウインドウに進捗状況を表示)+(ファイルの処理)
ができません。
目指したいのは、
(ウインドウに進捗状況を表示)+(ファイルの処理)+(何らかのボタンで中断処理)
です。
解決手段わかる方、ご教示お願いします!

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

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答2

0

余談ですが、sg.Print() での中断やってみました。こんな感じになります。
(注意点: あまり深くデバッグしてないので、他で不都合が出ることがあるかも知れません。)

イメージ説明

python

1def hook_cancelable_debug_close(): 2 from functools import wraps 3 import PySimpleGUI as sg 4 import PySimpleGUI.PySimpleGUI as _sg 5 6 _sg_print = sg.Print 7 _sg_debug_close = _sg._DebugWin.Close 8 9 class ClosedException(Exception): 10 pass 11 12 @wraps(_sg_debug_close) 13 def _close(self): 14 _sg_debug_close(self) 15 raise ClosedException 16 17 @wraps(_sg_print) 18 def _print(self, *args, **kw): 19 try: 20 _sg_print(self, *args, **kw) 21 except ClosedException: 22 return False 23 return True 24 25 sg.Print = _print 26 _sg._DebugWin.Close = _close 27 28 29 30import PySimpleGUI as sg 31 32# sg.Print 関数の差し替え。 33hook_cancelable_debug_close() 34 35import time 36for num in range(1000): 37 if not sg.Print(num): # <-- Quit ボタンを押した時中断 38 break 39 time.sleep(0.1)

投稿2020/05/28 15:47

teamikl

総合スコア8664

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

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

sugar_p

2020/05/29 00:48

ありがとうございます! 試してみたいと思います。
guest

0

ベストアンサー

簡単な方法: 対象を一つづつ処理するのであれば、
sg.one_line_progress_meterを使うと楽できます。

python

1 2with open(filepath) as infile: 3 for line in infile: 4 if not sg.one_line_progress_meter(...): 5 break # 中断 6 # ファイル処理

ここから、ステップアップとして

  • 進捗ダイアログ以外のUI操作も可能にする -> timeout イベントを使う
  • 複数のファイルを同時に処理する -> スレッドを使う

等が考えられます。

以下は timeout で処理するデモ(スレッドは使ってません)
工夫が必要な点:

  • ファイルの処理を「ジェネレータ」として実装
    timeout イベント内で next() で読み出すことで、

 1ステップづつ実行が実現できます

  • window.read の timeout パラメータは、必要なときのみ設定

イメージ説明

python

1 2from contextlib import closing 3import PySimpleGUI as sg 4 5layout = [ 6 [sg.Text("File:"), sg.Input(__file__, key="-INPUT-FILE-")], 7 [sg.Text("Status:"), 8 sg.ProgressBar(key="-PROCESSING-", size=(30, 20), max_value=100)], 9 [sg.Button("Start", key="-START-"), sg.Button("Stop", key="-STOP-")], 10] 11 12 13 14def gen_bytes_count(filepath): 15 import os 16 # Total Bytes 17 filesize = os.stat(filepath).st_size 18 count = 0 19 20 # NOTE: バイト数カウントのためバイナリで開いてます 21 # テキストで開いた場合、文字数 != バイト数(ファイルサイズ) と一致しません 22 with open(filepath, "rb") as infile: 23 for line in infile: 24 count += len(line) 25 yield (int(100*count/filesize), count) 26 27task = None 28options = {} 29timeout_options = {"timeout":100, "timeout_key":"-timeout-"} 30 31def task_cancel(): 32 global task 33 task = None 34 options.clear() 35 36def task_start(filepath): 37 global task 38 task = gen_bytes_count(filepath) 39 options.update(timeout_options) 40 41 42with closing(sg.Window('Bytes Count', layout)) as window: 43 44 while True: 45 event, values = window.read(**options) 46 # print(event) 47 if not event: 48 break 49 elif event == "-STOP-": 50 task_cancel() 51 elif event == "-START-": 52 task_start(values["-INPUT-FILE-"]) 53 elif event == "-timeout-": 54 if not task: # 処理するファイルが無い時 55 continue 56 57 info = next(task, None) 58 if not info: # ファイル処理が終わった時 59 task_cancel() 60 continue 61 62 status, count = info 63 window["-PROCESSING-"].update_bar(status) 64 sg.Print(status, count) 65 ret = sg.OneLineProgressMeter( 66 'Byte count', status, 100, "", '{}'.format(count)) 67 if not ret: # 進捗ダイアログの Cancel が押された時 68 task_cancel() 69 continue 70 71

投稿2020/05/28 04:21

編集2020/05/28 07:26
teamikl

総合スコア8664

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

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

sugar_p

2020/05/28 07:09

ご回答ありがとうございます! if not sg.one_line_progress_meter(...): break # 中断 をfor文中に追記することで中断処理を行うことができました。 (任意のタイミングで中断はできてないのかもしれませんが) 発展バージョンとしてサンプルコード書いてくれた部分は、 難しく全ては理解できないですが、少しずつトライしてみようと思います。 欲を言って申し訳ありませんが、もう一つ質問させて頂いてもよろしいでしょうか? デバッグウインドウsg.Print()の閉じ方をご存じでしょうか? 公式サイトではPrintClose()かeasy_print_close()で閉じることができると 書いてありましたが、どちらもNameErrorが出ます。
teamikl

2020/05/28 07:21

sg.one_line_progress_meter を追記する場所はどこにしてますか。 ファイル単位のforループであれば、ファイル単位での処理の中断 ファイル内部の処理(CSVなら行毎)であれば行の処理中に中断可能です。 >デバッグウインドウsg.Print()の閉じ方 モジュールはどの様にインポートしてますか? import PySimpleGUI as sg としていれば、sg.PrintClose() で閉じられます。 "sg." を忘れてないか確認してみて下さい。 もしくは参考にしたコードが from PySimpleGUI import * となっていたのかもしれません。
sugar_p

2020/05/28 07:34

すみません、もう一つ質問させてください。 プログレスメーターと同じように for file_path in files_path:    # ファイル毎に処理 sg.Print(ファイル名 + "処理中")    # デバッグウインドウ   (ファイル処理部) sg.Print(ファイル名 + "処理完了") if not sg.Print(): break を書いてみると、1周目の処理でプログラムが終了してしまいます。 これはどうしてでしょうか?
teamikl

2020/05/28 07:39 編集

>if not sg.Print(): <-- Print が原因かな。 ここでNone が返るので必ず break します --> ループを抜ける sg.one_line_progress_meter と同じようには使えません。
sugar_p

2020/05/28 07:41 編集

コメントありがとうございます! プログレスメータの処理中断と、sg.PrintClose()の件 理解できました。
sugar_p

2020/05/28 07:47

>>if not sg.Print(): <-- Print が原因かな。 >ここでNone が返るので必ず break します --> ループを抜ける >sg.one_line_progress_meter と同じようには使えません。 分かりました。ありがとうございます。 sg.Print()の場合はもう少し複雑な処理になるということでしょうか
teamikl

2020/05/28 08:09

>sg.Print()の場合はもう少し複雑な処理 もし「デバッグウインドウを閉じた時に中断したい」という事であれば、 簡単にはできなさそうです。 「Quit」が押されたのを、ライブラリ外から検知できない為。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問