1

I have a Tree based on a QAbstractItemModel and a qml TreeView to display its content. Now I would like to have a two-part UI with the TreeView on the left and some input form for different fields from the model on the right. The input fields should be connected/mapped to the current/selected item in the TreeView.

In traditional QtWidget based code I was using QDataWidgetMapper for this, which worked reasonably well (and which looks even better in Qt5 now).

As a first prototype I was using two ListViews, setting the seconds delegate.height to the height of the listView and autoscrolling it.

ListView {
    id: listView2
    x: 300
    y: 146
    width: 263
    height: 160
    interactive: false
    flickableDirection: Flickable.VerticalFlick
    boundsBehavior: Flickable.StopAtBounds
    snapMode: ListView.SnapOneItem
    clip: true
    currentIndex: core.product.index
    //highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
    focus: true
    delegate: Item {
        width: parent.width
        height: listView2.height
        Row {
            id: row2
            spacing: 10

            Text {
                text: name
                anchors.verticalCenter: parent.verticalCenter
                font.bold: true
            }

            Text {
                text: type
                anchors.verticalCenter: parent.verticalCenter
                font.bold: true
            }

            Loader {
                source: {
                    if (model.type == "SingleGrasp") {
                        "SingleGrasp.qml"
                    } else {
                        "MultGraspTrans.qml"
                    }
                }
            }
        }
    }
    model: core.product.graspModel
}

Now I'm considering doing the same with a TreeView, but it looks like a hack. Which you can see here:

TreeView {
    id: leafView
    x: 300
    y: 146
    width: 263
    height: 160
    clip: true
    focus: true
    TableViewColumn {
        title: "Name"
        role: "name"
    }
    style: TreeViewStyle {
        branchDelegate: Item {}
        indentation: 0
    }

    rowDelegate: Item {
        height: styleData.selected ? leafView.height * 0.99 : 0
    }
    itemDelegate: Item {
        visible: styleData.selected
        x: 5
        width: parent.width
        height: leafView.height
        Row {
            id: row12
            spacing: 10

            Text {
                text: model.name
                anchors.verticalCenter: parent.verticalCenter
                font.bold: true
            }

            Text {
                text: model.type
                anchors.verticalCenter: parent.verticalCenter
                font.bold: true
            }

            Loader {
                source: {
                    if (model.type == "SingleGrasp") {
                        "SingleGrasp.qml"
                    } else {
                        "MultGraspTrans.qml"
                    }
                }
            }
        }
    }
    headerDelegate: Item {}

    model: myModel
    selection: treeView1.selection
    //treeView1 has  selection: SelectionModel{model: myModel}

    function autoExpand(index ) {
        print(index)
        var oneUp = index

        do {

            print(oneUp)
            oneUp = oneUp.parent
            expand(oneUp)
            print("do")
            print(oneUp)
            //print(oneUp.isValid)
        } while (myModel.indexIsValid(oneUp));

    }

    Component.onCompleted: treeView1.selection.currentChanged.connect(autoExpand)
}

Would coding a flattening QAbstractProxyModel that maps the currently selected Item to a QAbstractListModel-like model be more reasonable?

Simon Schmeißer
  • 324
  • 4
  • 12

1 Answers1

0

I considered solving this via QSortFilterProxyModel in C++ but there actually is a pure QML solution:

TreeView {
   id: myTreeView
   model: myModel
   selection: ItemSelectionModel{ model: myModel }
 }

DelegateModel {
    id: leafViewModel

    groups: [
        DelegateModelGroup {
            name: "current"
            includeByDefault: false
        }
    ]

    filterOnGroup: "current"

    model: myModel
    delegate: Flow{
        Text {
            text: model.name
        }
        TextField {
            id: normalTextField2
            text: model.name
            onEditingFinished: model.name = text
        }
    }
    property var currentIndex: myTreeView.selection.currentIndex

    property int prevIndex: 0

    onCurrentIndexChanged: {
        items.get(prevIndex).inCurrent = false
        rootIndex = currentIndex.parent
        items.get(currentIndex.row).inCurrent = true
        prevIndex = currentIndex.row
    }
}

ListView {
    model: leafViewModel
}
Simon Schmeißer
  • 324
  • 4
  • 12