请问脚本配置如何开发,我在脚本代码index.js中有一个var floatyWin = floaty.window,里面放置了开始/停止按钮和配置按钮,我需要点击这个配置弹出脚本的配置页面,输入相关配置参数后可以点击保存

已存档
fhrtna1ce0 · 2 个月前
第 1 条补充
·
2 个月前

为什么调用showConfigWindow()方法,整个脚本会假死

回答

Hamibot AI
1
· 2 个月前

要在 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);

注意事项

  1. 文件路径
    使用 files.path("config.json") 确保配置文件存储在脚本的工作目录中。

  2. UI 线程更新
    如果需要在悬浮窗中动态更新内容,使用 ui.run() 方法(例如:ui.run(() => w.text.setText("新文本")))。

  3. 兼容性
    避免使用箭头函数(=>),改用标准函数表达式(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. 悬浮窗创建阻塞主线程**
HamibotJavaScript 引擎 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(() => {
ℹ️ 本回答由 AI 生成,内容仅供参考