I have a situation which I need a component which holds a ListView of its own type. Here is a simplified version:
myComp.qml
import QtQuick
Item {
Text {
id: name
text: qsTr("Hello")
}
ListView{
model: 5
delegate: MyComp{}
}
}
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
MyComp{
}
}
qmldir.txt
MyComp 1.0 myComp.qml
After running this, I get recursive instantiation error
which is expected.
My main questions are:
As @Atmo mentioned in the comments, you cannot declare a type in itself. However, in your case, an infinite loop will not occur.
As far as I know, there are two options for solving your problem:
The simplest option is to use a Loader [1]. I also suggest using DelegateChooser to switch between delegates, as you don't need to use a Loader on all sub-items and write conditions, etc.
For example:
Group.qml
import QtQuick
import QtQuick.Controls
import Qt.labs.qmlmodels
Control {
id: control
property alias model: listview.model
padding: 5
DelegateChooser {
id: chooser
role: 'type'
DelegateChoice {
roleValue: 'data'
Control {
required property var modelData
padding: 5
contentItem: Row {
spacing: 5
Repeater {
model: modelData.data
Label {
required property string modelData
padding: 5
width: 35
text: modelData
background: Rectangle {
radius: 2; border { width: 1; color: '#ccc'}
}
}
}
}
background: Rectangle {
radius: 5
border { width: 1; color: '#eee'}
}
}
}
DelegateChoice {
roleValue: 'group'
Loader {
required property var modelData
source: 'Group.qml'
width: control.availableWidth
onLoaded: item.model = modelData.data
}
}
}
contentItem: ListView {
id: listview
implicitHeight: contentHeight
spacing: 5
delegate: chooser
}
background: Rectangle {
color: '#aafbf3dd'
radius: 5; border { width: 1; color: '#dcc896'}
}
}
And usage is like:
Group {
anchors.fill: parent
model: [
{type: 'data', data: [1,2,3]},
{
type: 'group',
data: [
{type: 'data', data: [4,5,6,7]},
{type: 'data', data: [8,9,10,11]},
{type: 'group', data: [{type: 'data', data: [12,13,14]}]},
]
},
]
}
Preview:
This is a cleaner approach, as it doesn't require a Loader, but it does require using multiple files, which is fine. Here is a simplified example:
Group.qml
import QtQuick
import QtQuick.Controls
Control {
id: control
property alias model: listview.model
padding: 5
property Component delegate: Item {}
contentItem: ListView {
id: listview
spacing: 5
implicitHeight: contentHeight
delegate: control.delegate
}
background: Rectangle {
color: '#aafbf3dd'
radius: 5; border { width: 1; color: '#dcc896'}
}
}
Delegate.qml (simplified version)
import QtQuick
import QtQuick.Controls
import Qt.labs.qmlmodels
DelegateChooser {
id: chooser
role: 'type'
DelegateChoice {
roleValue: 'data'
Row {
required property var modelData
spacing: 5
Repeater {
model: modelData.data
Label {
required property string modelData
text: modelData
}
}
}
}
DelegateChoice {
roleValue: 'group'
Group {
required property var modelData
width: ListView.view.parent.width - 10
model: modelData.data
delegate: chooser
}
}
}
The usage remains the same:
Group {
anchors.fill: parent
model: [ /* same data */ ]
delegate: Delegate {}
}
Preview: