Go 与 QML 双向集成实战解析 therecipe/qt 的 cpp-qml-integration 示例【免费下载链接】qtQt binding for Go (Golang) with support for Windows / macOS / Linux / FreeBSD / Android / iOS / Sailfish OS / Raspberry Pi / AsteroidOS / Ubuntu Touch / JavaScript / WebAssembly项目地址: https://gitcode.com/gh_mirrors/qt/qtQML 以其声明式语法让 UI 开发变得简单高效而 Go经由 C 层则能提供更强的计算能力、更低的出错率与更灵活的底层控制。本指南基于当前仓库中的 cpp-qml-integration 示例深入讲解如何在 Go Qt 绑定therecipe/qt的 Felgo 应用中同时发挥 QML 与 C/Go 的优势掌握全局上下文属性与自定义 QML 类型两条核心集成路径并理解其背后的元对象代码生成原理。示例背景为什么要集成 QML 与 C/Go原文档README.md开宗明义Application Development with QML is simple and powerful. But Qt C offers many features, is faster and less error-prone.QML 应用开发简单且强大但 Qt C 功能更多、速度更快且更不易出错。示例的目的就是演示如何创建同时利用两种语言优势的应用。在 this 仓库中该 Felgo 示例被改写成了 Go 实现原文档面向 Felgo SDK 的 Qt C 工程这里则完全使用 Go 源码驱动同一套 QML 界面目录结构如下internal/examples/felgo/appdemos/cpp-qml-integration/ ├── main.go # 应用入口启动 Felgo/QML 引擎、注册对象 ├── myglobalobject.go # 集成方式一全局上下文对象 ├── myqmltype.go # 集成方式二自定义 QML 类型 ├── qml/ │ ├── Main.qml # 使用上述两类对象的 QML 界面 │ └── config.json # Felgo 应用配置标题/包名/方向等 ├── android/ ios/ darwin/ windows/ # 各平台打包资源 └── README.md # 原版说明文档该示例演示了两条核心集成路线全局上下文属性Global Context Property将一个 Go/C 对象挂到 QML 引擎的根上下文上QML 中任意位置都能直接以命名方式访问其属性和方法自定义 QML 类型Custom QML Type通过qmlRegisterType把 Go/C 类注册为可导入、可实例化的 QML 组件类型。运行环境与构建方式原 README 的安装步骤针对 Felgo SDK注册、下载、安装 Felgo SDK用 QtCreator 打开.pro工程并运行。由于本仓库是 Go 绑定版本实际运行方式等价地落到 Qt 绑定工具的部署流程上先通过qtsetup配置好对应平台的 Qt 环境再使用仓库中的部署工具 qtdeploy 生成并运行应用例如qtdeploy build desktop ./deploy/linux/cpp-qml-integration或在开发期直接使用go runmain.go 中对主 QML 文件路径的处理正是为了兼容这种运行方式详见下文启动流程一节。无论哪种方式都需要本机已安装 Qt建议 Qt 5.9与 go.mod 中模块github.com/therecipe/qt匹配以及可用的 Go 工具链。示例的 Felgo 应用配置位于 qml/config.json其中定义了应用的显示标题、包标识符、屏幕方向与版本信息{ title: FelgoCppQML, identifier: com.yourcompany.wizardEVP.FelgoCppQML, orientation: landscape, versioncode: 1, versionname: 1.0, stage: test }启动流程main.go 的关键链路应用入口 main.go 完整展示了Go 启动 Felgo 应用的六个关键步骤每一步都对应 Felgo/Qt 绑定的核心 API1. 创建 QApplicationwidgets.NewQApplication(len(os.Args), os.Args)所有 Qt 图形程序都需要先创建QApplication它是事件循环与全局状态的基础。2. 创建并初始化 FelgoApplicationfelgoApp : felgo.NewFelgoApplication(nil) felgoApp.SetPreservePlatformFonts(true) engine : qml.NewQQmlApplicationEngine(nil) felgoApp.Initialize(engine)FelgoApplication是 Felgo 框架在 Go 侧的封装见 felgo/felgo.go其Initialize方法将QQmlEngine指针透传给底层 C 实现完成 Felgo 运行时初始化felgo.go。SetPreservePlatformFonts(true)用于保留平台默认字体而非使用 Felgo 自带字体。3. 挂载全局上下文对象myGlobal : NewMyGlobalObject(nil) myGlobal.doSomething(TEXT FROM C) engine.RootContext().SetContextProperty(myGlobalObject, myGlobal)这是集成方式一的核心调用——对象以myGlobalObject的名字进入 QML 根上下文详见下文专节。4. 根据运行方式解析主 QML 文件路径mainQmlFile : Main.qml if strings.Contains(os.Args[0], /deploy/) { felgoApp.SetMainQmlFileName(strings.Split(os.Args[0], /deploy/)[0] /qml/ mainQmlFile) } else if core.QSysInfo_ProductType() ios || core.QSysInfo_ProductType() android { felgoApp.SetMainQmlFileName(qml/ mainQmlFile) } else { pwd, _ : os.Getwd() felgoApp.SetMainQmlFileName(pwd /qml/ mainQmlFile) }这段代码按三种场景分别设置主 QML 文件qtdeploy -fast部署包、iOS/Android 移动端、本地go run/build开发态。代码注释中保留了另一条发布路径// felgoApp.SetMainQmlFileName(qrc:/qml/ mainQmlFile)即把 QML/JS 文件通过 Qt 资源系统.qrc编译进二进制这是面向应用商店发布时的首选方式可以保护 QML 源码不被直接读取。5. 加载并执行 QMLengine.Load(core.NewQUrl3(felgoApp.MainQmlFileName(), 0))QQmlApplicationEngine.Load是 Qt 5.2 之后推荐的 QML 启动方式对应绑定实现见 qml/qml.go。6. 进入事件循环widgets.QApplication_Exec()另外main.go 中还注释掉了 Felgo Live 开发模式// felgo.NewFelgoLiveClient(engine, nil)启用后应用可作为 Live Client 连接 Felgo Live Server实现 QML 代码热更新调试Felgo 侧实现见 felgo/felgo.go。集成方式一全局上下文属性Context PropertyGo 侧定义myglobalobject.go 定义了一个继承core.QObject的类型并通过结构体标签声明它暴露给 QML 的能力type MyGlobalObject struct { core.QObject _ func() constructor:init _ int property:counter // 暴露为 QML 属性 _ func(text string) slot:doSomething,auto // 暴露为 QML 可调用的槽 } func (o *MyGlobalObject) init() { o.SetCounter(0) } func (o *MyGlobalObject) doSomething(text string) { println(MyGlobalObject doSomething called with, text) o.SetCounter(o.Counter() 1) }三个标签的含义如下标签作用constructor:init构造对象后自动调用init()方法完成初始化此处把counter置 0property:counter将counter声明为 QML 属性绑定生成时自动补齐Counter()读取与SetCounter()写入方法slot:doSomething,auto将doSomething(text string)声明为 QML 可调用的槽auto表示自动接入元对象系统这些标签由仓库的qtmoc工具cmd/qtmoc/main.go在编译期解析并据此生成对应的 C 桥接代码与元对象meta-object信息使 Go 类型真正成为 Qt 元对象系统中的一等公民。QML 侧使用在 Main.qml 中myGlobalObject直接可用// 1.1: 调用 doSomething() 槽QML 向 Go/C 传递字符串 AppButton { text: myGlobalObject.doSomething() onClicked: myGlobalObject.doSomething(TEXT FROM QML) } // 1.2: 直接改写 counter 属性自动触发 counterChanged 信号 AppButton { text: myGlobalObject.counter 1 onClicked: { myGlobalObject.counter myGlobalObject.counter 1 } } // 1.3: 属性绑定counter 变化时文本自动刷新 AppText { text: Global Context Property Counter: myGlobalObject.counter }三个交互点分别验证了三种能力QML → Go/C 方向调用onClicked中调用doSomething(TEXT FROM QML)触发 Go 侧实现并打印日志Go/C 属性可写myGlobalObject.counter ...会走属性的 setter并自动发出counterChanged信号声明式绑定AppText的text绑定到counter属性一变界面立即刷新——这正是 QML 属性系统的核心价值。此外Main.qml 底部还演示了用Connections元素监听上下文对象的信号Main.qmlConnections { target: myGlobalObject onCounterChanged: console.log(Counter changed to myGlobalObject.counter) }这证明上下文对象不仅能被主动调用也能被动通知 QML 侧。集成方式二注册自定义 QML 类型qmlRegisterTypeGo 侧定义myqmltype.go 演示了更正规的自定义 QML 类型路线func init() { MyQMLType_QmlRegisterType2(com.yourcompany.xyz, 1, 0, MyQMLType) } type MyQMLType struct { core.QObject _ string property:message _ func(value int) int slot:increment,auto _ func() slot:startCppTask,auto _ func() signal:cppTaskFinished } func (o *MyQMLType) init() { o.SetMessage() } func (o *MyQMLType) increment(value int) int { return value 1 } func (o *MyQMLType) startCppTask() { // 可在独立线程执行 CPU 密集任务如 AI、机器学习完成后发信号 o.doCppTask() } func (o *MyQMLType) doCppTask() { o.CppTaskFinished() }与方式一的差异点在于通过init()中的MyQMLType_QmlRegisterType2(com.yourcompany.xyz, 1, 0, MyQMLType)把类型注册到命名空间com.yourcompany.xyz、主版本 1、次版本 0QML 类型名为MyQMLType对应 Qt C 中的qmlRegisterType新增了signal:cppTaskFinished标签声明一个可从 Go 侧发射、供 QML 侧响应的信号startCppTask注释点明了典型用途把 CPU 密集计算AI、机器学习等放进 C/Go 侧执行完成后再通过信号把结果通知给 QML——这正是QML 管界面、C/Go 管计算的分工范例。QML 侧使用Main.qml 首先导入注册好的模块Main.qml// 自定义 import 以使用基于 C 的 QML 类型 MyQMLType import com.yourcompany.xyz 1.0然后像使用普通 QML 组件一样实例化并与之交互Main.qmlMyQMLType { id: typeFromCpp // 2.1: 属性绑定message 随 counter 自动重算 message: counter / 2 Math.floor(myGlobalObject.counter / 2) // 2.2: 响应属性变化信号 onMessageChanged: console.log(typeFromCpp message changed to typeFromCpp.message) // 2.3: 组件创建完成时调用 Go 侧槽 Component.onCompleted: myGlobalObject.counter typeFromCpp.increment(myGlobalObject.counter) // 2.4: 处理 Go 侧发射的自定义信号 onCppTaskFinished: { myGlobalObject.counter 0 } } AppText { text: Custom QML Type Message:\n typeFromCpp.message } AppButton { text: typeFromCpp.startCppTask() onClicked: { typeFromCpp.startCppTask() } }这里把两种集成方式串成了一个完整的联动闭环MyQMLType.message通过属性绑定与myGlobalObject.counter联动任何一方的变化都会触发onMessageChanged组件创建时Component.onCompleted调用 Go 侧increment槽返回值写回上下文对象的counter点击按钮触发startCppTask()Go 侧完成模拟的计算后发射cppTaskFinished信号QML 侧onCppTaskFinished处理器随即把计数器清零界面再次刷新。Main.qml 的注释还补充了一个进阶提示如果需要自定义类型具备可视化表现并容纳子元素应从QQuickItem而非QObject派生——这与 Qt 官方的 C 扩展 QML 规则完全一致。底层原理结构体标签如何变成 Qt 元对象上文反复出现的property/slot/signal/constructor标签是 therecipe/qt 绑定特有的声明式写法。它们并不会被 Go 运行时直接理解而是在构建阶段由qtmoccmd/qtmoc/main.go扫描解析后生成对应的 C 实现与 Qt 元对象meta-object代码。仓库内绑定代码生成器的解析逻辑可以印证这一点internal/binding/parser/function.go 定义了Function模型其中的Meta字段取值区分普通方法、构造器、信号等元类型例如Meta: SIGNALinternal/binding/parser/variable.go 中的propToFunc方法演示了属性 → 访问函数的生成规则为counter这类属性自动派生读取函数、setCounter写入函数当类属于 moc 模块时还会追加counterChanged信号函数见 variable.go这正是 QML 侧属性绑定与onCounterChanged能工作的前提internal/binding/parser/variable.go 的Variable结构还记录了Getter/Setter等访问器信息供生成器精确输出对应的 Go 绑定方法。也就是说从_ int \property:counter这样一行 Go 标签到 QML 中可读可写、可绑定的counter 属性中间经过了标签解析 → C 桥接代码生成 → moc 元对象编译 → Go 绑定封装的完整链路。理解这条链路是排查为什么 QML 里看不到我的属性/信号类问题的关键。发布、许可证与其他注意事项QML 资源保护发布到应用商店时建议将 QML/JS 编译进.qrc资源qrc:/qml/Main.qml避免明文暴露源码见 main.go 的注释跨平台部署示例自带了 android/、ios/、darwin/、windows/ 等平台的清单与应用图标资源配合 qtdeploy 可一键产出对应平台的安装包许可证示例的 LICENSE.txtREADME 中亦有说明采用 MIT 许可开源源码但不授予合并、发布、分发、转售其中附带图片、音频、视频资源的权利商用前需注意资源授权边界开发辅助原 README 中提到的 Felgo 官方文档、论坛与技术支持渠道与本示例对应的 Felgo 框架能力均可从 felgo/felgo.go 的公开 API 中进一步探索例如FelgoApplication的 import 路径管理、内容缩放SetContentScaleAndFileSelectors、许可证设置SetLicenseKey等。小结通过 cpp-qml-integration 示例可以完整掌握 therecipe/qt 中 Go/C 与 QML 双向协作的两套标准模式模式适用场景关键 API全局上下文属性全局单例、应用级服务配置、账户、日志等RootContext().SetContextProperty(...)自定义 QML 类型可复用的业务组件、需要可视化/容器能力的类型QmlRegisterType2(uri, 1, 0, TypeName)无论哪种模式本质都是在 Go 中声明元对象能力属性/槽/信号→ 编译期生成 C 桥接 → QML 引擎运行时完成双向绑定与调用。界面交给 QML 的声明式绑定与动画计算与业务逻辑交给 Go/C 的性能与严谨性——这正是该示例想要传达的工程分工哲学。【免费下载链接】qtQt binding for Go (Golang) with support for Windows / macOS / Linux / FreeBSD / Android / iOS / Sailfish OS / Raspberry Pi / AsteroidOS / Ubuntu Touch / JavaScript / WebAssembly项目地址: https://gitcode.com/gh_mirrors/qt/qt创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
mRemoteNG 外部工具变量参考:连接属性动态注入与转义规则完全指南 桌面应用网络 【免费下载链接】mRemoteNG mRemoteNG is the next generation of mRemote, open source, tabbed, multi-protocol, remote connections manager. 项目地址: https://gitcode.com/gh_mirrors/mr/mRemoteNG 点击查看 免费下载 mRemoteNG 的 变量&#… · 2026/9/23 11:08:11
NiFi 1.21.0 实现 MySQL 单表增量同步最佳实践 简介:本资源是一套基于Apache NiFi 1.21.0实现的MySQL到MySQL单表增量同步实战模板,面向大数据开发工程师、ETL工程师及NiFi初学者,解决CDC场景下日期字段解析、空值兼容性处理与SQL动态拼接等典型痛点。压缩包为8KB的ZIP文件,内含… · 2026/9/23 11:08:05
YOLOv8轮胎缺陷检测实战:源码解析、PyQt5 GUI与ONNX部署 简介:本资源是一套基于YOLOv8的轮胎缺陷检测系统完整工程包,面向从事工业质检、智能制造方向的开发者与深度学习学习者,可用于轮胎图像中debris、side_cut、ground、side等缺陷的自动识别与分类。包内共149个文件,以jpg与png图像样… · 2026/9/23 11:08:05
与的繁体图解原理:3个坑让你面试挂科 与的繁体图解原理:3个坑让你面试挂科 上周有个学员找我吐槽,说面试时被问“与的繁体在数据库里怎么存才不炸”,他愣了半天,只憋出一句“用UTF-8呗”。面试官没说话,直接让他回去等通知。 这就是典型的 面试被问原理答不上来 。… · 2026/9/23 11:49:11
10句经典英文励志名言:低谷时多撑一口气的认知行为疗法 1. 为什么这10句话能让人在低谷里多撑一口气1.1 从“打鸡血”到“真管用”的认知转变很多人第一次接触英文励志名言,是在学生时代的教室墙上,或者朋友圈的配图里。那时候觉得这些话就是“打鸡血”,读起来热血沸腾,合上手机该躺平还… · 2026/9/23 11:49:05
3个技巧搞定i排版微信编辑器性能优化 3个技巧搞定i排版微信编辑器性能优化 配置环境就卡半天,是不是让你抓狂?刚拿到i排版微信编辑器源码,本地跑不起来,或者一排版长文章就卡顿,这种痛我太懂了。很多应届生做技术博客或公众号运营时,第一反应就是装个编辑器工具,结果发现默认的样式在移… · 2026/9/23 11:49:05
我整理了四个用 GPT-5.6 降论文AIGC率巨有效的方法 各位同仁好,我是七哥。一个在高校里从事人工智能 相关领域研究,钻研用大模型AI实操的学术人。可以和七哥交流学术写作或Gemini、GPT、Claude 等大模型 学术实操相关问题,多多交流,相互成就,共同进步。
越来越多高校、期刊和学术平台开始在论文审核中加入AIGC检测,用来… · 2026/9/23 11:48:58
Python函数进阶:嵌套、闭包、装饰器、生成器与迭代器核心解析 函数写多了,早晚会撞上这几个概念。你把一个函数塞进另一个函数里,Python 不会报错;你写了个函数自己调自己,跑着跑着就栈溢出了;你看到别人代码里something挂在函数头上,一脸懵;你听说生成器省… · 2026/9/23 11:48:58
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29