JavaFX в приложение в системный трей

Я делаю простое приложение с помощью JavaFX UI, приложение просто делает это:

  • имеет значок systray, который при нажатии показывает окно, при нажатии снова скрывает его, на rightclick показывает меню с 1" выход " пункт

Я уже сделал пользовательский интерфейс и поместил приложение в лоток Sys, но я не могу показать / скрыть его с помощью обычного метода Actionlistener, но я получил эту ошибку:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = AWT-EventQueue-0

вот код:

import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionListener;


import javafx.application.Application;
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 Main extends Application{
    public static void main(String[] args) { 
        launch(args);       
    }

    @Override
    public void start(final Stage primaryStage) {
        primaryStage.setTitle("Hello World!");
        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();

        if (SystemTray.isSupported()) {         
            SystemTray tray = SystemTray.getSystemTray();
            Image image = Toolkit.getDefaultToolkit().getImage("Germany-politcal-map.jpg");
            PopupMenu popup = new PopupMenu();
            MenuItem item = new MenuItem("Exit");

            popup.add(item);

            TrayIcon trayIcon = new TrayIcon(image, "Amr_Trial", popup);

            ActionListener listener = new ActionListener() {                
                @Override
                public void actionPerformed(java.awt.event.ActionEvent arg0) {
                    // TODO Auto-generated method stub
                    System.exit(0);                 
                }               
            };                       

            ActionListener listenerTray = new ActionListener() {                
                @Override
                public void actionPerformed(java.awt.event.ActionEvent arg0) {
                    // TODO Auto-generated method stub                  
                    primaryStage.hide();
                }                   
            };            

            trayIcon.addActionListener(listenerTray);
            item.addActionListener(listener);

            try{
              tray.add(trayIcon);
            }catch (Exception e) {
              System.err.println("Can't add to tray");
            }
          } else {
            System.err.println("Tray unavailable");
          } 
        //
    }
}

3 ответов


оберните код в actionListener, который вызывает JavaFX в .runLater. Это выполнит код, который взаимодействует с системой JavaFX в потоке приложения JavaFX, а не пытается сделать это в потоке событий Swing (что вызывает у вас проблемы).

например:

ActionListener listenerTray = new ActionListener() {                
  @Override public void actionPerformed(java.awt.event.ActionEvent event) {
    Platform.runLater(new Runnable() {
      @Override public void run() {
        primaryStage.hide();
      }
    });
  }                   
};            

по умолчанию приложение будет выключение, когда это последнее окно скрыто. Чтобы переопределить это поведение по умолчанию, вызовите .setImplicitExit (false) прежде чем вы покажете первый этап применения. Затем вам нужно будет явно вызвать .exit () когда вам нужно приложение, чтобы действительно остановка.


Я создал демо для использования системного трея AWT в приложении JavaFX.


вы должны только изменить классы javafx в потоке javafx, прослушиватели на значке в трее, вероятно, будут работать в потоке swing. Вы можете сделать это, разместив runnable на платформе#runLater следующим образом:

Platform.runLater(new Runnable() {
    public void run() {
        primaryStage.hide();
    }
});

системный лоток еще не поддерживается в JavaFX. Вы можете отслеживать ход выполнения этой задачи в следующем выпуске JIRA:https://bugs.openjdk.java.net/browse/JDK-8090475
Проблема также предоставляет обходной путь, который может быть использован в JavaFX 8 для получения базовой поддержки.

функция не запланирована для JavaFX 8, поэтому она может быть выпущена в одном из следующих обновлений или даже в JavaFX 9.