QML学习笔记(十四)QML的自定义模块

前言

在前面的学习中,我们已经学会了自定义组件的实现方式,并通过属性暴露来让外部进行调用和交互。但只是这种程度还不足以满足我们实际开发的需求,为了实现定制组件的更好管理,我们需要引入模块的概念。

(在我学习的视频中,主要讲述了QT6+cmake的方法,但无奈我当前是QT5,所以我接下来只记录我学习QT5+qmake的模块实现)

一、前期准备

在正式学习之前,我们先准备我们的一系列文件。

新建工程QmlCustomModules,然后先在main.qml的同目录下,创建一个custom_buttons文件夹。

然后我们将之前的MButton.qml移动进去,并拷贝三个单独的按钮组件,分别为RedButton.qml、GreenButton.qml和BlueButton.qml。注意文件命名最好大写开头,至于里面的颜色修改,你懂的,代码我就只放红色按钮的上来吧。

最后把MButton改成GreyButton。

cpp 复制代码
import QtQuick 2.0

Item{
    id: rootId
    property alias buttonText: buttonTextId.text
    property alias buttonColor: containerRectId.color
    width: containerRectId.width
    height: containerRectId.height

    signal buttonClicked

    Rectangle {
        id: containerRectId
    //        width: 100
    //        height: 30
        width: buttonTextId.implicitWidth + 10
        height: buttonTextId.implicitHeight + 10
        color: "red"
        border{
            color: "black"
            width: 3
        }

        Text {
            id: buttonTextId
            text: qsTr("Button")
            anchors.centerIn: parent
        }

        MouseArea {
            id: mouseAreaId
            anchors.fill: parent
            onClicked: {
//                console.log("Clicked on the button")
                rootId.buttonClicked()
            }
        }
    }
}

一、QML Dir

在QT5阶段想要实现模块,需要依赖QML Dir文件,它是一种文本描述,用于说明我们的QML模块由哪些内容组成。

我们创建一个文本文件,并改名为qmldir,这里注意把txt后缀名也删掉,但后续打开时通用以记事本形式打开即可。

往里面写入文本描述:

cpp 复制代码
module custom_buttons
BlueButton 1.0 BlueButton.qml
RedButton 1.0 RedButton.qml
GreenButton 1.0 GreenButton.qml
GreyButton 1.0 GreyButton.qml

第一行是模块名称,module custom_buttons,这个名称必须和文件夹名称相同。

后面几行就可以设置模块名、版本和对应的qml文件,让我们遵循命名一致的规则。

二、导入模块

我们先将这些文件全部添加到qml.qrc中(右键,添加现有文件)。

最后就变成这样:

然后我们打开工程的pro文件,注意到这里的两行:

直接翻译一下:

cpp 复制代码
# 在Qt Creator的代码模型中用于解析QML模块的额外导入路径
QML_IMPORT_PATH =

# 仅为Qt Quick Designer解析QML模块时使用的额外导入路径
QML设计器导入路径 =

显然,我们需要对QML_IMPORT_PATH 进行设置,添加$PWD,这个东西代表当前目录。

最后,我们还要添加一行这个:

cpp 复制代码
DISTFILES += custom_buttons/qmldir

这里就用到了刚才准备的qmldir。

再然后,我们尝试引用模块,发现会报错,模块未安装。

那是因为,我们需要对main.cpp中的引擎添加导入路径。

cpp 复制代码
engine.addImportPath("qrc:/");

三、运行程序

成功能看到四个按钮,证明导入成功。

四、解决红字报错

到这里其实就已经结束,能够正常使用了。

但我对这句报错很不爽,明明都能成功运行了,为什么好像工程识别不出来一样。

最终问题是在pro中的这一句:

cpp 复制代码
QML_IMPORT_PATH = $PWD

我们修改成:

cpp 复制代码
QML_IMPORT_PATH += $$PWD

这里的修改点是使用了+=追加的方式,不要覆盖原本的路径。然后使用了$$,不要使用$

我问了一下kimi同学,它给了我如下总结:

一句话记: "= 是覆盖,+= 是追加;$$ 是 qmake 内建,$ 是 shell 变量。"

写法 作用域 结果 对 Creator 高亮
QML_IMPORT_PATH = $PWD 只在qmake运行期被 shell 展开 清空原路径,再塞一条展开后的绝对路径 静态分析认不得 $PWD仍标红
QML_IMPORT_PATH += $$PWD qmake + Creator 都识别 原路径保留,再追加一条 $$PWD 解析器能找到 $$PWD/Custombuttons/qmldir高亮正常

结论:
永远用 += $$PWD,既追加又跨平台,让运行期和高亮期同时满意。

简单来说就是Creator 的语法高亮引擎不认识$PWD,所以会标红。

五、总结

在学习本节之前,我其实就有疑问了 ,如果我们自定义组件越来越多,我是否能通过一个文件夹来进行存放。而且组件越来越多的话,我要怎么进行引用,总不能全部都import一遍吧。

而本节给了我答案,可以通过模块的方式去进行加载。可以看到我们一起import就可以使用到多个组件,其形式就跟c++的封装一样,十分方便和有趣。

相关推荐
The Sheep 20231 分钟前
Dotnet-Dapper的用法
java·开发语言
d111111111d7 分钟前
STM32TIM定时器外设学习,输出比较模式(舵机,驱动直流电机)
笔记·stm32·单片机·嵌入式硬件·学习
立志成为大牛的小牛8 分钟前
数据结构——四十、折半查找(王道408)
数据结构·学习·程序人生·考研·算法
马克学长29 分钟前
SSM基于Java的医疗器械销售系统oy281(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·开发语言·用户管理·ssm 框架·医疗器械销售系统
东方欲晓w36 分钟前
Git高效开发:常用命令速查指南
git·stm32·学习
nenchoumi311942 分钟前
ROS2 Humble 笔记(十)多机分布式通讯 DDS 与宿主机和Docker容器
笔记·机器人·ros2
lqj_本人1 小时前
Rust与Go:现代系统编程语言的深度对比
开发语言·golang·rust
清钟沁桐1 小时前
mlir 编译器学习笔记之六 -- 经典实现
笔记·学习·mlir
星释1 小时前
Rust 练习册 :Macros与宏系统
开发语言·后端·rust
l1t1 小时前
利用短整数类型和部分字符串优化DuckDB利用数组求解数独SQL
开发语言·数据库·sql·duckdb