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