Приложение JavaFX в системном лотке - программирование
Подтвердить что ты не робот

Приложение JavaFX в системном лотке

Я делаю простое приложение с использованием интерфейса JavaFX, приложение просто делает это:

  • имеет значок systray, который при щелчке показывает окно, при повторном нажатии скрывает его, на правой клавише отображается меню с пунктом "exit"

Я уже создал пользовательский интерфейс и поместил приложение в лоток Sys, но я не могу показать/скрыть его с помощью метода Normal 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");
          } 
        //
    }
}
4b9b3361

Ответ 1

Оберните код в actionListener, который обращается к JavaFX в Platform.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();
      }
    });
  }                   
};            

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


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

Ответ 2

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

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

Ответ 3

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

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