New Coder
New Coder

Reputation: 33

How to get the event of clicking outside of QML GridView items in Qt6?

I want to implement deselecting the current selection by clicking outside of the GridView items. The following code works fine in Qt5. However,the click event cannot be obtained in Qt6.

import QtQuick
import QtQuick.Controls

ApplicationWindow {
id: root
width: 640
height: 480
visible: true
title: qsTr("Hello World")

ListModel {
    id: listModel
     ListElement {
         name: "Jim Williams"
     }
     ListElement {
         name: "John Brown"
     }
     ListElement {
         name: "Bill Smyth"
     }
     ListElement {
         name: "Sam Wise"
     }
 }

GridView {
    id: gridView
    anchors.fill: parent
    cellWidth: 80
    cellHeight: 80
    model: listModel

    MouseArea {
         z: -1
         anchors.fill: parent
         onClicked: {
             console.log("out clicked!")
             gridView.currentIndex = -1
        }
    }

     delegate: Item {
         id: wrapper
         width: gridView.cellWidth
         height: gridView.cellHeight

         Rectangle {
             anchors.fill: parent
             anchors.margins: 4
             color: wrapper.GridView.isCurrentItem ? "#009688" :"#3d3d3d"

             Text {
                 anchors.fill: parent
                 color: "white"
                 text: name
             }
         }

         MouseArea {
             anchors.fill: parent
             onClicked: {
                gridView.currentIndex = index
             }
         }
       }
   }
 }

In Qt5, I set the z of the first MouseArea to -1, which can achieve the effect I want. But this method is invalid in Qt6 and cannot respond to the clicked event of the first MouseArea. What should I do in Qt6?

Upvotes: 0

Views: 287

Answers (2)

Stephen Quan
Stephen Quan

Reputation: 25871

This is one of the weird places where TapHandler works better than MouseArea. By defining a TapHandler inside your GridView you will be notified when you are interacting in an area that's in your GridView but not on any of your delegates. I also move the MouseArea to inside your Rectangle so even the white edges between the delegates is now clicking thru to the TapHandler.

import QtQuick
import QtQuick.Controls
Page {
    ListModel {
        id: listModel
        ListElement { name: "Jim Williams" }
        ListElement { name: "John Brown" }
        ListElement { name: "Bill Smyth" }
        ListElement { name: "Sam Wise" }
    }
    
    GridView {
        id: gridView
        anchors.fill: parent
        cellWidth: 80
        cellHeight: 80
        model: listModel
        TapHandler {
            onTapped: {
                console.log("out clicked!")
                gridView.currentIndex = -1
            }
        }
        delegate: Item {
            id: wrapper
            width: gridView.cellWidth
            height: gridView.cellHeight
            Rectangle {
                anchors.fill: parent
                anchors.margins: 4
                color: wrapper.GridView.isCurrentItem ? "#009688" :"#3d3d3d"
                Text {
                    anchors.fill: parent
                    color: "white"
                    text: name
                }
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        gridView.currentIndex = index
                    }
                }
            }
        }
    }
}

You can Try it Online!

Upvotes: 1

Jürgen Lutz
Jürgen Lutz

Reputation: 796

You can use just on mouse handler in the GridView and handle selections there. First you map the mouse position to the GridView coordinate system. Then you lookup the index at this position.

GridView {
    id: gridView
    anchors.fill: parent
    cellWidth: 80
    cellHeight: 80

    model: listModel

    MouseArea {
        anchors.fill: parent
        onClicked: (mouse) => {
            console.log("grid clicked!");

            let posInGridView = Qt.point(mouse.x, mouse.y)
            let posInContentItem = mapToItem(gridView.contentItem, posInGridView)
            let index = gridView.indexAt(posInContentItem.x, posInContentItem.y)

            gridView.currentIndex = index;
        }
    }

    delegate: Item {
        id: wrapper
        width: gridView.cellWidth
        height: gridView.cellHeight

        Rectangle {
            anchors.fill: parent
            anchors.margins: 4
            color: wrapper.GridView.isCurrentItem ? "#009688" :"#3d3d3d"

            Text {
                anchors.fill: parent
                color: "white"
                text: name
            }
        }
    }
}

Upvotes: 0

Related Questions