[QML]事无巨细开始实践QML开发(一)什么是QML,为什么学习QML,先写一个简单的页面
[QML]从零开始QML开发(一)什么是QML,为什么学习QML,先写一个简单的页面
QML开发和QWidget开发的区别
QML(Qt Meta-Object Language)是Qt提供的一种声明性语言,用于快速创建用户界面。相对而言,Qt Widgets是基于C++的桌面应用程序开发框架。
下面是QML和Qt Widgets之间的一些优缺点以及为何Qt公司大力推行QML开发的原因:
优点:
可视化设计:QML是一种基于标记的语言,使用了层叠样式表(CSS)类似的语法,使得界面设计变得直观轻松。
跨平台支持:QML与其他主流操作系统和设备无关,可以在多个平台上运行,包括桌面、移动和嵌入式设备。
快速迭代:QML具有热重载功能,可以实时编辑和查看界面的更改,加快了开发和调试的速度。
良好的动画和效果支持:QML通过内置的动画和效果组件,使得界面的交互和动态效果实现变得简单。
灵活和可维护性:QML允许将界面元素分解为可重用的组件,使得代码结构化,易于拓展和维护。
缺点:
学习曲线:QML需要学习新的语法和概念,相对于传统的C++开发,可能需要一些时间来适应和掌握。
性能:与原生C++应用程序相比,QML在某些情况下可能会有性能上的损失,尤其是在复杂界面或需要大量渲染的场景中。
Qt公司推行QML开发的原因:
用户体验:QML提供了现代化、用户友好的界面设计能力,可以创建吸引人且交互性强的用户界面。
多平台支持:QML通过跨平台的特性,可以将开发的应用程序轻松地移植到不同的操作系统和设备上,提高了开发效率和代码的重用性。
易用性和开发效率:QML的可视化设计和声明性语法使得开发者可以更快速地构建和迭代界面,减少了开发周期。
这也是一种真正在Qt上进行前后端分离的方案,这倒是挺新颖的。个人在简单体验了一下QML开发之后,感觉QML是一个很类似前端CSS的技术,把页面变成一个单独的模块,也算是一种完美贯彻MVC模式的工具吧(毕竟之前还是会有很多人把业务放到界面里面去写,而且也会被人疯狂乱喷)某种意义上来说,这也是一种真正在Qt上进行前后端分离的方案,这倒是挺新颖的。
另外值得一提的点,QML作为一种几乎是描述性语言的存在,其跨平台的支持理论上应该显著好于QWidget的,所以新项目的开发(大概率是要兼容多系统)尽量在QML的基础上开发吧!
这就又相当于是我学了一门新的语言了,但既然已经有了QWidget的开发经验,再去开发前端html页面想必难度也不会大到哪里去,那么就来看看效果吧
开发准备
作为一名高贵的windows开发,那自然是要使用宇宙第一IDE:Visual Studio 2022 + Qt 5.14.2
为什么不用Qt 6 ?因为我这台开发电脑上没有装Qt 6 ,不过具体使用起来大差不差。
然后比较重要的一点是,QML本身可能对中文的支持有点问题,也就是说QML中如果出现了中文,可能就会出现乱码。当然了不止QML中会出现乱码,在QWidget中也会出现乱码,不同的是可以在QWidget中使用#pragma characterset("utf8")解决,但是在QML文件中不允许这样的语法出现(实际上QML是一套自己的语法),所以只能通过保存文件为UTF-8 with BOM的方式来规避掉这种可能出现的问题。
这也是为什么我们说QML比较适合新项目----因为你也不能保证以前的老项目的代码文件是以UTF8 with BOM格式保存的,也不可能把以前的老代码全部转换成UTF8 with BOM,这个是比较需要注意的。
至于说怎么转,网上教程一大堆,我只说我的做法 : 下载插件 Format on Save for VS2022(当然了每个vs版本肯定都会有的)
具体方法就是:扩展--》管理扩展--》联机--》搜索并下载Format on Save for VS2022--》下载完成--》VS上方菜单栏点击工具--》选项--》Format On Save -->UTF8-->Enable ForceUtf8WithBom 改为True
OK,让我们开启我们的第一个项目,怎么创建的就不说了,反正就是你在创建项目的时候直接创建一个QtQuick项目就可以了,我们来直接看项目内部:
先来看main函数,这个
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
先不管,这一段是给整个程序设置了一个支持高DPI的模式,这个无所谓
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
在这段代码中,使用QQmlApplicationEngine来加载和运行一个QML界面。
首先,创建了一个QQmlApplicationEngine对象,该对象用于加载和管理QML应用程序。
然后,使用engine.load(QUrl(QStringLiteral("qrc:/main.qml")))
语句加载名为"main.qml"的QML文件。在这里,使用QUrl::fromLocalFile()
函数将文件路径转换为QUrl格式,"qrc:"表示该文件位于Qt资源(qrc)中。
接下来,通过engine.rootObjects().isEmpty()
判断加载的QML界面是否成功。engine.rootObjects()
返回根对象的列表,如果列表为空,则表示加载失败。
如果加载的QML界面成功,程序继续执行后续的逻辑。否则,返回-1,可能表示加载失败或发生错误。
简而言之,这段代码的作用是加载并检查一个QML界面是否成功加载,如果加载成功,则继续执行其他相关操作。
然后我们双击一下这个main.qml文件,进来看看,内容大概如下:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
}
没错,就这么简单,就是几句话就表示了一个窗口,没有那么多规定复杂的构造函数,信号,Q_OBJECT宏之类的,而是一个由Qt完全封装好了的QML文件
让我们来编译执行一下,大概效果就是生成了一个窗口:
让我们来写一个按钮,添加代码如下:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Button{
x:100 //设置按钮的横坐标
y:100 //设置纵坐标
text:"我是按钮" //按钮标题
//一个类似JS风格的函数
function slotAnyway(){
console.log("slotAnyway")
}
//信号槽连接
onClicked: {
slotAnyway()
console.log("点击")
}
}
}
再编译执行一下:
然后按一下这个按钮就会弹出对应的提示。onClick是点击函数,至于这个函数是什么意思,将会在之后的文章中着重讲一下,这里不讲信号槽这些概念。
预览
写到这里,不禁让我头皮发麻,因为这里有一个非常严重的问题就是:我怎么知道现在界面是什么情况的?之前有一帮B开发就是用纯代码写QWidget,而且不能预览,调试起来真的麻烦的我想杀人。
当然了,Qt肯定也想到了这个问题,不然他们也不会一开始就提供.ui给用户去编辑了,相对的,Qt也肯定提供了一套QML的预览工具以供开发者调用,这个工具就是 :qmlscene.exe,这个工具的位置在你的Qt安装目录的指定版本下的bin目录,比如D:\DevTools\Qt_5.14.2\5.14.2\msvc2017_64\bin\qmlscene.exe
怎么用呢?其实也简单,就是直接双击qmlscene.exe,然后再选择指定的.qml文件就行了
当然了,这肯定有点低能,我们也不可能这么做。正确的做法是
右键main.qml->..打开方式->浏览->找到qmlscene.exe
,注意不能设置为默认,否则你就不能编辑这个.qml文档了,只需要每次预览的时候双击一下就可以了
之后简单说一下关于QML控件、信号、槽、锚、属性相关的内容
调试
当然了,你肯定会好奇这种代码怎么调试,你会好奇地在qml字段上打上一个断点然后尝试调试,结果你发现行不通。
当然了,Qt也考虑到了这个问题,当你需要调试这个程序的时候,请右键项目-》属性-》Qt Project Settings->QML->Enable QMl Debugging->改为是,这样之后你在qml文件中打上的断点就可以被命中了,当然了这也带来一个问题,就是当你在之后删掉这个断点后,每次调试或者启动这个程序都会告诉你程序命中了断点但是找不到这个断点,不过这并不是什么首要的问题,不是吗?