QML与JavaScript 交互的四种方式

目录

引言

在Qt6中,QML引擎深度集成了JavaScript。本文将用四个示例,展示QML与Javascript的四种交互方式:内联调用、外部文件、信号处理、工作线程(WorkerScript)。


交互方式说明

方式一:内联调用

演示效果

适用场景:逻辑简单,仅在当前组件内部使用的短代码。

在 QML 根元素内直接定义 function,就像在 HTML 中写 JS 一样。

关键代码 (来自 JSInlineFunc.qml ):

qml 复制代码
Rectangle {
    // 1. 定义一个内联 JS 函数
    function calculateArea(w, h) {
        return w * h
    }

    Text {
        // 2. 属性绑定中直接调用:当 width 或 height 变化时自动重算
        text: "计算面积: " + calculateArea(this.width, this.height) 
    }

    Button {
        // 3. 在信号处理器(如 onClicked)中调用
        onClicked: {
            var result = calculateArea(100, 100)
            textResult.text = "Area: " + result
        }
    }
}

关键点

  • 作用域:这些函数可以访问该 QML 文件内的所有 id 和属性。
  • 绑定特性:在属性绑定(如 text: ...)中使用时,若参数发生变化,函数会自动重新执行 。

方式二:外部文件

演示效果

适用场景:通用的工具函数(如日期格式化、字符串处理),需要在多个 QML 文件中共享。

关键代码

首先在 Utility.js 中定义函数,并使用 .pragma library 声明这是一个共享库 。

javascript 复制代码
// Utility.js
.pragma library 

function formatDate(date) {
    return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate()
}

然后在 JSImportFile.qml 中导入并使用 :

qml 复制代码
import "Utility.js" as Util // 定义别名为 Util

Text {
    // 使用 别名.函数名 进行调用
    text: "日期: " + Util.formatDate(new Date()) 
}

关键点

  • 必须使用 as 关键字定义别名(如Util),避免命名冲突。同时注意Util首字母要大写
  • 加上 .pragma library 后,该 JS 文件在整个应用程序中只有一份实例(单例),适合存放无状态的工具函数。如果不加这行,每个导入它的 QML 组件都会生成一个新的 JS 上下文副本。

方式三:信号处理

演示效果

适用场景:将复杂的逻辑封装在 JS 函数中,通过 QML 的信号(Signal)来触发,保持代码整洁。

关键代码 (来自 JSSignal.qml ):

qml 复制代码
Text {
    id: myText
    property int counter: 0

    // 1. 定义处理逻辑
    function handleButtonClick() {
        myText.counter++
    }

    Connections {
        target: myButton // 目标按钮
        // 2. 将按钮的 onClicked 信号连接到 JS 函数
        function onClicked() { myText.handleButtonClick() } 
    }
}

关键点

  • 这体现了 Qt 的 信号与槽 (Signal & Slot) 机制。JS 函数在 QML 中可以直接作为槽函数使用。
  • 这种方式解耦了 UI 元素(Button)和业务逻辑(Text 的计数逻辑)。

方式四:工作线程 (WorkerScript)

演示效果

适用场景:耗时操作(如图像处理、大规模计算)。如果在主线程做这些,界面会"卡死"。

原理 :使用 WorkerScript 将 JS 代码放到后台线程运行。注意:后台线程不能访问 QML 的 UI 元素(DOM),只能通过消息传递(Message Passing)交互。

关键代码 (来自 WorkerScriptDemo.qmlscript.mjs):

Step 1: QML 端 (发送与接收)

qml 复制代码
// 工作线程脚本
WorkerScript {
    id: myWorker
    source: "script.mjs"

    // 接收工作线程返回的消息
    onMessage: function (msgObj) {
        isProcessing = false;

        if (msgObj.error) {
            resultText = "错误: " + msgObj.error;
        } else {
            resultText = "计算结果: " + msgObj.result +
                    "\n耗时: " + msgObj.time + " ms" +
                    "\n任务ID: " + msgObj.taskId +
                    "\n原始消息: " + JSON.stringify(msgObj.originalMessage)
        }
    }
}

//发送按钮
Button {
    id: btnCalc
    text: "计算斐波那契数列"
    font.pointSize: 12
    enabled: !isProcessing && myWorker.ready
    onClicked: {
        isProcessing = true;
        resultText = "计算斐波那契数列 ...";
        myWorker.sendMessage({ 'taskId': 1001, 'n': textField.text, 'timestamp': Date.now() });
    }
}

Step 2: JS 端 (处理与回传)

javascript 复制代码
// script.mjs
// 计算斐波那契数列(递归,耗时操作)
function fibonacci(n) {
    function fib(n) {
        if (n <= 1) return n;
        return fib(n - 1) + fib(n - 2);
    }
    return fib(n);
}

// 监听主线程发送的消息
WorkerScript.onMessage = function(message) {   
    try {
        var startTime = Date.now();
        var result;
        
        // 计算斐波那契数列
        result = fibonacci(message.n || 30);        
        var endTime = Date.now();
        var processingTime = endTime - startTime;
        
        // 将结果发送回主线程
        WorkerScript.sendMessage({
            result: result,
            time: processingTime,
            taskId: message.taskId,
            originalMessage: message
        });
        
    } catch (error) {
        // 错误处理
        WorkerScript.sendMessage({
            error: error.toString(),
            originalMessage: message
        });
    }
}

关键点

  • 异步特性 :调用 sendMessage 后,主线程立即继续执行,不会等待。
  • 数据隔离 :Worker 内部无法访问 id: mainWindow 等 UI 对象,必须通过 message 对象传递所需的所有数据。

总结

方式 关键字 适用场景 备注
内联调用 function 简单的 UI 逻辑 访问方便,但不易复用
外部文件 import ... as 工具类库、常量定义 推荐使用 .pragma library
信号连接 Connections 响应事件 实现 UI 与逻辑解耦
工作线程 WorkerScript 耗时计算、网络请求 唯一不阻塞 UI 的方式

初学时从内联函数开始,随着代码量增加,逐渐将逻辑抽离到外部 JS 文件中。

工程下载

下载链接:QML与JavaScript 交互的四种方式

相关推荐
CQU_JIAKE5 分钟前
4.4【Q】
java·前端·javascript
笑鸿的学习笔记14 分钟前
Qt与CMake笔记之option、宏传递与Qt Creator项目设置
开发语言·笔记·qt
GISer_Jing19 分钟前
Electron 全场景调试实战指南
javascript·electron·状态模式
We་ct21 分钟前
JS手撕:性能优化、渲染技巧与定时器实现
开发语言·前端·javascript·面试·性能优化·定时器·性能
taWSw5OjU30 分钟前
vue对接海康摄像头-H5player
开发语言·前端·javascript
huwuhang42 分钟前
跨平台电子书阅读器 | Readest最新版 安卓版+PC版全平台
android·前端·javascript
Shirley~~43 分钟前
力扣hot100:每日温度
开发语言·javascript·ecmascript
条tiao条44 分钟前
不止语法糖:TypeScript Set 与 Map 深度解析
前端·javascript·typescript
freewlt1 小时前
React Server Components 深度解析:从原理到实战的完整指南
前端·javascript·react.js
zhensherlock1 小时前
Protocol Launcher 系列:1Writer iOS 上的 Markdown 文档管理
javascript·笔记·ios·typescript·node.js·iphone·ipad