320 lines
10 KiB
Markdown
320 lines
10 KiB
Markdown
# AxisInnovatorsBox Window API
|
||
|
||
[项目链接](https://gitea.lingqi.vip/lanxi/window-axis-innovators-box1.17) | [官网](https://box.lingqi.vip) | 简体中文
|
||
|
||
---
|
||
|
||
## 📖 项目概述
|
||
|
||
`AxisInnovatorsBoxWindowApi` 是专为 **AxisInnovatorsBox** 平台打造的核心扩展 API 库。它赋予开发者创建自定义插件的能力,支持窗口深度管理、跨语言事件交互及 UI 定制。该仓库包含完整的接口定义、开发文档及示例代码,旨在帮助开发者无缝接入并扩展 AxisInnovatorsBox 生态系统。
|
||
|
||
## ✨ 功能特性
|
||
|
||
* 🖥️ **全生命周期窗口管理** - 精确控制窗口创建、销毁、最小化/最大化及模态状态。
|
||
* 🎮 **事件驱动架构** - 基于发布/订阅模式的事件总线,支持系统级事件监听与自定义事件广播。
|
||
* 📦 **多语言插件引擎** - 原生支持 Java 插件,并通过 Jython 实现 Python 插件的无缝加载与互操作。
|
||
* 📄 **动态配置与国际化** - 支持通过 Properties 灵活管理配置,提供完整的 I18n 多语言支持。
|
||
* 📊 **统一日志系统** - 集成 Java 日志框架,自动捕获并同步 Python 插件的运行日志与异常堆栈。
|
||
|
||
---
|
||
|
||
## 🧩 插件开发指南
|
||
|
||
插件加载系统是程序的核心组件,由主程序内部自动调度。
|
||
|
||
### 1. Java 插件开发 (Jar)
|
||
Jar 格式插件需放置在 `/plug-in` 目录下。
|
||
|
||
**核心注解 `@PluginMeta`**:
|
||
用于描述插件的基本信息。系统会自动实例化被标记的类,并填充 `INSTANCE` 字段。
|
||
|
||
```java
|
||
package com.example.plugin;
|
||
|
||
import com.axis.innovators.box.plugins.PluginDescriptor;
|
||
import com.axis.innovators.box.plugins.PluginMeta;
|
||
import com.axis.innovators.box.events.GlobalEventBus;
|
||
import com.axis.innovators.box.events.StartupEvent;
|
||
import com.axis.innovators.box.events.SubscribeEvent;
|
||
import com.axis.innovators.box.window.MainWindow;
|
||
|
||
@PluginMeta(
|
||
id = "test_plugin",
|
||
name = "测试插件",
|
||
version = "1.0.0",
|
||
supportedVersions = {"0.0.2"},
|
||
description = "这是一个Java插件示例",
|
||
icon = "icon.png",
|
||
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_icon", "分类描述");
|
||
event.main().getRegistrationTool().addToolCategory(
|
||
category,
|
||
INSTANCE,
|
||
"templatePlugin::category"
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. Python 插件开发 (Script)
|
||
Python 插件需放置在 `/plug-in/python` 的子目录中(例如 `/plug-in/python/Examples`)。Python 脚本可直接调用 Java 类库。
|
||
|
||
**必要文件结构**:
|
||
* `metadata.json`: 插件元数据
|
||
* `main.py`: 入口脚本
|
||
|
||
**metadata.json 示例**:
|
||
```json
|
||
{
|
||
"id": "py_testing",
|
||
"name": "Python测试插件",
|
||
"version": "0.0.1",
|
||
"description": "Python脚本插件示例",
|
||
"author": "tzdwindows 7",
|
||
"dependencies": [],
|
||
"_comment": {
|
||
"path": "资源文件应放置在 plugins/{id}/ 目录下"
|
||
}
|
||
}
|
||
```
|
||
|
||
**main.py 示例**:
|
||
```python
|
||
"""
|
||
功能:注册自定义工具类别和工具项
|
||
"""
|
||
from com.axis.innovators.box.python import PyLocalSide
|
||
from javax.swing import AbstractAction
|
||
|
||
class MyAction(AbstractAction):
|
||
def actionPerformed(self, event):
|
||
print("[DEBUG] Python工具项被点击!事件源:", event.getSource())
|
||
|
||
def onStartup():
|
||
"""系统启动钩子函数"""
|
||
print('[INFO] 初始化Python插件...')
|
||
|
||
# 1. 创建工具类别
|
||
tool_category = PyLocalSide.getToolCategory(
|
||
u"数据分析", # 名称
|
||
u"analytics.png", # 图标
|
||
u"Python数据分析工具" # 描述
|
||
)
|
||
|
||
# 2. 创建并添加工具项
|
||
tool_action = MyAction()
|
||
tool_item = PyLocalSide.getToolItem(
|
||
u"生成图表",
|
||
u"chart.png",
|
||
u"点击生成报表",
|
||
1001,
|
||
tool_action
|
||
)
|
||
tool_category.addTool(tool_item)
|
||
|
||
# 3. 注册到系统
|
||
PyLocalSide.addToolCategory(
|
||
tool_category,
|
||
u"py_module::analysis"
|
||
)
|
||
print('[SUCCESS] Python插件加载完成')
|
||
|
||
# 将 onStartup 绑定到全局作用域,供 Java 端调用
|
||
if __name__ == '__main__':
|
||
globals()['onStartup'] = onStartup
|
||
```
|
||
|
||
### 3. CorePlugins (字节码增强)
|
||
CorePlugins 允许在类加载阶段修改目标类的字节码(ASM)。
|
||
|
||
**配置步骤**:
|
||
1. 在 `build.gradle` 中声明 Manifest 属性:
|
||
```groovy
|
||
jar {
|
||
manifest {
|
||
attributes 'CorePlugin': 'com.axis.core.template.TemplateLoadingCorePlugin'
|
||
}
|
||
}
|
||
```
|
||
2. 实现 `LoadingCorePlugin` 接口:
|
||
```java
|
||
public class TemplateLoadingCorePlugin implements LoadingCorePlugin {
|
||
@Override
|
||
public String getMainClass() {
|
||
return Template.class.getName(); // 返回插件主类
|
||
}
|
||
|
||
@Override
|
||
public String[] getASMTransformerClass() {
|
||
return new String[]{TemplateTransformer.class.getName()}; // 返回Transformer类
|
||
}
|
||
}
|
||
```
|
||
3. 实现 `IClassTransformer` 接口(使用 ASM 修改字节码):
|
||
```java
|
||
public class TemplateTransformer implements IClassTransformer {
|
||
@Override
|
||
public byte[] transform(String name, String transformedName, byte[] basicClass) {
|
||
// 使用 ASM ClassReader/ClassWriter 修改字节码
|
||
// 示例:将所有 private 字段和方法修改为 public
|
||
// ... (省略具体ASM代码,参考原文档)
|
||
return modifiedBytes;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📡 事件驱动系统
|
||
|
||
基于 `EventBus` 的发布/订阅模式,实现模块解耦与通信。
|
||
|
||
### 核心组件
|
||
* `EventBus`: 基础事件总线。
|
||
* `GlobalEventBus.EVENT_BUS`: **全局单例总线**,用于跨模块通信。
|
||
|
||
### 使用示例
|
||
```java
|
||
// 1. 定义事件
|
||
public class UserLoginEvent {
|
||
private final String username;
|
||
public UserLoginEvent(String u) { this.username = u; }
|
||
// getters...
|
||
}
|
||
|
||
// 2. 注册监听器 (@SubscribeEvent)
|
||
public class LoginLogger {
|
||
public LoginLogger() {
|
||
GlobalEventBus.EVENT_BUS.register(this);
|
||
}
|
||
|
||
@SubscribeEvent
|
||
public void onLogin(UserLoginEvent event) {
|
||
System.out.println("用户登录: " + event.getUsername());
|
||
}
|
||
}
|
||
|
||
// 3. 发布事件
|
||
GlobalEventBus.EVENT_BUS.post(new UserLoginEvent("admin"));
|
||
```
|
||
|
||
### 内置系统事件表
|
||
| 事件类名 | 描述 |
|
||
| :--- | :--- |
|
||
| `StartupEvent` | 程序启动完成事件,常用于注册工具栏 |
|
||
| `SettingsLoadEvents` | 设置界面初始化事件,用于添加设置项 |
|
||
| `MainWindowEvents` | 主窗口生命周期相关事件 |
|
||
| `CategoryRenderingEvent` | 工具栏分类渲染事件 |
|
||
| `OpenFileEvents` | 外部文件打开请求事件 |
|
||
| `TABUIEvents` | 选项卡 UI 属性变更事件 |
|
||
|
||
---
|
||
|
||
## 🌐 HTML 窗口集成 (JCEF)
|
||
|
||
通过 JCEF (Chromium) 渲染高性能 HTML/JS 界面,并支持与 Java 双向通信。
|
||
|
||
### 创建 HTML 窗口
|
||
```java
|
||
SwingUtilities.invokeLater(() -> {
|
||
WindowRegistry.getInstance().createNewChildWindow("ai_toolbox", builder -> {
|
||
builder.title("AI 工具箱")
|
||
.size(1280, 720)
|
||
.htmlPath(FolderCreator.getJavaScriptFolder() + "/ui/index.html") // 本地HTML路径
|
||
.build();
|
||
});
|
||
});
|
||
```
|
||
|
||
### Java 与 JavaScript 通信 (`CefMessageRouter`)
|
||
|
||
**1. JavaScript 调用 Java**
|
||
```javascript
|
||
// 在前端 JS 中调用
|
||
window.cefQuery({
|
||
request: JSON.stringify({ action: "getData", id: 1 }),
|
||
onSuccess: function(response) { console.log("Java返回:", response); },
|
||
onFailure: function(code, msg) { console.error("错误:", msg); }
|
||
});
|
||
```
|
||
|
||
**2. Java 处理请求**
|
||
```java
|
||
// 获取路由并添加处理器
|
||
CefMessageRouter router = window.getMsgRouter();
|
||
router.addHandler(new CefMessageRouterHandlerAdapter() {
|
||
@Override
|
||
public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId,
|
||
String request, boolean persistent, CefQueryCallback callback) {
|
||
if (request.contains("getData")) {
|
||
callback.success("{\"data\": \"Hello from Java\"}");
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
}, true);
|
||
```
|
||
|
||
**3. HTML 监听 Java 事件**
|
||
HTML 页面可监听来自 Java 的系统级通知:
|
||
* `javaFontsLoaded`: 字体加载完成。
|
||
* `javaThemeChanged`: 主题变更通知。
|
||
|
||
```javascript
|
||
document.addEventListener('javaThemeChanged', (e) => {
|
||
console.log('主题变更为:', e.detail);
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 核心 API 参考
|
||
|
||
### 1. `AxisInnovatorsBox` (主程序入口)
|
||
获取应用全局状态和核心管理器。
|
||
* `getInstance()` / `getMain()`: 获取单例。
|
||
* `getRegistrationTool()`: 获取工具注册器。
|
||
* `getRegistrationTopic()`: 获取主题注册器。
|
||
* `getMainWindow()`: 获取主窗口对象。
|
||
* `popupWindow(WindowsJDialog)` / `clearWindow(...)`: 窗口堆栈管理。
|
||
|
||
### 2. `RegistrationTool` (工具注册)
|
||
在 `StartupEvent` 中使用,用于向主界面添加功能入口。
|
||
* `addToolCategory(category, regName)`: 注册工具分类。
|
||
* `getToolCategory(UUID)`: 获取已注册分类。
|
||
|
||
### 3. `RegistrationTopic` (主题注册)
|
||
在初始化阶段注册自定义 LookAndFeel 或主题类。
|
||
* `addTopic(topicClass, name, tip, icon, regName)`: 注册主题。
|
||
* **注意**: 注册名称 (`regName`) 必须唯一,否则会抛出异常。
|
||
|
||
### 4. `RegistrationSettingsItem` (设置项注册)
|
||
在 `SettingsLoadEvents` 中使用,向设置中心添加面板。
|
||
* `addSettings(JPanel panel, String title, Icon icon, String tip, PluginDescriptor plugin, String regName)`: 注册设置页。
|
||
|
||
### 5. `StateManager` (状态持久化)
|
||
用于保存插件配置或用户偏好设置(键值对)。
|
||
* `saveState(key, value)`: 持久化保存。
|
||
* `getStateAsString(key)` / `getStateAsInt(key)`: 读取配置。
|
||
|
||
### 6. `LanguageManager` (国际化)
|
||
* `addLanguage(Language lang)`: 注册新的语言包。
|
||
* `getLanguage(String id)`: 获取特定语言资源。
|
||
|
||
### 7. `WindowRegistry` (窗口管理)
|
||
统一管理 JCEF 和原生 Swing 窗口的生命周期。
|
||
* `createNewChildWindow(id, config)`: 创建模态子窗口。
|
||
* `unregisterWindow(id)`: 安全关闭并注销窗口。 |