tzdwindows 7 fe4142902c feat(render): 实现动态缩放支持与文本渲染优化
- 为 BoundingBox 类添加获取中心点坐标的便捷方法
- 重构 Mesh2D 悬停提示框绘制逻辑,支持基于摄像机缩放的动态尺寸计算
- 在 ModelRender 中新增带缩放参数的文本渲染方法
- 重写 MultiSelectionBoxRenderer 以适配动态缩放,统一使用像素单位配置
- 优化 ParametersManagement 日志记录方式
- 修复 TextRenderer 字体颜色传递问题
- 更新 TextShader 着色器代码以兼容新的渲染管线和透明度处理
2025-11-21 16:46:37 +08:00
2025-08-18 00:15:31 +08:00
2025-02-05 15:02:27 +08:00
2025-02-05 15:02:27 +08:00
2025-11-16 13:53:18 +08:00
2025-02-05 15:02:27 +08:00

AxisInnovatorsBoxWindowApi

项目链接 | 官网 | 简体中文


项目概述

AxisInnovatorsBoxWindowApi 是一个为 AxisInnovatorsBox 平台设计的管理API接口库开发者可通过此API创建自定义插件实现窗口管理、事件交互等核心功能。该仓库提供了接口定义、类说明文档及插件开发示例代码帮助开发者快速接入AxisInnovatorsBox生态系统。


功能特性

  • 🖥️ 窗口生命周期管理 - 创建/销毁窗口、调整窗口状态(最小化/最大化)
  • 🎮 事件驱动交互 - 支持窗口事件监听与自定义事件触发
  • 📦 跨语言插件支持 - 基于 Java 平台无缝加载 Python 插件提供标准插件基类Java/Python实现快速扩展
  • 📄 动态配置管理 - 通过 properties 配置文件灵活加载多语言插件(支持 Java/Python 插件声明)
  • 📊 统一日志追踪 - 集成 Java 平台日志系统,同步记录 Python 插件的运行状态与异常信息

插件加载系统说明

  • 插件加载系统核心组件。
  • 插件加载系统由 程序内部 完成

注册Jar插件

  • Jar插件在/plug-in中添加
@PluginMeta(id = "test", name = "测试插件",
        supportedVersions = {"0.0.2"},
        description = "测试插件",
        icon = "",
        registeredName = "test")
public class Template {
    public static PluginDescriptor INSTANCE = null;

    public Template() {
        GlobalEventBus.EVENT_BUS.register(this);
    }



   @SubscribeEvent
   public void onStartup(StartupEvent event) {
      MainWindow.ToolCategory category = new MainWindow.ToolCategory("测试插件", "test", "测试插件");
      event.main().getRegistrationTool().addToolCategory(
              category,
              INSTANCE,
              "templatePlugin"
      );
   }
}
  • 插件加载系统会自动填充 INSTANCE 内容
  • 使用PluginMeta注册插件信息

Python插件注册

  • Python插件在/plug-in/python中添加
  • Python可以直接调用Java类实现对插件系统的控制
  • 插件还需要单独的放在一个子文件夹中,如/plug-in/python/Examples
  • Python插件需要声明一个metadata.json文件
{
  "id": "testing",
  "name": "测试",
  "version": "0.0.1",
  "description": "测试插件",
  "author": "tzdwindows 7",
  "dependencies": [],
  "_comment": {
    "warning": "本文件为插件元数据配置,修改后需重启应用生效",
    "path": "插件资源应放置在plugins/{id}/目录下"
  }
}
  • Python插件需要声明一个main.py文件做为插件的主脚本
"""
工具模块初始化脚本
功能向Axis Innovators Box注册自定义工具类别和工具项
作者tzdwindows 7
版本1.1
"""
from com.axis.innovators.box.python import PyLocalSide
from javax.swing import AbstractAction

class MyAction(AbstractAction):
    def actionPerformed(self, event):
        """工具项点击事件处理"""
        print("[DEBUG] Tool item clicked! Event source:", event.getSource())

def onStartup():
    """
    系统启动时自动执行的初始化逻辑
    功能:
    1. 创建工具类别
    2. 创建工具项并绑定动作
    3. 注册到系统全局工具集
    """
    print('[INFO] 正在初始化自定义工具...')

    # --------------------------
    # 创建工具类别(参数顺序:显示名称,图标资源名,描述)
    # --------------------------
    tool_category = PyLocalSide.getToolCategory(
        u"数据分析工具",          # 显示名称GUI可见
        u"analytics_icon.png",   # 图标文件名(需存在于资源目录)
        u"高级数据分析功能集合"     # 悬停提示描述
    )

    # --------------------------
    # 创建工具项参数顺序显示名称图标描述ID动作对象
    # --------------------------
    tool_action = MyAction()
    tool_item = PyLocalSide.getToolItem(
        u"数据可视化",           # 工具项显示名称
        u"chart_icon.png",       # 工具项图标
        u"生成交互式数据图表",     # 工具项描述
        1001,                   # 工具项唯一ID需在配置中统一管理
        tool_action             # 点击触发的动作
    )
    tool_category.addTool(tool_item)

    # --------------------------
    # 注册工具类别到系统(参数:类别对象,全局唯一注册名称)
    # --------------------------
    PyLocalSide.addToolCategory(
        tool_category,
        u"custom_module::data_analysis_tools"  # 推荐命名规则:模块名::功能名
    )
    print('[SUCCESS] 工具类别注册成功')

if __name__ == '__main__':
    result = 0
    errorResult = ""

# 确保Jython运行时可以访问onStartup函数
# 原理:将函数显式绑定到全局字典
globals()['onStartup'] = onStartup

声明CorePlugins

  • CorePlugins核心组件可以修改部分模块的字节码。
  • CorePlugins需要在jar的属性中添加 CorePlugins: CorePlugins类位置
  • 自动化构建在build.gradle中添加如下代码
jar {
    manifest {
        attributes 'CorePlugin': 'com.axis.core.template.TemplateLoadingCorePlugin'
    }
}
  • CorePlugins核心组件需要实现 CorePlugins 接口,如:
package com.axis.core.template;

import com.axis.innovators.box.plugins.LoadingCorePlugin;
import com.axis.innovators.template.Template;

/**
 * 注册core插件
 */
public class TemplateLoadingCorePlugin implements LoadingCorePlugin {
    @Override
    public String getMainClass() {
        // 返回主类名
        return Template.class.getName();
    }

    @Override
    public String[] getASMTransformerClass() {
        // 返回字节码转换器类名
        return new String[]{TemplateTransformer.class.getName()};
    }
}
  • IClassTransformer的实现
package com.axis.core.template;

import com.axis.innovators.box.plugins.IClassTransformer;
import org.objectweb.asm.*;

/**
 * core plugin transformer
 * @author tzdwindows 7
 */
public class TemplateTransformer implements IClassTransformer {
    @Override
    public byte[] transform(String s, String s1, byte[] bytes) {
        ClassReader classReader = new ClassReader(bytes);
        ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);

        ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5, classWriter) {
            @Override
            public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
                if ((access & Opcodes.ACC_PRIVATE) != 0) {
                    access = (access & ~Opcodes.ACC_PRIVATE) | Opcodes.ACC_PUBLIC;
                    System.out.println("Changing field access to public: " + name);
                }
                return super.visitField(access, name, descriptor, signature, value);
            }

            @Override
            public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
                System.out.println(name + " , descriptor:" + descriptor);
                if ((access & Opcodes.ACC_PRIVATE) != 0) {
                    access = (access & ~Opcodes.ACC_PRIVATE) | Opcodes.ACC_PUBLIC;
                    System.out.println("Changing method access to public: " + name);
                }
                return super.visitMethod(access, name, descriptor, signature, exceptions);
            }
        };

        classReader.accept(classVisitor, 0);
        return classWriter.toByteArray();
    }
}

事件系统说明

  • 事件驱动架构核心组件。
  • 事件总线系统,支持跨模块通信。
  • 事件总线由 EventBus & GlobalEventBus 实现

1.. EventBus & GlobalEventBus 说明

应用程序内的事件驱动架构核心组件:

package com.axis.innovators.box.events;

/**
 * 事件总线系统(支持多总线实例隔离)
 */
public class EventBus {
    // 核心方法
    public void register(Object listener);  // 注册监听器
    public void unregister(Object target);  // 注销监听器
    public boolean post(Object event);      // 发布事件
    public void shutdown();                 // 关闭总线
}

public class GlobalEventBus {
    public static final EventBus EVENT_BUS = new EventBus();  // 全局单例总线
}
  • EventBus:用于处理应用程序内各个模块之间的事件通信。
  • GlobalEventBus:用于处理应用程序内各个模块之间的事件通信,支持多总线实例隔离。

2. EventBus & GlobalEventBus 使用示例

示例1基础事件处理

// 1. 定义事件类型
public class UserLoginEvent {
    private final String username;
    private boolean cancelled;

    public UserLoginEvent(String username) {
        this.username = username;
    }

    // Getter/Setter...
}

// 2. 创建监听器类
public class SecurityLogger {
    @SubscribeEvent
    public void logLoginAttempt(UserLoginEvent event) {
        System.out.println("[安全审计] 登录尝试: " + event.getUsername());
    }
}

// 3. 使用全局总线
public class Main {
    public static void main(String[] args) {
        // 注册监听器
        GlobalEventBus.EVENT_BUS.register(new SecurityLogger());

        // 模拟用户登录
        UserLoginEvent loginEvent = new UserLoginEvent("admin");
        GlobalEventBus.EVENT_BUS.post(loginEvent);
    }
}
  • 示例2事件取消机制
 // 1. 定义可取消事件
public class FileDeleteEvent {
    private final Path filePath;
    private boolean cancelled;

    // 构造方法/getters/setters...
}

// 2. 创建权限校验监听器
public class PermissionValidator {
    @SubscribeEvent
    public void validateDeletePermission(FileDeleteEvent event) {
        if (!checkAdminAccess()) {
            event.setCancelled(true);
            System.out.println("文件删除被拒绝:权限不足");
        }
    }

    private boolean checkAdminAccess() {
        // 权限校验逻辑
        return false;
    }
}

// 3. 主业务流程
public class FileManager {
    public void deleteFile(Path path) {
        FileDeleteEvent event = new FileDeleteEvent(path);
        GlobalEventBus.EVENT_BUS.post(event);

        if (!event.isCancelled()) {
            // 执行删除操作
            System.out.println("正在删除文件: " + path);
        }
    }
}

3.所有系统所支持的事件

  • com.axis.innovators.box.events.CategoryRenderingEvent: 分类栏的渲染事件
  • com.axis.innovators.box.events.MainWindowEvents: 主窗口事件
  • com.axis.innovators.box.events.OpenFileEvents: 接收文件事件
  • com.axis.innovators.box.events.SettingsLoadEvents: 程序初始化事件
  • com.axis.innovators.box.events.StartupEvent: 程序启动事件
  • com.axis.innovators.box.events.TABUIEvents: 选项卡Ui属性事件

HTML窗口集成指南

我们实现了一套高性能的HTML渲染系统通过Java Chromium Embedded Framework (JCEF) 将HTML内容无缝集成到Java桌面应用中底层基于jcefmaven项目。

核心实现步骤

1. 创建HTML窗口

// 创建窗口引用
AtomicReference<BrowserWindowJDialog> htmlWindow = new AtomicReference<>();

SwingUtilities.invokeLater(() -> {
    // 通过窗口注册表创建子窗口
    WindowRegistry.getInstance().createNewChildWindow("main", builder -> {
        htmlWindow.set(builder
            .title("Axis Innovators Box AI 工具箱")  // 窗口标题
            .parentFrame(parentFrame)              // 父级窗口
            .icon(getApplicationIcon())            // 应用图标
            .size(1280, 720)                      // 初始尺寸
            .htmlPath(getHtmlResourcePath())       // HTML文件路径
            .operationHandler(createOperationHandler()) // 自定义操作处理器
            .build());
    });

    // 配置消息路由
    configureMessageRouter(htmlWindow.get());
});

2. 辅助方法

// 获取应用图标
private Image getApplicationIcon() {
    return new ImageIcon(Objects.requireNonNull(
        MainApplication.class.getClassLoader()
            .getResource("icons/logo.png")
    )).getImage();
}

// 获取HTML资源路径
private String getHtmlResourcePath() {
    return FolderCreator.getJavaScriptFolder() + "/AIaToolbox_dark.html";
}

3. 配置消息路由器

private void configureMessageRouter(BrowserWindowJDialog window) {
    CefMessageRouter msgRouter = window.getMsgRouter();
    if (msgRouter == null) return;

    msgRouter.addHandler(new CefMessageRouterHandlerAdapter() {
        @Override
        public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId,
                               String request, boolean persistent, CefQueryCallback callback) {
            // 处理来自HTML的请求
            handleBrowserRequest(request, callback);
            return true; // 表示已处理该请求
        }

        @Override
        public void onQueryCanceled(CefBrowser browser, CefFrame frame, long queryId) {
            // 处理请求取消逻辑
            System.out.println("请求被取消: " + queryId);
        }
    }, true); // true表示优先处理
}

HTML事件

HTML窗口内可以捕捉到一些Java的事件

事件名 介绍 触发时机
javaFontsLoaded Java字体加载完成 Java字体信息传输到HTML时或在在更新主题时
javaThemeChanged 在主题发生变化时触发 在更新主题时

具体示例

// 监听Java字体加载事件
document.addEventListener('javaFontsLoaded', function(event) {
   const fontInfo = event.detail;
   console.log('接收到Java字体信息:', fontInfo);

   // 应用Java字体到界面
   applyJavaFonts(fontInfo);
});
// 监听Java主题变化事件
document.addEventListener('javaThemeChanged', function(event) {
   const themeInfo = event.detail;
   console.log('接收到Java主题信息:', themeInfo);
   applyJavaTheme(themeInfo);
});

窗口管理系统说明

通过WindowRegistry统一管理应用窗口:

方法 说明
createNewWindow(String id, Consumer<Builder> config) 创建主窗口
createNewChildWindow(String id, Consumer<Builder> config) 创建模态子窗口
getWindow(String id) 获取已注册窗口
unregisterWindow(String id) 关闭指定窗口

CefMessageRouter 使用指南

实现Java与JavaScript双向通信的核心组件

  1. 消息处理流程

    • JavaScript → Java: 通过window.cefQuery()发送请求
    • Java → JavaScript: 使用CefFrame.executeJavaScript()执行脚本
  2. 核心方法

// JavaScript调用示例
function callJavaMethod(data) {
    window.cefQuery({
        request: JSON.stringify(data),
        onSuccess: response => console.log("Success:", response),
        onFailure: (err, msg) => console.error("Error:", msg)
    });
}
  1. 最佳实践
    • 使用JSON格式进行数据交换
    • 为不同功能模块使用独立的路由处理器
    • 在窗口关闭前移除所有路由处理器

生命周期管理

// 关闭窗口时清理资源
htmlWindow.get().addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosing(WindowEvent e) {
        window.getMsgRouter().dispose();
        CefApp.getInstance().dispose();
    }
});

核心类说明

1. AxisInnovatorsBox

窗口实例的核心操作类,提供以下功能:

  • getMain(): 获取当前AxisInnovatorsBox实例
  • getMainWindow(): 获取主窗口实例
  • quit(): 退出程序
  • organizingCrashReports(Exception): 组织崩溃报告,用于在应用程序发生异常时生成崩溃报告。
  • popupWindow(WindowsJDialog): 弹出新的窗口,并将其添加到窗口列表中。
  • isWindowStartup(WindowsJDialog): 判断指定的窗口是否已经启动。
  • clearWindow(WindowsJDialog): 清除指定的窗口,并将其从窗口列表中移除。
  • reloadAllWindow(): 重新加载窗口。
  • getRegistrationTool(): 获取注册工具实例。
  • getArgs(): 获取命令行参数。
  • isWindow(): 判断窗口是否已经启动。
  • getVersion(): 获取应用程序的版本号。
  • getRegistrationTopic(): 获取注册主题实例。
  • getAuthor(): 获取应用程序的作者信息。
  • getStateManager(): 获取状态管理器实例。

2. RegistrationTool

负责在 应用程序启动阶段 注册和管理工具分类的核心组件,具备插件系统集成能力:

package com.axis.innovators.box.register;

/**
 * 工具分类注册中心(窗口启动前必须完成注册)
 */
public class RegistrationTool {
    // 构造方法关联主程序实例
    public RegistrationTool(AxisInnovatorsBox main) { ... }
    
    // 核心功能方法
    public boolean addToolCategory(ToolCategory category, String regName);
    public void addToolCategory(ToolCategory category, PluginDescriptor descriptor, String regName);
    public ToolCategory getToolCategory(UUID id);
    public UUID getUUID(String registeredName);
}
  • addToolCategory(ToolCategory category, String regName): 向工具分类注册中心添加一个新的工具分类。
  • addToolCategory(ToolCategory category, PluginDescriptor descriptor, String regName): 向工具分类注册中心添加一个新的工具分类,同时关联插件描述符。
  • getToolCategory(UUID id): 通过UUID获取工具分类。
  • getUUID(String registeredName): 通过注册名称获取UUID。

注册示例

// 创建调试工具分类
MainWindow.ToolCategory debugCategory = new MainWindow.ToolCategory(
    "逆向分析工具", 
    "icons/debugger.png",
    "二进制逆向分析工具集"
);

// 添加工具项(带点击事件)
debugCategory.addTool(new MainWindow.ToolItem(
    "内存分析器",
    "icons/memory.png",
    "实时查看进程内存映射",
    1,
    new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            JOptionPane.showMessageDialog(null, "启动内存分析模块...");
        }
    }
));

// 注册到系统(必须在窗口初始化前完成)
try {
    registrationTool.addToolCategory(debugCategory, "system:reverseEngineering");
} catch (RegistrationError ex) {
    System.err.println("注册失败: " + ex.getMessage());
}

3. RegistrationTopic

负责在 应用程序初始化阶段 统一管理UI主题注册的核心组件支持类名/LookAndFeel双模式主题注入

package com.axis.innovators.box.register;

/**
 * 主题注册中心(窗口初始化前必须完成注册)
 */
public class RegistrationTopic {
    // 核心注册方法
    public void addTopic(String topicClass, String name, String tip, Icon icon, String regName);
    public void addTopic(LookAndFeel laf, String name, String tip, Icon icon, String regName);
    
    // 状态管理方法
    public boolean isLoading(String themeName);
    public void setLoading(String themeName);
}
  • addTopic(String topicClass, String name, String tip, Icon icon, String regName): 向主题注册中心添加一个新的主题。
  • addTopic(LookAndFeel laf, String name, String tip, Icon icon, String regName): 向主题注册中心添加一个新的主题同时关联LookAndFeel。
  • isLoading(String themeName): 判断指定主题是否正在加载。
  • setLoading(String themeName): 设置指定主题为正在加载状态。

注册示例

try {
        // 重复注册相同名称
        topicRegistry.addTopic("com.axis.light.MaterialTheme",
                                       "质感浅色",
                                       "Material Design风格",
                               materialIcon, 
        "theme:light");  // 已存在同名注册
} catch (RegistrationError ex) {
        // 捕获异常并提示theme:light duplicate registered names
        JOptionPane.showMessageDialog(null, ex.getMessage());
}

4. StateManager

应用程序状态管理工具类,提供跨会话的配置持久化能力:

package com.axis.innovators.box.tools;

/**
 * 状态持久化管理器(线程安全)
 */
public class StateManager {
    // 构造方法
    public StateManager();  // 默认使用toolbox.properties
    public StateManager(String customFileName);  // 自定义状态文件名
    
    // 核心操作方法
    public void saveState(String key, [int|long|boolean...] value);
    public [String|int|boolean...] getStateAs[Type](String key);
}
  • saveState(String key, [int|long|boolean...] value): 保存状态到配置文件。
  • getStateAs[Type](String key): 从配置文件获取状态。
  • [String|int|boolean...]: 支持多种数据类型保存到配置文件,并支持多种数据类型从配置文件获取。

5. RegistrationSettingsItem

负责管理系统 设置中心 的配置面板注册,支持插件化扩展设置项的核心组件:

package com.axis.innovators.box.register;

/**
 * 设置项注册中心(集成插件配置扩展能力)
 */
public class RegistrationSettingsItem extends WindowsJDialog {
    // 核心注册方法
    public void addSettings(JPanel panel, String title, Icon icon, String tip, String regName);
    public void addSettings(JPanel panel, String title, Icon icon, String tip, 
                            PluginDescriptor plugin, String regName);
    
    // 查询方法
    public static List<RegistrationSettingsItem> getRegistrationsByPlugin(PluginDescriptor plugin);
}
  • addSettings(JPanel panel, String title, Icon icon, String tip, String regName): 向设置项注册中心添加一个新的设置项。
  • addSettings(JPanel panel, String title, Icon icon, String tip, PluginDescriptor plugin, String regName): 向设置项注册中心添加一个新的设置项,同时关联插件描述符。
  • getRegistrationsByPlugin(PluginDescriptor plugin): 通过插件描述符获取关联的设置项列表。

6. LanguageManager

应用程序多语言管理核心组件,支持动态加载与合并多语言资源:

package com.axis.innovators.box.register;

/**
 * 国际化语言管理中心(支持插件扩展语言包)
 */
public class LanguageManager {
    // 核心操作方法
    public static void addLanguage(Language lang);
    public static void loadLanguage(String regName);
    public static Language getLoadedLanguages();
    public static Language getLanguage(String identifier);
}
  • addLanguage(Language lang): 向语言管理中心添加一个新的语言包。
  • loadLanguage(String regName): 加载指定语言包。
  • getLoadedLanguages(): 获取当前系统加载的语言包。
  • getLanguage(String identifier): 通过标识符获取语言包。
Description
No description provided
Readme 859 MiB
Languages
Java 41.4%
JavaScript 33.5%
C 17.3%
HTML 3.9%
CSS 2.5%
Other 1.4%