请问脚本配置如何开发,我在脚本代码index.js中有一个var floatyWin = floaty.window,里面放置了开始/停止按钮和配置按钮,我需要点击这个配置弹出脚本的配置页面,输入相关配置参数后可以点击保存
为什么调用showConfigWindow()方法,整个脚本会假死
回答
要在 Hamibot 中实现脚本配置功能,并通过悬浮窗中的配置按钮打开配置界面,你可以按照以下步骤进行开发:
1. 配置文件管理
Hamibot 脚本默认支持 JSON 格式的配置文件(如 config.json
)。你可以手动创建一个配置文件,或在代码中动态生成。以下是保存和读取配置的基本逻辑:
// 保存配置到文件
function saveConfig(config) {
var path = files.path("config.json");
files.write(path, JSON.stringify(config, null, 2));
}
// 从文件读取配置
function loadConfig() {
var path = files.path("config.json");
if (files.exists(path)) {
return JSON.parse(files.read(path));
}
return {};
}
2. 配置悬浮窗设计
当用户点击“配置按钮”时,弹出一个悬浮窗用于输入参数并保存:
// 创建配置悬浮窗
function showConfigWindow() {
var config = loadConfig();
var w = floaty.rawWindow(
<vertical padding="16">
<text>参数1:</text>
<input id="param1" text="{{config.param1}}" />
<text>参数2:</text>
<input id="param2" text="{{config.param2}}" />
<button id="saveBtn" text="保存" style="Widget.AppCompat.Button.Colored" />
</vertical>
);
w.saveBtn.click(function () {
var newConfig = {
param1: w.param1.text(),
param2: w.param2.text()
};
saveConfig(newConfig);
toast("配置已保存");
w.close();
});
// 设置悬浮窗位置(可选)
w.setPosition(500, 500);
}
3. 绑定配置按钮点击事件
在你的主悬浮窗中,将“配置按钮”与 showConfigWindow
函数绑定:
var floatyWin = floaty.window(
<vertical>
<button id="startBtn">开始</button>
<button id="stopBtn">停止</button>
<button id="configBtn" text="配置" />
</vertical>
);
// 点击配置按钮时打开配置窗口
floatyWin.configBtn.click(function () {
showConfigWindow();
});
4. 使用配置参数
在脚本逻辑中,通过 loadConfig()
读取用户保存的参数:
var config = loadConfig();
log("参数1:" + config.param1);
log("参数2:" + config.param2);
注意事项
-
文件路径:
使用files.path("config.json")
确保配置文件存储在脚本的工作目录中。 -
UI 线程更新:
如果需要在悬浮窗中动态更新内容,使用ui.run()
方法(例如:ui.run(() => w.text.setText("新文本"))
)。 -
兼容性:
避免使用箭头函数(=>
),改用标准函数表达式(function () {}
),因为 Hamibot 使用的是 Rhino 1.7.15 引擎。
完整代码示例
// 文档地址 https://docs.hamibot.com/
var floatyWin = floaty.window(
<vertical>
<button id="startBtn">开始</button>
<button id="stopBtn">停止</button>
<button id="configBtn" text="配置" />
</vertical>
);
// 保存配置
function saveConfig(config) {
var path = files.path("config.json");
files.write(path, JSON.stringify(config, null, 2));
}
// 加载配置
function loadConfig() {
var path = files.path("config.json");
if (files.exists(path)) {
return JSON.parse(files.read(path));
}
return {};
}
// 显示配置悬浮窗
function showConfigWindow() {
var config = loadConfig();
var w = floaty.rawWindow(
<vertical padding="16">
<text>参数1:</text>
<input id="param1" text="{{config.param1}}" />
<text>参数2:</text>
<input id="param2" text="{{config.param2}}" />
<button id="saveBtn" text="保存" style="Widget.AppCompat.Button.Colored" />
</vertical>
);
w.saveBtn.click(function () {
var newConfig = {
param1: w.param1.text(),
param2: w.param2.text()
};
saveConfig(new
***
# 补充回答 1
脚本假死通常是由于 **UI 创建阻塞了主线程** 或 **悬浮窗未正确释放资源**,以下是具体原因和修复方案:
---
### **1. 悬浮窗创建阻塞主线程**
Hamibot 的 JavaScript 引擎 Rhino 是单线程模型,如果 `showConfigWindow()` 中创建悬浮窗时包含耗时操作(如复杂布局计算、同步文件读写),会导致主线程阻塞,表现为脚本假死。
#### **解决方案:异步创建悬浮窗**
将悬浮窗创建逻辑放入 `threads.start()` 线程中执行,避免阻塞主线程:
```javascript
function showConfigWindow() {
threads.start(function () {
var config = loadConfig();
var w = floaty.rawWindow(
<vertical padding="16">
<text>参数1:</text>
<input id="param1" text="{{config.param1}}" />
<text>参数2:</text>
<input id="param2" text="{{config.param2}}" />
<button id="saveBtn" text="保存" />
</vertical>
);
// UI 事件监听必须在主线程
ui.post(() => {
w.saveBtn.click(function () {
var newConfig = {
param1: w.param1.text(),
param2: w.param2.text()
};
saveConfig(newConfig);
toast("配置已保存");
w.close();
});
});
w.setPosition(500, 500); // 设置悬浮窗位置
});
}
2. 悬浮窗未正确关闭
如果悬浮窗未调用 w.close()
或因异常退出,可能会导致多个悬浮窗叠加或资源泄漏,最终卡死。
修复点:确保悬浮窗自动释放
-
在
saveBtn.click
回调中强制关闭悬浮窗:w.saveBtn.click(function () { ... w.close(); // 确保关闭悬浮窗 });
-
添加异常捕获防止崩溃:
try { // 悬浮窗逻辑 } catch (e) { toast("配置窗口异常:" + e.message); }
3. 布局文件错误导致渲染失败
如果 XML 布局语法错误(如标签未闭合、组件名错误),会导致 floaty.rawWindow
报错并卡死。
验证方法:简化布局测试
先用最简布局测试是否正常:
var w = floaty.rawWindow(
<vertical padding="16">
<text>测试</text>
<button id="saveBtn">保存</button>
</vertical>
);
若能正常显示,则逐步添加原布局内容,定位错误来源。
4. 文件读写冲突
在 saveConfig()
或 loadConfig()
中,如果频繁读写文件且未处理异常,可能导致 IO 阻塞。
优化文件操作
-
使用
files.atomic()
确保文件读写原子性:function saveConfig(config) { var path = files.path("config.json"); files.atomic(path, "w", function (stream) { stream.write(JSON.stringify(config, null, 2)); }); }
-
避免在循环中频繁读写文件。
完整优化代码示例
// 文档地址 https://docs.hamibot.com/
var floatyWin = floaty.window(
<vertical>
<button id="startBtn">开始</button>
<button id="stopBtn">停止</button>
<button id="configBtn" text="配置" />
</vertical>
);
// 保存配置
function saveConfig(config) {
var path = files.path("config.json");
files.atomic(path, "w", function (stream) {
stream.write(JSON.stringify(config, null, 2));
});
}
// 加载配置
function loadConfig() {
var path = files.path("config.json");
if (files.exists(path)) {
return JSON.parse(files.read(path));
}
return {};
}
// 显示配置悬浮窗
function showConfigWindow() {
threads.start(function () {
var config = loadConfig();
var w = floaty.rawWindow(
<vertical padding="16">
<text>参数1:</text>
<input id="param1" text="{{config.param1}}" />
<text>参数2:</text>
<input id="param2" text="{{config.param2}}" />
<button id="saveBtn" text="保存" />
</vertical>
);
ui.post(() => {