ウィンドウ・アプリケーション
ウィンドウ ・ アプリケーションはグラフィカルな表現やマウス操作に適したアプリケーションです。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.javaimport 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.MFManifest-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.javaimport 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.javaimport 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
フォルダーには他にもサンプルコードがあります。ぜひ試してみてください。