Qt6 QML Book/Quick入门/QML语法

QML Syntax

QML语法

QML is a declarative language used to describe how objects relate to each other. QtQuick is a framework built on QML for buidling the user interface of your application. It breaks down the user interface into smaller elements, which can be combined into components. QtQuick describes the look and the behavior of these user interface elements. This user interface description can be enriched with JavaScript code to provide simple but also more complex logic. In this perspective, it follows the HTML-JavaScript pattern but QML and QtQuick are designed from the ground up to describe user interfaces, not text-documents.

QML是一种声明性语言,用于描述对象之间的关系。QtQuick是一个基于QML之上的框架,用于构建应用程序的用户界面。它将用户界面分解成小元素,这些元素也可以组合成组件。QtQuick可以设置这些元素的外观和行为。也可以使用JavaScript代码丰富用户界面,以提供简洁而复杂的逻辑。从这个角度来看,它遵循HTML-JavaScript模式,但是为QML和QtQuick重新设计过,且不是简单文本文档。

In its simplest form, QtQuick lets you create a hierarchy of elements. Child elements inherit the coordinate system from the parent. An x,y coordinate is always relative to the parent.

简单说,QtQuick允许您创建层次结构的元素。子元素继承父元素坐标系统。x,y坐标总是相对于父坐标。

TIP

QtQuick builds on QML. The QML language only knows of elements, properties, signals and bindings. QtQuick is a framework built on QML. Using default properties, the hierarchy of QtQuick elements can be constructed in an elegant way.

QtQuick基于QML。QML语言只知道元素、属性、信号和绑定。QtQuick是一个基于QML的框架。通过默认属性,QtQuick元素的层次结构,以一种优雅的方式表现。

Let’s start with a simple example of a QML file to explain the different syntax.

我们从一个简单的QML文件示例开始,以了解不同的语法。

// RectangleExample.qml

import QtQuick

// The root element is the Rectangle 根元素是矩形
Rectangle {
    // name this element root 将此元素id命名为root
    id: root

    // properties: <name>: <value> 属性:<名称>:<值>
    width: 120; height: 240

    // color property 颜色属性
    color: "#4A4A4A"

    // Declare a nested element (child of root) 声明一个嵌套元素(根的子元素)
    Image {
        id: triangle

        // reference the parent 引用父对象属性
        x: (parent.width - width)/2; y: 40

        source: 'assets/triangle_red.png'
    }

    // Another child of root 根的另一个子元素
    Text {
        // un-named element 无id的元素

        // reference element by id 通过id引用元素属性
        y: triangle.y + triangle.height + 20

        // reference root element 参考根元素属性
        width: root.width

        color: 'white'
        horizontalAlignment: Text.AlignHCenter
        text: 'Triangle'
    }
}
  • The import statement imports a module. An optional version in the form of <major>.<minor> can be added.
  • import语句导入一个模块。版本号省略,形式为<主版本号>.<次版本号>
  • Comments can be made using // for single line comments or /\* \*/ for multi-line comments. Just like in C/C++ and JavaScript
  • 注释可以用//来表示单行注释,用/*……*/来表示多行注释。和C/C++和JavaScript一样
  • Every QML file needs to have exactly one root element, like HTML
  • 每个QML文件都需要有一个根元素,类似HTML
  • An element is declared by its type followed by { }
  • 元素先类型声明,后跟{}
  • Elements can have properties, they are in the form name: value
  • 元素有属性,形式是 属性名: 属性值
  • Arbitrary elements inside a QML document can be accessed by using their id (an unquoted identifier)
  • QML文档中的属性,可以通过它们的id(不带引号)来访问
  • Elements can be nested, meaning a parent element can have child elements. The parent element can be accessed using the parent keyword
  • 元素可以嵌套,即父元素可以有子元素。可以使用parent访问父元素属性

With the import statement you import a QML module by name. In Qt5 you had to specify a major and minor version (e.g. 2.15), this is now optional in Qt6. For the book content we drop this optional version number as normally you automatically want to choose the newest version available from your selected Qt Kit.

使用import语句,可以按名称导入QML模块。在Qt5中,你必须指定一个主、次版本号(例如2.15),但在Qt6中可以省略的。对于本书的内容,我们省略了版本号,这相当于自动选用Qt开发套件中的最新版本。

TIP

Often you want to access a particular element by id or a parent element using the parent keyword. So it’s good practice to name your root element “root” using id: root. Then you don’t have to think about how the root element is named in your QML document.

通常通过id访问特定元素,或者使用parent关键字访问父元素。所以最好将根元素命名为root,使用id: root。这样就不必考虑如何在QML文件中命名根元素。

TIP

You can run the example using the Qt Quick runtime from the command line from your OS like this:

可以使用Qt Quick运行时,从操作系统的命令行运行该示例,如下所示

$ $QTDIR/bin/qml RectangleExample.qml

Where you need to replace the $QTDIR to the path to your Qt installation. The qml executable initializes the Qt Quick runtime and interprets the provided QML file.

可以使用Qt Quick运行时,从操作系统的命令行运行该示例,如下所示

In Qt Creator, you can open the corresponding project file and run the

在Qt Creator中,可以打开相应的项目文件并运行

document RectangleExample.qml.

Properties

属性

Elements are declared by using their element name but are defined by using their properties or by creating custom properties. A property is a simple key-value pair, e.g. width: 100text: 'Greetings'color: '#FF0000'. A property has a well-defined type and can have an initial value.

通过元素名声明元素,通过元素属性或自定义属性来定义元素。一个属性是一个简单的键值对,例如,width: 100, text: 'Greetings', color: '#FF0000'。属性具有确定类型,且可以有初始值。

Text {
    // (1) identifier 标识符
    id: thisLabel

    // (2) set x- and y-position 设置x和y坐标
    x: 24; y: 16

    // (3) bind height to 2 * width 将高度绑定为宽度的2倍
    height: 2 * width

    // (4) custom property 自定义属性
    property int times: 24

    // (5) property alias 属性别名
    property alias anotherTimes: thisLabel.times

    // (6) set text appended by value 设置附加值的文本
    text: "Greetings " + times

    // (7) font is a grouped property 字体是一个分组属性
    font.family: "Ubuntu"
    font.pixelSize: 24

    // (8) KeyNavigation is an attached property KeyNavigation是一个附加属性
    KeyNavigation.tab: otherLabel

    // (9) signal handler for property changes 属性更改的信号处理器
    onHeightChanged: console.log('height:', height)

    // focus is need to receive key events 焦点是获取键盘事件前提
    focus: true

    // change color based on focus value 根据焦点值改变颜色
    color: focus ? "red" : "black"
}

Let’s go through the different features of properties:

让我们来看看属性的不同特性:

  • (1) id is a very special property-like value, it is used to reference elements inside a QML file (called “document” in QML). The id is not a string type but rather an identifier and part of the QML syntax. An id needs to be unique inside a document and it can’t be reset to a different value, nor may it be queried. (It behaves much like a reference in the C++ world.)

  • (1)id是一个非常特殊的属性,用于引用QML文件(在QML中称为document)中的元素。id不是字符串类型,而是一个标识符,是QML语法的一部分。id在同一文件中必须是唯一的,不能重置值,也不能查询。(它很像c++中的引用。)

  • (2) A property can be set to a value, depending on its type. If no value is given for a property, an initial value will be chosen. You need to consult the documentation of the particular element for more information about the initial value of a property.

  • (2)一个属性可以根据类型设置一个值。如果属性没有给定值,那么将会赋予一个初始值。您需要查阅特定元素的文档,以获得关于属性初始值的更多信息。

  • (3) A property can depend on one or many other properties. This is called binding. A bound property is updated when its dependent properties change. It works like a contract, in this case, the height should always be two times the width.

  • (3)一个属性可以依赖于一个或多个其他属性。这被称为绑定。当关联属性发生变化时,绑定属性将被更新。它就像一个契约,例如,高度总是宽度的两倍。

  • (4) Adding new properties to an element is done using the property qualifier followed by the type, the name and the optional initial value (property <type> <name> : <value>). If no initial value is given, a default initial value is chosen.

  • (4)可以给元素添加新属性,需要属性限定符、类型、名称和可选的初始值(property <类型> <名称> : <初始值>)。如果没有给初始值,则会使用默认的初始值。

TIP

You can also declare one property to be the default property using default keyword. If another element is created inside the element and not explicitly bound to a property, it is bound to the default property. For instance, This is used when you add child elements. The child elements are added automatically to the default property children of type list if they are visible elements.

可以使用default关键字将一个属性声明为默认属性。如果在元素内部创建了另一个元素,并且没有显式地绑定到某个属性,那么它将绑定到默认属性。例如,在添加子元素时。如果子元素是可见元素,则会自动添加到类型列表的默认属性中。

  • (5) Another important way of declaring properties is using the alias keyword (property alias <name>: <reference>). The alias keyword allows us to forward a property of an object or an object itself from within the type to an outer scope. We will use this technique later when defining components to export the inner properties or element ids to the root level. A property alias does not need a type, it uses the type of the referenced property or object.

  • (5) 声明属性的另一种重要方法是,使用alias关键字(property alias <别名>: <引用对象>)。alias关键字允许我们将对象的属性或对象本身,从类型内部暴露出来。通过这种方法,可以把组件内部属性或元素id导出到根级属性,稍后内容会具体命题组。属性别名不需要类型,它使用被引用的属性或对象的类型。

  • (6) The text property depends on the custom property times of type int. The int based value is automatically converted to a string type. The expression itself is another example of binding and results in the text being updated every time the times property changes.

  • (6) text属性依赖于int类型的值。基于int的值会自动转换为字符串类型。表达式本身是绑定的另一个示例,每当times属性更改时都会更新文本。

  • (7) Some properties are grouped properties. This feature is used when a property is more structured and related properties should be grouped together. Another way of writing grouped properties is font { family: "Ubuntu"; pixelSize: 24 }.

  • (7)有些属性是分组属性。当一个属性更结构化并相关的属性应该组合在一起时,就会使用这个特性。这个分组属性的另一种写法是font {family: "Ubuntu";pixelSize: 24}。

  • (8) Some properties belong to the element class itself. This is done for global settings elements which appear only once in the application (e.g. keyboard input). The writing is <Element>.<property>: <value>.

  • (8) 有些属性属于元素类型本身。这是为元素设置的全局属性,在应用程序只出现一次(如键盘输入)。格式为<元素类型>.<属性>: <值>

  • (9) For every property, you can provide a signal handler. This handler is called after the property changes. For example, here we want to be notified whenever the height changes and use the built-in console to log a message to the system.

  • (9) 对于每个属性,都可以提供一个信号处理器。信号处理器在属性更改后被调用。例如,在这里,我们想在高度发生变化时得到通知,并使用内置控制台向系统打印一条消息。

WARNING

提醒

An element id should only be used to reference elements inside your document (e.g. the current file). QML provides a mechanism called "dynamic scoping", where documents loaded later on overwrite the element IDs from documents loaded earlier. This makes it possible to reference element IDs from previously loaded documents if they have not yet been overwritten. It’s like creating global variables. Unfortunately, this frequently leads to really bad code in practice, where the program depends on the order of execution. Unfortunately, this can’t be turned off. Please only use this with care; or, even better, don’t use this mechanism at all. It’s better to export the element you want to provide to the outside world using properties on the root element of your document.

元素id只能用于引用qml文件(当前文件)中的元素。QML提供了一种称为“动态作用域”的机制,后加载的qml文件将覆盖前面加载的qml文件的元素id。若先前加载的文件id未被覆盖,仍然可以引用它们。这就像创建全局变量一样。不幸的是,这种代码可读性极差,且程序结果取决于执行的顺序。不幸的是,这种机制不能关闭。请小心使用,或者,最好不使用这个机制。建议在qml文件的根元素上使用属性或别名,导出需要供外部元素访问的属性。

Scripting

脚本处理

QML and JavaScript (also known as ECMAScript) are best friends. In the JavaScript chapter we will go into more detail on this symbiosis. Currently, we just want to make you aware of this relationship.

QML和JavaScript(也称为ECMAScript)是高度集成的。在JavaScript一章中,我们将更详细地讨论这种共生关系。目前,只是了解这种关系。

Text {
    id: label

    x: 24; y: 24
 
    // custom counter property for space presses 自定义计数器属性
    property int spacePresses: 0

    text: "Space pressed: " + spacePresses + " times"

    // (1) handler for text changes. Need to use function to capture parameters
    //文本更改的处理器。需要使用函数来捕获参数
    onTextChanged: function(text) { 
        console.log("text changed to:", text)
    }

    // need focus to receive key events需要接收键盘事件
    focus: true

    // (2) handler with some JS 使用JS的事件处理器
    Keys.onSpacePressed: {
        increment()
    }

    // clear the text on escape 按下退出键时,清除label的文本
    Keys.onEscapePressed: {
        label.text = ''
    }

    // (3) a JS function JS函数
    function increment() {
        spacePresses = spacePresses + 1
    }
}
  • (1) The text changed handler onTextChanged prints the current text every time the text changed due to the space bar being pressed. As we use a parameter injected by the signal, we need to use the function syntax here. It's also possible to use an arrow function ((text) => {}), but we feel function(text) {} is more readable.

  • (1) 每当空格键被按下时,文本会发生更改,文本变化处理器onTextChanged会打印当前文本。当使用由信号注入的参数时,需要使用函数语法。也可以使用箭头函数((text) =>{}),但我们认为function(text) {} 可读性更好。

  • (2) When the text element receives the space key (because the user pressed the space bar on the keyboard) we call a JavaScript function increment().

  • (2) 当文本元素接收到空格键事件时(用户按下了键盘上的空格键),我们调用一个JavaScript函数increment()。

  • (3) Definition of a JavaScript function in the form of function <name>(<parameters>) { ... }, which increments our counter spacePressed. Every time spacePressed is incremented, bound properties will also be updated.

  • (3) 定义JS函数的格式为function <函数名>(<参数>) { ... },它将增加计数器spacePressed的值。每次spacePressed被增加时,绑定的属性值也将被同步更新。

Binding

绑定处理

The difference between the QML : (binding) and the JavaScript = (assignment) is that the binding is a contract and keeps true over the lifetime of the binding, whereas the JavaScript assignment (=) is a one time value assignment.

QML:(绑定)和JavaScript =(赋值)之间的区别在于,绑定是一个契约,并在绑定的生命周期内保持绑定值更新,而JavaScript赋值(=)只是一次赋值操作。

The lifetime of a binding ends when a new binding is set on the property or even when a JavaScript value is assigned to the property. For example, a key handler setting the text property to an empty string would destroy our increment display:

绑定的生命周期,会在属性设置新绑定或属性赋值时结束。例如,将text属性设置为空字符串后,text属性将不会再显示计数器的值

Keys.onEscapePressed: {
    label.text = ''
}

After pressing escape, pressing the space bar will not update the display anymore, as the previous binding of the text property (text: “Space pressed: ” + spacePresses + ” times”) was destroyed.

按下escape后,按下空格键后,将不再显示更新值,因为之前绑定的文本属性(text: Space pressed: + spacePresses + times)已被破坏。

When you have conflicting strategies to change a property as in this case (text updated by a change to a property increment via a binding and text cleared by a JavaScript assignment) then you can’t use bindings! You need to use assignment on both property change paths as the binding will be destroyed by the assignment (broken contract!).

当改变一个属性有冲突时,如通过绑定一个属性来更新文本,然后通过JavaScript赋值清除文本,就不能使用绑定!在有绑定的属性上使用赋值,绑定将被赋值破坏(破坏契约!)

示例源码下载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值