nsis
nsis

Reputation: 53

QML DelegateModel: Access DelegateModel from delegate

I'm trying to create a ListView with different delegates and a drag'n'drop functionality. The delegates shall be loaded with a Loader.

The QML Documentation provides a working example for a ListView without a Loader: http://doc.qt.io/qt-5/qtquick-tutorials-dynamicview-dynamicview3-example.html

However, using the Loader I get the error: Cannot read property 'DelegateModel' of undefined

I do not understand how I can access the DelegateModel from the Loader.

A hint to the solution is highly appreciated!

main.qml:

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Window 2.0
import QtQuick.Dialogs 1.1
import QtQml.Models 2.3

Window {
    id: mainroot

    visible: true
    width: 640
    height: 480

    Rectangle{
        id:viewContainer

        anchors.fill: parent

        DelegateModel {
            id: visualModel

            model: ListModel{
                id:m_model

                ListElement{
                    type:1
                    m_text :"Text1"
                }

                ListElement{
                    type:1
                    m_text :"Text2"
                }
            }

            delegate:        Loader{
                id:idLoader

                width: view.width
                height: childrenRect.height

                Component.onCompleted: {
                    switch(type){
                    case 1:
                        idLoader.setSource("TestDelegate.qml", {"m_text": m_text})
                        break;
                    }
                }
            }
        }

        ListView{
            id: view

            anchors.fill: parent
            spacing: 5

            model: visualModel
        }
    }
}

TestDelegate.qml:

    import QtQuick 2.7

MouseArea {
    id: dragArea

    property bool held: false
    property string m_text

    anchors { left: parent.left; right: parent.right }
    height: 50
    width: view.width

    drag.target: held ? content : undefined
    drag.axis: Drag.YAxis

    onPressAndHold: held = true
    onReleased: held = false

    Rectangle {
        id: content

        anchors {
            horizontalCenter: parent.horizontalCenter
            verticalCenter: parent.verticalCenter
        }
        width: dragArea.width
        height: textfield.implicitHeight


        Drag.active: dragArea.held
        Drag.source: dragArea
        Drag.hotSpot.x: width / 2
        Drag.hotSpot.y: height / 2

        border.width: 1
        border.color: "lightsteelblue"
        color: dragArea.held ? "lightsteelblue" : "white"
        Behavior on color { ColorAnimation { duration: 100 } }
        radius: 2
        states: State {
            when: dragArea.held

            ParentChange { target: content; parent: viewContainer }
            AnchorChanges {
                target: content
                anchors { horizontalCenter: undefined; verticalCenter: undefined }
            }
        }

        Text{
            id: textfield

            anchors.centerIn: parent
            text: m_text
        }

    }
    DropArea {
        anchors { fill: parent; margins: 10 }

        onEntered: {
            visualModel.items.move(
                    idLoader.item.drag.source.DelegateModel.itemsIndex,
                    idLoader.item.dragArea.DelegateModel.itemsIndex)
        }
    }
}

Upvotes: 2

Views: 2676

Answers (1)

eyllanesc
eyllanesc

Reputation: 243975

The items defined in the file loaded with Loader or in general with any other .qml file that is imported should not depend directly on the main file since the ids have a scope, it is better to expose properties, in your case:

╭------------------------------------------╮
|                   bool held        ------┿--->
|  TestDelegate     string m_text    ------┿--->
|  ============     DelegateModel md ------┿--->
|                   int index        ------┿--->
╰------------------------------------------╯

Considering the above, the solution is the following:

main.qml

import QtQuick 2.7
import QtQuick.Window 2.0
import QtQml.Models 2.3

Window {
    id: mainroot
    visible: true
    width: 640
    height: 480

    Rectangle{
        id:viewContainer
        anchors.fill: parent

        DelegateModel {
            id: visualModel
            model: ListModel{
                id:m_model
                Component.onCompleted: {
                    for(var i=0; i< 40; i++){
                        m_model.append({"type": 1, "m_text": "Text" + i})
                    }
                }
            }
            delegate:
                Loader{
                id: idLoader
                width: view.width
                height: childrenRect.height
                property int index: DelegateModel.itemsIndex
                onIndexChanged: if(status == Loader.Ready) idLoader.item.index = index
                Component.onCompleted: {
                    switch(type){
                    case 1:
                        idLoader.setSource("TestDelegate.qml", {
                                               "m_text": m_text,
                                               "index": index,
                                               "md": visualModel
                                           })
                        break;
                    }
                }
            }
        }
        ListView{
            id: view
            anchors.fill: parent
            spacing: 5
            model: visualModel
        }
    }
}

TestDelegate.qml

import QtQuick 2.7
import QtQml.Models 2.3

MouseArea {
    id: dragArea
    property bool held: false
    property string m_text
    property DelegateModel md: null
    property int index : -1;
    anchors { left: parent.left; right: parent.right }
    height: 50
    width: view.width
    drag.target: held ? content : undefined
    drag.axis: Drag.YAxis
    onPressAndHold: held = true
    onReleased: held = false
    Rectangle {
        id: content
        anchors {
            horizontalCenter: parent.horizontalCenter
            verticalCenter: parent.verticalCenter
        }
        width: dragArea.width
        height: textfield.implicitHeight
        Drag.active: dragArea.held
        Drag.source: dragArea
        Drag.hotSpot.x: width / 2
        Drag.hotSpot.y: height / 2
        border.width: 1
        border.color: "lightsteelblue"
        color: dragArea.held ? "lightsteelblue" : "white"
        Behavior on color { ColorAnimation { duration: 100 } }
        radius: 2
        states: State {
            when: dragArea.held
            ParentChange { target: content; parent: viewContainer }
            AnchorChanges {
                target: content
                anchors { horizontalCenter: undefined; verticalCenter: undefined }
            }
        }
        Text{
            id: textfield
            anchors.centerIn: parent
            text: m_text
        }
    }
    DropArea {
        anchors { fill: parent; margins: 10 }
        onEntered: {
            if(md !== null)
                md.items.move(drag.source.index, dragArea.index)
        }
    }
}

Upvotes: 1

Related Questions