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

问题描述 投票:0回答:4

我有一个相当大的 Qml 组件,因此我想使其成为可重用的组件,但它太小/非通用,因此我想避免创建自己的 .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 对象的可重用性,同时仍然能够更改它们的属性。

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


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

qt qml components loader reusability
4个回答
4
投票

我认为您正在寻找

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"
        }
    }
}

2
投票

在Qt5.15中有一个新的内联组件语法:

component <component name> : BaseType {
    // declare properties and bindings here
}

在下面的示例中,我从

NormalText
定义
Text
,随后,从
HeadingText
定义
NormalText
,然后,我在同一个 QML 文件中使用它们:

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

Page {
    anchors.fill: parent
    component NormalText : Text {
        Layout.fillWidth: true
        font.pointSize: 12
        wrapMode: Text.WordWrap
    }
    component HeadingText : NormalText {
        font.pointSize: 14
        font.bold: true
    }
    ColumnLayout {
        width: parent.width
        HeadingText { text: "Introduction" }
        NormalText { text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." }
        NormalText { text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." }
    }
}

您可以在线尝试!

参考资料:


1
投票

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

如果组件被重用 - 即使在一个文件中,而不仅仅是通过

Repeaters
ListViews
等方式 - 您应该考虑创建一个单独的文件,以保持文件干净且可读。

如果您创建内联组件,然后通过

Loader
创建实例只是为了能够创建它们,它们会带来开销,如果组件确实很大,或者您确实需要,那么这是可以容忍的
Loader
表示动态更改源的可能性。否则,只会让一切变得复杂,并增加资源消耗。

将代码放入多个文件中几乎没有任何损失。因此,当您有一个合理的、逻辑上封闭的单元时,尤其是当您要在文件中多次重复使用它时。

当您计划将其用作

Component
时,请使用
delegate
。有些人喜欢在使用它的地方直接声明
delegate
。如果只有很少的属性需要设置,我就会这样做。
特别是如果您有多个共享相同
Views
原型的
delegate
,则最好使用
Component

如果您确实需要使用

Loader
(因为您需要
Loader
而不是用于非动态对象创建),那么您可以使用
Component
来避免需要
onLoaded
事件。它使您能够预配置组件,并设置事件处理程序,而无需
Connections
对象。

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

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

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


0
投票

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

所以你可以有一个

property Rectangle obj: null
,然后:

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

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

item.prop = Qt.binding(function() { bindingExpressions... })
© www.soinside.com 2019 - 2024. All rights reserved.