前言
通过以上1-5文档的介绍,Quick与QML的概念及QML语法、类型、文件作用等已叙述个大概,接下来是对QML语法进行展开来说。
其实,学习任何一门语言或者做任何一件事情,并不用一开始就要求尽善尽美,做个无懈可击;如果可以做到是最好,最不到也不用气馁。子曰:温故而知新,可以为师矣。
保持好心态,每天都有所收获,不亦乐乎?
关于1-5文档内容链接如下:
- 概述及Quick应用程序创建流程
链接: https://blog.csdn.net/MrHHHHHH/article/details/135069075 - 创建Qt Quick UI工程
链接: https://blog.csdn.net/MrHHHHHH/article/details/135073614 - QML类型
链接: https://blog.csdn.net/MrHHHHHH/article/details/135105211 - QML语法格式及命名规范
链接: https://blog.csdn.net/MrHHHHHH/article/details/135127788 - QML基本类型及示例用法
链接: https://blog.csdn.net/MrHHHHHH/article/details/135142260
语法基础:示例说明
cpp
import QtQuick
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Rectangle{
width: 200
height: 200
border.color: "blue"
property color nextColor : "red"
onNextColorChanged:
console.log("nextColor:" + nextColor.toString())
property list<Rectangle> childRects: [
Rectangle{color:"red"},
Rectangle{color:"blue"}
]
MouseArea{
anchors.fill: parent
onClicked: {
for(var i = 0; i < 2; ++i){
console.log("color", i, parent.childRects[i].color)
}
}
}
}
}
- import
import作用是导入对应的QtQuick模块,它包含了各种QML类型及相关的可使用的模块;
如果不使用import语句,则import下面的Window类就无法使用 - 对象和属性
之前的QtWidgets有一个对象树,QML文档呢也是一个对象树;
上述代码,创建了两个对象:根对象Window和子对象Rectangle;
对象声明如下:
cpp
对象类型
{
}
大括号内包含了对象的id、属性值、子对象等。
每个根对象声明一般会指定一个id,可以通过这个id在其他对象中识别并引用该对象,id值在一个组件的作用域内必须
是唯一的。
虽然id
看起来和属性一样,但它并不是一个属性。更像是这个类型的引用。
接下来往下分析:
cpp
Rectangle{
width: 200
height: 200
x: 50
y: 100
}
Rectangle是一个对象的类型,如果使用了该类型,则代码中的Rectangle为对象或者实例。
对象一般都有属性值,如Rectangle,有宽、高、位置属性等。
属性是通过"属性:值"方式进行初始化,属性和值之间用:
隔开,每个属性后可以加;
,也可以不加。如果写成一句的话,就必须添加;
如
cpp
width: 200
height: 200
x: 50
y: 100
或者
cpp
width: 200;height: 200;x: 50;y: 100
- 注释
大部分语言的注释其实都是类似的。
单行注释:
cpp
// 该行是注释
多行注释:
cpp
/*
多行注释
*/
- 赋值和绑定
cpp
Rectangle{
width: 200
height: 200
x: 50
y: 100
}
以上给出的int值呢,就是初始化赋值的。
当值内包含其他对象或属性的引用时,就进行了一个绑定。这样,当值改变时,属性会自动更新了新的值。
如:
cpp
Item{
width:200
Rectangle{
width: parent.width - 50
height: 200
x: 50
y: 100
}
}
Rectangle的width属性和Item的width属性绑定,当Item的width属性改变时,Rectangle的width属性会自动更新。
- 布局
界面美观全靠样式和布局,anchors.centerIn: parent
使Rectangle处于parent的中央位置。
除了anchors
,QML还有其他多种布局。如Row、Column等
cpp
Rectangle{
width: 200
height: 200
anchors.centerIn: parent
}
- 输出
在QtWidgets进行编程时,使用QDebug
类进行调试输出;在QML中,使用console.log
、console.debug
进行输出。
cpp
MouseArea{
anchors.fill: parent
onClicked: {
for(var i = 0; i < 2; ++i){
console.log("color", i, parent.childRects[i].color)
}
}
}
在某个鼠标区域,点击,打印color
import导入语句
import语句允许客户端告诉引擎在QML文档中使用哪些模块、JavaScript资源和组件目录。可以在文档中使用的类型取决于文档导入了哪些模块、资源和目录。
默认情况,QML文档可以访问到同目录下的对象类型,不用import导入。
不导入会报错的。
import导入语句有三种不同类型的导入。每种导入类型的语法略有不同,不同的导入类型适用不同的语义。
- 模块(命名空间)导入
最常见的导入类型是模块导入。客户端可以导入QML模块,这些模块将QML对象类型和JavaScript资源注册到给定的名称空间中。
模块导入的一般形式如下:
cpp
import <ModuleIdentifier> [<Version.Number>] [as <Qualifier>]
<ModuleIdentifier>
是一个以点分隔URI表示法指定的标识符,它唯一地标识模块提供的类型命名空间。- <Version.Number>是MajorVersion的一个版本。MinorVersion,它指定了各种对象类型和JavaScript资源的哪些定义将由于导入而可用。它可以省略,在这种情况下,将导入模块的最新版本。也可以只省略次要版本。然后导入给定主版本的最新次要版本。
<Qualifier>
是一个可选的本地命名空间标识符,如果给定,模块提供的对象类型和JavaScript资源将被安装到该标识符中。如果省略,模块提供的对象类型和JavaScript资源将被安装到全局命名空间中。
模块导入的示例如下:
cpp
import QtQuick
此导入允许使用QtQuick模块提供的所有类型,而无需指定限定符。例如,创建矩形的客户端代码如下:
cpp
import QtQuick
Rectangle {
width: 200
height: 100
color: "red"
}
带有version的不限定导入的示例如下:
cpp
import QtQuick 2.10
在这种情况下,QtQuick 2.11及更高版本或更高主要版本(如6.0)中定义的任何类型都不能用于该文件。
一个限定模块导入的例子如下,这个很有用
,如果自定义类型和QML类型中都含有某一类型,为了区别,就需要使用带有限定符的导入语句:
cpp
import QtQuick as Quick
Quick.Rectangle {
width: 200
height: 100
color: "red"
}
cpp
import QtQuick as CoreItems
import "../textwidgets" as MyModule
CoreItems.Rectangle {
width: 100; height: 100
MyModule.Text { text: "自定义Item!" }
CoreItems.Text { text: "Qt Quick!" }
}
请注意,如果QML文档没有导入提供特定QML对象类型的模块,而是试图使用该对象类型,则会发生错误。例如,下面的QML文档没有导入QtQuick,因此尝试使用矩形类型将失败:
cpp
Rectangle {
width: 200
height: 100
color: "red"
}
在这种情况下,引擎将发出错误并拒绝加载文件。
从Qt6开始,已经移除了QML版本控制,导入模块不用指定版本号。
- 目录导入语句
包含QML文档的目录也可以直接导入到QML文档中。这为将QML类型划分为可重用的组提供了一种简单的方法:文件系统上的目录。
目录导入的一般形式如下:
cpp
import"<DirectoryPath>" [as <Qualifier>]
注意:导入路径是网络透明的:应用程序可以从远程路径导入文档,就像从本地路径导入文档一样简单。如果目录是远程的,它必须包含一个目录导入,其中列出qmldir文件,因为如果该qmldir文件不存在,QML引擎无法确定远程目录的内容。
<Qualifier>
的类似语义适用于目录导入和模块导入。
可以导入QML文件的本地目录,而无需任何额外的设置或配置。也可以导入QML文件的远程目录,但需要存在一个列出qmldir文件的目录。本地目录可以选择性地包含一个目录清单qmldir文件,以便定义应该提供给导入该目录的客户端的类型名称,并指定应该向导入者提供的JavaScript资源。
- 本地目录导入
本地文件系统上的任何QML文件都可以使用引用该目录的绝对或相对文件系统路径的import语句导入本地目录,从而使文件能够使用该目录中定义的对象类型。
如果本地目录包含列出qmldir文件的目录,则将使用qmldir文件中指定的类型名称提供类型;否则,它们将以从QML文档的文件名派生的类型名提供。只允许文件名以大写字母开头,以""结尾。如果目录中没有指定qmldir文件,".qml"将作为类型公开。
Ex:
有一个QML项目目录结构。在顶层目录myapp下,有一组常用的UI组件在名为mycomponents的子目录下,主应用程序代码在名为main的子目录下,如下所示:
main/application.qml
文件可以使用相对路径导入mycomponents目录,允许它使用该目录中定义的qml对象类型:
目录可以导入到限定的本地命名空间中,在这种情况下,目录中提供的任何类型的使用都必须是限定的:
导入本地目录的能力对于应用程序内组件集和应用程序原型等情况非常方便,尽管如果模块目录移动到另一个位置,任何导入此类模块的代码都必须更新其相关的导入语句。如果使用QML模块,则可以避免这种情况,因为导入的安装模块带有唯一标识符字符串,而不是文件系统路径。
- 远程目录导入
如果QML文件目录包含一个列出qmldir文件的目录,也可以从远程位置导入该目录。
例如,如果上一个例子中的myapp目录托管在"http://www.my-example-server.com",并且mycomponents目录包含一个定义如下的qmldir文件:
然后,可以使用URL将该目录导入到远程mycomponents目录:
注意,当一个文件通过网络导入一个目录时,它只能访问该目录中的qmldir文件中指定的QML和JavaScript文件。
警告:当从远程服务器导入目录时,开发人员应该始终小心,只从可信源加载目录,以避免加载恶意代码。
- 目录清单qmldir文件
一个目录列表 qmldir 文件与模块定义 qmldir 文件有明显的不同。目录列表 qmldir 文件允许快速轻松地共享一组 QML 文档,但它不定义用于注册文档中定义的 QML 对象类型的类型命名空间,也不支持对这些 QML 对象类型进行版本控制。
目录列表 qmldir 文件的语法如下:
命令 | 语法 | 描述 |
---|---|---|
对象类型声明 | <TypeName> <FileName> |
允许QML文档使用指定的类型名进行暴露,例子: RoundedButton RoundedBtn.qml |
内部对象类型声明 | internal <TypeName> <FileName> |
内部对象类型声明允许将QML文档注册为仅对目录导入中包含的其他QML文档可用的类型。例子: internal HighlightedButton HighlightedBtn.qml |
JavaScript资源声明 | <Identifier> <FileName> |
JavaScript资源声明允许通过给定的标识符公开JavaScript文件。例子: MathFunctions mathfuncs.js |
本地文件系统目录可以选择性地包含qmldir文件。这允许引擎只向导入目录的客户机公开某些QML类型。此外,除非在qmldir文件中声明,否则目录中的JavaScript资源不会暴露给客户端。
- JavaScript资源导入语句
JavaScript资源可以直接导入到QML文档中。每个JavaScript资源都必须有一个用来访问它的标识符。
JavaScript资源导入的一般形式如下:
cpp
import "<JavaScriptFile>" as <Identifier>
- 来自模块的JavaScript资源
Javascript文件可以由模块提供,方法是在指定模块的qmldir文件中添加标识符定义。
例如,如果用下面的qmldir文件指定projects.MyQMLProject.MyFunctions模块,并安装到QML导入路径中:
cpp
module projects.MyQMLProject.MyFunctions
SystemFunctions 1.0 SystemFunctions.js
UserFunctions 1.0 UserFunctions.js
如果模块被导入到文档本地命名空间中,JavaScript资源标识符必须以命名空间限定符为前缀才能使用:
cpp
import QtQuick
import projects.MyQMLProject.MyFunctions as MyFuncs
import org.example.Functions as TheirFuncs
Item {
Component.onCompleted: {
MyFuncs.SystemFunctions.cleanUp();
TheirFuncs.SystemFunctions.shutdown();
}
}
QML导入路径
当导入一个已标识的模块时,QML 引擎会在导入路径中搜索匹配的模块。
导入路径由 QQmlEngine::importPathList() 返回,定义了引擎搜索的默认位置。默认情况下,该列表包括:
- 当前文件所在的目录
- QLibraryInfo::QmlImportsPath 指定的位置
- 由 QML_IMPORT_PATH 环境变量指定的路径
- 资源中的 qrc:/qt-project.org/imports 路径。
可以通过 QQmlEngine::addImportPath() 或 QML_IMPORT_PATH 环境变量添加其他导入路径。在运行 qml 工具时,还可以使用 -I 选项添加导入路径。
可以通过使用路径分隔符将多个导入路径连接起来,在 QML_IMPORT_PATH 环境变量中指定多个导入路径。在 Windows 上,路径分隔符是分号 (😉,在其他平台上是冒号 (😃。这意味着在 QML_IMPORT_PATH 中不能指定资源路径或 URL,因为它们本身包含冒号。不过,可以通过编程方式调用 QQmlEngine::addImportPath() 添加资源路径和 URL。
结论
可能第一次看有些摸不着头脑,第二次看也是,但全部看完,再回头看,轻舟已过万重山
。