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

时间:2016-09-21 09:38:50

标签: qt qml qqmlcomponent

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

我曾试图使用Component& Loader,但似乎不是我想要的。 (它仍然封装了整个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
}

3 个答案:

答案 0 :(得分:3)

我还想建议一个基于默认属性和重新显示的解决方案:

可以嵌入另一个项目的项目:

<强> 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是本案的最佳解决方案

答案 1 :(得分:1)

您必须使用Loader与组件。你可以去:

Loader {
   source: "Something.qml"
}

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

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

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

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

另外,从您的main.qml代码示例 - qml文件中不能有多个根元素。

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

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

答案 2 :(得分: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" }
            }
        }
    }
}