feat(gui): 重构主界面并添加新功能

- 重新设计了主窗口布局,增加了侧边栏和内容面板
- 添加了分类按钮和设置按钮
- 实现了内存分析面板的自动补全功能
- 优化了日志文件生成和异常处理机制- 更新了依赖库版本
This commit is contained in:
tzdwindows 7
2025-08-12 20:30:41 +08:00
parent 4b7c153756
commit 9d684b310f
20 changed files with 2645 additions and 1121 deletions

View File

@@ -65,6 +65,8 @@ dependencies {
//implementation 'com.formdev:flatlaf:0.26' //implementation 'com.formdev:flatlaf:0.26'
implementation 'commons-io:commons-io:2.14.0' implementation 'commons-io:commons-io:2.14.0'
implementation 'com.formdev:flatlaf:3.2.1' // FlatLaf核心 implementation 'com.formdev:flatlaf:3.2.1' // FlatLaf核心
implementation 'com.formdev:flatlaf-extras:3.2.1' // 扩展组件 implementation 'com.formdev:flatlaf-extras:3.2.1' // 扩展组件
implementation 'com.formdev:flatlaf-intellij-themes:3.2.1' // 官方主题包 implementation 'com.formdev:flatlaf-intellij-themes:3.2.1' // 官方主题包
@@ -74,6 +76,7 @@ dependencies {
implementation files('libs/JNC-1.0-jnc.jar') implementation files('libs/JNC-1.0-jnc.jar')
implementation files('libs/dog api 1.3.jar') implementation files('libs/dog api 1.3.jar')
implementation files('libs/DesktopWallpaperSdk-1.0-SNAPSHOT.jar')
implementation 'org.fxmisc.richtext:richtextfx:0.11.0' // 更新后的richtextfx implementation 'org.fxmisc.richtext:richtextfx:0.11.0' // 更新后的richtextfx
implementation 'org.bitbucket.mstrobel:procyon-core:0.5.36' // 使用JitPack版本 implementation 'org.bitbucket.mstrobel:procyon-core:0.5.36' // 使用JitPack版本
@@ -112,6 +115,21 @@ dependencies {
//runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3', // JWT实现 //runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3', // JWT实现
// 'io.jsonwebtoken:jjwt-jackson:0.12.3' // JWT序列化 // 'io.jsonwebtoken:jjwt-jackson:0.12.3' // JWT序列化
implementation 'org.json:json:20230618'
implementation 'org.lwjgl:lwjgl:3.3.1'
implementation 'org.lwjgl:lwjgl-glfw:3.3.1'
implementation 'org.lwjgl:lwjgl-opengl:3.3.1'
implementation 'org.lwjgl:lwjgl:3.3.1:natives-windows' // Windows natives
implementation 'org.lwjgl:lwjgl-glfw:3.3.1:natives-windows'
implementation 'org.lwjgl:lwjgl-opengl:3.3.1:natives-windows'
implementation 'org.bytedeco:javacv-platform:1.5.7' // JavaCV
implementation 'org.bytedeco:javacpp-platform:1.5.7' // JavaCPP
implementation 'com.madgag:animated-gif-lib:1.4'
implementation 'org.openjfx:javafx-web:17'
runtimeOnly 'com.mysql:mysql-connector-j' runtimeOnly 'com.mysql:mysql-connector-j'
@@ -136,12 +154,15 @@ dependencies {
implementation 'me.friwi:jcefmaven:122.1.10' implementation 'me.friwi:jcefmaven:122.1.10'
implementation 'com.alphacephei:vosk:0.3.45' // Java API implementation 'com.alphacephei:vosk:0.3.45' // Java API
implementation 'net.java.dev.jna:jna:5.12.1' // 本地库加载 implementation 'net.java.dev.jna:jna:5.13.0'
implementation 'net.java.dev.jna:jna-platform:5.13.0'
// 高性能音频处理 // 高性能音频处理
implementation 'org.apache.commons:commons-math3:3.6.1' implementation 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:31.1-jre' implementation 'com.google.guava:guava:31.1-jre'
implementation 'com.github.javaparser:javaparser-symbol-solver-core:3.25.9'
// 中文拼音处理 // 中文拼音处理
implementation 'com.belerweb:pinyin4j:2.5.1' implementation 'com.belerweb:pinyin4j:2.5.1'

View File

@@ -1,3 +1,3 @@
#Current Loaded Language #Current Loaded Language
#Sat May 31 10:30:35 CST 2025 #Wed Jul 02 20:11:55 CST 2025
loadedLanguage=system\:zh_CN loadedLanguage=system\:zh_CN

Binary file not shown.

View File

@@ -17,6 +17,7 @@ import com.axis.innovators.box.util.Tray;
import com.axis.innovators.box.util.UserLocalInformation; import com.axis.innovators.box.util.UserLocalInformation;
import com.axis.innovators.box.verification.UserTags; import com.axis.innovators.box.verification.UserTags;
import com.formdev.flatlaf.FlatLightLaf; import com.formdev.flatlaf.FlatLightLaf;
import com.sun.management.HotSpotDiagnosticMXBean;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Appender;
@@ -78,6 +79,10 @@ public class AxisInnovatorsBox {
public AxisInnovatorsBox(String[] args, boolean isDebug) { public AxisInnovatorsBox(String[] args, boolean isDebug) {
this.args = args; this.args = args;
this.isDebug = isDebug; this.isDebug = isDebug;
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
organizingCrashReports(throwable instanceof Exception ?
(Exception) throwable : new Exception(throwable));
});
} }
/** /**
@@ -358,7 +363,7 @@ public class AxisInnovatorsBox {
if (appender instanceof FileAppender fileAppender) { if (appender instanceof FileAppender fileAppender) {
String fileName = fileAppender.getFileName(); String fileName = fileAppender.getFileName();
if (fileName != null && !addedFiles.contains(fileName)) { if (fileName != null && !addedFiles.contains(fileName)) {
addFileToZip(zos, new File(fileName), "logs/"); addFileToZip(zos, new File(fileName), "logs/" + new File(fileName).getName());
addedFiles.add(fileName); addedFiles.add(fileName);
} }
} }
@@ -387,7 +392,7 @@ public class AxisInnovatorsBox {
for (File file : logFiles) { for (File file : logFiles) {
String absolutePath = file.getAbsolutePath(); String absolutePath = file.getAbsolutePath();
if (!addedFiles.contains(absolutePath)) { if (!addedFiles.contains(absolutePath)) {
addFileToZip(zos, file, "logs/"); addFileToZip(zos, file, "logs/" + file.getName());
addedFiles.add(absolutePath); addedFiles.add(absolutePath);
} }
} }
@@ -436,6 +441,24 @@ public class AxisInnovatorsBox {
addFileToZip(zos, generateSystemProperties(), "debug_files/system_properties.txt"); addFileToZip(zos, generateSystemProperties(), "debug_files/system_properties.txt");
// 7. 添加环境变量 // 7. 添加环境变量
addFileToZip(zos, generateEnvironmentVariables(), "debug_files/environment_variables.txt"); addFileToZip(zos, generateEnvironmentVariables(), "debug_files/environment_variables.txt");
// 8.生成dump文件
addFileToZip(zos, generateFileDump(), "debug_files/dump.hprof");
}
private File generateFileDump() throws IOException {
final String javaLibraryPath = System.getProperty("java.library.path");
String jvmFolder = javaLibraryPath.contains(";")
? javaLibraryPath.substring(0, javaLibraryPath.indexOf(';'))
: javaLibraryPath;
logger.info("JVM folder: {}", jvmFolder);
File dumpFile = File.createTempFile("dump", ".hprof");
String dumpFilePath = dumpFile.getAbsolutePath();
if (!dumpFile.delete()) {
throw new IOException("Failed to delete temporary placeholder file");
}
HotSpotDiagnosticMXBean bean = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
bean.dumpHeap(dumpFilePath, true);
return new File(dumpFilePath);
} }
private File generateClassLoaderInfo() throws IOException { private File generateClassLoaderInfo() throws IOException {
@@ -606,8 +629,7 @@ public class AxisInnovatorsBox {
return; return;
} }
String entryName = entryPath + file.getName(); ZipEntry zipEntry = new ZipEntry(entryPath);
ZipEntry zipEntry = new ZipEntry(entryName);
zos.putNextEntry(zipEntry); zos.putNextEntry(zipEntry);
try (FileInputStream fis = new FileInputStream(file)) { try (FileInputStream fis = new FileInputStream(file)) {
@@ -805,6 +827,22 @@ public class AxisInnovatorsBox {
} }
public static void run(String[] args, boolean isDebug) { public static void run(String[] args, boolean isDebug) {
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
if (main != null) {
main.organizingCrashReports(throwable instanceof Exception ?
(Exception) throwable : new Exception(throwable));
} else {
// 如果主类尚未初始化,创建临时实例处理崩溃
new AxisInnovatorsBox(args, isDebug)
.organizingCrashReports(throwable instanceof Exception ?
(Exception) throwable : new Exception(throwable));
}
});
// 设置EDT(事件调度线程)的异常处理器
System.setProperty("sun.awt.exception.handler", EDTCrashHandler.class.getName());
main = new AxisInnovatorsBox(args,isDebug); main = new AxisInnovatorsBox(args,isDebug);
try { try {
main.initLog4j2(); main.initLog4j2();
@@ -880,7 +918,6 @@ public class AxisInnovatorsBox {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
}, "TrayThread").start(); }, "TrayThread").start();
} catch (Exception e) { } catch (Exception e) {
logger.error("Failed to load plugins", e); logger.error("Failed to load plugins", e);
if (main.ex != null) { if (main.ex != null) {
@@ -972,4 +1009,16 @@ public class AxisInnovatorsBox {
public StateManager getStateManager() { public StateManager getStateManager() {
return stateManager; return stateManager;
} }
/**
* 专门处理EDT线程异常的处理器
*/
public static class EDTCrashHandler {
public void handle(Throwable throwable) {
if (main != null) {
main.organizingCrashReports(throwable instanceof Exception ?
(Exception) throwable : new Exception(throwable));
}
}
}
} }

View File

@@ -126,10 +126,7 @@ public class Main {
} }
} }
// 添加JVM关闭钩子确保锁释放
static { static {
Runtime.getRuntime().addShutdownHook(new Thread(() -> { Runtime.getRuntime().addShutdownHook(new Thread(Main::releaseLock));
releaseLock();
}));
} }
} }

View File

@@ -55,7 +55,7 @@ public class CefAppManager {
private static void initializeDefaultSettings() { private static void initializeDefaultSettings() {
initLock.lock(); initLock.lock();
try { try {
settings.windowless_rendering_enabled = false; settings.windowless_rendering_enabled = true;
settings.javascript_flags = "--expose-gc"; settings.javascript_flags = "--expose-gc";
settings.cache_path = FolderCreator.getLibraryFolder() + "/jcef/cache"; settings.cache_path = FolderCreator.getLibraryFolder() + "/jcef/cache";
settings.root_cache_path = FolderCreator.getLibraryFolder() + "/jcef/cache"; settings.root_cache_path = FolderCreator.getLibraryFolder() + "/jcef/cache";

View File

@@ -1,138 +0,0 @@
package com.axis.innovators.box.events;
import com.axis.innovators.box.gui.MainWindow;
import java.awt.*;
/**
* 分类栏的渲染事件
* @author tzdwindows 7
*/
public class CategoryRenderingEvent {
private final MainWindow.CustomTabbedPaneUI ui;
private final Graphics graphics;
private final int tabPlacement;
private final int tabIndex;
private final int x;
private final int y;
private final int width;
private final int height;
private final boolean isSelected;
private boolean isEnd = false;
public CategoryRenderingEvent(MainWindow.CustomTabbedPaneUI ui, Graphics graphics, int tabPlacement, int tabIndex, int x, int y, int width, int height, boolean isSelected) {
this.ui = ui;
this.graphics = graphics;
this.tabPlacement = tabPlacement;
this.tabIndex = tabIndex;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.isSelected = isSelected;
}
public MainWindow.CustomTabbedPaneUI getUi() {
return ui;
}
public Graphics getGraphics() {
return graphics;
}
public int getTabPlacement() {
return tabPlacement;
}
public int getTabIndex() {
return tabIndex;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public boolean isSelected() {
return isSelected;
}
public boolean isEnd() {
return isEnd;
}
public void setEnd(boolean end) {
isEnd = end;
}
public static class paintTabBorder {
private final MainWindow.CustomTabbedPaneUI event;
private final Graphics graphics;
private final int tabPlacement;
private final int tabIndex;
private final int x;
private final int y;
private final int width;
private final int height;
private final boolean isSelected;
public paintTabBorder(MainWindow.CustomTabbedPaneUI event, Graphics graphics, int tabPlacement, int tabIndex, int x, int y, int width, int height, boolean isSelected) {
this.event = event;
this.graphics = graphics;
this.tabPlacement = tabPlacement;
this.tabIndex = tabIndex;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.isSelected = isSelected;
}
public MainWindow.CustomTabbedPaneUI getEvent() {
return event;
}
public Graphics getGraphics() {
return graphics;
}
public int getTabPlacement() {
return tabPlacement;
}
public int getTabIndex() {
return tabIndex;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public boolean isSelected() {
return isSelected;
}
}
}

View File

@@ -34,6 +34,7 @@ public class MainWindow extends JFrame {
private final Color CARD_COLOR = Color.WHITE; private final Color CARD_COLOR = Color.WHITE;
private final List<ToolCategory> categories = new ArrayList<>(); private final List<ToolCategory> categories = new ArrayList<>();
private SystemTray systemTray; private SystemTray systemTray;
private JPanel contentPanel;
//private TrayIcon trayIcon; //private TrayIcon trayIcon;
public MainWindow() { public MainWindow() {
@@ -67,7 +68,7 @@ public class MainWindow extends JFrame {
getContentPane().setBackground(new Color(0, 0, 0, 0)); getContentPane().setBackground(new Color(0, 0, 0, 0));
JPanel mainPanel = new JPanel(); JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.setOpaque(true); mainPanel.setOpaque(true);
@@ -86,8 +87,87 @@ public class MainWindow extends JFrame {
setVisible(false); setVisible(false);
} }
}); });
JPanel sideBar = createSideBar();
mainPanel.add(sideBar, BorderLayout.WEST);
contentPanel = new JPanel(new BorderLayout());
contentPanel.setOpaque(false);
mainPanel.add(contentPanel, BorderLayout.CENTER);
mainPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
add(mainPanel);
} }
private JPanel createSideBar() {
JPanel sidebar = new JPanel();
sidebar.setLayout(new BoxLayout(sidebar, BoxLayout.Y_AXIS));
sidebar.setBackground(new Color(35, 35, 35));
sidebar.setPreferredSize(new Dimension(180, getHeight()));
// 添加分类按钮
for (ToolCategory category : categories) {
JButton button = new JButton(category.getName());
button.setAlignmentX(Component.CENTER_ALIGNMENT);
button.setMaximumSize(new Dimension(160, 40));
button.setForeground(Color.WHITE);
button.setBackground(new Color(60, 60, 60));
button.setFocusPainted(false);
button.setBorderPainted(false);
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
button.addActionListener(e -> {
JPanel toolsPanel = createToolsPanel(category);
toolsPanel.setOpaque(false);
contentPanel.removeAll();
JScrollPane scrollPane = new JScrollPane(toolsPanel);
scrollPane.setBorder(null);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
scrollPane.getVerticalScrollBar().setUI(new CustomScrollBarUI());
contentPanel.add(scrollPane, BorderLayout.CENTER);
contentPanel.revalidate();
contentPanel.repaint();
});
sidebar.add(Box.createVerticalStrut(10));
sidebar.add(button);
}
// 添加设置按钮
JButton settingsButton = new JButton("设置");
settingsButton.setAlignmentX(Component.CENTER_ALIGNMENT);
settingsButton.setMaximumSize(new Dimension(160, 40));
settingsButton.setForeground(Color.WHITE);
settingsButton.setBackground(new Color(45, 45, 45));
settingsButton.setFocusPainted(false);
settingsButton.setBorderPainted(false);
settingsButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
settingsButton.addActionListener(e -> showSettings());
sidebar.add(Box.createVerticalGlue());
sidebar.add(settingsButton);
// 添加关于按钮
JButton aboutButton = new JButton("关于");
aboutButton.setAlignmentX(Component.CENTER_ALIGNMENT);
aboutButton.setMaximumSize(new Dimension(160, 40));
aboutButton.setForeground(Color.WHITE);
aboutButton.setBackground(new Color(45, 45, 45));
aboutButton.setFocusPainted(false);
aboutButton.setBorderPainted(false);
aboutButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
aboutButton.addActionListener(e -> JOptionPane.showMessageDialog(this, "作者: tzdwindows7"));
sidebar.add(Box.createVerticalStrut(10));
sidebar.add(aboutButton);
return sidebar;
}
private JPanel createFooter() { private JPanel createFooter() {
JPanel footer = new JPanel(); JPanel footer = new JPanel();
footer.setLayout(new BoxLayout(footer, BoxLayout.X_AXIS)); footer.setLayout(new BoxLayout(footer, BoxLayout.X_AXIS));
@@ -652,11 +732,6 @@ public class MainWindow extends JFrame {
protected void paintTabBackground(Graphics g, int tabPlacement, protected void paintTabBackground(Graphics g, int tabPlacement,
int tabIndex, int x, int y, int w, int h, int tabIndex, int x, int y, int w, int h,
boolean isSelected) { boolean isSelected) {
CategoryRenderingEvent event = new CategoryRenderingEvent(this, g, tabPlacement, tabIndex, x, y, w, h, isSelected);
GlobalEventBus.EVENT_BUS.post(event);
if (event.isEnd()){
return;
}
Graphics2D g2d = (Graphics2D) g.create(); Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
@@ -669,15 +744,6 @@ public class MainWindow extends JFrame {
g2d.fillRoundRect(x + 2, y + 2, w - 4, h - 4, 10, 10); g2d.fillRoundRect(x + 2, y + 2, w - 4, h - 4, 10, 10);
g2d.dispose(); g2d.dispose();
} }
@Override
protected void paintTabBorder(Graphics g, int tabPlacement,
int tabIndex, int x, int y, int w, int h,
boolean isSelected) {
GlobalEventBus.EVENT_BUS.post(new CategoryRenderingEvent.paintTabBorder(this, g,
tabPlacement,
tabIndex, x, y, w, h, isSelected));
}
} }
private class CardMouseAdapter extends MouseAdapter { private class CardMouseAdapter extends MouseAdapter {

View File

@@ -14,9 +14,7 @@ import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader; import javax.swing.table.JTableHeader;
import javax.swing.table.TableRowSorter; import javax.swing.table.TableRowSorter;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionListener; import java.awt.event.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
@@ -30,7 +28,7 @@ import java.text.DecimalFormat;
import java.util.List; import java.util.List;
import java.util.Timer; import java.util.Timer;
import java.util.*; import java.util.*;
import java.util.concurrent.CancellationException; import java.util.concurrent.*;
public class MemoryAnalysisPanel extends JPanel { public class MemoryAnalysisPanel extends JPanel {
private static final DecimalFormat MB_FORMAT = new DecimalFormat("#,##0.00"); private static final DecimalFormat MB_FORMAT = new DecimalFormat("#,##0.00");
@@ -92,6 +90,14 @@ public class MemoryAnalysisPanel extends JPanel {
private final JTable specificClassInstanceTable; private final JTable specificClassInstanceTable;
private final DefaultTableModel specificClassInstanceModel; private final DefaultTableModel specificClassInstanceModel;
// 自动补全相关组件
private JPopupMenu autoCompletePopup;
private JList<String> autoCompleteList;
private DefaultListModel<String> autoCompleteModel;
private ScheduledExecutorService autoCompleteExecutor;
private final Map<String, List<String>> classCache = new ConcurrentHashMap<>();
private final Set<String> loadedPackages = ConcurrentHashMap.newKeySet();
// 特定类分析面板组件 // 特定类分析面板组件
private JPanel visualizationPanel; private JPanel visualizationPanel;
private JLabel ratioLabel; private JLabel ratioLabel;
@@ -99,6 +105,10 @@ public class MemoryAnalysisPanel extends JPanel {
private JTextField instanceSearchField; private JTextField instanceSearchField;
private TableRowSorter<DefaultTableModel> instanceSorter; private TableRowSorter<DefaultTableModel> instanceSorter;
// 可调整大小的分割面板
private JSplitPane mainSplitPane;
private JSplitPane infoVisualizationSplitPane;
private JSplitPane visualizationInstanceSplitPane;
public MemoryAnalysisPanel() { public MemoryAnalysisPanel() {
super(new BorderLayout()); super(new BorderLayout());
@@ -280,6 +290,231 @@ public class MemoryAnalysisPanel extends JPanel {
// 初始刷新 - 只加载内存使用和内存池数据 // 初始刷新 - 只加载内存使用和内存池数据
showLoadingDialog("正在初始化内存数据..."); showLoadingDialog("正在初始化内存数据...");
refreshInitialData(); refreshInitialData();
// 初始化自动补全系统
initAutoCompleteSystem();
}
private void initAutoCompleteSystem() {
// 创建自动补全组件
autoCompleteModel = new DefaultListModel<>();
autoCompleteList = new JList<>(autoCompleteModel);
autoCompleteList.setFont(DebugWindow.MONOSPACE_FONT);
autoCompleteList.setBackground(new Color(50, 50, 50));
autoCompleteList.setForeground(FOREGROUND);
autoCompleteList.setSelectionBackground(ACCENT);
autoCompleteList.setSelectionForeground(FOREGROUND);
autoCompleteList.setFixedCellHeight(25);
autoCompletePopup = new JPopupMenu();
autoCompletePopup.setBorder(BorderFactory.createLineBorder(new Color(80, 80, 80)));
autoCompletePopup.add(new JScrollPane(autoCompleteList));
// 添加选择监听器
autoCompleteList.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 1) {
selectAutoCompleteItem();
}
}
});
// 添加键盘监听器
specificClassField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
handleAutoCompleteKeyPress(e);
}
});
// 添加文档监听器
specificClassField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
scheduleAutoCompleteUpdate();
}
@Override
public void removeUpdate(DocumentEvent e) {
scheduleAutoCompleteUpdate();
}
@Override
public void changedUpdate(DocumentEvent e) {
scheduleAutoCompleteUpdate();
}
});
// 初始化线程池
autoCompleteExecutor = Executors.newSingleThreadScheduledExecutor();
}
private void scheduleAutoCompleteUpdate() {
// 取消之前的任务
autoCompleteExecutor.shutdownNow();
autoCompleteExecutor = Executors.newSingleThreadScheduledExecutor();
// 安排新任务
autoCompleteExecutor.schedule(() -> {
SwingUtilities.invokeLater(this::updateAutoCompleteSuggestions);
}, 300, TimeUnit.MILLISECONDS);
}
private void updateAutoCompleteSuggestions() {
String text = specificClassField.getText().trim();
if (text.isEmpty()) {
autoCompletePopup.setVisible(false);
return;
}
// 获取或加载建议
List<String> suggestions = getAutoCompleteSuggestions(text);
autoCompleteModel.clear();
if (suggestions.isEmpty()) {
autoCompletePopup.setVisible(false);
return;
}
// 添加到模型
for (String suggestion : suggestions) {
autoCompleteModel.addElement(suggestion);
}
// 显示弹出菜单
if (!autoCompletePopup.isVisible()) {
showAutoCompletePopup();
}
// 选择第一个项目
autoCompleteList.setSelectedIndex(0);
}
private List<String> getAutoCompleteSuggestions(String input) {
String packagePrefix = input.contains(".") ?
input.substring(0, input.lastIndexOf('.') + 1) :
"";
// 如果包名部分发生变化,重新加载该包下的类
if (!classCache.containsKey(packagePrefix) || !loadedPackages.contains(packagePrefix)) {
loadPackageClasses(packagePrefix);
}
List<String> allClasses = classCache.getOrDefault(packagePrefix, new ArrayList<>());
String searchTerm = input.toLowerCase();
// 过滤匹配的类
List<String> suggestions = new ArrayList<>();
for (String className : allClasses) {
if (className.toLowerCase().contains(searchTerm)) {
suggestions.add(className);
}
// 限制数量
if (suggestions.size() >= 100) {
break;
}
}
// 按匹配度排序
suggestions.sort((s1, s2) -> {
int pos1 = s1.toLowerCase().indexOf(searchTerm);
int pos2 = s2.toLowerCase().indexOf(searchTerm);
return Integer.compare(pos1, pos2);
});
return suggestions;
}
private void loadPackageClasses(String packageName) {
// 对于根包的特殊处理
if (packageName.isEmpty()) {
packageName = "";
}
List<String> classes = new ArrayList<>();
Class<?>[] allClasses = instrumentation.getAllLoadedClasses();
for (Class<?> clazz : allClasses) {
String className = clazz.getName();
// 只处理包匹配的类
if (packageName.isEmpty() || className.startsWith(packageName)) {
classes.add(className);
}
}
// 缓存结果
classCache.put(packageName, classes);
loadedPackages.add(packageName);
}
private void showAutoCompletePopup() {
if (specificClassField.isShowing()) {
// 计算弹出位置
Point location = specificClassField.getLocationOnScreen();
location.y += specificClassField.getHeight();
// 设置弹出大小
int width = Math.max(specificClassField.getWidth(), 400);
int height = Math.min(autoCompleteModel.size() * 25, 300);
autoCompletePopup.setPopupSize(width, height);
// 显示弹出菜单
autoCompletePopup.show(specificClassField, 0, specificClassField.getHeight());
}
}
private void handleAutoCompleteKeyPress(KeyEvent e) {
if (!autoCompletePopup.isVisible()) return;
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
moveSelection(-1);
e.consume();
break;
case KeyEvent.VK_DOWN:
moveSelection(1);
e.consume();
break;
case KeyEvent.VK_ENTER:
selectAutoCompleteItem();
e.consume();
break;
case KeyEvent.VK_ESCAPE:
autoCompletePopup.setVisible(false);
e.consume();
break;
case KeyEvent.VK_TAB:
if (autoCompleteList.getSelectedIndex() >= 0) {
selectAutoCompleteItem();
e.consume();
}
break;
}
}
private void moveSelection(int direction) {
int selected = autoCompleteList.getSelectedIndex();
int newIndex = selected + direction;
if (newIndex >= 0 && newIndex < autoCompleteModel.size()) {
autoCompleteList.setSelectedIndex(newIndex);
autoCompleteList.ensureIndexIsVisible(newIndex);
}
}
private void selectAutoCompleteItem() {
String selected = autoCompleteList.getSelectedValue();
if (selected != null) {
specificClassField.setText(selected);
autoCompletePopup.setVisible(false);
specificClassField.requestFocus();
// 将光标移动到文本末尾
specificClassField.setCaretPosition(selected.length());
}
} }
private JPanel createSpecificClassAnalysisPanel() { private JPanel createSpecificClassAnalysisPanel() {
@@ -316,41 +551,44 @@ public class MemoryAnalysisPanel extends JPanel {
inputPanel.add(classLabel, BorderLayout.WEST); inputPanel.add(classLabel, BorderLayout.WEST);
inputPanel.add(fieldPanel, BorderLayout.CENTER); inputPanel.add(fieldPanel, BorderLayout.CENTER);
// 主内容面板 (使用网格袋布局) // 使用分割面板替代网格袋布局
JPanel mainContentPanel = new JPanel(new GridBagLayout()); mainSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
mainContentPanel.setBackground(BACKGROUND); mainSplitPane.setDividerLocation(0.4); // 初始比例为40%
GridBagConstraints gbc = new GridBagConstraints(); mainSplitPane.setResizeWeight(0.4);
gbc.fill = GridBagConstraints.BOTH; mainSplitPane.setBorder(BorderFactory.createEmptyBorder());
gbc.weightx = 1.0; mainSplitPane.setContinuousLayout(true);
gbc.insets = new Insets(5, 5, 5, 5); mainSplitPane.setDividerSize(5);
mainSplitPane.setBackground(BACKGROUND);
// 类信息面板 // 上半部分:类信息面板
JPanel infoPanel = createClassInfoPanel(); JPanel infoPanel = createClassInfoPanel();
gbc.gridx = 0; infoPanel.setMinimumSize(new Dimension(100, 100));
gbc.gridy = 0;
gbc.gridwidth = 2; // 下半部分:可视化+实例列表
gbc.weighty = 0.4; JSplitPane bottomSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
mainContentPanel.add(infoPanel, gbc); bottomSplitPane.setDividerLocation(0.3); // 初始比例为30%
bottomSplitPane.setResizeWeight(0.3);
bottomSplitPane.setContinuousLayout(true);
bottomSplitPane.setDividerSize(5);
bottomSplitPane.setBackground(BACKGROUND);
// 可视化面板 // 可视化面板
visualizationPanel = createVisualizationPanel(); visualizationPanel = createVisualizationPanel();
gbc.gridx = 0; visualizationPanel.setMinimumSize(new Dimension(100, 100));
gbc.gridy = 1;
gbc.gridwidth = 1;
gbc.weighty = 0.1;
mainContentPanel.add(visualizationPanel, gbc);
// 实例列表面板 // 实例列表面板
JPanel instancesPanel = createInstancesPanel(); JPanel instancesPanel = createInstancesPanel();
gbc.gridx = 1; instancesPanel.setMinimumSize(new Dimension(100, 100));
gbc.gridy = 1;
gbc.gridwidth = 1; bottomSplitPane.setLeftComponent(visualizationPanel);
gbc.weighty = 0.5; bottomSplitPane.setRightComponent(instancesPanel);
mainContentPanel.add(instancesPanel, gbc);
mainSplitPane.setTopComponent(infoPanel);
mainSplitPane.setBottomComponent(bottomSplitPane);
// 添加主内容面板到中心 // 添加主内容面板到中心
panel.add(inputPanel, BorderLayout.NORTH); panel.add(inputPanel, BorderLayout.NORTH);
panel.add(mainContentPanel, BorderLayout.CENTER); panel.add(mainSplitPane, BorderLayout.CENTER);
return panel; return panel;
} }

View File

@@ -5,11 +5,11 @@ import java.nio.file.Paths;
public class Main { public class Main {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
HighAccuracySpeechRecognition recognizer = new HighAccuracySpeechRecognition( //HighAccuracySpeechRecognition recognizer = new HighAccuracySpeechRecognition(
"C:\\Users\\Administrator\\Desktop\\声音识别模型\\vosk-model-cn-0.22", // "C:\\Users\\Administrator\\Desktop\\声音识别模型\\vosk-model-cn-0.22",
"output" // "output"
); //);
//
recognizer.processAudio(Paths.get("G:\\鬼畜素材\\工作间\\哪吒-嗵嗵\\哪吒-嗵嗵1.wav")); //recognizer.processAudio(Paths.get("G:\\鬼畜素材\\工作间\\哪吒-嗵嗵\\哪吒-嗵嗵1.wav"));
} }
} }

View File

@@ -0,0 +1,4 @@
package org.tzd.explorer;
public class DesktopIconRenderer {
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB