System Tray in JavaFx

Java SDK (since version 1.5) provides default support of system tray, which works fine in Windows, Linux and MacOS. But, unfortunately, this feature is disable for JavaFX.

Let’s see how to enable this possibility using reflection.

TrayManager

Let’s create simple JavaFx class, which will work with java.awt.SystemTray and java.awt.TrayIcon via reflection. Note it will not wrap all methods of these classes – it will just provide main possibilities.

public class TrayManager {

var trayIcon : Object;
var trayIconClass : Class;
public-init var icon : java.awt.Image;

init {

trayIconClass = Class.forName(“java.awt.TrayIcon”);
var constructor = trayIconClass.getConstructor(java.awt.Image.class);
trayIcon = constructor.newInstance(icon);
}

public function setPopupMenu(popup : PopupMenu) {

var method = trayIconClass.getDeclaredMethod(“setPopupMenu”, PopupMenu.class);
method.invoke(trayIcon, popup);
}

public function setToolTip(tooltip : String) {

var method = trayIconClass.getDeclaredMethod(“setToolTip”, String.class);
method.invoke(trayIcon, tooltip);
}

public function showIcon() {

var trayClass = Class.forName(“java.awt.SystemTray”);
var trayMethod = trayClass.getDeclaredMethod(“getSystemTray”);
var systemTray = trayMethod.invoke(null);
var trayAddMethod = trayClass.getDeclaredMethod(“add”, trayIconClass);
trayAddMethod.invoke(systemTray, trayIcon)
}

public function hideIcon() {

var trayClass = Class.forName(“java.awt.SystemTray”);
var trayMethod = trayClass.getDeclaredMethod(“getSystemTray”);
var systemTray = trayMethod.invoke(null);
var trayAddMethod = trayClass.getDeclaredMethod(“remove”, trayIconClass);
trayAddMethod.invoke(systemTray, trayIcon)
}

public function addActionListener(actionListener : ActionListener) {

var method = trayIconClass.getDeclaredMethod(“addActionListener”, ActionListener.class);
method.invoke(trayIcon, actionListener);
}

public function addMouseListener(actionListener : MouseListener) {

var method = trayIconClass.getDeclaredMethod(“addMouseListener”, MouseListener.class);
method.invoke(trayIcon, actionListener);
}

}

So as you can see it provides the following methods:

  • setPopupMenu for linking tray icon with popup menu;
  • setToolTip for setting tooltip to icon;
  • showIcon/hideIcon for showing and hiding tray icon;
  • addActionListener/addMouseListener for adding event listeners.

How to use TrayManager

Now let’s see how to use this class.

First you need to create popup menu (we uses jfxtras library):

var popupMenuEntries:NativeMenuEntry[] = [];
insert [

// insert some entries

] into popupMenuEntries;

popupMenu = NativePopupMenu {

items: popupMenuEntries

};

Now we may create tray icon and show it:

var tray = TrayIconReflection {

icon: (logoIcon.platformImage as java.awt.Image)

};

tray.setPopupMenu(popupMenu);
tray.setToolTip(“Application name”);
tray.addActionListener(ActionListener {

override function actionPerformed(e) {
showApp(true);
}

});

tray.addMouseListener(MouseListener {

override function mouseClicked(e : MouseEvent) {
if (e.getButton() == MouseEvent.BUTTON1) {
showApp(true);
}
}
override function mousePressed(e : MouseEvent) {
}
override function mouseReleased(e : MouseEvent) {
}
override function mouseEntered(e : MouseEvent) {
}
override function mouseExited(e : MouseEvent) {
}

});
tray.showIcon();

Wow. It works 🙂