带鼠标区域或DropArea的ListView多选

ListView Multiple Selection With Mouse Area or DropArea

我想在 ListView 上进行多项选择。我可以使用 QT.modifier 的 control 或 shift 键来完成此操作。但是我想做的是我想通过用鼠标或触摸屏按住一个项目来启动选择。也就是说,当我按住一个项目时,ListView 将滚动并选择下一个项目。

import QtQuick 2.12
import QtQuick.Controls 2.12
    
ListView {
    id: control

    orientation: ListView.Horizontal

    add: Transition {
            NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 }
            NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: 400 }
    }

    displaced: Transition {
            NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }
    }

    focus: true
    Keys.onSpacePressed: model.insert(0, { "name": "Waypoint " + model.count })
   
    property int mulBegin: 0
       
    signal checkOne(int idx)
        
    signal checkMul(int idx)

    Connections{
        target: control
                
        onCheckOne: control.mulBegin=idx;
    }

    clip: true
         
    boundsBehavior: Flickable.StopAtBounds
        
    spacing: 2

    model: ListModel {}
    delegate: Rectangle{
        width: 100; height: 30
        border.width: 1
        radius:25
        Text {
            anchors.centerIn: parent
            text: name
        }
        id: item_delegate
                 
        property bool checked: false
        border.color: "gray"
        color: item_delegate.checked? "green" : "red"
        Connections{
            target: control
            onCheckOne: item_delegate.checked=(idx===index);
            onCheckMul: {
                                 
                if(idx>control.mulBegin){
                    item_delegate.checked=(index>=control.mulBegin&&index<=idx);
                }else{
                    item_delegate.checked=(index<=control.mulBegin&&index>=idx);
                }
            }
        }
        MouseArea{
            id: item_mousearea
            anchors.fill: parent
            onClicked: {
                                
                switch(mouse.modifiers){
                case Qt.ControlModifier:
                    item_delegate.checked=!item_delegate.checked;
                    break;
                case Qt.ShiftModifier:
                    control.checkMul(index);
                    break;
                default:
                    control.checkOne(index);
                    control.mulBegin=index;
                    break;
                }
            }
        }

    }

    ScrollBar.vertical: ScrollBar {
    }
}

您可以使用 onPositionChanged 处理程序,但我认为还有许多其他可能性。

我按照你的代码写了一个小例子。关键是将鼠标位置映射到 ListView.

中找到正确的元素
import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 600
    height: 600

    Rectangle {
        id: root
        width: 400
        height: 400

        ListView {
            id: control
            width: parent.width / 2
            height: parent.height
            anchors.right: parent.right

            property int mulBegin: 0

            signal checkOne(int idx)
            signal checkMul(int idx)

            Connections{
                target: control

                function onCheckOne(idx)
                {
                    control.mulBegin=idx;
                }
            }

            clip: true
            boundsBehavior: Flickable.StopAtBounds

            ListModel {
                id: myModel
                ListElement { number: "1"; extraData: "extra-1-" }
                ListElement { number: "2"; extraData: "extra{2}" }
                ListElement { number: "3"; extraData: "extra_3_" }
                ListElement { number: "4"; extraData: "extra*4*" }
                ListElement { number: "5"; extraData: "extra$" }
            }

            model: myModel

            delegate: Item {
                id: item_delegate
                width: control.width
                height: 50

                property bool checked: false

                Rectangle {
                    id: rect
                    width: control.width
                    height: 50
                    anchors.horizontalCenter: parent.horizontalCenter
                    anchors.verticalCenter: parent.verticalCenter

                    border.color: "gray"
                    color: item_delegate.checked? "green" : "red"
                    Connections{
                        target: control
                        function onCheckOne(idx) { item_delegate.checked=(idx===index); }
                        function onCheckMul(idx) {

                            if(idx>control.mulBegin){
                                item_delegate.checked=(index>=control.mulBegin&&index<=idx);
                            }else{
                                item_delegate.checked=(index<=control.mulBegin&&index>=idx);
                            }
                        }
                    }

                    Text {
                        anchors.centerIn: parent
                        text: number + " / " + extraData
                    }
                }

                MouseArea {
                    id: item_mousearea
                    anchors.fill: parent

                    onClicked: {

                        switch(mouse.modifiers){
                        case Qt.ControlModifier:
                            item_delegate.checked=!item_delegate.checked;
                            break;
                        case Qt.ShiftModifier:
                            control.checkMul(index);
                            break;
                        default:
                            control.checkOne(index);
                            control.mulBegin=index;
                            break;
                        }
                    }

                    onPressAndHold: {
                        // It is possible to do the same using the onPress handler
                        // but then it collides with the current ControlModifier functionality.
                        // In fact, due to the default case in the onClicked handler, it is not
                        // strictly necessary to implement this slot.
                        console.log("onPressAndHold: " + index)
                        control.checkMul(index)
                    }

                    onPositionChanged: {
                        console.log("onPositionChanged: " + index)

                        // map the coordinate
                        var point = mapToItem(control, mouse.x, mouse.y)

                        console.log("mouse position (x, y): " + mouse.x, mouse.y
                                    + " mapToItem (x, y): "
                                    + point.x,
                                    + point.y)

                        var item = control.childAt(point.x, point.y)

                        if(item)
                        {
                            var indexAtPoint = control.indexAt(point.x, point.y)
                            var itemAtIndex = control.itemAtIndex(indexAtPoint)

                            console.log("item found at index: " + indexAtPoint
                                        + " data from item model: " + itemAtIndex.ListView.view.model.get(indexAtPoint).extraData)

                            control.checkMul(indexAtPoint)
                        }
                    }

                    onReleased: {
                        // another option is to put here the code from onPositionChanged
                        // but it is actually a different approach with a different behaviour
                    }
                }
            }
        }
    }
}