我正在使用JavaFX UI创建一个简单的应用程序,该应用程序只是这样做:
我已经制作了用户界面并将应用程序放入了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");
}
//
}
}
答案 0 :(得分:19)
将代码包装在actionListener中,该代码在Platform.runLater中回调到JavaFX。这将执行与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();
}
});
}
};
默认情况下,应用程序将shutdown when it's last window is hidden。要覆盖此默认行为,请在显示第一个应用程序阶段之前调用Platform.setImplicitExit(false)。然后,当您需要应用程序真正关闭时,您需要显式调用Platform.exit()。
我创建了一个demo for using the AWT system tray within a JavaFX application。
答案 1 :(得分:4)
您应该只修改javafx线程上的javafx类,托盘图标上的侦听器可能会在swing线程上运行。您可以通过将runnable发布到Platform#runLater来执行此操作,如下所示:
Platform.runLater(new Runnable() {
public void run() {
primaryStage.hide();
}
});
答案 2 :(得分:1)
JavaFX尚不支持系统托盘。您可以根据以下JIRA问题跟踪此任务的进度:https://bugs.openjdk.java.net/browse/JDK-8090475
该问题还提供了一种解决方法,可以在JavaFX 8中使用它来获得基本支持。
JavaFX 8并未规划该功能,因此可能会在以下某个更新中发布,甚至可能在JavaFX 9中发布。
答案 3 :(得分:0)
我解决了您的问题。带有AWT的JavaFX。我有一个应用程序示例,该示例在您留下左手提示时显示和隐藏。我真的希望对你有用
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);
}
}
答案 4 :(得分:0)
无耻的自我插入,但是我为JavaFX图标开发了一个小的包装库,该库使用名为FXTrayIcon的SystemTray。
它抽象出了所有讨厌的AWT位,从而消除了猜测要在哪个线程上运行代码的麻烦。它可以作为对Maven Central的依赖。