桌面应用少不了要用到系统托盘,但是JavaFX并没有给我们提供系统托盘(至少我没找见),不过也不要紧,我们可以用java.awt.SystemTray。
// 我们的自定义系统托盘
class MySysTray {
private TrayIcon trayIcon = null;
private Timeline timeline = new Timeline();
public void initSystemTray() {
// 1、创建托盘按钮
PopupMenu popupMenu = new PopupMenu();
MenuItem showItem = new MenuItem("显示"); popupMenu.add(showItem);
MenuItem hideItem = new MenuItem("隐藏"); popupMenu.add(hideItem);
MenuItem quitItem = new MenuItem("退出"); popupMenu.add(quitItem);
// 2、创建动作事件监听器(awt的古老操作)
ActionListener actionListener = new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
// 多次使用显示和隐藏设置false
Platform.setImplicitExit(false);
// 获得按钮并执行相应操作
MenuItem item = (MenuItem) e.getSource();
if (item.getLabel().equals("退出")) {
// 移除托盘图标
SystemTray.getSystemTray().remove(trayIcon);
// 关闭应用
Platform.exit();
// 延迟500毫秒关闭进程
Timeline timeline = new Timeline();
timeline.setCycleCount(1);
timeline.setAutoReverse(false);
KeyFrame keyFrame = new KeyFrame(Duration.millis(500), new EventHandler() {
public void handle(ActionEvent t) {
// 彻底退出进程
System.exit(0);
}
});
timeline.getKeyFrames().clear();
timeline.getKeyFrames().add(keyFrame);
timeline.play();
}
else if (item.getLabel().equals("显示")) {
Platform.runLater(new Runnable() {
public void run() {
stage.show();
}
});
}
else if (item.getLabel().equals("隐藏")) {
Platform.runLater(new Runnable() {
public void run() {
stage.hide();
}
});
}
}
};
// 3、给按钮添加动作事件监听
showItem.addActionListener(actionListener);
quitItem.addActionListener(actionListener);
hideItem.addActionListener(actionListener);
try {
// 4、我们的托盘图标
trayIcon = new TrayIcon(ImageIO.read(new File(Constants.RESOURCES + "img" + File.separator + "sysicon.png")), Constants.TITLE, popupMenu);
// 5、鼠标悬浮时的提示信息
trayIcon.setToolTip(Constants.TITLE);
// 6、添加到系统托盘
SystemTray.getSystemTray().add(trayIcon);
// 7、给托盘图标添加鼠标监听
trayIcon.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
// 多次使用显示和隐藏设置false
Platform.setImplicitExit(false);
// 鼠标单击一次
if (e.getClickCount() == 2) {
timeline.stop();
timeline.setCycleCount(1);
timeline.setAutoReverse(false);
KeyFrame keyFrame = new KeyFrame(Duration.millis(10), new EventHandler() {
public void handle(ActionEvent t) {
if (stage.isShowing()) {
stage.hide();
}else{
stage.show();
}
}
});
timeline.getKeyFrames().clear();
timeline.getKeyFrames().add(keyFrame);
timeline.play();
}
}
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
说明及注意事项
1、使用Timeline来控制双击事件时最大化和隐藏的时间延迟;
2、使用Platform.runLater(new Runnable() {})来执行单击最大化、最小化和退出操作;
3、使用java.awt.MenuItem创建菜单项(按钮);
4、通过设置Platform.setImplicitExit(false),使应用可以多次切换显示和隐藏;
5、一般使用Platform.exit();关闭应用并不能从人物关闭其中关闭进程,随意最好再使用System.exit(0)退出进程;
6、如果不在stage.show()前添加Platform.setImplicitExit(false),那么点击窗口的关闭按钮后就不能再通过系统托盘显示;
如果系统托盘中文乱码(原因是JVM中的编码格式跟windows默认编码不一致),肯定是你的JVM的环境变量没有设置这个-Dfile.encoding=GB18030,这个时候如果你用的Eclipse在Run Configurations中的VM arguments中添加即可,如下图:
如果你实在cmd中启动,同样设置下设个属性即可,如下图:
如果你是打包成EXE程序了,那么你可能不会遇到乱码问题。
package zkh.javafx.learn.systemtray;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import javax.imageio.ImageIO;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import javafx.util.Duration;
import zkh.javafx.util.Constants;
/**
* SystemTray
*/
// 继承javafx.application.Application是JavaFX的开始
public class SysTray extends Application {
public Stage stage = null;
/**
* Stage:就是你能看到的整个软件界面(窗口)
* Scene:就是除了窗口最上面有最大、最小化及关闭按钮那一行及窗口边框外其它的区域(场景)
* 场景(Scene)是一个窗口(Stage)必不可少的
*/
@Override
public void start(Stage stage) throws Exception {
// (如果需要的话)定位横纵坐标,避免太靠边上遮盖菜单栏,,这两行如果不屑,一般电脑默认是居中屏幕显示,但在有些电脑会跑偏
// stage.setX(0);stage.setY(4);
// stage和Scene不再注释
this.stage = stage;
// 创建一个标签,用于存放我们的Hello World文本,并设置让它在父容器中居中
Label label = new Label("系统托盘演示"); label.setAlignment(Pos.CENTER);
// 添加到系统托盘
new MySysTray().initSystemTray();
// (如果不在stage.show()前使用这个,那么点击窗口的关闭按钮后就不能再通过系统托盘显示)多次使用显示和隐藏设置false
Platform.setImplicitExit(false);
// 1、初始化一个场景
Scene scene = new Scene(label, 800, 600);
// 2、将场景放入窗口
stage.setScene(scene);
// 3、打开窗口
stage.show();
}
// 我们的自定义系统托盘
class MySysTray {
private TrayIcon trayIcon = null;
private Timeline timeline = new Timeline();
public void initSystemTray() {
// 1、创建托盘按钮
PopupMenu popupMenu = new PopupMenu();
MenuItem showItem = new MenuItem("显示"); popupMenu.add(showItem);
MenuItem hideItem = new MenuItem("隐藏"); popupMenu.add(hideItem);
MenuItem quitItem = new MenuItem("退出"); popupMenu.add(quitItem);
// 2、创建动作事件监听器(awt的古老操作)
ActionListener actionListener = new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
// 多次使用显示和隐藏设置false
Platform.setImplicitExit(false);
// 获得按钮并执行相应操作
MenuItem item = (MenuItem) e.getSource();
if (item.getLabel().equals("退出")) {
// 移除托盘图标
SystemTray.getSystemTray().remove(trayIcon);
// 关闭应用
Platform.exit();
// 延迟500毫秒关闭进程
Timeline timeline = new Timeline();
timeline.setCycleCount(1);
timeline.setAutoReverse(false);
KeyFrame keyFrame = new KeyFrame(Duration.millis(500), new EventHandler() {
public void handle(ActionEvent t) {
// 彻底退出进程
System.exit(0);
}
});
timeline.getKeyFrames().clear();
timeline.getKeyFrames().add(keyFrame);
timeline.play();
}
else if (item.getLabel().equals("显示")) {
Platform.runLater(new Runnable() {
public void run() {
stage.show();
}
});
}
else if (item.getLabel().equals("隐藏")) {
Platform.runLater(new Runnable() {
public void run() {
stage.hide();
}
});
}
}
};
// 3、给按钮添加动作事件监听
showItem.addActionListener(actionListener);
quitItem.addActionListener(actionListener);
hideItem.addActionListener(actionListener);
try {
// 4、我们的托盘图标
trayIcon = new TrayIcon(ImageIO.read(new File(Constants.RESOURCES + "img" + File.separator + "sysicon.png")), Constants.TITLE, popupMenu);
// 5、鼠标悬浮时的提示信息
trayIcon.setToolTip(Constants.TITLE);
// 6、添加到系统托盘
SystemTray.getSystemTray().add(trayIcon);
// 7、给托盘图标添加鼠标监听
trayIcon.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
// 多次使用显示和隐藏设置false
Platform.setImplicitExit(false);
// 鼠标单击一次
if (e.getClickCount() == 2) {
timeline.stop();
timeline.setCycleCount(1);
timeline.setAutoReverse(false);
KeyFrame keyFrame = new KeyFrame(Duration.millis(10), new EventHandler() {
public void handle(ActionEvent t) {
if (stage.isShowing()) {
stage.hide();
}else{
stage.show();
}
}
});
timeline.getKeyFrames().clear();
timeline.getKeyFrames().add(keyFrame);
timeline.play();
}
}
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main( String[] args ){
// 启动软件
Application.launch(args);
}
}
效果动图:
JavaFX+Jfoenix 学习笔记(十)--系统托盘及解决中文乱码问题源码
好了,多看注释!