Qt QML:可重用对象的文件内定义

Qt QML: in-file definition of reusable objects

我有一个相当大的 Qml 组件,因此我想使它成为一个可重用的组件,但它太大 small/non-generic 以至于我想避免创建自己的 .qml 文件。 似乎组件是在同一个文件中定义可重用对象的正确方法,但是当我这样做时,我不知道如何访问和更改所包含对象的属性。

更具体地说,想象一下有这样一个文件内定义

Component {
id: myReusableComponent
// This cannot be set because component does not allow properties
// (Would work fine in a separate file myReusableComponent.qml)
// property alias string innerText: innerText.text
Rectangle {
    id: rect
    width: 200
    height: 200
    color: "red"
    Text {
        id: innerText
        text: "Want to set text later"
    }
}

我以后如何重用这个组件,同时改变它的一些属性? 我知道以下语法无效,但我想像这样使用它:

Loader {
id: hello
sourceComponent: myReusableComponent
item.innerText: "Hello" }

Text { text: "Some other stuff in between" }

Loader {
id: world
sourceComponent: myReusableComponent
item.anchors.left: hello.right
item.rect.width: 100
item.rect.color: "blue"
item.innerText: "World" }

Loader {
id: excl
sourceComponent: myReusableComponent
item.rect.color: "green"
item.innerText: "!!!" }
etc...

有什么想法吗?还是有根本不同的方式来做到这一点?
我本质上想要的是就地定义的 QML 对象的可重用性,同时仍然能够更改它们的属性。

好像有关系但是没有解决创建多个对象的问题。中继器似乎很有用,但没有给我想要的灵活性。


注意:我将在此处添加一些关于答案的评论,因为它们可能会在评论中被忽略。 我喜欢 Blabbouze、derM 和 ddriver 的所有三个答案! 我接受了 Blabbouze 的回答,因为它提供了一个最接近我所寻找的具体解决方案。 但是,我也不知道 Loaders 的开销,可能会在阅读 derM 的回答后考虑使用不同的方法。 最后,ddriver 建议的动态对象创建并不是我想要的,但可能对其他人有用。 谢谢大家!

我认为您正在寻找 onLoaded() 信号。当 Loader 成功创建 Component.

时发出

然后您可以使用 item 访问您加载的类型属性。

import QtQuick 2.7
import QtQuick.Controls 2.0


ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")


    Component {
        id: myReusableComponent
        Rectangle {
            id: rect
            property alias innerText: innerText.text

            width: 200
            height: 200
            color: "red"
            Text {
                id: innerText
                text: "Want to set text later"
            }
        }
    }


    Loader {
        id: hello
        sourceComponent: myReusableComponent
        onLoaded: {
            item.innerText = "hello"
        }
    }

    Loader {
        id: world
        sourceComponent: myReusableComponent
        anchors.left: hello.right
        onLoaded: {
            item.width =  100
            item.color =  "blue"
            item.innerText =  "World"
        }
    }
}

您也可以尝试对组件使用动态对象创建。

所以你可以有一个property Rectangle obj: null,然后:

Component.onCompleted: {
  obj = myReusableComponent.createObject(parentItem, {"width" : 100, "color" : "blue" }
}

除了 Blabbouze 的回答之外,除了作业(不会自动更新为绑定)之外,如果您使用以下格式,您还可以拥有绑定:

item.prop = Qt.binding(function() { bindingExpressions... })

首先我会尝试解释为什么你不想这样做

如果组件被重用 - 即使在一个文件中,而不仅仅是通过 RepeatersListViews e.t.c - 你应该考虑创建一个单独的文件,以保持你的文件干净且可读。

如果您创建内联组件,然后通过 Loader 创建实例只是为了能够创建它们,它们会带来开销,如果组件确实是可以容忍的巨大的,或者你真的需要 Loader 来动态更改源的可能性。否则,它只会帮助您使一切变得复杂,并增加资源消耗。

将代码放到多个文件中几乎没有任何惩罚。所以这样做,当你有一个合理的、逻辑上封闭的单元时——尤其是当你要在一个文件中多次重复使用它时。

如果您打算将其用作 delegate,请使用 Component。有些人喜欢直接在使用它的地方声明 delegate 。如果要设置的属性很少,我会这样做。
特别是如果你有多个 Views 共享相同的 delegate-prototype,使用 Component.

是个好主意

如果你真的需要使用 Loader(因为你需要 Loader 而不是为了创建非动态对象)那么你可以使用 Component 来避免onLoaded 事件的需要。它使您能够 预配置 组件,并在不需要 Connections-Object 的情况下设置事件处理程序。

好的 - 现在对您问题的简短回答
您可以通过多种方式创建组件的实例:

  • 加载器
  • 视图(ListView、GridView、Repeater ...)
  • 在任何可以执行 JS 代码的地方使用 JS (componentID.createObject(parent)) 创建动态对象。

阅读:http://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html#creating-objects-dynamically