I'm looking for how to input for Loader inside Component. Here is my problem.
// CustomSplitView.qml
import QtQuick 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.14
Pane {
function addItem(text, item) {
/**
Here is the problem part I think.
"headerText" is correctly applied to the 'template' object,
but "content" is not.
**/
splitView.addItem(template.createObject(null, {"headerText": text, "content": item}))
}
Component {
id: template
Pane {
property alias headerText: label.text
property alias content: loader.sourceComponent
ColumnLayout { anchors.fill: parent
Label { id: label }
Loader {
id: loader
Layout.fillWidth: true; Layout.fillHeight: true
sourceComponent: Rectangle { color: "Green" }
} // Loader
} // ColumnLayout
} // Pane
} // Component
SplitView {
id: splitView
anchors.fill: parent
} // SplitView
} // Pane
// Usage
Pane {
Component {
id: redRect
Rectangle { color: "Red" }
} // Component
Column { anchors.fill: parent
Button {
text: "add"
onClicked: customSplitView.addItem("RED", redRect.createObject())
} // Button
CustomSplitView { id: customSplitView }
} // Column
} // Pane
Result: When "add" button clicked, adding item inside of the split view has "RED" text but green rectangle appears, not red.
It's not a size issue. (detailed resizing code has been omitted for code simplicity) Any advise will helps a lot, for what I missed, or other approaches.
CodePudding user response:
Whenever you want to dynamically create (and, possibly destroy) components, I would highly recommend using a model with a delegate. This will implementation pain that you're getting with createObject
. With an appropriate structured ListModel
parameter passing becomes trivial:
import QtQuick
import QtQuick.Controls
Page {
header: Button {
text: "add"
onClicked: customSplitView.addItem("X", "lightsteelblue", 200, 300)
}
CustomSplitView {
id: customSplitView
}
}
// CustomSplitView.qml
import QtQuick
import QtQuick.Controls
Pane {
anchors.fill: parent
SplitView {
anchors.fill: parent
Repeater {
model: ListModel {
id: listModel
}
delegate: Rectangle {
SplitView.preferredWidth: w
SplitView.preferredHeight: h
color: col
Text {
anchors.centerIn: parent
text: txt
}
}
}
}
function addItem(txt, col, w, h) {
listModel.append( { txt, col, w, h } );
}
Component.onCompleted: {
addItem( "RED", "red", 200, 200 );
addItem( "GREEN", "green", 200, 200 );
addItem( "ORANGE", "orange", 200, 200 );
}
}
You can Try it Online!
CodePudding user response:
Thanks for insight of Stephen Quan, I could instantiate Component
type as an argument of function.
// CustomSplitView.qml
import QtQuick 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.14
Pane {
function addItem(text, component) {
listModel.append( {text, component} )
} // addItem
SplitView { id: splitView
anchors.fill: parent
Repeater {
model: ListModel { id: listModel } // ListModel
delegate: Pane {
property string _headerText: text /* input "text" */
property var _component: component /* input "component" */
ColumnLayout { anchors.fill: parent
Label { text: _headerText }
Loader { Layout.fillWidth: true; Layout.fillHeight: true
sourceComponent: _component
Component.onCompleted: sourceComponent.createObject()
} // Loader
} // ColumnLayout
} // Loader
} // Repeater
} // SplitView
} // Pane
// Usage
Window {
Component { id: rectComponent
Rectangle {
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
} // Rectangle
} // Component
Component { id: labelComponent
Label {
text: "Label " Math.random()
} // Label
} // Component
Pane { anchors.fill: parent
ColumnLayout { anchors.fill: parent
CustomSplitView { id: customSplitView
Layout.fillWidth: true; Layout.fillHeight: true
orientation: Qt.Horizontal
} // customSplitView
Button {
text: "Add"
onClicked: {
customSplitView.addItem(
"Label", Math.random() < 0.5 ? rectComponent : labelComponent)
} // onClicked
} // Button
} // ColumnLayout
} // Pane
} // Window
Now the "add" button generates random color of rectangle or random label randomly.