feat(gui): 添加系统托盘功能并优化 UI
- 实现系统托盘支持,包含打开主界面、反编译工具和退出程序的菜单项 - 添加窗口关闭时隐藏而不是退出的功能 -优化托盘图标,使用圆角图像 - 增加中文字体支持和全局字体设置- 移除 AIChatDialog 中的 MathJax 配置- 更新 BoxClassLoader,添加 com.dustinredmond 包的访问权限 - 在 build.gradle 中添加 SystemTray4J 和 JavaFX相关依赖
This commit is contained in:
@@ -114,6 +114,13 @@ dependencies {
|
|||||||
implementation 'com.kitfox.svg:svg-salamander:1.0'
|
implementation 'com.kitfox.svg:svg-salamander:1.0'
|
||||||
|
|
||||||
implementation 'com.vladsch.flexmark:flexmark:0.64.8'
|
implementation 'com.vladsch.flexmark:flexmark:0.64.8'
|
||||||
|
|
||||||
|
// SystemTray4J 核心库
|
||||||
|
implementation 'com.github.kwhat:jnativehook:2.2.2'
|
||||||
|
implementation 'com.dustinredmond.fxtrayicon:FXTrayIcon:4.0.1' // 增强版
|
||||||
|
|
||||||
|
// JavaFX 模块
|
||||||
|
implementation 'org.openjfx:javafx-graphics:21'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分离依赖项到 libs 目录
|
// 分离依赖项到 libs 目录
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.axis.innovators.box.gui;
|
package com.axis.innovators.box.gui;
|
||||||
|
|
||||||
import com.axis.innovators.box.AxisInnovatorsBox;
|
import com.axis.innovators.box.AxisInnovatorsBox;
|
||||||
|
import com.axis.innovators.box.decompilation.gui.ModernJarViewer;
|
||||||
import com.axis.innovators.box.events.*;
|
import com.axis.innovators.box.events.*;
|
||||||
import com.axis.innovators.box.register.RegistrationSettingsItem;
|
import com.axis.innovators.box.register.RegistrationSettingsItem;
|
||||||
import com.axis.innovators.box.register.LanguageManager;
|
import com.axis.innovators.box.register.LanguageManager;
|
||||||
@@ -11,11 +12,14 @@ import org.apache.logging.log4j.Logger;
|
|||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
|
import javax.swing.plaf.FontUIResource;
|
||||||
import javax.swing.plaf.PanelUI;
|
import javax.swing.plaf.PanelUI;
|
||||||
import javax.swing.plaf.basic.BasicScrollBarUI;
|
import javax.swing.plaf.basic.BasicScrollBarUI;
|
||||||
import javax.swing.plaf.basic.BasicTabbedPaneUI;
|
import javax.swing.plaf.basic.BasicTabbedPaneUI;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.ConvolveOp;
|
import java.awt.image.ConvolveOp;
|
||||||
import java.awt.image.Kernel;
|
import java.awt.image.Kernel;
|
||||||
@@ -34,6 +38,8 @@ public class MainWindow extends JFrame {
|
|||||||
private final List<ToolCategory> categories = new ArrayList<>();
|
private final List<ToolCategory> categories = new ArrayList<>();
|
||||||
private final boolean isBackground = true;
|
private final boolean isBackground = true;
|
||||||
private final boolean isBlur = true;
|
private final boolean isBlur = true;
|
||||||
|
private SystemTray systemTray;
|
||||||
|
private TrayIcon trayIcon;
|
||||||
|
|
||||||
public MainWindow() {
|
public MainWindow() {
|
||||||
setIconImage(LoadIcon.loadIcon("logo.png", 32).getImage());
|
setIconImage(LoadIcon.loadIcon("logo.png", 32).getImage());
|
||||||
@@ -63,6 +69,8 @@ public class MainWindow extends JFrame {
|
|||||||
setSize(1200, 800);
|
setSize(1200, 800);
|
||||||
setLocationRelativeTo(null);
|
setLocationRelativeTo(null);
|
||||||
|
|
||||||
|
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||||
|
|
||||||
getContentPane().setBackground(new Color(0, 0, 0, 0));
|
getContentPane().setBackground(new Color(0, 0, 0, 0));
|
||||||
|
|
||||||
JPanel mainPanel = new JPanel();
|
JPanel mainPanel = new JPanel();
|
||||||
@@ -76,18 +84,128 @@ public class MainWindow extends JFrame {
|
|||||||
mainPanel.add(createCategoryTabs(), BorderLayout.CENTER);
|
mainPanel.add(createCategoryTabs(), BorderLayout.CENTER);
|
||||||
|
|
||||||
add(mainPanel);
|
add(mainPanel);
|
||||||
|
createSystemTray();
|
||||||
|
addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private BufferedImage toBufferedImage(Image img) {
|
private void createSystemTray() {
|
||||||
if (img instanceof BufferedImage) {
|
if (!SystemTray.isSupported()) {
|
||||||
return (BufferedImage) img;
|
logger.error("系统托盘不支持!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
BufferedImage bimage = new BufferedImage(
|
|
||||||
img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
|
// 初始化系统托盘
|
||||||
Graphics2D bGr = bimage.createGraphics();
|
systemTray = SystemTray.getSystemTray();
|
||||||
bGr.drawImage(img, 0, 0, null);
|
|
||||||
bGr.dispose();
|
// 1. 加载并处理圆角图标(修正图像类型)
|
||||||
return bimage;
|
ImageIcon rawIcon = LoadIcon.loadIcon("logo.png", 64);
|
||||||
|
Image roundedImage = createRoundedIcon(rawIcon.getImage(), 16);
|
||||||
|
|
||||||
|
// 2. 创建支持中文的弹出菜单
|
||||||
|
PopupMenu popup = new PopupMenu();
|
||||||
|
|
||||||
|
// 3. 创建菜单项(使用标准AWT组件)
|
||||||
|
MenuItem openItem = createBaseMenuItem("打开主界面", e -> setVisible(true));
|
||||||
|
MenuItem decompileItem = createBaseMenuItem("打开反编译工具", e ->
|
||||||
|
new ModernJarViewer(null).setVisible(true));
|
||||||
|
MenuItem exitItem = createBaseMenuItem("退出程序", e -> AxisInnovatorsBox.getMain().quit());
|
||||||
|
|
||||||
|
// 4. 构建菜单结构
|
||||||
|
popup.add(openItem);
|
||||||
|
popup.addSeparator();
|
||||||
|
popup.add(decompileItem);
|
||||||
|
popup.addSeparator();
|
||||||
|
popup.add(exitItem);
|
||||||
|
|
||||||
|
// 5. 创建托盘图标
|
||||||
|
trayIcon = new TrayIcon(roundedImage, "轴创工具箱", popup);
|
||||||
|
trayIcon.setImageAutoSize(true);
|
||||||
|
|
||||||
|
// 6. 添加事件监听
|
||||||
|
addTrayEventListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
systemTray.add(trayIcon);
|
||||||
|
} catch (AWTException ex) {
|
||||||
|
logger.error("添加系统托盘图标失败", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础菜单项创建方法(解决方法不存在问题)
|
||||||
|
private MenuItem createBaseMenuItem(String text, ActionListener action) {
|
||||||
|
MenuItem item = new MenuItem(text);
|
||||||
|
item.addActionListener(action);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 圆角图标生成(修正版)
|
||||||
|
private Image createRoundedIcon(Image source, int cornerRadius) {
|
||||||
|
int size = Math.max(source.getWidth(null), source.getHeight(null));
|
||||||
|
BufferedImage output = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
|
Graphics2D g2 = output.createGraphics();
|
||||||
|
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
|
// 创建剪切路径
|
||||||
|
RoundRectangle2D roundRect = new RoundRectangle2D.Float(0, 0, size, size, cornerRadius, cornerRadius);
|
||||||
|
g2.setClip(roundRect);
|
||||||
|
g2.drawImage(source, 0, 0, size, size, null);
|
||||||
|
|
||||||
|
g2.dispose();
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加事件监听
|
||||||
|
private void addTrayEventListeners() {
|
||||||
|
// 双击恢复窗口
|
||||||
|
trayIcon.addActionListener(e -> setVisible(true));
|
||||||
|
|
||||||
|
// 右键菜单触发兼容处理
|
||||||
|
trayIcon.addMouseListener(new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
if (e.isPopupTrigger()) {
|
||||||
|
trayIcon.getPopupMenu().show(e.getComponent(), e.getX(), e.getY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化中文字体(在main方法或构造函数中调用)
|
||||||
|
private void initChineseFont() {
|
||||||
|
String[] fontPriority = {
|
||||||
|
"Microsoft YaHei",
|
||||||
|
"PingFang SC",
|
||||||
|
"SimSun",
|
||||||
|
Font.DIALOG
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String fontName : fontPriority) {
|
||||||
|
if (isFontAvailable(fontName)) {
|
||||||
|
setGlobalFont(new Font(fontName, Font.PLAIN, 12));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字体可用性检查
|
||||||
|
private boolean isFontAvailable(String fontName) {
|
||||||
|
return Arrays.asList(GraphicsEnvironment
|
||||||
|
.getLocalGraphicsEnvironment()
|
||||||
|
.getAvailableFontFamilyNames())
|
||||||
|
.contains(fontName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全局字体设置
|
||||||
|
private void setGlobalFont(Font font) {
|
||||||
|
FontUIResource fontRes = new FontUIResource(font);
|
||||||
|
UIManager.put("MenuItem.font", fontRes);
|
||||||
|
UIManager.put("Menu.font", fontRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class BoxClassLoader extends URLClassLoader {
|
|||||||
"java.", "javax.", "sun.", "com.sun.", "jdk.",
|
"java.", "javax.", "sun.", "com.sun.", "jdk.",
|
||||||
"org.xml.", "org.w3c.", "org.apache.",
|
"org.xml.", "org.w3c.", "org.apache.",
|
||||||
"javax.management.", "javax.swing."
|
"javax.management.", "javax.swing."
|
||||||
, "javafx.","org.jnativehook."
|
, "javafx.","org.jnativehook.","com.dustinredmond."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -479,7 +479,6 @@ public class AIChatDialog extends JFrame {
|
|||||||
Node document = markdownParser.parse(markdown);
|
Node document = markdownParser.parse(markdown);
|
||||||
processedHtml = htmlRenderer.render(document);
|
processedHtml = htmlRenderer.render(document);
|
||||||
|
|
||||||
// 强化 MathJax 配置
|
|
||||||
processedHtml = String.format("""
|
processedHtml = String.format("""
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|||||||
Reference in New Issue
Block a user