QML学习笔记(七)QML的基本数据类型
前言
在本节中,我们将探索QML的基本数据类型。这些类型将为你的QML应用程序提供底层的支持。如果没有对此有基本的认识,我们是无法继续学习下去的。
此前,我们已经使用过整数来控制窗口的宽度和高度,也简单使用过字符串类型来控制窗口中的文本内容。然而除此之外,QML其实还提供了大量丰富的数据类型,允许我们在代码中使用。例如:颜色、矩形、点、尺寸、数组等等,这些数据类型都类似于QWidget中的实现,我们无需太过担心。
想要完全掌握所有的数据类型,一定是任重而道远的,但没关系,我们可以一点一点,一个一个地学会它。
在此之前,我们先通过帮助文档,看一下它是怎么说的?
帮助文档里列出了这么多基础类型,很多看着就觉得熟悉,只是还不知道具体怎么用。像什么bool布尔值,double小数,整数int,list列表,string字符串这些类型。
在这里,我先建立一个叫做QmlExploringDataTypes的空工程,然后开始学习吧。
一、设置属性
QML中,我们想要创建一个变量的话,需要理解为“为组件新增一个属性”,所以一般来说会解释为设置属性、新增属性。
既然是属性,就必须先给一个叫property的标志,然后再进行具体的类型tyepe和初始化值。
这里我们按照步骤,初始化一系列属性:
property string mString: "https://www.baidu.com"property int mInt: 45property bool isFemale: trueproperty double mDouble: 77.5property url mUrl: "https://www.bilibili.com"
大部分都没什么好说的,但初学的话建议还是手敲一下。这里初始化赋值的时候不用=,用的是:冒号,这一点和直接给组件设置属性是一样的,比如x:20这种。
二、应用属性
接下来,我们新增一个Rectangle,尝试应用这些值。
代码如下:
Rectangle{width: 200height: 200 + mIntanchors.centerIn: parentcolor: "blue"Text {id: mTextIdanchors.centerIn: parenttext: mStringfont.bold: isFemale ? true : false}}
运行结果:
代码中,我们首先在高度上应用了int型:
width: 200
height: 200 + mInt
从效果图中可以看到,高度是明显高于宽度的,也就说明这里的赋值能够成功应用上。
然后是文本:
text: mStirng
显然,这串网址也成功显示出来了。看来只要类型相同,就可以进行简单的运算和直接赋值了。
我们再看这一句:font.bold: isFemale ? true : false
首先,font是Text的一个属性,我们可以修改font的子属性来控制字体相关的表现效果,bold正是其中一种,代表是否加粗。
然而我们讨论的是isFemale这种,事实上直接赋值也未尝不可,但这里使用了三元运算符,代表它作为bool类型,是可以像在C++代码中一样进行简单运算的。
虽然图片上不太明显,但我可以告诉你字体确实是加粗了。
三、通用属性类型
可以看到var能帮我们初始化很多类型,其中也包括刚才的int、bool、string(并不推荐)。除此之外,我们可以利用var来设置颜色、矩形、向量、尺寸,甚至可以设置数组,设置由不同内容组成的对象,还可以设置函数。
接下来,我们将这一大段代码复制到我们自己的代码中。
对了,在正式开始应用之前,我们先在Window这个最顶层元素的最下方,插入一段代码:
Component.onCompleted: {console.log("app is running...")}
这个东西我们还没有深入了解,我们可以简单理解为当qml完成所有的初始化和加载后,会自动调用这个接口。此时因为所有东西已经初始化好了,所以可以直接调用和进行一些代码上的操作。或者,我们简单理解为这是构造函数的入口即可。
接下来,我们直接在这个地方写一些代码,这先把完整代码po一遍:
import QtQuick 2.14
import QtQuick.Window 2.14Window {visible: truewidth: 640height: 480title: qsTr("QML Data Types Demo")property string mString: "https://www.baidu.com"property int mInt: 45property bool isFemale: trueproperty double mDouble: 77.5property url mUrl: "https://www.bilibili.com"property var aNumber: 100property var aBool: falseproperty var aString: "Hello world!"property var anotherString: String("#FF008800")property var aColor: Qt.rgba(0.2, 0.3, 0.4, 0.5)property var aRect: Qt.rect(10, 10, 10, 10)property var aPoint: Qt.point(10, 10)property var aSize: Qt.size(10, 10)property var aVector3d: Qt.vector3d(100, 100, 100)property var anArray: [1, 2, 3, "four", "five", (function() { return "six"; })]property var anObject: { "foo": 10, "bar": 20 }property var aFunction: (function() { return "one"; })Rectangle{width: 200height: 200 + mIntanchors.centerIn: parentcolor: "blue"Text {id: mTextIdanchors.centerIn: parenttext: mStringfont.bold: isFemale ? true : false}}Component.onCompleted: {console.log("app is running...")print("The value of mString is: " + mString)console.log("The lue of mInt is: " + mInt)if (isFemale){console.log("You may wear a dress")} else {console.log("You may wear a suit")}console.log("The value of mDouble is: " + mDouble)console.log("The value of mUrl is: " + mUrl)if (mString === mUrl) {console.log("They are the same")}else {console.log("They are not the same")}}
}
运行,查看打印信息:
符合预期。Component.onCompleted: {}里的代码有些过于简单了,我就不多解释了。值得一提的是,这里虽然能用if/else,但不同类型之间的对比居然没有报不合法,如string和url。为了避免它自动进行类型转换,这里推荐用===,而不用==。
我们继续添加代码,应用一下var的东西:
console.log("---------------Playing with var datatype------------")
console.log("The value of aNumber is: " + aNumber)
console.log("The value of aBool is: " + aBool)
console.log("The value of aString is: " + aString)
console.log("The value of anotherString is: " + anotherString)
console.log("The value of aRect are x:" + aRect.x + ", y:" + aRect.y + ", width:" + aRect.width + ", height:" + aRect.height)
console.log("The value of the array is: " + anArray.length)
打印信息:
我们还可以遍历数组,查看数组中的内容:
anArray.forEach(function(value, index){if( index === 5){console.log(value())} else {console.log(value)}})
因为数组定义的时候,第六个参数是一个函数,如果我把括号去掉,会看到:
你可能会问,用for循环来遍历是否可以,答案是ok的!并且写法和C++完全一样。
四、复杂属性设置
我们添加两个新属性:
property var aFont: Qt.font( { family: "Consolas", pointSize: 30, bold: false } )
property date mDate: "2025-09-21"
我们先说第一个属性:字体。它有点类似于QFont,在使用了var通用类型的转换时,它直接适配了Qt.font。显然,Qt.font是字体类型,但具体的定义时什么呢?我们可以查看帮助文档。
可以看到,字体的属性有相当多,在这里就不多赘述了。我们主要关注初始化时直接初始化其属性的方式。像Qt.rgba和Qt.rect这种类型,我们直接用类似构造函数的方式去创建即可,但font的属性并不是参数,没有这种直接的方式进行操作。没关系,我们可以用{}括起来,然后在里面设置其属性。
property var aFont: Qt.font( { family: “Consolas”, pointSize: 30, bold: false } )
对了,之前不是有一个Rectangle吗,里面也用到了字体,我们可以直接设置一下。
虽然文字大得夸张,但确实应用上去了,不是吗?
最后,我们说一下日期这个类型,这也是非常常用的。
property date mDate: “2025-09-21”
可以看到他的赋值就跟设置字符串似的,但如果打印它,你觉得会是这条字符串吗?
事实上,打印出来的并不是那一串字符串,而是一串包含了时分秒,甚至还有星期和时区的信息。
这是因为,当我们把一个 字符串 “2025-09-21” 赋给了 date 类型的属性,QML 引擎会自动调用 new Date(“2025-09-21”) 帮你转成了 Date 对象;而 Date 对象在 console.log 里会被隐式地调用 toString(),于是你看到的就是带星期、月份、时分秒和时区的那一长串。
至于这里的隐式转换,字符串只要符合 ECMA-262 定义的 ISO 格式(YYYY-MM-DD 或完整 ISO),QML 引擎就会自动 new Date(“2025-09-21”)。
由于没给时分秒,会自动按 本地时区 00:00:00 解析,于是得到
Sun Sep 21 00:00:00 2025 GMT+0800 (中国标准时间)。
而打印时console.log 收到的是对象,不是字符串,于是自动调用 Date.prototype.toString(),也就出现了我们看到的那一串东西。
那如何按照我们想要的格式来打印呢?如果你在QWidget中也做过类似的工作,应该就有头绪了。
那就是,利用 Qt 的 Qt.formatDate / Qt.formatDateTime:
console.log("The date is: " + Qt.formatDate(mDate, “yyyy-MM-dd”))
虽然写法和QDatetime不一样,但也是类似的。
五、总结
在这一节中,我们学习到了一些基本数据类型的设置和引用,包括常见类型和通用类型,并且在相关组件的设置和代码段中成功应用。
有关qm的数据类型有很多,我们不可能全部掌握,但最起码能知道c++常用类型和QWidget常用封装类在qml中的对应实现。之后就算是碰到了新的类型,只要结合帮助文档和搜索引擎,相信也不会有太大问题的。