问题现象:
Java8-java21 目前使用的java21无法使用awt的TrayIcon类创建中文菜单。 大部分的解决方案是:添加VM参数:
-Dfile.encoding=GBK 但是项目其他模块如文件读写、字符串都是UTF-8 改变项目的编码为GBK不现实。
经过查找发现这个问题对于awt的PopupMenu目前无解(java21也不行),只有使用swring的JPopupMenu可以
参考:https://lanlan2017.github.io/blog/2b294c47/
完整代码:
package top.sirgo.printer.gui;
import javafx.application.Platform;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
public class Tray {
private final Stage primaryStage;
private TrayIcon trayIcon;
private JDialog jDialog = null;
private JPopupMenu jPopupMenu = null;
public Tray(Stage primaryStage, URL iconUrl, String title) {
this.primaryStage = primaryStage;
initTray(iconUrl, title);
}
private void initTray(URL iconUrl, String title) {
if (!SystemTray.isSupported()) return;
// 创建菜单
JPopupMenu awtMenu = createJpopMenu();
// 加载托盘图标
Image image = createTrayImage(iconUrl);
// 创建托盘图标
trayIcon = new TrayIcon(image, title);
trayIcon.setImageAutoSize(true);
// 添加事件监听
addTrayListeners();
try {
SystemTray.getSystemTray().add(trayIcon);
} catch (AWTException e) {
e.printStackTrace();
}
}
private PopupMenu createMenu() {
PopupMenu menu = new PopupMenu();
// 创建菜单项
MenuItem openItem = createMenuItem("打开程序", e -> showStage());
MenuItem exitItem = createMenuItem("退出程序", e -> exitApp());
// 设置全局字体
Font chineseFont = new Font("Microsoft YaHei", Font.PLAIN, 12);
menu.setFont(chineseFont);
menu.add(openItem);
menu.addSeparator();
menu.add(exitItem);
return menu;
}
private MenuItem createMenuItem(String text, ActionListener action) {
MenuItem item = new MenuItem(text);
item.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
item.addActionListener(action);
return item;
}
private JPopupMenu createJpopMenu() {
jDialog = new JDialog();
//关闭JDialog的装饰器
jDialog.setUndecorated(true);
//jDialog作为JPopupMenu载体不需要多大的size
jDialog.setSize(1, 1);
//创建JPopupMenu
//重写firePopupMenuWillBecomeInvisible
//消失后将绑定的组件一起消失
jPopupMenu = new JPopupMenu() {
@Override
public void firePopupMenuWillBecomeInvisible() {
jDialog.setVisible(false);
System.out.println("JPopupMenu不可见时绑定载体组件jDialog也不可见");
}
};
jPopupMenu.setSize(150, 30);
// 使用Swing组件创建菜单项
JMenuItem openItem = createJMenuItem("打开程序", e -> showStage());
JMenuItem exitItem = createJMenuItem("退出程序", e -> exitApp());
jPopupMenu.add(openItem);
jPopupMenu.add(exitItem);
return jPopupMenu;
}
private JMenuItem createJMenuItem(String text, ActionListener action) {
JMenuItem jMenuItem = new JMenuItem(text);
jMenuItem.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
jMenuItem.addActionListener(action);
return jMenuItem;
}
private Image createTrayImage(URL iconUrl) {
try {
return ImageIO.read(iconUrl.openStream());
} catch (IOException e) {
e.printStackTrace();
return new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
}
}
private void addTrayListeners() {
trayIcon.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent e) {
if (e.getClickCount() == 2) {
showStage();
}
}
@Override
public void mouseReleased(MouseEvent e) {
//左键点击
if (e.getButton() == 1) {
showStage();
} else if (e.getButton() == 3 && e.isPopupTrigger()) {
if (jDialog == null || jPopupMenu == null) {
return;
}
// 右键点击弹出JPopupMenu绑定的载体以及JPopupMenu
jDialog.setLocation(e.getX() + 5, e.getY() - 5 - jPopupMenu.getHeight());
// 显示载体
jDialog.setVisible(true);
// 在载体的0,0处显示对话框
jPopupMenu.show(jDialog, 0, 0);
}
}
});
}
private void showStage() {
Platform.runLater(() -> {
if (primaryStage.isIconified() || !primaryStage.isShowing()) {
primaryStage.show();
primaryStage.setIconified(false);
}
});
}
private void exitApp() {
Platform.runLater(() -> {
primaryStage.close();
SystemTray.getSystemTray().remove(trayIcon);
System.exit(0);
});
}
}
评论区