-
-
Save jewelsea/e231e89e8d36ef4e5d8a to your computer and use it in GitHub Desktop.
| 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); | |
| } | |
| } |
Just for convenience, the RT-17503 link has been migrated to the JDK Bug System .
Isn't 5 years enough to implement it?
Isn't 5 years enough to implement it?
I guess not
any news on this issue yet?
Still no change... I'm sad.
The javafx team is lazy af
I guess they abandoned javafx, that's why they open sourced it.
Will this ever get implemented?
Any good news?
6 years later???
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 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
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
When can I come kiss you? @dustinkredmond
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
When can I come kiss you? @dustinkredmond
Star the repo and that's even better than a kiss in my opinion. :D
I thought I already did!!! Thanks for reminding me to do it again. It didn't work the first time for whatever reason.
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
When can I come kiss you? @dustinkredmond
Star the repo and that's even better than a kiss in my opinion. :D
And so I just "kissed" you! 🤣 Thanks so much for putting some effort into this workaround. If I had the knowledge, I would have contributed to this component which seems quite needed for a decent JavaFx control set.
No news yet??
Thanks also to @ dustinkredmond, I hope his project helps me
托盘图标显示后,点击桌面空白位置,托盘图标不关闭,如何处理?
zZZzzZZZZ
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.