ウィンドウ アプリケーション

ウィンドウ アプリケーションはグラフィカルな表現やマウス操作に適したアプリケーションです。Graphical User Interface GUI アプリケーションと呼ばれることもあります。

AWT Swing JavaFX SWT 等の UI ツールキットを使用している場合はウィンドウ アプリケーションにしましょう。

オプション -g を指定するとウィンドウ アプリケーションになります。

ウィンドウ アプリケーションの特徴

  • プログラム実行時にコンソール コマンドプロンプト が表示されなくなります。

  • スプラッシュスクリーンの表示に対応しています。

  • 標準出力/標準エラー出力がファイルに書き出されます。System.out.println() e.printStackTrace() などの出力を確認することができます。拡張フラグ NOLOG を指定するとこのファイル出力機能を無効にすることができます。

  • キャッチされなかった例外をエラーダイアログで表示します。最上位の main メソッドでもキャッチされずに アプリケーション外まで伝播した例外をダイアログで表示します。同時に例外のスタックトレースがファイルに出力されるので アプリケーションの異常終了時の状態を把握しやすくなります。

  • スレッドが異常終了した場合もエラーダイアログを表示してアプリケーション プロセスを終了させます。スタックトレースはファイルに出力されます。マルチスレッド アプリケーションで一部のスレッドが異常終了したまま動作が続行されてしまう危険性がなくなります。拡張フラグ IGNORE_UNCAUGHT_EXCEPTION を指定するとこの機能を無効にすることができます。

SwingSet2 EXE にしてみよう

Swing のサンプルプログラム SwingSet2.jar EXE にする場合は次のようにします。

コマンドプロンプト
C:¥>exewrap -g SwingSet2.jar

処理が完了すると SwingSet2.exe が出力されます。

アイコンをダブルクリックして実行します。

スプラッシュスクリーンが表示された後 Swing のデモアプリが起動しました。

簡単なプログラムを作ってみよう

ウィンドウに文字を表示する簡単なプログラムを作って EXE にしてみましょう。

以下のソースコードを SwingSample1.java というファイル名で作成します。

SwingSample1.java
import java.awt.Font; import javax.swing.JFrame; import javax.swing.JLabel; import static javax.swing.SwingConstants.*; public class SwingSample1 { public static void main(String[] args) { StringBuilder text = new StringBuilder(); if(args.length == 0) { text.append("Hello, World!!"); } else { for(String arg : args) { text.append(arg + " "); } } JFrame frame = new JFrame("SwingSample1"); frame.setSize(320, 240); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel label = new JLabel(text.toString()); label.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16)); label.setHorizontalAlignment(CENTER); frame.getContentPane().add(label); frame.setLocationRelativeTo(null); frame.setVisible(true); } }

コマンドプロンプトを起動します。Java コンパイラ javac exewrap が使えるように PATH 環境変数を設定しておいてください。

javac コマンドでソースコード SwingSample1.java をコンパイルすると SwingSample1.class ファイルが出来上がります。

コマンドプロンプト
C:¥>javac SwingSample1.java

出力された SwingSample1.class ファイルを実行可能な Java アーカイブ形式 jar にまとめます。実行可能 JAR ファイルを作成するときはエントリーポイントとなるメインクラスを記述したマニフェストファイルが必要になります。

本来は以下のようなマニフェストファイルを作成するのですが メインクラスの指定のみであればマニフェストファイルを作成せずに jar コマンドの引数でメインクラスを指定することもできます。

MANIFEST.MF
Manifest-Version: 1.0 Main-Class: SwingSample1

今回はマニフェストファイルを用意せずに引数でメインクラスを指定します。jar コマンドの引数 e がメインクラスを指定するオプションです。引数の SwingSample1 がメインクラスの指定です。

コマンドプロンプト
C:¥>jar cfe SwingSample1.jar SwingSample1 SwingSample1.class

マニフェストファイルで指定する場合は m オプションを使って以下のようにします。

コマンドプロンプト
C:¥>jar cfm SwingSample1.jar MANIFEST.MF SwingSample1.class

最後に exewrap SwingSample1.jar を実行ファイル EXE にします。

コマンドプロンプト
C:¥>exewrap -g SwingSample1.jar exewrap 1.6.0 for x64 (64-bit) Architecture: x64 (64-bit) Target: Java 5.0 (1.5.0.0) SwingSample1.exe (64-bit) version 0.0.0.0

実行ファイルには製品名や著作権表示 バージョンなど様々なプロパティ情報を指定することができます。詳細については 基本オプション を参照してください。

実行ファイルが出来上がりました。

アイコンをダブルクリックして実行してみましょう。

上手くいきましたね!

JavaVM プロセスを共有して複数のウィンドウを表示する

exewrap には javaw.exe ではできないいくつかの拡張機能があります。拡張機能の 1 JavaVM プロセス共有機能を試してみましょう。

以下のソースコードを SwingSample2.java というファイル名で作成します。

SwingSample2.java
import java.awt.Font; import javax.swing.JFrame; import javax.swing.JLabel; import static javax.swing.SwingConstants.*; public class SwingSample2 { private static int count = 0; public static void main(String[] args) { StringBuilder text = new StringBuilder(); if(args.length == 0) { text.append("Hello, World!!"); } else { for(String arg : args) { text.append(arg + " "); } } count++; JFrame frame = new JFrame("SwingSample2 #" + count); frame.setSize(320, 240); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); JLabel label = new JLabel(text.toString()); label.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16)); label.setHorizontalAlignment(CENTER); frame.getContentPane().add(label); frame.setLocationRelativeTo(null); frame.setVisible(true); } }

コンパイルして実行可能 JAR にまとめる手順は先程と同様です。

コマンドプロンプト
C:¥>javac SwingSample2.java C:¥>jar cfe SwingSample2.jar SwingSample2 SwingSample2.class

exewrap SwingSample2.jar を実行ファイル EXE を作成します。このとき -e オプションを使って JavaVM を共有する拡張フラグ SHARE を指定します。詳細については 拡張フラグ を参照してください

コマンドプロンプト
C:¥>exewrap -g -e SINGLE SwingSample2.jar exewrap 1.6.0 for x64 (64-bit) Architecture: x64 (64-bit) Target: Java 5.0 (1.5.0.0) SwingSample2.exe (64-bit) version 0.0.0.0

実行ファイルが出来上がりました。

それではアイコンをダブルクリックして実行してみましょう。

タイトルバーに #1 と表示されていることに注目してください。そして もう 1 度アイコンをダブルクリックして SwingSample2.exe を実行します。

今度はタイトルバーに #2 と表示されています。分かりにくいかもしれませんが 2 回目の起動は非常に高速だったと思います。なぜなら 2 回目は JavaVM を作成せずに 起動済の JavaVM でプログラムを実行しているからです。

タイトルバーの #1 #2 という表示は以下のクラス変数 スタティック変数 によって実現しています。

private static int count = 0;

SwingSample2.exe を実行する度に同じ JavaVM 内で main メソッドが呼ばれ count++ によってタイトルバーに表示される数字が増加していきます。

すべてのウィンドウを閉じると JavaVM プロセスは終了します。その後 もう 1 SwingSample2.exe を実行するとタイトルバーの表示は再び #1 から始まります。すでにプロセスが存在していれば JavaVM を共有して相乗りする プロセスが存在していなければ JavaVM を作成してプログラムを開始するという動作になっています。

JavaVM は同じプログラム SwingSample2.exe 内でのみ共有されます。たとえば 無関係の OtherApp.exe を起動して JavaVM が作成されていたとしても SwingSample2.exe がその JavaVM を共有することはありません。

これは Excel の動作をイメージしてもらうと分かりやすいと思います。Excel のファイル xlsx を最初にダブルクリックして Excel を起動するときはスプラッシュスクリーンが表示され初期化に少し時間がかかってからウィンドウが表示されます。次に他の Excel ファイルをダブルクリックして開くときにはスプラッシュスクリーンは表示されず短時間でウィンドウが表示されます。このとき EXCEL.EXE 1 つしか起動しておらず 1 つのプロセスが 2 つのウィンドウを提供しています。

拡張フラグ SHARE を使うと Excel と同じような動作を簡単に実現できます。

二重起動を禁止して起動済みのウィンドウを最前面に表示する

JavaVM プロセスを共有する拡張フラグ SHARE を使うと アプリケーションの二重起動を禁止して さらに既存のウィンドウを最前面に表示することもできます。

以下のソースコードを SwingSample3.java というファイル名で作成します。

SwingSample3.java
import java.awt.Font; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.SwingUtilities; import static javax.swing.SwingConstants.*; public class SwingSample3 { private static int count = 0; private static JFrame frame; private static JLabel label; public static void main(String[] args) { final StringBuilder text = new StringBuilder(); if(args.length > 0) { for(String arg : args) { text.append(arg + " "); } } if(count++ > 0) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if(frame != null) { if(text.length() > 0) { label.setText(text.toString()); } if((frame.getExtendedState() & JFrame.ICONIFIED) != 0) { frame.setExtendedState(frame.getExtendedState() & ~JFrame.ICONIFIED); } frame.toFront(); } } }); return; } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { frame = new JFrame("SwingSample3"); frame.setSize(320, 240); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); label = new JLabel(text.length() > 0 ? text.toString() : "Hello, World!!"); label.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16)); label.setHorizontalAlignment(CENTER); frame.getContentPane().add(label); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } }

コンパイルして実行可能 JAR にまとめる手順は先程と同様です。

コマンドプロンプト
C:¥>javac SwingSample3.java C:¥>jar cfe SwingSample3.jar SwingSample3 SwingSample3.class

exewrap SwingSample3.jar を実行ファイル EXE を作成します。このとき -e オプションを使って JavaVM を共有する拡張フラグ SHARE を指定します。詳細については 拡張フラグ を参照してください

コマンドプロンプト
C:¥>exewrap -g -e SINGLE SwingSample3.jar exewrap 1.6.0 for x64 (64-bit) Architecture: x64 (64-bit) Target: Java 5.0 (1.5.0.0) SwingSample3.exe (64-bit) version 0.0.0.0

実行ファイルが出来上がりました。

それではアイコンをダブルクリックして実行してみましょう。

拡張フラグ SHARE によってアプリケーションを起動するたびに起動済みプロセスの main メソッドが呼ばれるのはさきほどのサンプルと同じです。このサンプルでは 初回の main メソッド呼び出しかどうかを判定して 2 回目以降の main メソッド呼び出しであれば既存のウィンドウを最前面に表示するようにしています。さらにウィンドウがアイコン化 タスクバーに収まった状態 になっている場合はアイコン化も解除しています。

ウィンドウのアイコン化を解除して最前面に表示する
if((frame.getExtendedState() & JFrame.ICONIFIED) != 0) { frame.setExtendedState(frame.getExtendedState() & ~JFrame.ICONIFIED); } frame.toFront();

表示されている SwingSample3.exe のウィンドウを他のウィンドウで隠してから さらに SwingSample3.exe をダブルクリックしてみてください。ウィンドウが増えていくのではなく起動済みのウィンドウが最前面に表示されます。

exewrap の配布物に含まれている samples フォルダーには他にもサンプルコードがあります。ぜひ試してみてください。


次は exewrap の様々な機能について見ていきましょう。