Creating tray icon using JavaFX

后端 未结 5 584
南方客
南方客 2021-02-07 15:48

I want to write a tray icon via JavaFx, but I only find that can write by awt. Is there any way that can write it use JavaFx?

It w

相关标签:
5条回答
  • 2021-02-07 16:30

    If you'd prefer to not use AWT directly, I've created a small project FXTrayIcon which translates JavaFX MenuItems to AWT MenuItems and abstracts away all of the ugly AWT bits. It's at least a small help until JavaFX supports this natively.

    See it on my GitHub page

    0 讨论(0)
  • 2021-02-07 16:31

    If this is to be believed, JavaFX will feature tray icons in a future update. Till then stick to AWT. Keep track of the development using this thread on the JDK bug system. Hope this helps.

    0 讨论(0)
  • 2021-02-07 16:37

    You can't with pure JavaFX, but you can use AWT with JavaFX:

    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);
        }
    }
    

    code source

    0 讨论(0)
  • 2021-02-07 16:38

    To make a system tray try following code:

    Original document link: https://docs.oracle.com/javase/tutorial/uiswing/misc/systemtray.html

        //Check the SystemTray is supported
        if (!SystemTray.isSupported()) {
            System.out.println("SystemTray is not supported");
            return;
        }
        final PopupMenu popup = new PopupMenu();
    
        URL url = System.class.getResource("/images/new.png");
        Image image = Toolkit.getDefaultToolkit().getImage(url);
    
        final TrayIcon trayIcon = new TrayIcon(image);
    
        final SystemTray tray = SystemTray.getSystemTray();
    
        // Create a pop-up menu components
        MenuItem aboutItem = new MenuItem("About");
        CheckboxMenuItem cb1 = new CheckboxMenuItem("Set auto size");
        CheckboxMenuItem cb2 = new CheckboxMenuItem("Set tooltip");
        Menu displayMenu = new Menu("Display");
        MenuItem errorItem = new MenuItem("Error");
        MenuItem warningItem = new MenuItem("Warning");
        MenuItem infoItem = new MenuItem("Info");
        MenuItem noneItem = new MenuItem("None");
        MenuItem exitItem = new MenuItem("Exit");
    
        //Add components to pop-up menu
        popup.add(aboutItem);
        popup.addSeparator();
        popup.add(cb1);
        popup.add(cb2);
        popup.addSeparator();
        popup.add(displayMenu);
        displayMenu.add(errorItem);
        displayMenu.add(warningItem);
        displayMenu.add(infoItem);
        displayMenu.add(noneItem);
        popup.add(exitItem);
    
        trayIcon.setPopupMenu(popup);
    
        try {
            tray.add(trayIcon);
        } catch (AWTException e) {
            System.out.println("TrayIcon could not be added.");
        }
    

    Example system tray image in Windows 10

    To invoke method of Javafx from awt event handler you may follw the following way:

    yourAwtObject.addActionListener(e -> {
        Platform.runLater(() -> primaryStage.show());
    });
    
    0 讨论(0)
  • 2021-02-07 16:43

    i made it. JavaFX with AWT. I have one example of a application that shows and hides when you make left clic. i really hope works for you

    import java.awt.AWTException;
    import java.awt.Image;
    import java.awt.SystemTray;
    import java.awt.Toolkit;
    import java.awt.TrayIcon;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.net.URL;
    import javafx.application.Application;
    import static javafx.application.Application.launch;
    import javafx.application.Platform;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class MainApp2 extends Application {
    
    int stateWindow = 1;
    
    @Override
    public void start(final Stage stage) throws Exception {
    
        //Check the SystemTray is supported
        if (!SystemTray.isSupported()) {
            System.out.println("SystemTray is not supported");
            return;
        }
    
        URL url = System.class.getResource("/image/yourImage.png");
        Image image = Toolkit.getDefaultToolkit().getImage(url);
    
        //image dimensions must be 16x16 on windows, works for me
        final TrayIcon trayIcon = new TrayIcon(image, "application name");
    
        final SystemTray tray = SystemTray.getSystemTray();
    
        //Listener left clic XD
        trayIcon.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent event) {
                if (event.getButton() == MouseEvent.BUTTON1) {
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            if (stateWindow == 1) {
                                stage.hide();
                                stateWindow = 0;
                            } else if (stateWindow == 0) {
                                stage.show();
                                stateWindow = 1;
                            }
                        }
                    });
                }
    
            }
        });
    
        try {
            tray.add(trayIcon);
        } catch (AWTException e) {
            System.out.println("TrayIcon could not be added.");
        }
    
        stage.setTitle("Hello man!");
        Button btn = new Button();
        btn.setText("Say 'Hello man'");
        btn.setOnAction(new EventHandler<ActionEvent>() {
    
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello man!");
            }
        });
        StackPane root = new StackPane();
        root.getChildren().add(btn);
        stage.setScene(new Scene(root, 300, 250));
        Platform.setImplicitExit(false);
        stage.show();
    
    }
    
    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
    }
    
    0 讨论(0)
提交回复
热议问题