#はじめに
C# GUIアプリケーションからPythonスクリプトを実行する ではPythonスクリプトの実行が終わるまで他の操作はできない状況であった。しかし、もっと複雑なアプリケーションを考えた場合、あるPytnon等のプロセスをバックグラウンドで実行開始し、その後呼び出し元の画面にもどって別の操作をしたり、別のプロセスを実行できると便利だ。また実行中の全てのプロセスを一覧表示し、実行状況を確認したり、キャンセル等の操作も行えるとさらに便利だ。これを行うプロトタイプを作成してみた。
#実現イメージ
実現したいことを図にするとこんな感じになる。
- プロセス実行画面でプロセスの実行を開始すると、その画面は閉じることができ、プロセスはバックグラウンドで実行される。その後プロセス管理画面でプロセスの状況(終わったかどうか等)を確認できる。
- 途中で詳細な実行状況を見たい場合は、プロセス管理画面で「Detail」ボタンをクリックすると、そのプロセスの進捗状況をプロセス詳細画面でいつでも参照できる。
- 複数のプロセスの進捗状況を、複数のプロセス詳細画面で同時に見ることができる。
#実現方法
ソースはhttps://github.com/kimisyo/PythonParallelExecutor で公開している。名前はPythonがついているが、コマンドラインで呼び出せるものであれば容易に修正は可能である。
C# GUIアプリケーションからPythonスクリプトを実行する からの変更したポイントは以下の通りである。
- プロセスを実行する際に指定するプロセスクラスのExited, OutputDataReceived, ErrorDataReceivedイベントに対し、親のフォームのイベントハンドラを紐づけるよう変更する。
- 親フォームでは実行されたプロセスの情報(プロセスクラス)を保持しておき、DataGridViewのDataSourceと連動させておく。また、OutputDataReceived,ErrorDataReceivedイベントハンドラに実行中の各プロセスからの標準出力データが送られてくるので、これをプロセス別に保持しておく。
- プロセスの実行詳細画面を表示する際は、それまでにOutputDataReceived, ErrorDataReceivedで受け取った内容を標準出力のエリアに初期表示する。
- そして肝になる部分が、OutputDataReceived, ErrorDataReceivedイベントハンドラにおいて標準入出力データを受け取る度に全子画面にイベント発行する点だ。子画面のイベントハンドラはそれをうけとってテキストエリアに進捗状況(標準出力のデータ)を表示する。もちろん、子画面がいつも存在するとはかぎらないため、プロセス実行詳細画面を表示する際にイベントとイベントハンドラを紐づけ、プロセス実行詳細画面を閉じる際にそれを解除している。コードでいうと、PythonCommandExecutorForm.csの
this.parentForm.MyProgressEvent += handler;
,this.parentForm.MyProgressEvent -= this.handler;
のように記載しているところになる。
#おわりに
今まで避けてきたイベントの仕組みについて理解が深まった。イベントの仕組みを理解すると、各画面部品が非同期に連動するの独立性の高いアプリケーションが簡単に作れそうな気がする。