如何编写整洁的Qml代码
如何编写整洁的Qml代码
无疑,使用Qml技术能够开发出符合当前趋势的杰出的用户界面。Qml语言有着简洁和易学的语法,但代码并非天然就有清晰的层次。如果不注意,很容易搞乱。因此,需要学习如何编写整洁的Qml代码,以使你的程序易于维护。进而节省成本和时间。
Qml代码整洁的关键
到底是什么使得Qml代码整洁?本文从这一问题出发。代码会一团糟吗?是的,如果你不意识到这一点,会不小心在很多地方做错。
Qml代码格式
代码的风格主是代码格式化的方式。是代码看起来的样子。我发现这个定义非常平实易懂。它虽然不影响程序的运行,但它确实影响了代码的可读性。所以,它影响了程序的可维护性,也会耗费开发者未来做出改变的时间。
代码的格式涉及缩进、空格及换行的使用、代码分组及组织。这大多关乎个人习惯,没必要为诸如括号应该在哪儿这样的小问题较真。目标是在整个项目中有一致的代码格式。我见过有的软件开发者自已都没有一致的代码格式,那在多人在同一代码库中协同开发时就更显困难。这是尝试自动代码格式的原因。
Tip #1 更好的代码格式
Qml 代码倾向于有许多嵌套级别,并且代码很快就会向右延伸太多。因此,我的第一个建议是,将缩进减至2个空格以降低影响。
为了能实现这个目的,进入Qt Creator 的Tools->Options
菜单,并找到Qt Quick
设置。会找到一个关于代码风格的Tab页。你无法修改默认风格,但可以点Copy
铵钮以创建自己的风格。
为自己新建的代码风格命名后,点击Edit
按钮来为新风格修改细节。这里可以调整更多细节,但至少先将缩进做下修改。你会看到缩进和Tab的大小都是4。将它们减至2。这些更改应会反映在代码编辑器和重新格式化文件等工具中。
Tip #2 更好的代码格式
另一个提示就是使用 QML/JS重新格式文件 工具。它是如何工作的?它将你的代码重新模式化并让其看上去更好一些。看下下面的组件。
- import QtQuick 2.0
- Item
- {
- id: root
-
- width:30;height:50;
-
- Text {
- id: textItem
- font.pixelSize: 48; wrapMode: Text.WordWrap
- lineHeight: 0.75
- Behavior on color { ColorAnimation { duration: 120; easing.type: Easing.OutElastic} }
- states: [State {
- name: "pressed"
- when: mouse.pressed
- PropertyChanges {
- target: textItem
- color :Qt.lighter(root.color)
- }}
- ]
- }
- MouseArea {
- id: mouse
- anchors.fill: parent
- onClicked: {
- // ...
- }
- }
- function foo()
- {
- // ...
- }}
这肯定不是你见过的最漂亮的代码。它有很多问题,包括每行的缩进都不同、错误的花括号位置、有时缺失空格、有时又有多余的空格。想快速修复它,从Qt Creator的顶部菜单栏找到Tools
菜单,然后在QML/JS
组里找到Reformat file
。运行这个工具可以节省大量时间。
- import QtQuick 2.0
- Item {
- id: root
- width: 30
- height: 50
- Text {
- id: textItem
- font.pixelSize: 48
- wrapMode: Text.WordWrap
- lineHeight: 0.75
- Behavior on color {
- ColorAnimation {
- duration: 120
- easing.type: Easing.OutElastic
- }
- }
- states: [
- State {
- name: "pressed"
- when: mouse.pressed
- PropertyChanges {
- target: textItem
- color: Qt.lighter(root.color)
- }
- }
- ]
- }
- MouseArea {
- id: mouse
- anchors.fill: parent
- onClicked: {
- // ...
- }
- }
- function foo() {// ...
- }
- }
如果你有足够的决心放弃Qt Creator对Qml代码格式的一些控制,那么试着设置“Reform file
”工具,以便在文件保存时自动运行。
QML代码规范
代码规范/约定超越了代码格式的范畴。Qml代码可以被格式化,从代码整洁的角度看上去很好,但它仍需要打磨。官方的规范是非常好的开始,请按官方建议来做。
以下是我们遵循的,以提供高质量Qt Qml软件开发服务和整洁的Qml代码为目的的规范。我们也会要求应聘者完成技术分工时遵循这些规范。
1.根项id
为了提高可读性和可追溯性,建议将文件中的顶级元素命名为root
。然后,在每个文件中,你就会知道 root
是指向的是顶级元素。
- import QtQuick 2.0
- Item {
- id: root
- }
2.Qml字符转换
对用户可见的字符应该都被qsTr()
函数包含。 此外,不要使用结束翻译作为默认显示的字符串,而是使用 THIS_NOTATION。比如,不要写成qsTr("This is displayed"),而应该写成qsTr("THIS_IS_DISPLAYED")。多亏了这种方法,如果任何字符串缺少翻译,我们可以立即在 UI 中看到。
3.有私有对象
在 Qml 代码里,封装和适当的范围界定很重要。就象在C++ 中不能让类的所有成员都是公有的,在Qml代码中也是一样。并非所有的属性与函数都对外可见。经常有一些帮助属性或方法,它们没有值,甚至当从外部访问时会产生危害。因此建议将其包装成内部Qt对象。
- QtObject {
- id: _ // or id: internal
-
- readonly property real timeout: 1000
- property bool isExpanded: false
- function addDestination() {
- // ...
- }
- }
4.各类属性的顺序
官方的规范里涵盖了属性顺序,我们定义的略微不同,且更为细节。这在大型项目中会有回报。
- import QtQuick 2.15
- import QtQuick.Controls 2.15 // Qt modules first
- import com.scythestudio.ownmodule 1.0 // then own modules
- import "./controls/" // then local directories
- // A hypothetical custom button item.
- Item {
- id: root
- /// The text to be placed on the button
- property string title: "title" // properties declaration
- /// The button's background color
- property alias color: button.color
- signal buttonClicked() // signal declaration
- Button { // child items
- id: button
- width: parent.width // properties derived from Item
- height: parent.height
- icon.color: "black" // Button's own properties
- onClicked: {
- root.buttonClicked()
- }
- }
- states: State { // states
- name: "selected"
- PropertyChanges { target: button; icon.color: "red" }
- }
- transitions: Transition { // transitions
- from: ""
- to: "selected"
- ColorAnimation { target: button; duration: 200 }
- }
- PropertyAnimation { // special items
- id: closeDelayAnimation
- // ...
- }
- Timer { // special items
- }
- Connections { // special items
- target: someCppController
- function onProcessFailed() {
- // ...
- }
- }
- QtObject { // private item
- id: _
- readonly property real timeout: 1000
- property bool isExpanded: false
- function addDestination() {
- // ...
- }
- }
- onWidthChanged: { // slots
- }
- function close() { // public functions
- isExpanded = false
- closeDelayAnimation.start()
- }
- }
以上代码片段可以得出很多规范,这里强调三条:
- 函数定义倾向于放在文件底部,以便首先看清组件的子项,并快速理解元素是如何构建的。
- 状态和转换往往会快速增长,这就是为什么它们应该放在子项的下面,尽管它们也是属性;
- 组件的公有API应该被详细记录
Qml最佳实践
Qt框架文档中,可以找到Qml和Qt Quick的最佳实践。这些非常有用,且其中不少的要义是关于代码整洁的。最为关键的一条是将UI与逻辑分离的原则。当写Qml代码时,可能会尝试使用Qml和JavaScript实现很多事情,包括应用程序逻辑和网络交互。
应该将这些事情放在C++ 中处理,这样前端写的Qml和后端写的C++ 才有清晰的分界线。也因此,程序结构会有更好的可扩展性。数据模型几乎总是应该在C++ 中实现。仅当模型数据是静态的时,才有可能在Qml代码中处理。否则,可能将在处理Qml模型高级操作而浪费时间,或在C++ 重写模型。
另一个好的做法是使用qmllint 工具,有助于定位Qml代码中问题。这是一个相当有用的工具,可以警告很多问题,包括未使用导入和对属性的不例规访问。Qt公司现正为此工具与Qt Creator IDE更好地结合而努力。
整洁的代码为何至关重要
这一点上你应该理解整洁的代码意味着什么,以及你应该如何来确保所写代码符合规范。接下来我们来回答为何编写整洁的代码至关重要。这实际上是为了高质量的代码。当遵循一系列的规范和约定,很容易来定位问题,也会节省大量时间。此外,由于干净的代码概念包括良好的实践,遵循这些指引的开发人员编写代码具有艺术性。在审查过程中不需要费多大劲。
当编写代码时,需要做出许多微小的决定,并且在一段时间后查看相同的代码之后,您宁愿不知道为什么要以特定方式编写代码。另一方面,当您遵循干净的 Qml 代码规则时,您会将这些小决定外包给代码。它可以释放你的思维资源。
最后,当然,编写干净的 Qml 代码最重要的原因是它显着提高了项目的可维护性。有人说你写了一次代码,但它被读了多次。因此,你需要关心代码的可读性以及所有良好实践。然后,你和其他开发人员更容易进入项目,了解特定部分并进行更改。
现在你可能会问你的团队应该对遵循干净的 Qml 代码规则有多严格。好吧,这一切都取决于你当前正在进行的项目的规模。未来有多少人参与或将参与也很重要。我的观点是,在确保高质量代码方面努力永无止境。即使你准备了一个小演示来展示哪些代码将被公开,遵循所有这些规则以最终对你的工作结果感到满意是件好事。一段时间后,它进入血液,开发人员甚至不再将其视为额外的努力。
如果你在维护一个长期项目,例如 Qt 框架,您有很多理由对代码质量进行严格限制。我在一篇博文中描述了我在 Qt Charts in Qt 6.2 做贡献的经历。有很多约定和规则要遵循,实际上一开始很难习惯它们。虽然有 CI/CD 机制可以节省审阅者的时间,例如,寻找错别字。一开始,让我的代码符合所有这些要求是一件很困难的事。尽管如此,我知道这是这个项目的必备品,我可以说它甚至是令人愉快的。
要点和一般规则
- 维护一个干净的 Qml 代码库是一个健康的 Qt 项目的一个重要方面;
- KISS--保持简短和简单。不是为你,而是为读者。始终选择更简单的实现选项而不是更复杂的实现选项;
- 记录已创建项目的公共接口 (API);
- 不要添加描述如何实现某事的注释。如果读者无法从您的代码中推断出这一点,那么代码就需要重构。注释如果写的解决方案不明显,可能看起来令人莫名其妙;
- 不要重新造轮子;
- 代码应适配现有的代码库。如果有改进想法,请先与其他开发人员讨论;
- 遵循编码以及良好Qml实践的规范。