第53篇 Qt Quick项目详解
导语
前面我们一起创建了一个Qt Quick项目,并对里面的文件进行了简单的讲解,虽然这只是一个HelloWorld程序,但对于没有Qt Quick编程经验的同学来说,这个项目还是有点复杂。在这一篇中,我们将从最简单的QML文件讲起,然后逐渐丰富项目内容,帮助大家由浅及深的进行学习,进一步了解Qt Quick项目的构成。
环境:Windows 7 + Qt 5.5.0+ Qt Creator 3.4.2
目录
- 一、创建空项目
- 二、添加QML文件
- 三、运行程序
- 四、扩展QML程序
- 五、添加C++代码
- 六、使用资源文件
正文
一、创建空项目
1、首先打开Qt Creator,然后选择“新建文件或项目”菜单项,在选择模板页面选择“其他项目”分类中的“Empty qmake Project”,我们先来创建一个空项目,后面逐步往里面添加文件。点击“choose”按钮确定选择,如下图所示。
2、在项目位置页面,将项目名称修改为myqml
,然后选择好创建路径。如下图所示。
3、后面的步骤直接使用默认设置即可。
二、添加QML文件
1、创建好的空项目只有一个.pro
项目文件,现在里面的内容也是空的。我们先不去管它,下面向该项目中添加文件。在myqml
文件夹上右击,在弹出的菜单中选择“添加新文件”,如下图所示。
2、在弹出的新建文件对话框中选择Qt分类中的“QML File(Qt Quick 2)”一项。如下图所示。(说明一下:这里要添加QML文件,模板可以选择Qt Quick 1、Qt Quick 2和QtQuickUI File三种,Qt Quick 1会导入QtQuick 1.1模块,里面的内容都是Qt 4时代的;而QtQuick 2导入的是QtQuick 2.0模块,是Qt 5中的新版本;QtQuick UI文件生成后会默认使用设计器,因为我们这一节直接讲代码,不涉及设计器的内容,所以不选择这个模板。其实,使用哪个模板都一样,因为到文件里面可以直接修改导入模块语句,初学者在这里不要纠结。)
3、下面设置文件的名称为main
,路径保持默认即可,现在的路径就是项目源码路径。然后点击“下一步”按钮,如下图所示。
4、最后是项目管理页面,可以看到,新创建的文件默认添加到了myqml.pro
项目中,直接点击“完成”按钮完成文件的添加建,如下图所示。
三、运行程序
1、可以看到添加的文件就是main.qml
,后缀.qml
表明该文件是一个QML文件,其内容如下。
import QtQuick 2.0
Rectangle {
width: 100
height: 62
}
这是一个最简单的QML文件,它会显示一个宽100像素高62像素的矩形。这里的import
语句上一节已经提到过了,它会导入相应的模块,比如这里导入了QtQuick 2.0模块。下面的Rectangle
是矩形对象,用来定义一个矩形项目(项目类似于C++中的窗口或者部件),里面的width
和height
是Rectangle
的属性,用来设置矩形相关参数。
2、QML文件与C++文件是不同的,它不需要进行编译,可以直接运行。在Qt中提供了两个运行QML文件的工具qmlviewer和qmlscene,前者是Qt 4时代的产物,主要用来显示导入了QtQuick 1.1模块的QML文件,而qmlscene用来显示导入了QtQuick 2.0以后版本的QML文件。选择“工具→外部→QtQuick→Qt Quick 2Preview”菜单项即可在qmlscene中显示现在打开的QML文档的内容。如下图所示。
运行效果如下图所示。
四、扩展QML程序
1、添加文本显示
可以看到现在的程序就是一个空白的窗口,什么都没有。下面我们来扩展该程序,将main.qml
文件的内容更改如下:
import QtQuick 2.0
Rectangle {
width: 100
height: 62
Text {
text: "hello World"
}
}
这里添加了一个Text
对象,它用来显示一块文本,其text
属性用来指定要显示的文本内容。下面先按下Ctrl+S
快捷键保存该文件,然后在qmlscene中查看显示效果,如下图所示。
2、使用锚布局
我们看到现在可以显示hello world文本了,但是文本默认显示在了左上角,我们希望它可以在窗口中间显示,下面继续添加代码:
Text {
text: "hello World"
anchors.centerIn: parent
}
这里使用了anchor
锚的概念进行了布局,在QML中每一个项目都有一组无形的锚,分别在上、下、左、右、中心等处,它们可以定义项目自身和其他项目的相对位置。比如这里的centerIn
就是指Text
项目在parent
项目的中心,这里的parent
就是指Text
的父项目Rectangle
。在anchor
后面一般指定其他项目的id
,如果是父子项目,也可以像现在这样指定parent
。
下面先保存代码(以后每次修改都需要保存后才能显示,后面不再提醒),然后在qmlscene中运行,效果如下图所示。
3、添加鼠标互动。
前面的代码已经完成了一个简单的Hello World界面,下面我们添加代码实现点击界面退出程序的效果:
import QtQuick 2.0
Rectangle {
width: 100
height: 62
Text {
text: "hello World"
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit()
}
}
}
我们在Rectangle
中又添加了一个MouseArea
子对象,这个从字面上翻译就是鼠标区域,它是一个不可见的项目,就是说我们在窗口上并不能看到它的存在,通过该对象可以实现鼠标互动。anchors.fill
是进行填充,这里就是将鼠标区域覆盖整个Rectangle
窗口。onClicked
其实就是Qt C++中的信号处理函数,这里一般叫做信号处理器,其语法是on<Signal>
,所以这里就是Clicked
单击信号的处理,当在窗口上单击鼠标后会执行Qt.quit()
函数,这是个全局函数,执行结果就是使程序退出。
大家可以在qmlscene中运行程序,然后在窗口上点击鼠标查看运行效果。
4、使用组件
前面创建的是main.qml
文件,本意是让其作为主要文件,成为程序的入口。但是如果按照现在的做法,程序越写越复杂,main.qml
的内容会越来越多,越来越乱。为了避免在main.qml
中添加过多的代码,我们一般将具体的实现代码放到单独的文件中。
下面首先在QML目录中添加新文件,如下图所示。
模板依然选择Qt分类中的QML File(QtQuick 2),文件名称设置为MyHelloWorld
,请注意首字母要大写,如下图所示。
添加完成后,将main.qml
中的内容全部复制粘贴过来,如下图所示。
下面我们修改main.qml
文件的内容如下:
import QtQuick 2.0
Item {
MyHelloWorld {
anchors.fill: parent
}
}
像这样在一个单独文档中的QML代码段,就定义了一个对象类型,它也叫做组件,这个文件的名称必须以大写字母开头。比如这里创建了一个MyHelloWorld
类型,在其他QML文件中可以直接使用同一目录下自定义的对象类型,所以,我们在main.qml
中直接创建了MyHelloWorld
对象。这里根对象使用了Item
,在Qt Quick中,所有可视项目都继承自Item
,因为在main.qml
中我们只需要创建一个窗口,不需要进行内容设置,所以一般使用Item
即可,当然,如果想使用Rectangle
等也是可以的。
使用组件除了可以简化代码外,更重要的是它可以被重复使用,如果在一个代码中需要多次使用相同的部件或者功能,将它们作为组件就没必要多次编写相同的代码了。大家可以保存文件后在qmlscene中运行程序,查看效果。
5、id
属性和属性别名
前面提到过id
属性,其实它就是一个对象的名字,来唯一确定一个对象,在其他对象中可以通过id
引用该对象。下面我们将MyHelloWorld.qml
文件的内容更改如下:
import QtQuick 2.0
Rectangle {
width: 100
height: 62
property alias mArea: mouseArea
Text {
text: "hello World"
anchors.centerIn: parent
}
MouseArea {
id: mouseArea
anchors.fill: parent
}
}
这里我们首先更改了MouseArea
对象,设置其id
为mouseArea
,这样就可以在Rectangle
中通过mouseArea
来访问MouseArea
对象。为了可以在MyHelloWorld.qml
文件外访问Rectangle
内的子对象,我们需要在Rectangle
中自定义属性,并且该属性需要是子对象的属性别名,例如这里我们声明了一个mArea
属性,alias
表明mArea
是mouseArea
的别名,这样在MyHelloWorld.qml
文件外就可以通过mArea
来操作MouseArea
对象了。
下面我们修改main.qml
文件:
import QtQuick 2.0
Item {
MyHelloWorld {
anchors.fill: parent
mArea.onClicked: {
Qt.quit()
}
}
}
这里直接在MyHelloWorld
对象中通过mArea
调用了onClicked
处理器。现在保存文件,然后通过qmlscene
运行程序,查看效果。
到这里我们已经基本还原了上一篇中创建的Qt Quick应用中qml
文件的内容,从最简单的程序开始,逐渐丰富代码,现在大家应该已经对QML程序有了一定的认识。下面我们继续丰富程序,使其成为一个可以编译运行的项目。
五、添加C++代码
1、添加main.cpp
文件。首先在myqml
目录上右击,选择“添加新文件”,如下图所示。在弹出的对话框中选择C++分类中的“C++Source File”。
2、文件名称设置为main
,如下图所示。
3、添加完成后将main.cpp
文件的内容修改为:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("../myqml/main.qml")));
return app.exec();
}
这里主要就是普通的Qt C++中main()
函数,关键是其中创建了QQmlApplicationEngine
对象来加载QML文件,这个是固定的用法。因为现在编译运行程序的本地目录是自动生成的目录,它与myqml
源码目录是同级目录,所以加载main.qml
文件需要指定相对路径。
2、更改项目文件。现在在myqml.pro
文件中已经自动添加了一些代码,我们只需在最后添加一句代码:
QT += quick qml
这样就表明项目中使用了QtQuick
和QtQml
模块。
3、修改main.qml
文件。要在C++程序中使用QQmlApplicationEngine
加载QML文件,要求顶层窗口使用Window
项目,就是在main.qml
中的根对象使用Window
对象来代替Item
对象,因为Window
默认是不显示的,所以还有设置其visible
属性为true
,这个也是固定用法,大家以后照着做即可。修改后的main.qml
文件如下:
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
visible: true
MyHelloWorld {
anchors.fill: parent
mArea.onClicked: {
Qt.quit()
}
}
}
这里还导入了QtQuick.Window
2.0,这是因为该模块包含了Window
类型。现在我们可以按下Ctrl+R
快捷键来编译运行程序了,效果如下图所示。
六、使用资源文件
因为QML文件是普通的文本文件,但在程序运行时需要使用这些文件来创建界面,将其直接放在程序外是不安全的,所以我们的做法是将QML文件放到资源文件中。
1、添加资源文件。继续在myqml目录上右击,选择添加新文件,模板选择Qt分类中的“Qt Resource File”,如下图所示。
然后将文件名称设置为“qml”,如下图所示。
2、文件创建好之后会自动打开,这里我们先点击“添加”按钮,选择“添加前缀”,如下图所示。
这里将前缀设置为/
,如下图所示。(其实前缀使用什么都可以,这里为了简便,只保留斜杠)
3、再次点击“添加”按钮,这次选择“添加文件”,如下图所示。
在弹出的对话框中,选择源码目录中所有的QML文件,如下图所示。完成后点击Ctrl+S
保存资源文件。
4、添加完成以后,可以在左边文件列表中看到资源文件。如下图所示。
5、因为已经在资源文件中添加了QML文件,所以以前在项目中的QML文件就不再需要了。双击打开myqml.pro
文件, 然后将其中的:
DISTFILES += \
main.qml \
MyHelloWorld.qml
代码删除掉,点击Ctrl+S
保存项目文件。这时项目中的文件列表如下图所示。
6、最后修改main.cpp
文件。因为现在使用了资源文件,所以要更改main.cpp
文件中QML文件的路径,将其修改为:
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
到这里整个项目就修改完成了,大家可以运行程序,查看效果。这个项目将作为我们的模板,后面的章节会在这个项目的基础上进行修改来讲解,项目的创建过程就不再赘述。
小结
这一篇中我们将上一篇讲解的Qt Quick项目进行拆解分析,以初学者的角度,从最简单的几行代码开始,一点点丰富程序,一步步进行分析讲解,最终还原了整个程序。本节内容让大家可以从根本上掌握Qt Quick程序的构建,并且也提供了一种学习的方法,一种分析大型复杂程序的方法,就是所谓的剖析法,希望大家用心过一遍,为以后的学习打好基础。