タスクトレイアイコン本来の使い方
本稿を書くきっかけになった.NET Framework版の『タスクトレイにアイコンとバルーンを表示する』では「レベル3:NotifyIconの本来の使い方」として実践的な使い方を紹介しています。こちらでも同様の機能を実装してみましょう。
- 機能1:ウィンドウを閉じたときにタスクトレイアイコンを表示する
- 機能2:タスクトレイのアイコンをダブルクリックするとウィンドウが表示される
- 機能3:タスクトレイ内でアイコンを右クリックするとメニューが表示され、そのメニューの終了をクリックするとアプリケーションが終了する
これらの機能を実現するには何通りかの設計が考えられますが、タスクトレイアイコンやメニューをあらかじめ準備しておき、イベントリスナーではそれらの表示・非表示を切り替えるというアプローチを取りたいと思います。
それではソースコードからcreateTrayAndBalloon()メソッドを削除して、Visual Editorで作成したばかりの状態から作っていきましょう。
タスクトレイアイコンの初期化
private void createSShell() { sShell = new Shell(); sShell.setText("タスクトレイとバルーンTips"); sShell.setSize(new Point(300, 75)); sShell.setLayout(new GridLayout()); createTrayItem(); } private void createTrayItem() { // TODO Auto-generated method stub }
createSShell()メソッドからcreateTrayItem()メソッドを呼び出すようにソースコードを追加し、中身を実装します。
private void createTrayItem() { Display display = Display.getDefault(); Tray tray = display.getSystemTray(); if (tray == null) return; // TrayItemの作成 item = new TrayItem(tray, SWT.NONE); Image image = display.getSystemImage(SWT.ICON_INFORMATION); item.setImage(image); item.setVisible(false); }
また、TrayItemはイベントリスナーから参照できるようにフィールドとして定義します。
private TrayItem item;
TrayItemはitem.setVisible(false)によって非表示にしておきます。
OSによってはitemフィールドがnullになる場合があるため、この後に実装するイベントリスナーでは注意する必要があります。
ポップアップメニューの初期化
タスクトレイアイコンと同じ要領でcreatePopupMenu()メソッドを追加します。
private void createSShell() { sShell = new Shell(); sShell.setText("タスクトレイとバルーンTips"); sShell.setSize(new Point(300, 75)); sShell.setLayout(new GridLayout()); createTrayItem(); createPopupMenu(); } private void createPopupMenu() { // TODO Auto-generated method stub }
createPopupMenu()メソッドを実装します。
private void createPopupMenu() { if (item == null) return; menu = new Menu(sShell, SWT.POP_UP); MenuItem quit = new MenuItem(menu, SWT.PUSH); quit.setText("終了"); }
itemフィールドがnullの場合はメニューを表示できないため、nullチェックを行います。MenuもTrayItemと同様にフィールドとして定義します。
private Menu menu;
タスクトレイアイコンに表示するメニューはコンストラクタの第1引数にShellオブジェクト、第2引数のスタイルにSWT.POP_UPを指定します。メニューはデフォルトで非表示のため、Menu#setVisible(false)メソッドの呼び出しは省略できます。メニュー項目となるMenuItemは、コンストラクタの第1引数に親のMenuオブジェクト、第2引数にSWT.PUSHを指定します。
初期化は以上になります。
MenuItemのスタイル定数にはSWT.PUSHのほかにSWT.RADIOやSWT.CHECK、さらに区切り線になるSWT.SEPARATOR、サブメニューを構築するSWT.CASCADEがあります。
機能1の実装(ウィンドウを閉じたときにタスクトレイアイコンを表示する)
ウィンドウを閉じるときのイベントはShellに対するShellListenerで受け取ることができます。再びVisual Editorに戻り、タイトルバーを右クリックし、[Events]-[shellClosed]を選択します。

すると、次のソースコードが追加されます。
sShell.addShellListener(new org.eclipse.swt.events.ShellAdapter() { public void shellClosed(org.eclipse.swt.events.ShellEvent e) { System.out.println("shellClosed()"); // TODO Auto-generated Event stub shellClosed() } });
これを次のように修正します。
sShell.addShellListener(new org.eclipse.swt.events.ShellAdapter() { public void shellClosed(org.eclipse.swt.events.ShellEvent e) { hideShellAndShowTray(e); } });
ある程度の行数になる処理はメソッドに分割した方が見た目がすっきりします。hideShellAndShowTray(ShellEvent)メソッドを実装します。
private void hideShellAndShowTray(ShellEvent e) { if (item == null) return; // TrayItemの表示 item.setVisible(true); // 非表示にして終了しない e.doit = false; sShell.setVisible(false); }
itemがnullの場合は何もしないことで、デフォルトのイベント処理によってウィンドウが閉じられ、アプリケーションが終了します。item.setVisible(true)でタスクトレイアイコンを表示します。
e.doit = falseでアプリケーションが終了しないように設定します。ShellEvent#doitフィールドはデフォルトのイベント処理を実行するかどうかを指定します。デフォルトではtrueのため、ウィンドウを閉じるというデフォルトのイベント処理が行われます。その処理を実行しないようにするためにdoitフィールドにfalseを代入します。これにより、ウィンドウは表示されたままになるので、sShell.setVisible(false)で非表示にします。
この段階で実行すると、ウィンドウの[閉じる]ボタンのクリックでウィンドウが非表示になり、タスクトレイアイコンが表示されます。ただし、ポップアップメニューが表示されないため、終了できません。実行した場合はConsoleビューの[Terminate]ボタンで強制終了してください。
機能2の実装(タスクトレイのアイコンをダブルクリックするとウィンドウが表示される)
タスクトレイアイコンのダブルクリックはTrayItemに対するSelectionListenerで受け取ることができます。
Visual Editorで[item]の上で右クリックし、[Events]-[Add Events]を選択します。

[selection]の[widgetDefaultSelected]を選択して、[Finish]ボタンをクリックします。
次のソースコードが追加されます。
item.addSelectionListener(new org.eclipse.swt.events.SelectionListener() { public void widgetDefaultSelected( org.eclipse.swt.events.SelectionEvent e) { System.out.println("widgetDefaultSelected()"); // TODO Auto-generated Event stub widgetDefaultSelected() } public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { } });
ここで必要なメソッドはwidgetDefaultSelected(SelectionEvent)だけなので、次のようにSelectionAdapterクラスを使う方法に書き換えます。
item.addSelectionListener(
new org.eclipse.swt.events.SelectionAdapter() {
public void widgetDefaultSelected(
org.eclipse.swt.events.SelectionEvent e) {
showShellAndHideTray();
}
});
}
private void showShellAndHideTray() {
// TODO Auto-generated method stub
}
さらにshowShellAndHideTray()メソッドを実装します。
private void showShellAndHideTray() { sShell.setMinimized(false); sShell.setVisible(true); item.setVisible(false); }
sShell.setMinimized(false)で最小化の状態で非表示にした場合を想定して、最小化を解除します。sShell.setVisible(true)でウィンドウを非表示から表示の状態に変更します。item.setVisible(false)でタスクトレイアイコンを非表示にします。
ここまでの状態で実行すると、ウィンドウの[閉じる]ボタンのクリックでウィンドウが非表示になり、タスクトレイアイコンが表示されます。さらにタスクトレイアイコンをダブルクリックするとウィンドウが表示され、タスクトレイアイコンが非表示になります。しかし、ここでもまだ終了することができないので、実行した場合はConsoleビューの[Terminate]ボタンで強制終了してください。
機能3の実装(タスクトレイ内でアイコンを右クリックするとメニューが表示され、そのメニューの終了をクリックするとアプリケーションが終了する)
TrayItemでの右クリックのイベントは少々特殊で、Visual Editorでは設定できません。これまではウィジェットに対してadd○○Listener(○○Listener listener)というメソッドを呼び出してイベントリスナーを登録していましたが、addListener(int eventType, Listener listener)というローレベルのメソッドを使用することになります。
TrayItemでの右クリックのイベントは、SWT.MenuDetectというイベントタイプで受け取ることができます。
item.addListener(SWT.MenuDetect, new Listener() {
public void handleEvent(Event event) {
showPopupMenu();
}
});
}
private void showPopupMenu() {
// TODO Auto-generated method stub
}
showPopupMenu()を実装します。
private void showPopupMenu() { menu.setVisible(true); }
menu.setVisible(true)でポップアップメニューを表示します。これでポップアップメニューが表示されるようになりました。

後は、メニューの[終了]をクリックするとアプリケーションが終了するようにメニューのイベントを処理します。Java Beansビューの[quit]の上で右クリックし、[Events]-[Add Events]を選択します。

[selection]の[widgetSelected]を選択し、[Finish]ボタンをクリックします。
次のソースコードが追加されます。
quit.addSelectionListener(new org.eclipse.swt.events.SelectionListener() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { System.out.println("widgetSelected()"); // TODO Auto-generated Event stub widgetSelected() } public void widgetDefaultSelected( org.eclipse.swt.events.SelectionEvent e) { } });
今回もwidgetSelected(SelectionEvent)メソッドだけが必要なので、SelectionAdapterクラスを使う方法に書き換えます。
quit.addSelectionListener(
new org.eclipse.swt.events.SelectionAdapter() {
public void widgetSelected(
org.eclipse.swt.events.SelectionEvent e) {
quitApplication();
}
});
}
private void quitApplication() {
// TODO Auto-generated method stub
}
quitApplication()メソッドを実装します。
private void quitApplication() { sShell.dispose(); }
ここで注意したいのはsShell.close()ではないということです。sShell.close()にしてしまうとShellEventイベントが発生し、shellClosed(ShellEvent)メソッドが呼び出されるので、アプリケーションを終了できません。dispose()メソッドによってウィンドウを破棄することで、アプリケーションが終了します。
これですべての処理が完成しました。
まとめ
SWTを使用することによって、これまでJavaではできないとされがちだったことが、より容易にできるようになっています。
本稿を執筆するきっかけとなった.NET Framework版の『タスクトレイにアイコンとバルーンを表示する』と比較するとVisual Editorの不安定な部分や、機能が十分ではない部分が目立ったかと思います。しかし、SWTはオープンソースであるという点やクロスプラットフォームで動作できるという点、IBMをはじめとする多数の企業が参加して改良が続けられている点は非常に魅力的です。
本稿をきっかけとしてSWTに興味を持っていただければ何よりです。
参考資料
- SWTのソースコード(Eclipseに含まれる)
- SWT Snippets
- CodeZine 『タスクトレイにアイコンとバルーンを表示する』 おぎわら@.NET道場 著、2006年7月


