2012-09-24 73 views
16

我使用JavaFX UI制作一个简单的应用程序,该应用程序只是简单地做到这一点:的JavaFX应用程序在系统托盘

  • 有一个系统托盘图标,点击它时显示一个窗口,当再次点击隐藏它,在右击显示了1“退出”项目

我已经作出的UI,并把应用程序在任务栏中的菜单,但使用普通的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"); 
      } 
     // 
    } 
} 

回答

19

裹在回调的JavaFX在Platform.runLater的ActionListener的代码。这将执行在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。要覆盖此默认行为,请在显示第一个应用程序Stage之前调用Platform.setImplicitExit(false)。当您需要应用程序真正关闭时,您将需要明确地调用Platform.exit()


我创建了一个demo for using the AWT system tray within a JavaFX application

+0

是被释放,我只是发现,在文档页面,THX了很多。 但是,当我隐藏它,即使我使用show() – amrlab

+0

更新答案来解释隐式/显式退出行为,它不会再次出现。 – jewelsea

+0

真的,Thx很多,我一直在寻找这个! – amrlab

4

您应该只修改了JavaFX线程上的JavaFX类,托盘图标的听众很可能Swing线程上运行。您可以通过发布可运行于平台#runLater像这样做:

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

JavaFX还不支持系统托盘。您可以在以下JIRA问题下跟踪此任务的进度:https://bugs.openjdk.java.net/browse/JDK-8090475
该问题还提供了一种解决方法,该解决方案可用于JavaFX 8中以获得基本支持。

的功能是没有计划为JavaFX 8,所以它可能在下列更新之一,甚至用JavaFX 9

+4

很高兴在没有注册的情况下看到jira内容。 – aphex

+1

功能跟踪现在位于:https://bugs.openjdk.java.net/browse/JDK-8092115 –

相关问题