Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I correctly handle mouse events in a QML TableView with overlapping mouse areas?

I've got a delegate attached to my TableViewColumn that contains a MouseArea. I use the MouseArea to detect double clicks on individual cells in the table, which allows me to show a TextField for editing purposes.

The problem is the delegate MouseArea blocks mouse events from propagating through to TableView. This means that the selection behaviour of TableView no longer works. Specifically, I have SelectionMode.ExtendedSelection enabled.

The MouseArea child item is simple and originally looked like this:

MouseArea{
    id: mousearea
    anchors.fill: parent
    onDoubleClicked: {
        showTextField()
    }
}

After consulting the documentation, it looked like this should work:

MouseArea{
    id: mousearea
    anchors.fill: parent
    propagateComposedEvents: true        // new
    onDoubleClicked: {
        showTextField()
    }
    onPressed: mouse.accepted = false    // new
}

Which it does, except now I cannot pick up double click events anymore (in MouseArea)! Which makes sense, as it states later in the documentation:

pressed(MouseEvent mouse)

When handling this signal, use the accepted property of the mouse parameter to control whether this MouseArea handles the press and all future mouse events until release. The default is to accept the event and not allow other MouseAreas beneath this one to handle the event. If accepted is set to false, no further events will be sent to this MouseArea until the button is next pressed.

There does not seem to be a way to capture mouse events for individual cells at the TableView level. It's my first day playing around with QML, so I might have missed something obvious here, but what are my options? Note I'm using PyQt.

like image 994
mohamedmoussa Avatar asked Mar 17 '17 05:03

mohamedmoussa


1 Answers

If it is only the the selection you want to achive you can set the selection manually:

TableView {
    id: tv
    itemDelegate: Item {
        Text {
            anchors.centerIn: parent
            color: styleData.textColor
            elide: styleData.elideMode
            text: styleData.value
        }
        MouseArea {
            id: ma
            anchors.fill: parent
            onPressed: {
                tv.currentRow = styleData.row
                tv.selection.select(styleData.row) // <-- select here.
            }
            onClicked: {
                console.log(styleData.value)
            }
        }
    }

    TableViewColumn {
        role: 'c1'
        title: 'hey'
        width: 100
    }
    TableViewColumn {
        role: 'c2'
        title: 'tschau'
        width: 100
    }
    model: lm
}

Right now I only select. But you can write your very own selection/deselection-logic.

You might also map from the TableView.__mouseArea to the delegate.

import QtQuick 2.7
import QtQuick.Controls 1.4

ApplicationWindow {
    id: appWindow
    width: 1024
    height: 800
    visible: true

    ListModel {
        id: lm
        ListElement { c1: 'hallo1'; c2: 'bye' }
        ListElement { c1: 'hallo2'; c2: 'bye' }
        ListElement { c1: 'hallo3'; c2: 'bye' }
        ListElement { c1: 'hallo4'; c2: 'bye' }
        ListElement { c1: 'hallo5'; c2: 'bye' }
        ListElement { c1: 'hallo6'; c2: 'bye' }
        ListElement { c1: 'hallo7'; c2: 'bye' }
        ListElement { c1: 'hallo8'; c2: 'bye' }
        ListElement { c1: 'hallo9'; c2: 'bye' }
    }

    TableView {
        id: tv
        itemDelegate: Item {
            id: mydelegate
            signal doubleclicked()
            onDoubleclicked: console.log(styleData.value)
            Text {
                anchors.centerIn: parent
                color: styleData.textColor
                elide: styleData.elideMode
                text: styleData.value
            }

            Connections {
                target: tv.__mouseArea
                onDoubleClicked: {
                    // Map to the clickposition to the delegate
                    var pos = mydelegate.mapFromItem(tv.__mouseArea, mouse.x, mouse.y)
                    // Check whether the click was within the delegate
                    if (mydelegate.contains(pos)) mydelegate.doubleclicked()
                }
            }
        }

        TableViewColumn {
            role: 'c1'
            title: 'hey'
            width: 100
        }
        TableViewColumn {
            role: 'c2'
            title: 'tschau'
            width: 100
        }
        model: lm
    }
}
like image 179
derM Avatar answered Nov 15 '22 01:11

derM