feat(gui): 添加系统托盘功能并优化 UI
- 实现系统托盘支持,包含打开主界面、反编译工具和退出程序的菜单项 - 添加窗口关闭时隐藏而不是退出的功能 -优化托盘图标,使用圆角图像 - 增加中文字体支持和全局字体设置- 移除 AIChatDialog 中的 MathJax 配置- 更新 BoxClassLoader,添加 com.dustinredmond 包的访问权限 - 在 build.gradle 中添加 SystemTray4J 和 JavaFX相关依赖
This commit is contained in:
251
src/main/java/com/axis/innovators/box/gui/ModernTrayApp.java
Normal file
251
src/main/java/com/axis/innovators/box/gui/ModernTrayApp.java
Normal file
@@ -0,0 +1,251 @@
|
||||
package com.axis.innovators.box.gui;
|
||||
|
||||
import com.axis.innovators.box.AxisInnovatorsBox;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
/**
|
||||
* 创建一个具有圆角效果的系统托盘图标,并添加右键菜单。
|
||||
* (未完成)
|
||||
* @author tzdwindows 7
|
||||
*/
|
||||
public class ModernTrayApp {
|
||||
private static final int ITEM_WIDTH = 145;
|
||||
private static final int ITEM_HEIGHT = 29;
|
||||
private static final int ICON_SIZE = 16;
|
||||
private static final int WINDOW_CORNER = 6;
|
||||
private static final Color MENU_BG_COLOR = new Color(250, 250, 250);
|
||||
|
||||
private TrayIcon trayIcon;
|
||||
private JPopupMenu popupMenu;
|
||||
private JWindow mainWindow;
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
if (!System.getProperty("os.name").contains("Windows")) {
|
||||
JOptionPane.showMessageDialog(null, "本程序仅支持Windows系统");
|
||||
return;
|
||||
}
|
||||
new ModernTrayApp().initTray();
|
||||
}
|
||||
|
||||
private void initTray() {
|
||||
try {
|
||||
// 1. 加载并缩放托盘图标
|
||||
Image trayImage = LoadIcon.loadIcon("logo.png", 32).getImage();
|
||||
trayIcon = new TrayIcon(trayImage, "轴创工具箱");
|
||||
trayIcon.setImageAutoSize(true);
|
||||
// 2. 创建主窗口
|
||||
createMainWindow();
|
||||
|
||||
// 3. 创建圆角菜单
|
||||
createRoundPopupMenu();
|
||||
|
||||
// 4. 配置系统托盘
|
||||
SystemTray.getSystemTray().add(trayIcon);
|
||||
trayIcon.addMouseListener(new TrayMouseListener());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void createMainWindow() {
|
||||
mainWindow = new JWindow() {
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
// 创建临时图形上下文
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
|
||||
// 启用高质量渲染
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
|
||||
// 绘制透明背景(关键步骤)
|
||||
g2.setComposite(AlphaComposite.Clear);
|
||||
g2.fillRect(0, 0, getWidth(), getHeight());
|
||||
g2.setComposite(AlphaComposite.SrcOver);
|
||||
|
||||
// 绘制圆角面板
|
||||
g2.setColor(MENU_BG_COLOR);
|
||||
g2.fillRoundRect(0, 0, getWidth(), getHeight(), WINDOW_CORNER, WINDOW_CORNER);
|
||||
|
||||
// 绘制边框
|
||||
g2.setColor(new Color(220, 220, 220));
|
||||
g2.drawRoundRect(0, 0, getWidth()-1, getHeight()-1, WINDOW_CORNER, WINDOW_CORNER);
|
||||
|
||||
g2.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
mainWindow.setSize(ITEM_WIDTH, ITEM_HEIGHT * 3 + 10);
|
||||
mainWindow.setShape(new RoundRectangle2D.Float(0, 0,
|
||||
mainWindow.getWidth(), mainWindow.getHeight(), WINDOW_CORNER, WINDOW_CORNER));
|
||||
|
||||
|
||||
// 合并后的焦点监听器
|
||||
mainWindow.addWindowFocusListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowLostFocus(WindowEvent e) {
|
||||
closeMenuAndWindow();
|
||||
}
|
||||
});
|
||||
mainWindow.setType(Window.Type.POPUP);
|
||||
}
|
||||
|
||||
private void closeMenuAndWindow() {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
// 添加淡出动画
|
||||
new Thread(() -> {
|
||||
for (float opacity = 1.0f; opacity > 0; opacity -= 0.1f) {
|
||||
final float finalOpacity = opacity;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
mainWindow.setOpacity(finalOpacity);
|
||||
});
|
||||
try { Thread.sleep(20); } catch (InterruptedException e) {}
|
||||
}
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
popupMenu.setVisible(false);
|
||||
mainWindow.setVisible(false);
|
||||
mainWindow.setOpacity(1.0f); // 重置透明度
|
||||
});
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void updateWindowShape() {
|
||||
RoundRectangle2D shape = new RoundRectangle2D.Float(
|
||||
0, 0,
|
||||
mainWindow.getWidth(), mainWindow.getHeight(),
|
||||
WINDOW_CORNER, WINDOW_CORNER
|
||||
);
|
||||
mainWindow.setShape(shape);
|
||||
}
|
||||
|
||||
private void updateWindowSize(int width, int height) {
|
||||
mainWindow.setSize(width, height);
|
||||
updateWindowShape();
|
||||
}
|
||||
|
||||
private void createRoundPopupMenu() {
|
||||
popupMenu = new JPopupMenu(){
|
||||
@Override
|
||||
protected void firePopupMenuCanceled() {
|
||||
closeMenuAndWindow();
|
||||
super.firePopupMenuWillBecomeInvisible();
|
||||
}
|
||||
};
|
||||
popupMenu.setLayout(new GridLayout(0, 1, 0, 1));
|
||||
|
||||
JPanel customSeparator = new JPanel() {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
g.setColor(new Color(220, 220, 220));
|
||||
g.fillRect(5, getHeight()/2, getWidth()-10, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(ITEM_WIDTH, 4);
|
||||
}
|
||||
};
|
||||
customSeparator.setOpaque(false);
|
||||
|
||||
popupMenu.add(ComponentFactory.createTextComponent("AxisInnovatorsBox",
|
||||
new Color(0, 0, 0),
|
||||
15,
|
||||
new Dimension(ITEM_WIDTH, 4)));
|
||||
popupMenu.add(ComponentFactory.createTextComponent(" ————"
|
||||
+ AxisInnovatorsBox.getVersion(),
|
||||
new Color(83, 83, 83),
|
||||
12,
|
||||
new Dimension(ITEM_WIDTH, 4)));
|
||||
|
||||
popupMenu.add(customSeparator);
|
||||
addStyledMenuItem("打开主界面", "home.png");
|
||||
addStyledMenuItem("Java反编译", "decompile.png");
|
||||
popupMenu.add(customSeparator);
|
||||
|
||||
addStyledMenuItem("退出程序", "exit.png");
|
||||
}
|
||||
|
||||
private void addStyledMenuItem(String text, String iconPath) {
|
||||
JMenuItem item = new JMenuItem(text) {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// 绘制背景
|
||||
if (isArmed()) {
|
||||
g2.setColor(new Color(161, 161, 161));
|
||||
g2.fillRoundRect(0, 0, getWidth(), getHeight(), 4, 4);
|
||||
}
|
||||
|
||||
// 绘制图标
|
||||
Image icon = LoadIcon.loadIcon(iconPath, ICON_SIZE).getImage();
|
||||
g2.drawImage(icon, 8, (ITEM_HEIGHT - ICON_SIZE)/2, null);
|
||||
|
||||
// 绘制文本
|
||||
g2.setFont(new Font("微软雅黑", Font.PLAIN, 12));
|
||||
g2.setColor(Color.DARK_GRAY);
|
||||
g2.drawString(text, 28, (ITEM_HEIGHT + g2.getFontMetrics().getAscent())/2 - 1);
|
||||
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(ITEM_WIDTH, ITEM_HEIGHT);
|
||||
}
|
||||
};
|
||||
|
||||
item.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
|
||||
item.setOpaque(false);
|
||||
popupMenu.add(item);
|
||||
}
|
||||
|
||||
private class TrayMouseListener extends MouseAdapter {
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if (e.isPopupTrigger()) {
|
||||
showMenu(e.getX(), e.getY());
|
||||
}
|
||||
}
|
||||
|
||||
private void showMenu(int x, int y) {
|
||||
Point mousePos = MouseInfo.getPointerInfo().getLocation();
|
||||
Point menuLocation = calculateMenuPosition(mousePos);
|
||||
|
||||
mainWindow.setLocation(menuLocation);
|
||||
mainWindow.setVisible(true);
|
||||
popupMenu.show(mainWindow.getContentPane(), 0, 0);
|
||||
}
|
||||
|
||||
private Point calculateMenuPosition(Point pos) {
|
||||
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
int menuHeight = mainWindow.getHeight();
|
||||
|
||||
// 默认显示在鼠标右上方
|
||||
int finalX = pos.x + 16; // 向右偏移16px
|
||||
int finalY = pos.y - menuHeight - 8; // 向上偏移8px
|
||||
|
||||
// 右侧边界检测
|
||||
if (finalX + ITEM_WIDTH > screenSize.width) {
|
||||
finalX = screenSize.width - ITEM_WIDTH - 8;
|
||||
}
|
||||
|
||||
// 顶部溢出检测
|
||||
if (finalY < 0) {
|
||||
finalY = pos.y + 16; // 改为显示在下方
|
||||
}
|
||||
|
||||
return new Point(finalX, finalY);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user