Swing Application Framework その2:ライフサイクル

フレームワーク利用時のアプリケーションのライフサイクルは以下の流れで行われます。

  1. launch -- 起動時に、フレームワーク提供のこのメソッドを呼ぶ。
  2. initialize -- フレームワークからオーバーライドした本メソッドが呼ばれる。
  3. startup -- フレームワークからオーバーライドした本メソッドが呼ばれる。
  4. ready -- フレームワークからオーバーライドした本メソッドが呼ばれる。
  5. exit -- 終了時に、フレームワーク提供のこのメソッドを呼ぶ。
  6. shutdown -- フレームワークからオーバーライドした本メソッドが呼ばれる。


initialize・ready・shutdownはApplicationクラス内で空メソッドとして定義されており、必要時に実装します。最低限のアプリケーションではlaunch・startupを実装すれば済みます。
launchメソッドの呼び出しにより、initialize, startup, readyメソッドが順番に実行されることになります。

フレームワークを利用しない場合

フレームワークを利用しなかった場合の一般的なSwingアプリケーションの場合は以下の様になります。

public class BasicApp implements Runnable {

    JFrame mainFrame;
    JLabel label;

    public void run() {
        mainFrame = new JFrame("BasicApp");
        label = new JLabel("Hello, world!");
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.add(label);
        mainFrame.pack();
        mainFrame.setVisible(true);
    }

    public static void main(String[] args) {
        Runnable app = new BasicApp();
        try {
            SwingUtilities.invokeAndWait(app);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 }

フレームワークを利用した場合

これは、フレームワークを利用すると、以下のように書けます。

public class BasicFrameworkApp extends Application {
    private JFrame mainFrame;
    private JLabel label;

    @Override
    protected void startup() {
        mainFrame = new JFrame("BasicFrameworkApp");
        mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        label = new JLabel("Hello, world!");
        mainFrame.add(label);
        mainFrame.pack();
        mainFrame.setVisible(true);
    }

    public static void main(String[] args) {
        Application.launch(BasicFrameworkApp.class, args);
    }
 }

フレームワークではlaunch メソッド実行で、EDS(イベントディスパッチスレッド)上で、最初にinitialize メソッドが呼ばれます。initialize メソッドはApplication上で空実装となっているので必要に応じてオーバーライドして初期化処理が行えます。
その後abstractとして定義してあるstartupメソッドが呼ばれるので、オーバーライドしてUI構築等を行います。startupが終了すると、フレームワークはready メソッドを呼びます。
こちらもApplication上で空実装となっているので必要に応じてオーバーライドしてUI初期化後のタスクを実装します。

SingleFrameApplicationの利用

SingleFrameApplication を使用すると、上記ライフサイクルのほかにフレーム生成・リソースからのインジェクション・セッションの永続化などがサポートされます。

public class BasicSingleFrameApp extends SingleFrameApplication {
    JLabel label;

    @Override
    protected void startup() {
        getMainFrame().setTitle("BasicSingleFrameApp");
        label = new JLabel("Hello, world!");
        label.setFont(new Font("SansSerif", Font.PLAIN, 22));
        show(label);
    }

    public static void main(String[] args) {
        Application.launch(BasicSingleFrameApp.class, args);
    }
 }

SingleFrameApplicationではなく、Applicationを直接継承したサブクラスを作成した場合、アプリケーション終了時にApplicationはexitメソッドを直接呼びません。

以下の実装とすることで、Application内のshutdown()が呼ばれます。

    protected void startup() {
        mainFrame = new JFrame("BasicFrameworkApp");
        mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        mainFrame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                mainframe.setVisible(false);
                exit();
            }
        });
        label = new JLabel("Hello, world!");
        mainFrame.add(label);
        mainFrame.pack();
        mainFrame.setVisible(true);
    }

SingleFrameApplication では、フレームに自動で対応付けられたWindowListener がexitを呼び、それによりshutdown()メソッドが呼ばれます。この時、SingleFrameApplicationのshutdownメソッド内で終了時のセッションの永続化等を実施しているので、オーバーライドする場合は以下のようにすることを忘れないで下さい。

 @Override
 protected void shutdown() {
    super.shutdown();
    // ・・
 }

アプリケーション終了時の挙動

アプリケーションの終了時の挙動を制御するには、ExitListenerインターフェースの以下のメソッドを利用します。

  • public boolean canExit(EventObject e)
  • public void willExit(EventObject e)


以下の例では終了時に確認用のダイアログを表示する例です。

   @Override
    protected void startup() {
        ・・・
        addExitListener(new ExitListener() {
            public boolean canExit(EventObject e) {
                boolean bOkToExit = false;
                Component source = (Component) e.getSource();
                bOkToExit = JOptionPane.showConfirmDialog(source,
                                "Do you really want to exit?") ==
                                JOptionPane.YES_OPTION;
                return bOkToExit;
            }
            public void willExit(EventObject event) {

            }
        });
        show(exitButton);
    }