feat(theme): 实现Windows主题变更监听与动态更新

- 添加WindowsTheme工具类用于监听系统主题变更
- 实现runMonitorTopics方法监控主题变化并自动更新- 新增TopicsUpdateEvents事件类用于主题更新通知
- 重构setTopic方法使用updateTheme统一处理主题设置
-优化MainWindow背景透明度更新逻辑- 添加isSettingsVisible方法判断设置界面可见状态
- 移除RegisterTray类中的静态库加载代码
- 调整设置面板显示逻辑,支持重新显示已打开的设置窗口
-修复库加载错误日志信息
- 添加异常堆栈打印到崩溃报告组织方法中
This commit is contained in:
tzdwindows 7
2025-10-06 11:00:31 +08:00
parent adf659853d
commit 167bf6405f
7 changed files with 186 additions and 34 deletions

Binary file not shown.

View File

@@ -4,6 +4,8 @@ import com.axis.innovators.box.browser.WindowRegistry;
import com.axis.innovators.box.events.GlobalEventBus; import com.axis.innovators.box.events.GlobalEventBus;
import com.axis.innovators.box.events.OpenFileEvents; import com.axis.innovators.box.events.OpenFileEvents;
import com.axis.innovators.box.events.StartupEvent; import com.axis.innovators.box.events.StartupEvent;
import com.axis.innovators.box.events.TopicsUpdateEvents;
import com.axis.innovators.box.util.WindowsTheme;
import com.axis.innovators.box.window.*; import com.axis.innovators.box.window.*;
import com.axis.innovators.box.plugins.PluginDescriptor; import com.axis.innovators.box.plugins.PluginDescriptor;
import com.axis.innovators.box.plugins.PluginLoader; import com.axis.innovators.box.plugins.PluginLoader;
@@ -46,6 +48,8 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*; import java.io.*;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.lang.management.*; import java.lang.management.*;
@@ -69,6 +73,7 @@ public class AxisInnovatorsBox {
"tzdwindows 7", "tzdwindows 7",
"lyxyz5223", "lyxyz5223",
"\uD83D\uDC3EMr. Liu\uD83D\uDC3E", "\uD83D\uDC3EMr. Liu\uD83D\uDC3E",
"泽钰"
}; };
/** 我是总任务数 **/ /** 我是总任务数 **/
@@ -188,8 +193,9 @@ public class AxisInnovatorsBox {
LibraryLoad.loadLibrary("FridaNative"); LibraryLoad.loadLibrary("FridaNative");
LibraryLoad.loadLibrary("ThrowSafely"); LibraryLoad.loadLibrary("ThrowSafely");
LibraryLoad.loadLibrary("DogAgent"); LibraryLoad.loadLibrary("DogAgent");
LibraryLoad.loadLibrary("RegisterTray");
} catch (Exception e) { } catch (Exception e) {
logger.error("Failed to load the 'FridaNative' library", e); logger.error("Failed to load library", e);
} }
} }
@@ -222,6 +228,7 @@ public class AxisInnovatorsBox {
* 组织崩溃报告 * 组织崩溃报告
*/ */
public void organizingCrashReports(Exception e) { public void organizingCrashReports(Exception e) {
e.printStackTrace();
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
String systemOut = Log4j2OutputStream.systemOutContent.toString(); String systemOut = Log4j2OutputStream.systemOutContent.toString();
String systemErr = Log4j2OutputStream.systemErrContent.toString(); String systemErr = Log4j2OutputStream.systemErrContent.toString();
@@ -713,6 +720,28 @@ public class AxisInnovatorsBox {
return tempFile; return tempFile;
} }
/**
* 运行监控主题
*/
public void runMonitorTopics(){
WindowsTheme.setThemeChangeListener((themeName, darkTheme) -> {
logger.info("主题变更: {}, 暗主题: {}", themeName, darkTheme);
if (registrationTopic.isDarkMode() == darkTheme){
return;
}
try {
updateTheme(themeName,darkTheme);
} catch (UnsupportedLookAndFeelException e) {
throw new RuntimeException(e);
}
if (SwingUtilities.isEventDispatchThread()) {
reloadAllWindow();
} else {
SwingUtilities.invokeLater(this::reloadAllWindow);
}
});
}
private void addFileToZip(ZipOutputStream zos, File file, String entryPath) throws IOException { private void addFileToZip(ZipOutputStream zos, File file, String entryPath) throws IOException {
if (!file.exists()) { if (!file.exists()) {
return; return;
@@ -804,7 +833,7 @@ public class AxisInnovatorsBox {
private void setTopic() { private void setTopic() {
try { try {
boolean isDarkMode = SystemInfoUtil.isSystemDarkMode(); boolean isDarkMode = WindowsTheme.isDarkTheme();
// 1. 默认系统主题 // 1. 默认系统主题
main.registrationTopic.addTopic( main.registrationTopic.addTopic(
@@ -932,16 +961,26 @@ public class AxisInnovatorsBox {
// "system:blur",true // "system:blur",true
//); //);
LookAndFeel defaultLaf = isDarkMode ? new FlatMacDarkLaf() : new FlatMacLightLaf(); updateTheme("",isDarkMode);
UIManager.setLookAndFeel(defaultLaf);
main.registrationTopic.setLoading(
isDarkMode ? "system:flatMacDark_theme" : "system:flatMacLight_theme"
);
} catch (Exception e) { } catch (Exception e) {
logger.warn("Failed to load the system facade class", e); logger.warn("Failed to load the system facade class", e);
} }
} }
/**
* 更新主题
* @param themeName 主题名称
* @param isDarkMode 是否是暗主题
*/
public void updateTheme(String themeName,boolean isDarkMode) throws UnsupportedLookAndFeelException {
LookAndFeel defaultLaf = isDarkMode ? new FlatMacDarkLaf() : new FlatMacLightLaf();
UIManager.setLookAndFeel(defaultLaf);
main.registrationTopic.setLoading(
isDarkMode ? "system:flatMacDark_theme" : "system:flatMacLight_theme"
);
GlobalEventBus.EVENT_BUS.post(new TopicsUpdateEvents(themeName,isDarkMode));
}
/** /**
* 弹出窗口 * 弹出窗口
* @param windowsJDialog 窗口 * @param windowsJDialog 窗口
@@ -1051,7 +1090,7 @@ public class AxisInnovatorsBox {
try { try {
main.initLog4j2(); main.initLog4j2();
main.setTopic(); main.setTopic();
main.runMonitorTopics();
//main.popupLogin(); //main.popupLogin();
main.thread = new Thread(() -> { main.thread = new Thread(() -> {
try { try {
@@ -1155,6 +1194,12 @@ public class AxisInnovatorsBox {
isWindow = true; isWindow = true;
ex.setVisible(true); ex.setVisible(true);
Toolkit.getDefaultToolkit().addPropertyChangeListener("win.xpstyle.themeName",
evt -> {
logger.info("系统主题发生变化: {}", evt.getNewValue());
ex.updateTheme();
});
if (isDebug) { if (isDebug) {
SwingUtilities.invokeLater(this::createDebugWindow); SwingUtilities.invokeLater(this::createDebugWindow);
} }

View File

@@ -0,0 +1,28 @@
package com.axis.innovators.box.events;
/**
* 当主题变更时被调用
* @author tzdwindows 7
*/
public class TopicsUpdateEvents {
private final String themeName;
private final boolean darkTheme;
/**
* 构造函数
* @param themeName 主题名称
* @param darkTheme 是否是暗主题
*/
public TopicsUpdateEvents(String themeName, boolean darkTheme) {
this.themeName = themeName;
this.darkTheme = darkTheme;
}
public String getThemeName() {
return themeName;
}
public boolean isDarkTheme() {
return darkTheme;
}
}

View File

@@ -80,28 +80,31 @@ public class RegistrationSettingsItem extends WindowsJDialog {
JPanel aboutPanel = createAboutPanel(); JPanel aboutPanel = createAboutPanel();
JPanel themePanel = createThemePanel(); JPanel themePanel = createThemePanel();
registrationSettingsItem.addSettings(
pluginPanel, language.getText("settings.1.title"),
null, language.getText("settings.1.tip"), "system:settings_plugins_item"
);
registrationSettingsItem.addSettings( registrationSettingsItem.addSettings(
generalPanel, language.getText("settings.2.title"), generalPanel, language.getText("settings.2.title"),
null, language.getText("settings.2.tip"), "system:settings_appearance_item" null, language.getText("settings.2.tip"), "system:settings_appearance_item"
); );
registrationSettingsItem.addSettings( registrationSettingsItem.addSettings(
aboutPanel, language.getText("settings.3.title"), pluginPanel, language.getText("settings.1.title"),
null, language.getText("settings.3.tip"), "system:settings_information_item" null, language.getText("settings.1.tip"), "system:settings_plugins_item"
); );
registrationSettingsItem.addSettings( registrationSettingsItem.addSettings(
themePanel, language.getText("settings.4.title"), themePanel, language.getText("settings.4.title"),
null, language.getText("settings.4.tip"), "system:settings_theme_item" null, language.getText("settings.4.tip"), "system:settings_theme_item"
); );
registrationSettingsItem.addSettings(
aboutPanel, language.getText("settings.3.title"),
null, language.getText("settings.3.tip"), "system:settings_information_item"
);
registrationSettingsItemList.add( registrationSettingsItemList.add(
registrationSettingsItem registrationSettingsItem
); );
AxisInnovatorsBox.getMain().getMainWindow().showSettings(); // 重新显示
if (AxisInnovatorsBox.getMain().getMainWindow().isSettingsVisible()) {
AxisInnovatorsBox.getMain().getMainWindow().showSettings();
}
} }
private static JPanel createThemePanel() { private static JPanel createThemePanel() {

View File

@@ -12,11 +12,6 @@ import java.util.List;
*/ */
public class RegisterTray { public class RegisterTray {
static {
LibraryLoad.loadLibrary("RegisterTray");
//System.load("C:\\Users\\Administrator\\source\\repos\\RegisterTray\\x64\\Release\\RegisterTray.dll");
}
/** /**
* 托盘菜单项构建器(流畅接口) * 托盘菜单项构建器(流畅接口)
*/ */

View File

@@ -0,0 +1,64 @@
package com.axis.innovators.box.util;
/**
* Windows主题变更监听器
* @author tzdwindows 7
*/
public class WindowsTheme {
/**
* 设置主题改变监听器
* @param listener 监听器
*/
public static native void setThemeChangeListener(ThemeChangeListener listener);
/**
* 主题改变监听器
*/
public interface ThemeChangeListener {
/**
* 当主题改变时调用
* @param themeName 主题名称
* @param darkTheme 是否是暗主题
*/
void themeChanged(String themeName,boolean darkTheme);
}
/**
* 获取当前是否为暗色主题
* @return true-暗色主题, false-亮色主题
*/
public static native boolean isDarkTheme();
/**
* 获取当前主题名称
* @return 主题名称
*/
public static native String getThemeName();
//public static void main(String[] args) {
// try {
// System.load("C:\\Users\\Administrator\\source\\repos\\RegisterTray\\x64\\Release\\RegisterTray.dll");
//
// // 先测试直接获取主题信息的方法
// System.out.println("Current topic Name: " + WindowsTheme.getThemeName());
// System.out.println("Is it a dark theme: " + WindowsTheme.isDarkTheme());
//
// WindowsTheme.setThemeChangeListener(new WindowsTheme.ThemeChangeListener() {
// @Override
// public void themeChanged(String themeName, boolean darkTheme) {
// System.out.println("The theme has changed: " + themeName + " is dark theme: " + darkTheme);
// }
// });
//
// System.out.println("Start listening for theme changes... Press Enter to exit");
//
// System.in.read();
//
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// WindowsTheme.setThemeChangeListener(null);
// }
//}
}

View File

@@ -155,19 +155,7 @@ public class MainWindow extends JFrame {
this.backgroundOpacity = Math.max(0.0f, Math.min(1.0f, opacity)); this.backgroundOpacity = Math.max(0.0f, Math.min(1.0f, opacity));
this.cachedBlurredBackground = null; this.cachedBlurredBackground = null;
this.cachedBackgroundSize = null; this.cachedBackgroundSize = null;
AxisInnovatorsBox.getMain().reloadAllWindow();
// 重新绘制窗口
if (AxisInnovatorsBox.getMain().isWindow()) {
AxisInnovatorsBox.getMain().reloadAllWindow();
}
else {
getContentPane().removeAll();
revalidate();
repaint();
initUI();
updateTheme();
revalidate();
}
} }
/** /**
@@ -965,6 +953,36 @@ public class MainWindow extends JFrame {
return wrapper; return wrapper;
} }
/**
* 判断设置界面是否打开
* @return 设置界面是否可见
*/
public boolean isSettingsVisible(){
if (dialog == null) {
return false;
}
if (!dialog.isDisplayable()) {
dialog = null;
return false;
}
if (!dialog.isVisible()) {
return false;
}
try {
if (dialog.getParent() != this && dialog.getOwner() != this) {
dialog = null;
return false;
}
} catch (Exception e) {
dialog = null;
return false;
}
return true;
}
private JPanel createToolCard(ToolItem tool) { private JPanel createToolCard(ToolItem tool) {
JPanel card = new JPanel() { JPanel card = new JPanel() {
@Override @Override
@@ -1368,7 +1386,6 @@ public class MainWindow extends JFrame {
dialog.setSize(750, 550); dialog.setSize(750, 550);
dialog.setLocationRelativeTo(this); dialog.setLocationRelativeTo(this);
// 使用 JLayer + LayerUI 来对整个内容做统一的淡入 + 下滑(仿 Apple 风格)动画, // 使用 JLayer + LayerUI 来对整个内容做统一的淡入 + 下滑(仿 Apple 风格)动画,
// 这样子组件也会跟随一起动画,而不是只有背景绘制发生变化。 // 这样子组件也会跟随一起动画,而不是只有背景绘制发生变化。
JPanel inner = new JPanel(new BorderLayout()); JPanel inner = new JPanel(new BorderLayout());