Приложение JavaFX на панели задач

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

  • имеет значок на панели задач, при нажатии на который отображается окно, при повторном нажатии его скрывает, при щелчке правой кнопкой мыши показывает меню с 1 элементом «выход»

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

person amrlab    schedule 24.09.2012    source источник


Ответы (5)


Оберните код в 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();
      }
    });
  }                   
};            

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


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

person jewelsea    schedule 24.09.2012
comment
Да, я только что нашел это на странице документации, спасибо большое. Но когда я его скрываю, он больше не появляется, даже если я использую show () - person amrlab; 25.09.2012
comment
Обновленный ответ для объяснения неявного / явного поведения выхода. - person jewelsea; 25.09.2012
comment
действительно, Thx alot, я много искал это !! - person amrlab; 25.09.2012
comment
Если вам действительно нужно одно окно, и оно не является безумно сложным, вам следует придерживаться awt / swing и избавить себя от накладных расходов JavaFx, пока оно не получит поддержку значков в трее. - person ed22; 29.10.2019

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

Platform.runLater(new Runnable() {
    public void run() {
        primaryStage.hide();
    }
});
person Andy Till    schedule 24.09.2012

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

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

person Petr    schedule 01.09.2013
comment
Было бы неплохо видеть содержимое jira без регистрации. - person aphex; 03.04.2014

Я решил вашу проблему. JavaFX с AWT. У меня есть один пример приложения, которое показывает и скрывает, когда вы делаете левый клик. я действительно надеюсь, что сработает для тебя

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);
}
}
person algorithm    schedule 05.04.2020

Бесстыдный самоподключаемый модуль, но я разработал небольшую библиотеку-оболочку для значков JavaFX, использующую SystemTray, под названием FXTrayIcon.

Он абстрагирует все неприятные биты AWT и избавляет от необходимости угадывать, в каком потоке вы должны запускать код. Он доступен как зависимость от Maven Central.

person Dustin R    schedule 18.11.2020