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 交互的四种方式

相关推荐
徐某人..1 小时前
基于i.MX6ULL平台的智能网关系统开发
arm开发·c++·单片机·qt·物联网·学习·arm
豹哥学前端1 小时前
用猜数字游戏,一口气掌握 JavaScript 核心知识点(附完整代码)
前端·javascript
忆往wu前2 小时前
从0到1一步步拆解搭建,梳理一个 Vue3 简易图书后台全开发流程
前端·javascript·vue.js
shao9185162 小时前
第3章(2)——使用Gradio JavaScript Client
javascript·node.js·cdn·gradio·job·events·playcode
光影少年2 小时前
大屏页面,一次多个请求,请求加密导致 点击 全局时间选择器 时出现卡顿咋解决(面板收起会延迟1~2秒)
前端·javascript·vue.js·学习·前端框架·echarts·reactjs
Mr.mjw2 小时前
vue中封装一个环形进度条组件,根据外部盒子大小自适应变化
前端·javascript·vue.js
无心使然2 小时前
Openlayers调用ArcGis影像服务之一动态地图、地图切片(/exportImage)
前端·javascript·数据可视化
像我这样帅的人丶你还3 小时前
前端监控体系与实践(二):全局监控
前端·javascript·vue.js
(Charon)3 小时前
【C++/Qt】Qt 封装 TCP 客户端底层 Network 类:连接、收发、自动测试与错误处理
服务器·网络·qt·tcp/ip