Search code examples
gridviewqmlqt6

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?


Solution

  • 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!