◆PROCESSING 逆引きリファレンス
カテゴリー:制御系
ウィンドウが閉じる直前に何か処理を行うには
【解説】
プログラムを終了する前に、なにか処理を行いたい事は無いでしょうか? 例えば「終了しますか?」などの問い合わせを行い、「Yes]なら終了するが「No」なら終了しない等が考えられますよね。
PROCESSINGで作成されたアプリケーションは、ウィンドウの✕ボタンを押すとウィンドウが閉じてアプリケーションが終了してしまいます。
終了する直前になにか処理を行う事については、以前「プログラムの終了直前に何か処理を行うには」記事で、JavaのDispose()イベントをオーバラードする方法を紹介しました。
しかしこの方法では、Dispose() イベントがアプリケーションが終了する時に呼び出されるイベントであるため、上記のような問い合わせを行って終了を取りやめる事ができません。
今回は「アプリケーションが終了する時」に呼ばれるイベントではなく、「ウィンドウが閉じる直前」に呼ばれるイベントを利用して、先の問い合わせを実現する方法を紹介したいと思います。
【詳細】
PROCESSINGではWindowを閉じるイベントが、「プログラムを終了する動作」に自動的にセットされています。このため右上の✕ボタンを押下すると、アプリケーションが終了するわけです。
しかし自分でアプリケーションの終了をコントロールしたい場合は、このデフォルト動作が邪魔になります。
そこでPROCESSINGのWindowフレームに定義されているデフォルトの終了イベントを破棄し、自分たちが望むイベントに書き換えてやります。
PROCESSINGがもつWindowフレームは、PSurfaceから取得できます。
PSurfaceは内部でWindowフレームも管理しています。PSurfaceがもつWindowフレームは、以下のようにして取得します。
1 2 3 4 5 6 |
// PSurface がもつ Windowフレームを取得 private JFrame getJFrame(){ return (JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas)getSurface() .getNative()).getFrame(); } |
Frameが取得できたら、終了イベントを書き換えます。具体的には、以下の手順でプログラミングします。
- PSurface がもつ Windowフレームを取得
- 該当フレームから、getWindowListeners()でWindow操作用のイベントを取得
- 取得したイベントをremoveWindowListener()で削除
- 該当フレームに、addWindowListener()で新しいイベントをセット
新しいWindow クローズ動作は DO_NOTHING_ON_CLOSE に設定します。
DO_NOTHING_ON_CLOSE は、登録されたClose用のイベントを実行するだけで、他に処理は行いません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// Windowフレームを取得する JFrame frame = getJFrame(); // 該当Windowから、全てのWindow操作用イベントを削除し // 新しいイベントに書き換える for (final java.awt.event.WindowListener evt : frame.getWindowListeners()){ // イベントを削除する frame.removeWindowListener(evt); // Window Close 動作を再定義する // → 登録されている任意の WindowListener を呼び出すだけ frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE ); // 新しいWindow 操作イベントをセットする frame.addWindowListener(new WindowManage(this)); } |
関連する部分を抜き出すと、上記のような感じになります。
Windowフレームが操作された際に実行されるイベントは、WindowAdapterを継承している必要がありますが、上記サンプルで WindowManage とあるのは、そのWindowAdapterを継承した独自クラスです。
今回はWindowが閉じられる直前に処理を行う必要があるため、WindowAdapterを継承した独自クラスには windowClosing() を定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//----------------------- // Window 操作イベントクラス //----------------------- class WindowManage extends WindowAdapter{ PApplet myApplet; // コンストラクタ public WindowManage( PApplet _app ){ myApplet = _app; } // Close指示された時に動作する部分 public void windowClosing(WindowEvent e) { // Windowフレームを取得する JFrame frame = getJFrame(); // 問い合わせる int value = JOptionPane.showConfirmDialog( frame, "終了しますか?", "問い合わせ", JOptionPane.YES_NO_OPTION ); if( value == JOptionPane.YES_OPTION ){ // YESなら自分を終了する frame.dispose(); myApplet.exit(); } } } |
WindowManageクラスは上記のような感じになります。
自分自身を終了するため、コンストラクタで PAppletを受け取っています。
JavaのAWTやFrameについては、以下のサイト様などが参考となります。
- WisdomSoft 様
- Qiita 様:Processing3で閉じるボタンを押した時に終了確認する方法:@turtley_fms 様
【関連記事】
サンプルプログラム
終了時に問い合わせを行う例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
/** * PROCESSING 3 終了問い合わせSample * @auther MSLABO * @version 2018/10 1.0 */ import javax.swing.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; void setup(){ size(300,300); // Window操作イベントを書き換える redefineExitEvent(); } void draw(){ } // PSurface がもつ Windowフレームを取得 private JFrame getJFrame(){ return (JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas)getSurface() .getNative()).getFrame(); } // Window操作用のイベントを再定義する private void redefineExitEvent() { // Windowフレームを取得する JFrame frame = getJFrame(); // 該当Windowから、全てのWindow操作用イベントを削除し // 新しいイベントに書き換える for (final java.awt.event.WindowListener evt : frame.getWindowListeners()){ // イベントを削除する frame.removeWindowListener(evt); // Window Close 動作を再定義する // → 登録されている任意の WindowListener を呼び出すだけ frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE ); // 新しいWindow 操作イベントをセットする frame.addWindowListener(new WindowManage(this)); } } //----------------------- // Window 操作イベントクラス //----------------------- class WindowManage extends WindowAdapter{ PApplet myApplet; // コンストラクタ public WindowManage( PApplet _app ){ myApplet = _app; } // Close指示された時に動作する部分 public void windowClosing(WindowEvent e) { // Windowフレームを取得する JFrame frame = getJFrame(); // 問い合わせる int value = JOptionPane.showConfirmDialog( frame, "終了しますか?", "問い合わせ", JOptionPane.YES_NO_OPTION ); if( value == JOptionPane.YES_OPTION ){ // YESなら自分を終了する frame.dispose(); myApplet.exit(); } } } |
✕ボタンでウィンドウを閉じようとすると、「終了しますか?」と問い合わせが表示されます。
「はい」ならアプリケーションを終了し、「いいえ」なら終了しません。
注意点は「はい」の時、frame.dispose() でウィンドウを破棄してあげる事です。
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。