Как сделать какой-нибудь объект QML многократного использования, который может внедрить другой объект QML?

Как сделать какой-нибудь объект 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 ответа

Решение

Ответ, который я связал, работает так:

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

Я также хочу предложить решение, основанное на свойствах по умолчанию и переопределении:

Предмет, который может встраивать другой предмет:

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 лучшее решение для этого случая

Это не обязательно, что вы используете Loader с компонентом. Вы можете просто пойти:

Loader {
   source: "Something.qml"
}

Когда источник может быть загружен синхронно, вы можете напрямую использовать загрузчик item для таких вещей, как привязки, не беспокоясь о том, создан он или нет. Если вы загружаете по сети, вам придется отложить привязки до завершения элемента и использовать либо Binding элемент или Qt.binding() сделать это соответственно в декларативном или императивном порядке.

В вашем случае загрузчик будет уместным, а свойство для внутреннего динамического объекта будет Component, Таким образом, вы можете заполнить его либо встроенным компонентом, либо Qt.createComponent() из существующего источника.

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

Конечно, есть даже более продвинутые способы сделать это, например, "универсальный объект модели QML", который я обрисовал здесь. Он позволяет быстро и легко создавать деревья произвольной структуры данных как декларативно, так и императивно, и поскольку объект также является моделью, вы можете напрямую использовать списочные представления или элементы позиционирования с повторителями для компоновки графического интерфейса без фактического написания кода пользовательского интерфейса каждый раз.

Кроме того, из вашего main.qml Пример кода - вы не можете иметь более одного корневого элемента в файле qml.

Изменить: default property Подход на самом деле работает, если элемент перемещается в его собственный файл qml, так что вы можете просто:

default property alias innerObject: innerColumn.children

где innerColumn это идентификатор вашего ColumnLayout, Также, innerObject может быть любым допустимым именем, поскольку в качестве свойства по умолчанию оно фактически не будет использоваться.

Существует также возможность не использовать свойство по умолчанию, что полезно, когда корневой элемент все еще должен иметь своих собственных дочерних элементов, но при этом иметь возможность перенаправлять декларативные объекты в качестве дочерних объектов подобъекта:

property alias content: innerColumn.children
// and then
content: [ Obj1{}, Obj2{}, Obj3{} ] // will become children of innerColumn
Другие вопросы по тегам