由于项目的原因,接触到qml语言。经过一段时间的熟悉和使用,发现只要有基本的开发能力,那么快速掌握qml的入门知识,并不难。
本文首先将简单介绍qml, 紧接着引入第一个入门例子hello world。然后将采用图文并茂的示例来介绍qml的界面布局、监听事件、简单动画效果、自定义属性、自定组件等。最后再总结概述。
一、qml简介
qml是一种描述性的脚本语言,语法类似css, 可以在脚本中创建图像对象,并支持各种特效,并且文件是以.qml结尾。
qml文档描述 了一个对象树。各个元素可以以嵌套的方式来组合成复杂的图形功能。q ml是Qt quick的核心组件之一。
qml是运行时解释,不需要重新编译。
二、第一个例子
使用Qt Creator来创建空的qml工程,注意本文所有的示例均使用了Qt5.9的版本。
创建工程完成之后,pro文件添加使用quick组件,并且配置使用了C++11
QT += quick CONFIG += c++11
main.cpp的内容如下所示,这里可以暂时不需要了解其内容含义。只需要知道 这是程序启动的入口。
#include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
然后我们来介绍下main.qml的内容含义,import需要使用的组件,Window表示的是一个窗体,内部内容使用大括号包含起来,visible设置窗体的可见性,width表示窗体的宽度,height表示窗体的高度,title设置窗体的标题。
import QtQuick 2.9 import QtQuick.Window 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") }
运行后的效果图,是一个标题为Hello World的空窗体。
三、界面布局
qml通过anchor锚点来进行界面的布局, 首先看下效果图,一个黑色背景窗体,四边有四个红色边框的白色矩形,中间一个红色边框的白色正方形。
qml文件的实现如下,关键字Rectangle表示一个矩形组件,Rectangle可以嵌套使用。接下来说明顶部白色矩形的实现,定义id为topBar, 背景色color是白色,边框border.width的宽度是2,边框颜色border.color是红色。anchors.left: leftBar.right表示顶部矩形的左侧位于左侧边框的右侧。
import QtQuick 2.9 import QtQuick.Window 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Rectangle { anchors.fill: parent color: "#000000" Rectangle { id: leftBar width: 20 color: "white" border.width: 2 border.color: "red" anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom } Rectangle { id: rightBar width: 20 color: "white" border.width: 2 border.color: "red" anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom } Rectangle { id: topBar height: 20 color: "white" border.width: 2 border.color: "red" anchors.left: leftBar.right anchors.right: rightBar.left anchors.top: parent.top } Rectangle { id: bottomBar height: 20 color: "white" border.width: 2 border.color: "red" anchors.left: leftBar.right anchors.right: rightBar.left anchors.bottom: parent.bottom } Rectangle { id: centerblock width: 20 height: 20 color: "white" border.width: 2 border.color: "red" anchors.centerIn: parent } } }
四、函数功能
qml支持函数功能,通过两个不同时刻窗口对比来查看器效果,左侧窗口是当窗体宽度小于320像素的效果,右侧窗口是当窗体宽度小于640像素的效果。
qml文件实现中,Rectangle包含了Text文本对象,Text内部定义了函数getColor,当Rectangle的宽度小于320时,返回red, 当宽度小于等于640时,返回black, 其他情况返回blue。
import QtQuick 2.9 import QtQuick.Window 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Rectangle { id : root width: parent.width height: parent.height border.width: 2 border.color: "black" Text { anchors.centerIn: parent font.pointSize: { var threshold = 320 var minSize = 20 if (root.width <= threshold) { return minSize } else { var delta = root.width - threshold return delta / 10 + minSize } } font.bold: root.width > 800 text: root.width + " * " + root.height color: getColor() function getColor() { if (root.width <= 320) { return "red" } else if (root.width <= 640 ) { return "black" } else { return "blue" } } } } }
五、动画效果
qml支持动画效果,首先看下使用Behavior的效果图,窗体分为上下两个矩形,当鼠标按下上方区域不动的时候,下方矩形中的正方形就会从左上角移动到右下角,当鼠标释放的时候,正方形又会从右下角回到左上角。
qml文件中,上方矩形实现鼠标按下和释放的监控事件,并且接受事件中,修改下方矩形的x和y的坐标值。下方矩形实现上图所示的动画效果,easing.type指定的是一种缓和曲线。
import QtQuick 2.9 import QtQuick.Window 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Rectangle { id : clickRect width: parent.width;height: parent.height / 2 anchors.top: parent.top border.width: 2; border.color: "black" color: "white" Text { id: clickText anchors.centerIn: parent font.pointSize: 40 text: "Click" } MouseArea { anchors.fill: parent onPressed: { clickText.text = "Mouse Pressed" floatRect.x = displayRect.width - floatRect.width floatRect.y = displayRect.height - floatRect.height floatRect.color = "blue" } onReleased: { clickText.text = "Mouse Released" floatRect.x = 0 floatRect.y = 0 floatRect.color = "red" } } } Rectangle { id : displayRect width: parent.width; height: parent.height / 2 anchors.bottom: parent.bottom Rectangle { id: floatRect width:40; height:40 color: "red" x: 0 y: 0 Behavior on x { NumberAnimation { duration: 2000 easing.type: Easing.InSine } } Behavior on y { NumberAnimation { duration: 2000 } } Behavior on color { ColorAnimation { duration: 2000 } } } } }
六、自定义属性
qml支持自定义属性,调用自定义属性值显示文本信息
qml文件中,自定义属性以关键字property开始,然后是说明类型,最后是属性的名称和值。
import QtQuick 2.9 import QtQuick.Window 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Rectangle { id : root width: parent.width height: 480 border.width: 2 border.color: "black" property int halfWidth: width / 2 property string halfWidthStr : halfWidth + "" property string prefix : "halfWidth: " Text { font.pointSize: 40 text: root.prefix + root.halfWidthStr } } }
七、自定义组件
qml没有提供直接的圆形组件,所以,这里自定义圆形组件。
实现圆形组件Circle.qml, 定义了整型属性d, 可以由外部传入,radius表示半径。
import QtQuick 2.0 Rectangle { property int d width: d height: d radius: d /2 border.width: 1 border.color: "black" }
然后看下main.qml如何调用呢,其使用方法与通用组件的方式是一样的,如下所示自定义圆形组件Circle的使用。
import QtQuick 2.9 import QtQuick.Window 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Rectangle { anchors.fill: parent Circle { anchors.centerIn: parent d: parent.width < parent.height ? parent.width: parent.height } } }
八、Column定位器
qml提供的定位器的功能,比如Row、Column、Grid、Flow。下面就看下Column的使用效果。
首先自定义组件Article.qml, 该组件接受两个属性值,并且分别显示到两个Text对象上。
import QtQuick 2.0 Rectangle { property string title property string content width: 200 height: 90 border.width: 1 border.color: "black" Text { id : titleText anchors.left: parent.left anchors.top: parent.top font.pointSize: 40 font.bold: true text: title } Text { id: contextText anchors.left: parent.left anchors.top: titleText.bottom font.pointSize: 20 font.bold: false text: content } }
main.qml中使用Column定位器来组织显示Article对象。
import QtQuick 2.9 import QtQuick.Window 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Column { anchors.fill: parent Article {title: "title1"; content: "content1"} Article {title: "title2"; content: "content2"} } }
九、注册单例
qml还支持注册C++的单例模型,然后在qml中直接调用,实现了与C++代码的通信。
实现实现用于事件上报的单例模型,具体实现代码如下所示。
#ifndef JEVENTSENDER_H #define JEVENTSENDER_H #include <QObject> #include <QQmlEngine> #include <QDebug> class EventSender : public QObject { Q_OBJECT public: static QObject *qmlInstance (QQmlEngine *engine, QJSEngine *sctEngine) { (void)engine; (void)sctEngine; return getInstance(); } static EventSender *getInstance() { static EventSender s_instance; return &s_instance; } Q_INVOKABLE void SendEvent(QString event) { qDebug() << "SendEvent: " << event; } private: explicit EventSender(QObject *parent = nullptr) : QObject (parent) { } }; #endif // JEVENTSENDER_H
然后在main.cpp中将EventSender注册到qml中, 后续qml文件才能调用
#include <QGuiApplication> #include <QQmlApplicationEngine> #include "JEventSender.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); // 关键在这里,将EventSender注册到qml qmlRegisterSingletonType<EventSender>("EventSender", 1, 0, "EventSender", EventSender::qmlInstance); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
最后看下qml如何调用上面注册成功的单例,很简单,只要import EventSender, 然后就可以调用EventSender的函数。
import QtQuick 2.9 import QtQuick.Window 2.2 import EventSender 1.0 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") MouseArea { anchors.fill: parent onPressed: { EventSender.SendEvent("mouse press"); } } }
十、总结
本文通过一个简单的例子开始qml的学习,然后结合示例分别介绍说明了锚布局、函数功能、动画效果、自定义属性、自定义组件、定位器、注册单例的使用方法。这些基本的例子可以为后续深入的学习打下基础,同时也分享出来给大家参考。