I'm trying to make some qml components that are more general but have the flexibility of defaults but for items. Here are some example components
A.qml
import QtQuick 2.15
Rectangle {
property alias inner: inside.data
color: "red"
width: 40
height: 40
Item {
id: inside
}
}
B.qml
import shared.debug 1.0 as Debug
import QtQuick 2.15
Debug.A {
inner: Rectangle {
width: 30
height: 30
color: "blue"
}
}
C.qml
import shared.debug 1.0 as Debug
import QtQuick 2.15
Debug.B {
inner: Rectangle {
width: 20
height: 20
color: "black"
}
}
qmldir
module shared.debug
A 1.0 A.qml
B 1.0 B.qml
C 1.0 C.qml
Used here
Column {
spacing: 10
Debug.A {}
Debug.B {}
Debug.C {}
}
Im looking for a way to make the Debug.C show just the red and black squares, i understand why the blue is showing but i was hoping i could make a straight forward default and then have it be removed and overwritten when used by a child element.
Ive tried to make properties that dont use alias but thats the same problem. Ive also tried just hiding the original content but that feels roundabout in that the original items are still there just not visible.
CodePudding user response:
I would suggest using a Loader instead of an Item in A.qml:
import QtQuick 2.15
Rectangle {
property alias inner: inside.sourceComponent
color: "red"
width: 40
height: 40
Loader {
id: inside
}
}
Then you can replace that inside field with a Component of your choosing:
B.qml:
Debug.A {
inner: Component {
Rectangle {
width: 30
height: 30
color: "blue"
}
}
}
CodePudding user response:
The data
property is of type list<QtObject>
. It seems like binding to it multiple times will append.
Column {
spacing: 10
A { Component.onCompleted: console.log("A", inner.length) } // 0
B { Component.onCompleted: console.log("B", inner.length) } // 1
C { Component.onCompleted: console.log("C", inner.length) } // 2
}
Similar like making the alias to the data
property the default
which means all child items of component A
would be appended to the list.
component A: Rectangle {
default property alias inner: inside.data
color: "red"; width: 80; height: 80
Item {
id: inside
}
}
component B: A {
Rectangle { width: 40; height: 40; color: "blue" }
}
component C: B {
Rectangle { width: 20; height: 20; color: "black" }
}
To circumvent this you could make inner an Item
and bind it to the data or children property.
DANGER Keep in mind that this is a "hack". You should only use it if you know what you're doing. You can't add any other item into the inner Item
because the binding on data
will always overwrite it.
component A: Rectangle {
property Item inner
color: "red"; width: 80; height: 80
Item {
data: [inner]
}
}
component B: A {
inner: Rectangle { width: 40; height: 40; color: "blue" }
}
component C: B {
inner: Rectangle { width: 20; height: 20; color: "black" }
}
Column {
spacing: 10
A {}
B {}
C {}
}