【问题标题】:How to make some reusable QML object, which can inject another QML object?如何制作一些可重用的 QML 对象,它可以注入另一个 QML 对象?
【发布时间】:2016-09-21 09:38:50
【问题描述】:

如何制作一些可重用的 QML 对象,它可以注入另一个对象?

我曾经尝试过使用 ComponentLoader ,但似乎不是我想要的。 (它仍然封装了整个 QML 类型,缺乏弹性,难以重用)

使用示例:

Card.qml

import QtQuick 2.0
import QtQuick.Layouts 1.3

Rectangle {
    default property var innerObject
    property string titleText: "[Hello Untitled Title]"
    id: root
    color: "#fff"
    ColumnLayout {
        anchors.fill: parent
        Rectangle {
            id: header
            height: 10
            width: parent.width
            color: "#666"
            RowLayout {
                Text { text: titleText; color: "#fff" }
            }
        }

        // How to inject innerObject in here ?

    }
}

main.qml

import QtQuick 2.0
import QtQuick.Layouts 1.3

Card {
    titleText: "Image Information"
    ColumnLayout { /* .......*/ }   // innerObject
}

Card {
    titleText: "Image Viewer"
    Rectangle { /* .......*/ }      // innerObject
}

【问题讨论】:

标签: qt qml qqmlcomponent


【解决方案1】:

我链接的答案是这样的:

Main.qml

Card {
    titleText: "Image Viewer"
    innerObject: Rectangle {
        Component.onCompleted: {
            console.log(parent.objectName)
        }
    }
}

Card.qml

Rectangle {
    property string titleText: "[Hello Untitled Title]"

    default property alias innerObject : innercolumn.children


    id: root
    color: "#fff"
    ColumnLayout {
        id: innercolumn
        objectName: "column"
        anchors.fill: parent
        Rectangle {
            id: header
            height: 10
            width: parent.width
            color: "#666"
            RowLayout {
                Text { text: titleText; color: "#fff" }
            }
        }
    }
}

【讨论】:

  • 其实你完全不需要占位符项,直接default property alias innerObject: innerColumn.children
  • 至于default property 在“本地”使用它时没有启动它看起来像一个错误。应该没关系。
【解决方案2】:

我还想提出一个基于默认属性和重新设置的解决方案:

可以嵌入另一个Item的Item:

MyItem.qml

import QtQuick 2.7
import QtQuick.Layouts 1.2

Rectangle {
    id: root
    default property Item contentItem: null
    border {
        width: 1
        color: "#999"
    }
    ColumnLayout {
        anchors.fill: parent
        Rectangle {
            Layout.fillWidth: true
            height: 30
            color: "lightgreen"
        }
        Item {
            id: container
            Layout.fillWidth: true
            Layout.fillHeight: true
        }
    }
    onContentItemChanged: {
        if(root.contentItem !== null)
            root.contentItem.parent = container;
    }
}

可以如下使用:

main.qml

import QtQuick 2.7
import QtQuick.Window 2.0

Window {
    visible: true
    width: 600
    height: 600

    MyItem{
        width: 400
        height: 400
        anchors.centerIn: parent
        Text {
            text: "Hello!"
            anchors.centerIn: parent
        }
    }
}

但我仍然同意@ddriver 的观点,即Loader 是本案的最佳解决方案

【讨论】:

    【解决方案3】:

    您不必将Loader 与组件一起使用。你可以去:

    Loader {
       source: "Something.qml"
    }
    

    当源是可以同步加载的东西时,你可以直接使用加载器的item进行绑定之类的东西,而不用担心它是否被创建。如果您通过网络加载,则必须延迟绑定直到项目完成,并使用Binding 元素或Qt.binding() 以声明式或命令式的方式分别完成。

    在您的情况下,加载器将是合适的,并且内部动态对象的属性应该是Component。这样,您可以使用内联组件或现有源中的Qt.createComponent() 填充它。

    property Component innerObject
    ...
    innerObject: Component { stuff }
    ...
    innerObject: Qt.CreateComponent(source)
    

    当然,还有更高级的方法可以做到这一点,例如,我概述的“通用 QML 模型对象”here。它允许以声明式和命令式的方式快速轻松地创建任意数据结构树,并且由于对象也是一个模型,因此您可以直接使用列表视图或定位器元素与中继器来布局 gui,而无需每次都实际编写 UI 代码。

    此外,从您的 main.qml 代码示例中 - 一个 qml 文件中的根元素不能超过一个。

    编辑default property 方法实际上在将元素移动到其自己的 qml 文件时有效,所以基本上你也可以:

    default property alias innerObject: innerColumn.children
    

    其中innerColumn 是您的ColumnLayout 的ID。此外,innerObject 可以是任何合法名称,因为作为默认属性,它实际上不会被使用。

    还可以选择使用默认属性,这在根项仍需要有自己的子项但仍能够将声明性对象重定向为子项时很有用一个子对象:

    property alias content: innerColumn.children
    // and then
    content: [ Obj1{}, Obj2{}, Obj3{} ] // will become children of innerColumn
    

    【讨论】:

    • Card { titleText: "Image Viewer" data: Rectangle { Component.onCompleted: { console.log(parent.objectName) } } } 将打印内部对象名称,如果它在 Card.qml 中定义为默认属性别名数据:inner_space.data,其中 inner_space 是 Item { id: inner_space; objectName: "inner" }
    • @TeemuRisikko - 如果将其移动到单独的 qml 文件,它实际上可以工作。我从答案中删除了那部分。
    猜你喜欢
    • 2015-01-21
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 2021-03-22
    相关资源
    最近更新 更多