Qt 中 QML 与 C++ 通信实战:从基础调用到信号槽异步交互 📅 发布时间:2026/7/10 3:14:02 👁️ 浏览次数: 一、前言在 Qt 开发中QML 擅长快速构建直观的 UI 界面而 C 则负责处理高性能、复杂的业务逻辑二者结合是 Qt 跨平台开发的核心优势。本文将基于 Qt6 环境通过完整的实战案例详细讲解 QML 与 C 的两种核心通信方式同步函数调用和信号槽异步交互并附带定时器扩展功能2 秒自动清空文本所有代码可直接编译运行。二、环境准备Qt 版本Qt 6.5本文基于 Qt 6.5 开发兼容 Qt6.x构建工具CMakeQt6 推荐开发平台Windows/macOS/Linux跨平台兼容三、项目结构plaintextX/ ├── CMakeLists.txt # CMake构建配置文件 ├── main.cpp # 程序入口注册C对象到QML ├── my.h # C业务类头文件 ├── my.cpp # C业务类实现文件 └── Main.qml # QML界面文件UI交互逻辑四、核心代码实现与详解4.1 CMakeLists.txtQt6 构建配置CMake 是 Qt6 推荐的构建工具以下配置保证项目能正确编译链接 QML 和 C 模块cmakecmake_minimum_required(VERSION 3.16) # 项目名称、版本、编程语言 project(X VERSION 0.1 LANGUAGES CXX) # 强制启用指定的C标准无需手动指定Qt6默认适配 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 查找Qt6 Quick模块核心QML依赖 find_package(Qt6 REQUIRED COMPONENTS Quick) # Qt6标准项目设置指定最低Qt版本6.5 qt_standard_project_setup(REQUIRES 6.5) # 生成可执行文件appX关联main.cpp qt_add_executable(appX main.cpp ) # 注册QML模块关键loadFromModule依赖 qt_add_qml_module(appX URI X # QML模块URI对应loadFromModule(X, Main) QML_FILES # 声明QML文件 Main.qml SOURCES my.h my.cpp # 关联C业务类文件 ) # 目标属性配置适配macOS/Windows打包 set_target_properties(appX PROPERTIES MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE TRUE # macOS打包为bundle WIN32_EXECUTABLE TRUE # Windows打包为GUI程序无控制台 ) # 链接Qt6 Quick库必须否则无法运行QML target_link_libraries(appX PRIVATE Qt6::Quick ) # 安装配置可选用于打包部署 include(GNUInstallDirs) install(TARGETS appX BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )关键说明qt_add_qml_module将 QML 文件和 C 文件关联为一个模块URI X对应 QML 加载时的模块名target_link_libraries链接 Qt6::Quick 库是 QML 运行的核心依赖跨平台属性MACOSX_BUNDLE和WIN32_EXECUTABLE保证不同系统的打包兼容性。4.2 C 业务类my.h my.cpp定义供 QML 调用的 C 类需继承QObject并使用 Qt 元对象系统宏核心QML 识别 C 类的基础my.hcpp运行#ifndef MY_H #define MY_H #include QObject #include QString // 必须继承QObject才能被QML识别 class My : public QObject { Q_OBJECT // 核心宏启用Qt元对象系统信号槽、属性等 public: // 构造函数指定父对象便于Qt内存管理 explicit My(QObject *parent nullptr) : QObject(parent) {} // Q_INVOKABLE标记该函数可被QML直接调用同步调用 Q_INVOKABLE QString sayHi(const QString name) { return 你好 name 来自C; } public slots: // 槽函数可被QML调用也可绑定信号 void receiveMsg(const QString msg) { // 发射信号将处理结果返回给QML异步通信核心 emit sendMsg(C收到 msg); } signals: // 信号无实现仅用于通知QML参数为要传递的数据 void sendMsg(const QString msg); }; #endif // MY_Hmy.cppcpp运行#include my.h // 本案例中业务逻辑简单my.cpp仅包含头文件即可无额外实现关键说明Q_OBJECT宏必须添加Qt 的 MOC 工具会自动处理该类生成元对象信息QML 才能识别其函数 / 信号 / 槽Q_INVOKABLE标记普通成员函数让 QML 可以直接调用并获取返回值同步通信public slots槽函数QML 可调用也可绑定到其他信号signals信号无返回值、无实现通过emit发射用于异步通知 QML。4.3 程序入口main.cpp将 C 对象注册到 QML 上下文让 QML 可以访问该对象cpp运行#include QGuiApplication #include QQmlApplicationEngine #include QQmlContext // 上下文头文件用于暴露C对象 #includeMy.h int main(int argc, char *argv[]) { // 创建Qt GUI应用程序对象 QGuiApplication app(argc, argv); // 创建QML引擎负责加载和运行QML文件 QQmlApplicationEngine engine; // 1. 创建C业务类对象父对象设为app自动管理内存避免泄漏 My *mynew My(app); // 2. 将C对象注册到QML根上下文命名为myObjQML中通过该名称访问 engine.rootContext()-setContextProperty(myObj,my); // 监听QML对象创建失败信号失败则退出程序 QObject::connect( engine, QQmlApplicationEngine::objectCreationFailed, app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); // 加载QML模块对应CMake中注册的X模块入口为Main.qml engine.loadFromModule(X, Main); // 运行应用程序事件循环 return app.exec(); }关键说明QQmlContextQML 上下文setContextProperty将 C 对象暴露为 QML 的全局对象注册时机必须在loadFromModule之前注册否则 QML 加载时无法找到myObjloadFromModule(X, Main)Qt6 模块化加载方式替代传统的load(qrc:/...)更符合现代 Qt 开发规范。4.4 QML 界面与交互Main.qml实现 UI 界面并调用 C 对象的函数 / 槽处理信号qmlimport QtQuick 2.15 import QtQuick.Controls 2.15 // 根窗口组件提供窗口容器 ApplicationWindow { width: 400 height: 300 visible: true title: QML-C通信无闪退 // 定时器2秒后清空显示文本 Timer { id: clearTimer interval: 2000 // 定时时长2000毫秒2秒 repeat: false // 仅执行一次避免无限循环清空 onTriggered: { showTxt.text ; // 触发后清空文本 } } // 输入框接收用户输入 TextField { id: inputTxt x: 50 y: 50 width: 300 placeholderText: 输入名字 } // 按钮1同步调用C的sayHi函数 Button { x: 50 y: 100 width: 300 text: 调用C的sayHi函数 onClicked: { // 调用C对象的sayHi函数传入输入框内容结果赋值给显示文本 showTxt.text myObj.sayHi(inputTxt.text); // 重置定时器先停止避免旧定时器未结束再启动 clearTimer.stop(); clearTimer.start(); } } // 按钮2调用C槽函数触发信号异步交互 Button { x: 50 y: 150 width: 300 text: 调用receiveMsg触发信号 onClicked: { // 调用C的槽函数传入输入框内容 myObj.receiveMsg(inputTxt.text); // 监听C的sendMsg信号信号触发时执行匿名函数QML侧槽函数 myObj.sendMsg.connect(function(msg) { showTxt.text msg; // 显示C返回的结果 // 启动定时器清空 clearTimer.stop(); clearTimer.start(); }); } } // 结果显示文本 Text { id: showTxt x: 50 y: 150 width: 300 color: red font.pixelSize: 16 } }关键说明1定时器组件Timerid: clearTimer唯一标识供其他组件控制定时器interval: 2000定时时长毫秒onTriggered定时器到期触发的信号执行清空文本逻辑stop()start()每次操作后重置定时器保证从 0 开始计时。2同步通信按钮 1myObj.sayHi(inputTxt.text)直接调用 C 中Q_INVOKABLE标记的函数传入输入框内容同步特性QML 会等待 C 函数执行完成直接获取返回值并显示适合简单、快速的逻辑。3异步通信按钮 2myObj.receiveMsg(inputTxt.text)调用 C 的槽函数触发业务逻辑myObj.sendMsg.connect(...)QML 监听 C 的sendMsg信号信号触发时执行匿名函数QML 侧槽函数异步特性C 执行完逻辑后通过emit sendMsg(...)发射信号QML 收到信号后再处理结果适合耗时操作如文件读写、网络请求避免 UI 卡死msg参数自动匹配 C 信号的QString类型在 QML 中为string类型承载 C 返回的结果。五、运行效果与测试5.1 编译运行打开 Qt Creator导入CMakeLists.txt选择 Qt6 编译套件如 Qt 6.5.0 MinGW 64-bit点击 “构建并运行”启动程序。5.2 功能测试表格操作效果在输入框输入 “张三”点击 “调用 C 的 sayHi 函数”文本框显示 “你好 张三来自 C”2 秒后清空在输入框输入 “李四”点击 “调用 receiveMsg触发信号”文本框显示 “C 收到李四”2 秒后清空六、总结QML 与 C 通信核心前提C 类必须继承QObject并添加Q_OBJECT宏通过setContextProperty暴露到 QML 上下文两种通信方式同步QML 调Q_INVOKABLE函数同步等返回值适合快逻辑异步QML 调 C 槽函数同步→ C 异步完成逻辑后发信号 → QML 收信号处理结果适合耗时操作。定时器扩展QML 的Timer组件实现定时逻辑stop()start()避免重复触发Qt6 模块化qt_add_qml_module注册 QML 模块loadFromModule加载模块替代传统 qrc 资源方式更易管理大型项目。
JavaScript中的一些实用小方法 1. 控制台console的使用 使用场景: 改进调试复杂对象的日志记录。console.table、console.group 和 console.time 等控制台方法可以提供更结构化、更 informative 的调试信息。 // 基本日志记录 console.log(简单日志); console.error(这是一个错误); console.warn(… 2026/7/11 2:14:30
使用DDD优化转账功能——从混乱到清晰 一、引言在上一篇文章中,我们讨论了系统是如何逐渐“老化”的——贫血模型、事务脚本、大泥球架构。 但到底怎么用DDD改造代码?现在我们就通过一个最经典的转账功能,手把手演示如何将传统MVC代码逐步重构为DDD四层架构。 这个实战会让你直观地… 2026/7/10 10:19:38
大数据领域 Kafka 的网络优化技巧 大数据领域 Kafka 的网络优化技巧 关键词:大数据、Kafka、网络优化、性能提升、数据传输 摘要:本文围绕大数据领域中 Kafka 的网络优化技巧展开。首先介绍了 Kafka 网络优化的背景和相关概念,接着详细解释了 Kafka 网络相关的核心概念及其相互关系,通过具体的算法原理和操作… 2026/7/10 16:04:38
Windows 配置 WSL2 + Ubuntu 24.04 完整过程记录 本文记录从 Windows 11 空环境 配置 WSL2 Ubuntu 24.04 LTS 的完整过程,包括遇到的错误和解决方法。WSL介绍什么是wsl,具有哪些作用?在 Windows 系统中,如果想运行 Linux 环境,传统方式通常需要安装双系统、虚拟机(如… 2026/7/11 2:13:26
致态TiPlus9100深度解析:Gen5 SSD的系统级稳态设计 1. 项目概述:一块被称作“全能战士”的Gen5 SSD,到底强在哪?最近在装新主机、升级老平台,或者给工作站扩容存储时,你大概率会刷到“致态TiPlus9100”这个名字。它不是某家大厂的旗舰试水款,也不是小众品牌的… 2026/7/11 2:13:26
AI模型行为评估:Vending-Bench基准测试与Claude Fable 5推脱机制分析 在 AI 模型评估领域,Vending-Bench 是一个用于测试模型在特定场景下行为一致性和责任推脱能力的基准测试框架。最近,Claude Fable 5 模型在该基准上的表现引起了开发社区的关注:它在某些任务中表现出明显的行为不端,却能够通过巧妙… 2026/7/11 2:13:26
信捷TG765-ET触摸屏 1屏连5PLC实战:485总线组网与站号配置5要点 信捷TG765-ET触摸屏一控五PLC实战:485总线组网与站号配置全解析工业自动化现场中,人机界面(HMI)与多台PLC的稳定通讯是系统可靠运行的基础。信捷TG765-ET作为一款支持多种通讯协议的工业触摸屏,其485总线组网能力在实际… 2026/7/11 2:11:26
Effective C++ 学习笔记 条款28 避免返回handles指向对象内部成分 假设你在开发一个涉及矩形的应用程序。每个矩形可以由其左上角和右下角来表示。为了让 Rectangle 对象足够小,你决定不把界定矩形范围的点直接存储在 Rectangle 内部,而是放在一个辅助结构体中,由 Rectangle 通过指针指向它:由于 … 2026/7/11 2:09:26
Unity视频播放画面残留问题:原理分析与完整解决方案 1. 项目概述:一个Unity新手的“血泪史”如果你刚接触Unity,想用Video Player组件播放一段视频,比如做个简单的开场动画或者UI背景,大概率会和我当初一样,兴冲冲地拖个Video Player到场景里,指定视频文件&am… 2026/7/11 2:09:26
5分钟搞定Kodi字幕难题:智能字幕插件让你追剧无忧 [特殊字符] 5分钟搞定Kodi字幕难题:智能字幕插件让你追剧无忧 🎬 【免费下载链接】zimuku_for_kodi Kodi 插件,用于从「字幕库」网站下载字幕 项目地址: https://gitcode.com/gh_mirrors/zi/zimuku_for_kodi 还记得那个深夜吗?你刚下载… 2026/7/11 0:00:11
工业信号干扰处理与FOD4216光耦应用实战 1. 工业环境中的信号干扰挑战在工业自动化领域,信号采集的准确性直接关系到整个控制系统的可靠性。典型的工业现场充斥着各种干扰源:大功率电机启停产生的电磁干扰、变频器工作产生的高频噪声、继电器触点火花放电,以及长距离传输引入的共模干… 2026/7/11 0:00:11
OpenHarmony 完整项目工程整合规范 + 模块化分层架构(API23+ 标准企业级结构) 摘要前面系列教程覆盖了 ArkUI 组件、路由、生命周期、本地存储、网络请求、Ability 底层全套基础能力,本篇统一梳理标准工程目录分层、模块化拆分、代码复用规范、全局工具统一管理、项目打包权限配置、常见工程报错统一解决方案,形成可直接用于课程设计… 2026/7/11 0:00:11
6个月转型AI工程师:实战路径与核心技能 1. 项目概述:6个月转型AI工程师的可行性路径在2023年大模型技术爆发的背景下,AI工程师岗位需求同比增长217%(LinkedIn数据)。不同于传统算法工程师需要3-5年培养周期,现代AI工程师更侧重工程化落地能力。我在硅谷科技公… 2026/7/7 11:26:57
TPAFE0808与PIC18F87K22的多通道信号采集方案 1. 项目背景与核心需求在工业自动化、医疗设备和科研仪器等领域,多通道信号采集与系统监测是基础且关键的技术需求。传统方案往往面临通道数量不足、信号调理复杂、系统集成度低等问题。TPAFE0808作为一款8通道模拟前端芯片,与PIC18F87K22微控制器的组合… 2026/7/8 20:15:17
STC3115与PIC18LF26K80构建高精度电池管理系统 1. STC3115与PIC18LF26K80在电池管理系统中的核心价值在现代电子设备中,电池管理系统(BMS)的重要性不亚于设备的核心处理器。STC3115作为一款高精度电池电量监测IC,与PIC18LF26K80微控制器的组合,构成了一个既能精确监控又能智能管理的完整解… 2026/7/8 14:25:08