feat(theme): 动态主题适配及 UI 组件样式优化- 新增 updateTheme 方法以支持动态主题更新
- 优化 MainWindow 中的组件样式,包括按钮、滚动条等 - 调整侧边栏样式,增加选中状态和悬停效果 - 优化卡片背景和边框颜色,适应不同主题 - 修复部分组件在深色主题下的显示问题
@@ -889,10 +889,12 @@ public class AxisInnovatorsBox {
|
||||
for (WindowsJDialog windowsJDialog : windowsJDialogList) {
|
||||
windowsJDialog.getContentPane().removeAll();
|
||||
windowsJDialog.initUI();
|
||||
windowsJDialog.updateTheme();
|
||||
windowsJDialog.revalidate();
|
||||
windowsJDialog.repaint();
|
||||
}
|
||||
ex.initUI();
|
||||
ex.updateTheme();
|
||||
ex.revalidate();
|
||||
RegistrationSettingsItem.overloading();
|
||||
isWindow = true;
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
@@ -60,20 +61,20 @@ public class MainWindow extends JFrame {
|
||||
private WindowsJDialog dialog;
|
||||
|
||||
// 侧边栏颜色(比面板背景稍暗)
|
||||
private static final Color SIDEBAR_COLOR = Optional.ofNullable(UIManager.getColor("Panel.background"))
|
||||
private static Color SIDEBAR_COLOR = Optional.ofNullable(UIManager.getColor("Panel.background"))
|
||||
.orElse(new Color(0x3C3F41));
|
||||
|
||||
// 卡片背景(深色模式适配,比侧边栏稍亮)
|
||||
private static final Color CARD_BG = Optional.ofNullable(UIManager.getColor("control"))
|
||||
private static Color CARD_BG = Optional.ofNullable(UIManager.getColor("control"))
|
||||
.map(bg -> ThemeColors.brighten(bg, 0.1f))
|
||||
.orElse(new Color(0x4A4D50));
|
||||
|
||||
// 卡片边框(使用系统边框色或稍亮颜色)
|
||||
private static final Color CARD_BORDER = Optional.ofNullable(UIManager.getColor("controlHighlight"))
|
||||
private static Color CARD_BORDER = Optional.ofNullable(UIManager.getColor("controlHighlight"))
|
||||
.orElse(new Color(0x5C5F61));
|
||||
|
||||
// 文本颜色(直接使用系统主题的文本颜色)
|
||||
private static final Color TEXT_COLOR = Optional.ofNullable(UIManager.getColor("textText"))
|
||||
private static Color TEXT_COLOR = Optional.ofNullable(UIManager.getColor("textText"))
|
||||
.orElse(new Color(0xE0E0E0));
|
||||
|
||||
public MainWindow() {
|
||||
@@ -99,6 +100,8 @@ public class MainWindow extends JFrame {
|
||||
UIManager.put("TextArea.font", fontRes);
|
||||
UIManager.put("TabbedPane.font", fontRes);
|
||||
UIManager.put("TitledBorder.font", fontRes);
|
||||
UIManager.put("ScrollPane.border", BorderFactory.createEmptyBorder());
|
||||
UIManager.put("Panel.border", BorderFactory.createEmptyBorder());
|
||||
|
||||
// 图标
|
||||
setIconImage(LoadIcon.loadIcon("logo.png", 32).getImage());
|
||||
@@ -122,6 +125,8 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,13 +140,26 @@ public class MainWindow extends JFrame {
|
||||
* 初始化并显示 UI
|
||||
*/
|
||||
public void initUI() {
|
||||
categoryScrollPanes.clear();
|
||||
categoryToolPanels.clear();
|
||||
sideButtons.clear();
|
||||
cardScales.clear();
|
||||
cardElevations.clear();
|
||||
currentCategoryId = null;
|
||||
|
||||
// 清除现有UI组件
|
||||
if (layeredPane != null) {
|
||||
layeredPane.removeAll();
|
||||
}
|
||||
getContentPane().removeAll();
|
||||
|
||||
setTitle(LanguageManager.getLoadedLanguages().getText("mainWindow.title"));
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
setSize(1200, 800);
|
||||
setLocationRelativeTo(null);
|
||||
|
||||
// 主容器
|
||||
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder());
|
||||
mainPanel.setOpaque(true);
|
||||
Color panelBg = UIManager.getColor("Panel.background");
|
||||
if (panelBg == null) panelBg = new Color(245, 246, 248);
|
||||
@@ -221,6 +239,87 @@ public class MainWindow extends JFrame {
|
||||
|
||||
// 更新 UI 字体样式(确保生效)
|
||||
SwingUtilities.updateComponentTreeUI(this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新主题
|
||||
*/
|
||||
public void updateTheme() {
|
||||
// 1. 更新UI管理器默认值
|
||||
Font defaultFont = selectFont(new String[]{"Microsoft YaHei", "微软雅黑", "PingFang SC", "SimHei", "宋体", "新宋体", "SansSerif"}, 14);
|
||||
FontUIResource fontRes = new FontUIResource(defaultFont);
|
||||
UIManager.put("Label.font", fontRes);
|
||||
UIManager.put("Button.font", fontRes);
|
||||
UIManager.put("TextField.font", fontRes);
|
||||
UIManager.put("TextArea.font", fontRes);
|
||||
UIManager.put("TabbedPane.font", fontRes);
|
||||
UIManager.put("TitledBorder.font", fontRes);
|
||||
|
||||
// 2. 强制更新所有UI组件
|
||||
SwingUtilities.updateComponentTreeUI(this);
|
||||
|
||||
// 3. 手动更新关键组件
|
||||
|
||||
// 更新搜索框
|
||||
if (searchField != null) {
|
||||
searchField.defaultBorderColor = UIManager.getColor("TextField.borderColor");
|
||||
if (searchField.defaultBorderColor == null) {
|
||||
searchField.defaultBorderColor = new Color(180, 180, 180);
|
||||
}
|
||||
searchField.repaint();
|
||||
}
|
||||
|
||||
// 4. 特殊处理卡片颜色
|
||||
for (JComponent card : cardScales.keySet()) {
|
||||
card.repaint();
|
||||
}
|
||||
|
||||
// 5. 更新分类滚动面板
|
||||
for (JScrollPane scrollPane : categoryScrollPanes.values()) {
|
||||
scrollPane.getVerticalScrollBar().setUI(new CustomScrollBarUI());
|
||||
scrollPane.repaint();
|
||||
}
|
||||
|
||||
// 6. 更新主面板背景
|
||||
Component content = getContentPane();
|
||||
if (content instanceof JComponent) {
|
||||
JComponent contentPane = (JComponent) content;
|
||||
Color panelBg = UIManager.getColor("Panel.background");
|
||||
if (panelBg == null) panelBg = new Color(245, 246, 248);
|
||||
contentPane.setBackground(panelBg);
|
||||
contentPane.repaint();
|
||||
}
|
||||
|
||||
// 7. 更新所有按钮状态
|
||||
for (JButton btn : sideButtons.values()) {
|
||||
btn.setForeground(Optional.ofNullable(UIManager.getColor("textText"))
|
||||
.orElse(new Color(0xE0E0E0)));
|
||||
btn.repaint();
|
||||
}
|
||||
|
||||
// 8. 更新当前分类显示
|
||||
if (currentCategoryId != null) {
|
||||
JScrollPane currentPane = categoryScrollPanes.get(currentCategoryId);
|
||||
if (currentPane != null) {
|
||||
cardsLayout.show(cardsPanel, currentCategoryId);
|
||||
currentPane.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
if (sideBar != null) {
|
||||
sideBar.setBackground(getSidebarColor());
|
||||
sideBar.repaint();
|
||||
}
|
||||
|
||||
// 9. 确保窗口正确重绘
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private Color getSidebarColor() {
|
||||
return Optional.ofNullable(UIManager.getColor("Panel.background"))
|
||||
.orElse(new Color(0x3C3F41));
|
||||
}
|
||||
|
||||
private void syncLayeredBounds() {
|
||||
@@ -363,6 +462,14 @@ public class MainWindow extends JFrame {
|
||||
});
|
||||
}
|
||||
|
||||
public void updateThemeColors() {
|
||||
defaultBorderColor = UIManager.getColor("TextField.borderColor");
|
||||
if (defaultBorderColor == null) {
|
||||
defaultBorderColor = new Color(180, 180, 180);
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
@@ -433,19 +540,21 @@ public class MainWindow extends JFrame {
|
||||
sidebar.setOpaque(true);
|
||||
sidebar.setBackground(SIDEBAR_COLOR);
|
||||
sidebar.setPreferredSize(new Dimension(220, getHeight()));
|
||||
sidebar.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
||||
sidebar.setBorder(null);
|
||||
|
||||
// top: logo + app name
|
||||
JPanel top = new JPanel(new BorderLayout());
|
||||
top.setOpaque(false);
|
||||
JLabel logo = new JLabel(LoadIcon.loadIcon("logo.png", 36));
|
||||
logo.setBorder(BorderFactory.createEmptyBorder(8, 6, 8, 6));
|
||||
JLabel appName = new JLabel(LanguageManager.getLoadedLanguages().getText("mainWindow.title.2"));
|
||||
appName.setFont(new Font(selectFont("Segoe UI", "Microsoft YaHei", "SansSerif", 15).getName(), Font.BOLD, 15));
|
||||
appName.setForeground(Color.WHITE);
|
||||
appName.setBorder(BorderFactory.createEmptyBorder(8, 6, 8, 6));
|
||||
top.add(logo, BorderLayout.WEST);
|
||||
top.add(appName, BorderLayout.CENTER);
|
||||
|
||||
JPanel centerPanel = new JPanel();
|
||||
centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));
|
||||
centerPanel.setOpaque(false);
|
||||
|
||||
JLabel logo = new JLabel(LoadIcon.loadIcon("logo.png", 60));
|
||||
logo.setBorder(BorderFactory.createEmptyBorder(10, 6, 10 + 10, 6));
|
||||
logo.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||
centerPanel.add(logo);
|
||||
top.add(centerPanel, BorderLayout.CENTER);
|
||||
sidebar.add(top, BorderLayout.NORTH);
|
||||
|
||||
// list of categories
|
||||
@@ -468,7 +577,7 @@ public class MainWindow extends JFrame {
|
||||
listScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
listScroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
listScroll.getVerticalScrollBar().setUI(new CustomScrollBarUI());
|
||||
listScroll.setBackground(new Color(0,0,0,0));
|
||||
listScroll.setBackground(new Color(0, 0, 0, 0));
|
||||
|
||||
sidebar.add(listScroll, BorderLayout.CENTER);
|
||||
|
||||
@@ -478,59 +587,148 @@ public class MainWindow extends JFrame {
|
||||
bottom.setLayout(new BoxLayout(bottom, BoxLayout.Y_AXIS));
|
||||
bottom.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
|
||||
|
||||
//JButton settingsButton = new JButton("设置");
|
||||
//styleSideSmallButton(settingsButton);
|
||||
//settingsButton.addActionListener(e -> showSettings());
|
||||
//settingsButton.setBackground(SIDEBAR_COLOR);
|
||||
//bottom.add(settingsButton);
|
||||
//bottom.add(Box.createVerticalStrut(8));
|
||||
//
|
||||
//JButton aboutButton = new JButton("关于");
|
||||
//styleSideSmallButton(aboutButton);
|
||||
//aboutButton.addActionListener(e -> JOptionPane.showMessageDialog(this, "作者: tzdwindows7"));
|
||||
//bottom.add(aboutButton);
|
||||
|
||||
sidebar.add(bottom, BorderLayout.SOUTH);
|
||||
|
||||
return sidebar;
|
||||
}
|
||||
|
||||
private JButton createSideButton(ToolCategory category) {
|
||||
// 竖杠距离按钮左侧位置
|
||||
final int BAR_X = 8;
|
||||
// 竖杠宽度
|
||||
final int BAR_WIDTH = 5;
|
||||
// 竖杠到图标的空隙
|
||||
final int GAP_BAR_TO_ICON = 12;
|
||||
final Color SELECT_FILL = new Color(0, 120, 215, 20);
|
||||
Color HOVER_FILL;// 悬停颜色
|
||||
if (isDarkTheme()) {
|
||||
HOVER_FILL = new Color(0x535360);
|
||||
} else {
|
||||
HOVER_FILL = new Color(0xD0E0F6);
|
||||
}
|
||||
|
||||
JButton button = new JButton(category.getName());
|
||||
|
||||
button.setMaximumSize(new Dimension(Integer.MAX_VALUE, 44));
|
||||
button.setHorizontalAlignment(SwingConstants.LEFT);
|
||||
// icon 使用白色版本如果可用(你可以自己准备深色侧栏专用图标)
|
||||
ImageIcon ic = category.getIconImage() != null ? category.getIconImage() : LoadIcon.loadIcon(category.getIcon(), 18);
|
||||
button.setIcon(ic);
|
||||
button.setIconTextGap(12);
|
||||
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
button.setForeground(TEXT_COLOR);
|
||||
button.setBackground(TEXT_COLOR);
|
||||
button.setOpaque(false);
|
||||
button.setBorder(BorderFactory.createEmptyBorder(8, 12, 8, 12));
|
||||
button.setFocusPainted(false);
|
||||
button.setFont(new Font(selectFont("Segoe UI", "Microsoft YaHei", "SansSerif", 13).getName(), Font.PLAIN, 13));
|
||||
|
||||
button.addActionListener(e -> {
|
||||
// 切换分类时清空搜索并触发动画切换
|
||||
searchField.setText("");
|
||||
switchCategory(category.getId().toString(), false);
|
||||
});
|
||||
// 原始图标
|
||||
ImageIcon rawIcon = category.getIconImage() != null
|
||||
? category.getIconImage()
|
||||
: LoadIcon.loadIcon(category.getIcon(), 18);
|
||||
int rawIconWidth = (rawIcon != null) ? rawIcon.getIconWidth() : 18;
|
||||
final int ICON_PADDING_LEFT = BAR_X + BAR_WIDTH + GAP_BAR_TO_ICON; // 左侧为图标预留的偏移
|
||||
|
||||
// hover 效果(浅背景)
|
||||
button.addMouseListener(new MouseAdapter() {
|
||||
@Override public void mouseEntered(MouseEvent e) {
|
||||
if (!Objects.equals(currentCategoryId, category.getId().toString())) {
|
||||
button.setOpaque(true);
|
||||
button.setBackground(new Color(0x4A4D50)); // 深灰微亮
|
||||
// 包装一个带左侧内边距的 Icon,使图标整体右移
|
||||
Icon paddedIcon = new Icon() {
|
||||
@Override
|
||||
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||
if (rawIcon != null) {
|
||||
int dy = (getIconHeight() - rawIcon.getIconHeight()) / 2;
|
||||
rawIcon.paintIcon(c, g, x + ICON_PADDING_LEFT, y + dy);
|
||||
}
|
||||
}
|
||||
@Override public void mouseExited(MouseEvent e) {
|
||||
if (!Objects.equals(currentCategoryId, category.getId().toString())) {
|
||||
button.setOpaque(false);
|
||||
button.setBackground(new Color(0,0,0,0));
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return ICON_PADDING_LEFT + rawIconWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return (rawIcon != null) ? rawIcon.getIconHeight() : 18;
|
||||
}
|
||||
};
|
||||
|
||||
button.setIcon(paddedIcon);
|
||||
button.setHorizontalTextPosition(SwingConstants.RIGHT);
|
||||
button.setIconTextGap(16);
|
||||
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
|
||||
// 自定义 Border:只在当前被选中时绘制左侧竖杠
|
||||
Border indicatorBorder = new Border() {
|
||||
@Override
|
||||
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
|
||||
if (Objects.equals(currentCategoryId, category.getId().toString())) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.setColor(new Color(0x0162F1));
|
||||
g2.fillRect(BAR_X, y, BAR_WIDTH, height);
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets(Component c) {
|
||||
return new Insets(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBorderOpaque() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 将自定义竖杠 Border 和 内边距 EmptyBorder 组合
|
||||
button.setBorder(BorderFactory.createCompoundBorder(
|
||||
indicatorBorder,
|
||||
BorderFactory.createEmptyBorder(8, 8, 8, 20)
|
||||
));
|
||||
|
||||
// 样式
|
||||
button.setForeground(TEXT_COLOR);
|
||||
// 初始设为不填充,由 updateSelection 决定是否填充背景
|
||||
button.setOpaque(false);
|
||||
button.setContentAreaFilled(true); // 允许根据 opaque/background 填充(mouse/selected 状态会切换 opaque)
|
||||
button.setFocusPainted(false);
|
||||
button.setFont(new Font(
|
||||
selectFont("Segoe UI", "Microsoft YaHei", "SansSerif", 13).getName(),
|
||||
Font.PLAIN, 13
|
||||
));
|
||||
|
||||
// helper: 更新选中/未选中时的外观(填充透明浅蓝或透明)
|
||||
Runnable updateSelection = () -> {
|
||||
boolean selected = Objects.equals(currentCategoryId, category.getId().toString());
|
||||
if (selected) {
|
||||
button.setOpaque(true);
|
||||
button.setBackground(SELECT_FILL);
|
||||
} else {
|
||||
button.setOpaque(false);
|
||||
// 为避免残留,仍设置透明背景(透明颜色)
|
||||
button.setBackground(new Color(0, 0, 0, 0));
|
||||
}
|
||||
button.repaint();
|
||||
};
|
||||
|
||||
// 初始状态
|
||||
updateSelection.run();
|
||||
|
||||
// 点击
|
||||
button.addActionListener(e -> {
|
||||
searchField.setText("");
|
||||
switchCategory(category.getId().toString(), false);
|
||||
// 更新自己(外部如果也改变 currentCategoryId,外部应确保调用所有按钮的 repaint)
|
||||
updateSelection.run();
|
||||
});
|
||||
|
||||
// 悬停:仅在未选中时显示 hover 填充;离开时恢复选中/未选中外观
|
||||
button.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
if (!Objects.equals(currentCategoryId, category.getId().toString())) {
|
||||
button.setOpaque(true);
|
||||
button.setBackground(HOVER_FILL);
|
||||
button.repaint();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
// 恢复到选中/未选中状态
|
||||
updateSelection.run();
|
||||
}
|
||||
});
|
||||
|
||||
return button;
|
||||
@@ -570,39 +768,37 @@ public class MainWindow extends JFrame {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
int w = getWidth(), h = getHeight();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
try {
|
||||
int w = getWidth(), h = getHeight();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// 轻微阴影
|
||||
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.06f));
|
||||
g2.setColor(Color.BLACK);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
g2.fill(new RoundRectangle2D.Float(i, i, w - i*2, h - i*2, 12, 12));
|
||||
// 动态获取当前主题颜色
|
||||
Color cardBg = getCardBg();
|
||||
Color cardBorder = getCardBorder();
|
||||
Color shadowColor = isDarkTheme() ? new Color(30, 30, 30) : Color.BLACK;
|
||||
|
||||
// 1. 绘制阴影(根据主题调整透明度)
|
||||
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, isDarkTheme() ? 0.12f : 0.06f));
|
||||
g2.setColor(shadowColor);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
g2.fill(new RoundRectangle2D.Float(i, i, w - i*2, h - i*2, 12, 12));
|
||||
}
|
||||
|
||||
// 2. 绘制卡片背景(动态适应主题)
|
||||
g2.setComposite(AlphaComposite.SrcOver);
|
||||
g2.setColor(cardBg);
|
||||
g2.fill(new RoundRectangle2D.Float(0, 0, w, h, 12, 12));
|
||||
|
||||
// 3. 绘制边框(优化为单次绘制)
|
||||
g2.setColor(cardBorder);
|
||||
g2.setStroke(new BasicStroke(1f));
|
||||
g2.draw(new RoundRectangle2D.Float(0.5f, 0.5f, w - 1, h - 1, 12, 12));
|
||||
|
||||
// 4. 绘制内容(通过super.paintComponent)
|
||||
super.paintComponent(g);
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
// 卡片背景:使用浅灰而非突兀白色,跟 FlatLightLaf 保持协调
|
||||
g2.setComposite(AlphaComposite.SrcOver);
|
||||
Color bg = new Color(250, 250, 250);
|
||||
g2.setColor(bg);
|
||||
g2.fill(new RoundRectangle2D.Float(0, 0, w, h, 12, 12));
|
||||
|
||||
// 修改卡片背景和边框颜色
|
||||
g2.setColor(CARD_BG);
|
||||
g2.fill(new RoundRectangle2D.Float(0, 0, w, h, 12, 12));
|
||||
|
||||
// 边框
|
||||
g2.setColor(CARD_BORDER);
|
||||
g2.setStroke(new BasicStroke(1f));
|
||||
g2.draw(new RoundRectangle2D.Float(0.5f, 0.5f, w - 1, h - 1, 12, 12));
|
||||
|
||||
// 边框
|
||||
g2.setColor(CARD_BORDER);
|
||||
g2.setStroke(new BasicStroke(1f));
|
||||
g2.draw(new RoundRectangle2D.Float(0.5f, 0.5f, w - 1, h - 1, 12, 12));
|
||||
|
||||
g2.dispose();
|
||||
|
||||
super.paintComponent(g);
|
||||
}
|
||||
|
||||
@Override public boolean isOpaque() { return false; }
|
||||
@@ -681,6 +877,21 @@ public class MainWindow extends JFrame {
|
||||
return card;
|
||||
}
|
||||
|
||||
private boolean isDarkTheme() {
|
||||
return AxisInnovatorsBox.getMain().getRegistrationTopic().isDarkMode();
|
||||
}
|
||||
|
||||
private Color getCardBg() {
|
||||
return Optional.ofNullable(UIManager.getColor("control"))
|
||||
.map(bg -> ThemeColors.brighten(bg, 0.1f))
|
||||
.orElse(new Color(0x4A4D50));
|
||||
}
|
||||
|
||||
private Color getCardBorder() {
|
||||
return Optional.ofNullable(UIManager.getColor("controlHighlight"))
|
||||
.orElse(new Color(0x5C5F61));
|
||||
}
|
||||
|
||||
private String createToolTipHTML(ToolItem tool) {
|
||||
return "<html><body style='width:300px;padding:8px;'>" +
|
||||
"<h3 style='margin:0;color:#2c3e50;'>" + escapeHtml(tool.getName()) + "</h3>" +
|
||||
@@ -1018,8 +1229,11 @@ public class MainWindow extends JFrame {
|
||||
// ---------- 自定义滚动条 ----------
|
||||
public static class CustomScrollBarUI extends BasicScrollBarUI {
|
||||
@Override protected void configureScrollBarColors() {
|
||||
this.thumbColor = new Color(160, 160, 180);
|
||||
this.trackColor = new Color(245, 245, 248);
|
||||
this.thumbColor = UIManager.getColor("ScrollBar.thumb");
|
||||
if (thumbColor == null) thumbColor = new Color(160, 160, 180);
|
||||
|
||||
this.trackColor = UIManager.getColor("ScrollBar.track");
|
||||
if (trackColor == null) trackColor = new Color(245, 245, 248);
|
||||
}
|
||||
@Override protected JButton createDecreaseButton(int orientation) { return createInvisibleButton(); }
|
||||
@Override protected JButton createIncreaseButton(int orientation) { return createInvisibleButton(); }
|
||||
|
||||
@@ -60,4 +60,11 @@ public class WindowsJDialog extends JDialog {
|
||||
RegistrationTopic registrationTopic = axisInnovatorsBox.getRegistrationTopic();
|
||||
return registrationTopic.isDarkMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前窗口中更新主题
|
||||
*/
|
||||
public void updateTheme() {
|
||||
SwingUtilities.updateComponentTreeUI(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 3.0 KiB |