Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Demonstrate using the System Tray (AWT) to control a JavaFX application.
import javafx.application.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.*;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.net.URL;
import java.text.*;
import java.util.*;
// Java 8 code
public class JavaFXTrayIconSample extends Application {
// one icon location is shared between the application tray icon and task bar icon.
// you could also use multiple icons to allow for clean display of tray icons on hi-dpi devices.
private static final String iconImageLoc =
"http://icons.iconarchive.com/icons/scafer31000/bubble-circle-3/16/GameCenter-icon.png";
// application stage is stored so that it can be shown and hidden based on system tray icon operations.
private Stage stage;
// a timer allowing the tray icon to provide a periodic notification event.
private Timer notificationTimer = new Timer();
// format used to display the current time in a tray icon notification.
private DateFormat timeFormat = SimpleDateFormat.getTimeInstance();
// sets up the javafx application.
// a tray icon is setup for the icon, but the main stage remains invisible until the user
// interacts with the tray icon.
@Override public void start(final Stage stage) {
// stores a reference to the stage.
this.stage = stage;
// instructs the javafx system not to exit implicitly when the last application window is shut.
Platform.setImplicitExit(false);
// sets up the tray icon (using awt code run on the swing thread).
javax.swing.SwingUtilities.invokeLater(this::addAppToTray);
// out stage will be translucent, so give it a transparent style.
stage.initStyle(StageStyle.TRANSPARENT);
// create the layout for the javafx stage.
StackPane layout = new StackPane(createContent());
layout.setStyle(
"-fx-background-color: rgba(255, 255, 255, 0.5);"
);
layout.setPrefSize(300, 200);
// this dummy app just hides itself when the app screen is clicked.
// a real app might have some interactive UI and a separate icon which hides the app window.
layout.setOnMouseClicked(event -> stage.hide());
// a scene with a transparent fill is necessary to implement the translucent app window.
Scene scene = new Scene(layout);
scene.setFill(Color.TRANSPARENT);
stage.setScene(scene);
}
/**
* For this dummy app, the (JavaFX scenegraph) content, just says "hello, world".
* A real app, might load an FXML or something like that.
*
* @return the main window application content.
*/
private Node createContent() {
Label hello = new Label("hello, world");
hello.setStyle("-fx-font-size: 40px; -fx-text-fill: forestgreen;");
Label instructions = new Label("(click to hide)");
instructions.setStyle("-fx-font-size: 12px; -fx-text-fill: orange;");
VBox content = new VBox(10, hello, instructions);
content.setAlignment(Pos.CENTER);
return content;
}
/**
* Sets up a system tray icon for the application.
*/
private void addAppToTray() {
try {
// ensure awt toolkit is initialized.
java.awt.Toolkit.getDefaultToolkit();
// app requires system tray support, just exit if there is no support.
if (!java.awt.SystemTray.isSupported()) {
System.out.println("No system tray support, application exiting.");
Platform.exit();
}
// set up a system tray icon.
java.awt.SystemTray tray = java.awt.SystemTray.getSystemTray();
URL imageLoc = new URL(
iconImageLoc
);
java.awt.Image image = ImageIO.read(imageLoc);
java.awt.TrayIcon trayIcon = new java.awt.TrayIcon(image);
// if the user double-clicks on the tray icon, show the main app stage.
trayIcon.addActionListener(event -> Platform.runLater(this::showStage));
// if the user selects the default menu item (which includes the app name),
// show the main app stage.
java.awt.MenuItem openItem = new java.awt.MenuItem("hello, world");
openItem.addActionListener(event -> Platform.runLater(this::showStage));
// the convention for tray icons seems to be to set the default icon for opening
// the application stage in a bold font.
java.awt.Font defaultFont = java.awt.Font.decode(null);
java.awt.Font boldFont = defaultFont.deriveFont(java.awt.Font.BOLD);
openItem.setFont(boldFont);
// to really exit the application, the user must go to the system tray icon
// and select the exit option, this will shutdown JavaFX and remove the
// tray icon (removing the tray icon will also shut down AWT).
java.awt.MenuItem exitItem = new java.awt.MenuItem("Exit");
exitItem.addActionListener(event -> {
notificationTimer.cancel();
Platform.exit();
tray.remove(trayIcon);
});
// setup the popup menu for the application.
final java.awt.PopupMenu popup = new java.awt.PopupMenu();
popup.add(openItem);
popup.addSeparator();
popup.add(exitItem);
trayIcon.setPopupMenu(popup);
// create a timer which periodically displays a notification message.
notificationTimer.schedule(
new TimerTask() {
@Override
public void run() {
javax.swing.SwingUtilities.invokeLater(() ->
trayIcon.displayMessage(
"hello",
"The time is now " + timeFormat.format(new Date()),
java.awt.TrayIcon.MessageType.INFO
)
);
}
},
5_000,
60_000
);
// add the application tray icon to the system tray.
tray.add(trayIcon);
} catch (java.awt.AWTException | IOException e) {
System.out.println("Unable to init system tray");
e.printStackTrace();
}
}
/**
* Shows the application stage and ensures that it is brought ot the front of all stages.
*/
private void showStage() {
if (stage != null) {
stage.show();
stage.toFront();
}
}
public static void main(String[] args) throws IOException, java.awt.AWTException {
// Just launches the JavaFX application.
// Due to way the application is coded, the application will remain running
// until the user selects the Exit menu option from the tray icon.
launch(args);
}
}
@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Aug 27, 2014

JavaFX will get it's own system tray support in a latter release once RT-17503 Provide system tray support is implemented. Until then, using the AWT system tray as demonstrated in the sample code in this gist seems to work fine.

@thierrylafaye

This comment has been minimized.

Copy link

@thierrylafaye thierrylafaye commented Mar 14, 2016

Just for convenience, the RT-17503 link has been migrated to the JDK Bug System .

@ericek111

This comment has been minimized.

Copy link

@ericek111 ericek111 commented Dec 22, 2016

Isn't 5 years enough to implement it?

@oxodao

This comment has been minimized.

Copy link

@oxodao oxodao commented Jan 9, 2018

Isn't 5 years enough to implement it?

I guess not

@kinsleykajiva

This comment has been minimized.

Copy link

@kinsleykajiva kinsleykajiva commented Feb 12, 2018

any news on this issue yet?

@guiguidu60

This comment has been minimized.

Copy link

@guiguidu60 guiguidu60 commented Mar 28, 2018

Still no change... I'm sad.

@RafatRifaie

This comment has been minimized.

Copy link

@RafatRifaie RafatRifaie commented Jun 2, 2018

The javafx team is lazy af

@camabeh

This comment has been minimized.

Copy link

@camabeh camabeh commented Jul 7, 2018

I guess they abandoned javafx, that's why they open sourced it.

@gringofe

This comment has been minimized.

Copy link

@gringofe gringofe commented Mar 14, 2020

Will this ever get implemented?

@tharindusathis

This comment has been minimized.

Copy link

@tharindusathis tharindusathis commented Jun 19, 2020

Any good news?

@fellahi-ali

This comment has been minimized.

Copy link

@fellahi-ali fellahi-ali commented Aug 21, 2020

6 years later???

@dustinkredmond

This comment has been minimized.

Copy link

@dustinkredmond dustinkredmond commented Aug 21, 2020

I feel like someone should make a library for easily working with TrayIcons from JavaFX as the AWT API is not friendly to me as a JavaFX user. Guess that's another side project for me to do...

@dustinkredmond

This comment has been minimized.

Copy link

@dustinkredmond dustinkredmond commented Aug 24, 2020

I feel like someone should make a library for easily working with TrayIcons from JavaFX as the AWT API is not friendly to me as a JavaFX user. Guess that's another side project for me to do...

I succeeded in making this marginally easier. Have a look at my repo "FXTrayIcon", particularly at the test application that I wrote. Still uses AWT, but abstracts away some of the nastiness. FXTrayIcon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.