Qt6 QML Book/动态QML/动态加载组件

本文介绍了如何在QML中使用Loader元素动态加载不同的UI组件,并通过Connections元素处理信号连接。Loader作为占位符,根据source或sourceComponent属性加载内容。同时,利用Binding元素实现动态属性绑定。此外,详细讨论了在不同目标元素间切换信号监听的方法以及如何处理信号不匹配的情况。
摘要由CSDN通过智能技术生成

Loading Components Dynamically

动态加载组件

The easiest way to dynamically load different parts of QML is to use the Loader element. It serves as a placeholder to the item that is being loaded. The item to load is controlled through either the source property or the sourceComponent property. The former loads the item from a given URL, while the latter instantiates a Component.

动态加载QML不同部分的最简单方法是使用Loader元素类型。它用作正在加载的项的占位符。要加载的项通过source属性或sourceComponent属性进行控制。前者从给定的URL加载项,而后者实例化一个组件Component

As the loader serves as a placeholder for the item being loaded, its size depends on the size of the item, and vice versa. If the Loader element has a size, either by having set width and height or through anchoring, the loaded item will be given the loader’s size. If the Loader has no size, it is resized in accordance to the size of the item being loaded.

由于加载器充当正在加载的项目的占位符,其大小取决于项的大小,反之亦然。如果装载器Loader有一个尺寸,通过设置宽度width和高度height或通过锚定,装载的物品将被赋予装载器的尺寸。如果加载器Loader没有大小,则会根据正在加载的项大小调整其大小。

The example described below demonstrates how two separate user interface parts can be loaded into the same space using a Loader element. The idea is to have a speed dial that can be either digital or analog, as shown in the illustration below. The code surrounding the dial is unaffected by which item that is loaded for the moment.

下面描述的示例演示了如何使用Loader元素将两个独立的用户界面部件加载到同一个位置中。这个想法是要有一个可以是数字或模拟的快速拨号盘,如下图所示。表盘周围的代码不受当前加载的项目的影响。

The first step in the application is to declare a Loader element. Notice that the source property is left out. This is because the source depends on which state the user interface is in.

应用程序的第一步是声明一个Loader元素类型。请注意,源属性source被忽略。这是因为源source取决于用户界面处于哪个状态。

Loader {
    id: dialLoader

    anchors.fill: parent
}

In the states property of the parent of dialLoader a set of PropertyChanges elements drives the loading of different QML files depending on the state. The source property happens to be a relative file path in this example, but it can just as well be a full URL, fetching the item over the web.

在dialLoader父级的states属性中,一组PropertyChanges元素根据状态state驱动不同QML文件的加载。在本例中,source属性恰好是一个相对文件路径,但它也可以是一个完整的URL,通过web获取项目。

states: [
    State {
        name: "analog"
        PropertyChanges { target: analogButton; color: "green"; }
        PropertyChanges { target: dialLoader; source: "Analog.qml"; }
    },
    State {
        name: "digital"
        PropertyChanges { target: digitalButton; color: "green"; }
        PropertyChanges { target: dialLoader; source: "Digital.qml"; }
    }
]

In order to make the loaded item come alive, it is speed property must be bound to the root speed property. This cannot be done as a direct binding as the item not always is loaded and changes over time. Instead, a Binding element must be used. The target property of the binding is changed every time the Loader triggers the onLoaded signal.

为了使加载的项目激活,必须将它的speed属性绑定到root的speed属性。这不能作为直接绑定来完成,因为项目并不总是被加载并随时间而变化。相反,必须使用绑定元素类型Binding。每次加载程序Loader触发onLoaded信号时,绑定的目标属性target都会发生更改。

Loader {
    id: dialLoader

    anchors.left: parent.left
    anchors.right: parent.right
    anchors.top: parent.top
    anchors.bottom: analogButton.top

    onLoaded: {
        binder.target = dialLoader.item;
    }
}

Binding {
    id: binder

    property: "speed"
    value: speed
}

The onLoaded signal lets the loading QML act when the item has been loaded. In a similar fashion, the QML being loaded can rely on the Component.onCompleted signal. This signal is actually available for all components, regardless of how they are loaded. For instance, the root component of an entire application can use it to kick-start itself when the entire user interface has been loaded.

当项目已加载时,onLoaded信号允许加载QML动作。以类似的方式,正在加载的QML可以依赖于Component.onCompleted信号。该信号实际上适用于所有组件,无论它们是如何加载的。例如,整个应用程序的根组件可以在整个用户界面加载后使用它启动自己。

Connecting Indirectly

间接连接

When creating QML elements dynamically, you cannot connect to signals using the onSignalName approach used for static setup. Instead, the Connections element must be used. It connects to any number of signals of a target element.

动态创建QML元素对象时,无法使用静态设置的onSignalName方法连接到信号。相反,必须使用Connections元素类型。它连接到目标元素target的任意数量的信号。

Having set the target property of a Connections element, the signals can be connected, as usual, that is, using the onSignalName approach. However, by altering the target property, different elements can be monitored at different times.

设置了Connections元素类型的target属性后,可以像往常一样连接信号,即使用onSignalName方法。然而,通过改变目标属性target,可以在不同的时间监控不同的元素。

In the example shown above, a user interface consisting of two clickable areas is presented to the user. When either area is clicked, it is flashed using an animation. The left area is shown in the code snippet below. In the MouseArea, the leftClickedAnimation is triggered, causing the area to flash.

在上面显示的示例中,向用户呈现了一个由两个可单击区域组成的用户界面。单击任一区域时,都会使用动画进行闪烁。下面的代码片段显示了左侧区域。在鼠标区域MouseArea中,leftClickedAnimation被触发,导致该区域闪烁。

Rectangle {
    id: leftRectangle

    width: 290
    height: 200

    color: "green"

    MouseArea {
        id: leftMouseArea
        anchors.fill: parent
        onClicked: leftClickedAnimation.start();
    }

    Text {
        anchors.centerIn: parent
        font.pixelSize: 30
        color: "white"
        text: "Click me!"
    }
}

In addition to the two clickable areas, a Connections element is used. This triggers the third animation when the active, i.e. the target of the element, is clicked.

除了两个可点击的区域外,还使用了Connections元素类型。这会在单击活动对象(即元素的目标target)时触发第三个动画。

Connections {
    id: connections
    function onClicked() { activeClickedAnimation.start(); }
}

To determine which MouseArea to target, two states are defined. Notice that we cannot set the target property using a PropertyChanges element, as it already contains a target property. Instead a StateChangeScript is utilized.

为了确定MouseArea的目标,定义了两种状态。请注意,我们不能使用PropertyChanges元素设置目标属性target,因为它已经包含目标属性target。而是使用StateChangeScript。

states: [
    State {
        name: "left"
        StateChangeScript {
            script: connections.target = leftMouseArea
        }
    },
    State {
        name: "right"
        StateChangeScript {
            script: connections.target = rightMouseArea
        }
    }
]

When trying out the example, it is worth noticing that when multiple signal handlers are used, all are invoked. The execution order of these is, however, undefined.

在尝试该示例时,值得注意的是,当使用多个信号处理器时,所有信号都会被调用。然而,这些命令的执行顺序尚未确定。

When creating a Connections element without setting the target property, the property defaults to parent. This means that it has to be explicitly set to null to avoid catching signals from the parent until the target is set. This behavior does make it possible to create custom signal handler components based on a Connections element. This way, the code reacting to the signals can be encapsulated and re-used.

在不设置目标属性target的情况下创建Connections元素对象时,该属性默认为parent。这意味着必须将其显式设置为null,以避免在设置目标target之前捕获来自父级的信号。这种行为确实可以基于Connections元素类型创建自定义信号处理器组件。这样,对信号做出反应的代码就可以被封装和重用。

In the example below, the Flasher component can be put inside any MouseArea. When clicked, it triggers an animation, causing the parent to flash. In the same MouseArea the actual task being triggered can also be carried out. This separates the standardized user feedback, i.e. the flashing, from the actual action.

在下面的例子中,闪光灯组件Flasher可以放在任何鼠标区域MouseArea内。单击会触发动画,使父对象闪烁。在同一鼠标区域MouseArea中,也可以执行被触发的实际任务。这将标准化用户反馈(即闪烁)与实际操作分开。

import QtQuick

Connections {
	function onClicked() {
		// Automatically targets the parent
	}
}

To use the Flasher, simply instantiate a Flasher within each MouseArea, and it all works.

要使用闪光器Flasher,只需在每个MouseArea中实例化一个闪光器,就可以了。

import QtQuick

Item {
	// A background flasher that flashes the background of any parent MouseArea
}

When using a Connections element to monitor the signals of multiple types of target elements, you sometimes find yourself in a situation where the available signals vary between the targets. This results in the Connections element outputting run-time errors as signals are missed. To avoid this, the ignoreUnknownSignal property can be set to true. This ignores all such errors.

当使用连接元素类型Connections来监视多种类型的目标元素target的信号时,有时您会发现,在不同的目标之间,可用的信号会有所不同。这会导致Connections元素类型在信号丢失时输出运行时错误。为了避免这种情况,可以将ignoreUnknownSignal属性设置为true。这忽略了所有这些错误。

TIP

It is usually a bad idea to suppress error messages, and if you do, make sure to document why in a comment.

抑制错误消息通常是个坏主意,如果这样做,请确保在注释中记录原因。

Binding Indirectly

间接绑定

Just as it is not possible to connect to signals of dynamically created elements directly, nor it is possible to bind properties of a dynamically created element without working with a bridge element. To bind a property of any element, including dynamically created elements, the Binding element is used.

正如不可能直接连接到动态创建的元素的信号一样,也不可能在不使用桥接元素的情况下绑定动态创建的元素的属性。要绑定任何元素(包括动态创建的元素)的属性,可以使用绑定元素类型Binding

The Binding element lets you specify a target element, a property to bind and a value to bind it to. Through using a Binding element, it is, for instance, possible to bind properties of a dynamically loaded element. This was demonstrated in the introductory example in this chapter, as shown below.

Binding元素类型允许您指定目标元素、要绑定的属性和要绑定的值。例如,通过使用绑定元素,可以绑定动态加载的元素的属性。这在本章的介绍性示例中得到了演示,如下所示。

Loader {
    id: dialLoader

    anchors.left: parent.left
    anchors.right: parent.right
    anchors.top: parent.top
    anchors.bottom: analogButton.top

    onLoaded: {
        binder.target = dialLoader.item;
    }
}

Binding {
    id: binder

    property: "speed"
    value: speed
}

As the target element of a Binding not always is set, and perhaps not always has a given property, the when property of the Binding element can be used to limit the time when the binding is active. For instance, it can be limited to specific modes in the user interface.

由于绑定元素类型Binding的目标元素target并不总是被设置的,而且可能并不总是具有给定的属性,因此可以使用绑定元素Binding的when属性来限制绑定处于活动状态的时间。例如,它可以限制为用户界面中的特定模式。

The Binding element also comes with a delayed property. When this property is set to true the binding is not propagated to the target until the event queue has been emptied. In high load situations this can serve as an optimization as intermediate values are not pushed to the target.

Binding元素还带有延迟属性delayed。当此属性设置为true时,在清空事件队列之前,绑定不会传播到目标target。在高负载情况下,这可以作为优化,因为中间值不会推送到目标target

示例源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值