请问脚本配置如何开发,我在脚本代码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(() => {