QTableView Right Mouse Button selects
-
I have a table view that is set up with ExtendedSelection and SelectRows.
My problem is that right clicking on the table selects the row which I believe it should not do. Certainly for most similar controls of which I am aware, RMB only raises the context menu for the row in question. It is my firm belief that this behaviour is incorrect, but accept that the Qt development team may consider otherwise.
This might seem trivial, but in the case in question, selection of a row results in actions which can potentially be quite time consuming, so I would very much like that RMB doesn't select.
Is there any way to change the behaviour so that RMB only results in the customContextMenuRequested(const QPoint&) signal being emitted without sub-classing QTableView?
If I need to subclass is it just the mousePressEvent handler I need to override?
Thank you,
David -
Hi!
There's a work-around using an
eventFilter
, it basically works as a switch.- if RMB-> do no select
- else -> select
Here's how:
#ifndef MYEVENTFILTER_H #define MYEVENTFILTER_H #include <QObject> #include <QDebug> #include <QEvent> #include <QMouseEvent> #include <QTableWidget> class myEventFilter : public QObject { Q_OBJECT public: myEventFilter (QObject *parent = nullptr) {} protected: bool eventFilter(QObject * obj, QEvent * event) override { //qDebug()<<obj<<event->type(); if(event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); //eventFilter is installed on table viewport, because mousePressEvents are not captured if the eventFilter is installed on the table directly //The table could be accessed using viewport->parent() QTableWidget *tableWidget = static_cast<QTableWidget*>(obj->parent()); //if it's an RMB event, disable selection if(mouseEvent->button() == Qt::RightButton) { tableWidget->setSelectionMode(QAbstractItemView::NoSelection); } //else, get it back to normal else { tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); } } return QObject::eventFilter(obj, event); } }; #endif // MYEVENTFILTER_H
I hope this helps.
-
Hi!
There's a work-around using an
eventFilter
, it basically works as a switch.- if RMB-> do no select
- else -> select
Here's how:
#ifndef MYEVENTFILTER_H #define MYEVENTFILTER_H #include <QObject> #include <QDebug> #include <QEvent> #include <QMouseEvent> #include <QTableWidget> class myEventFilter : public QObject { Q_OBJECT public: myEventFilter (QObject *parent = nullptr) {} protected: bool eventFilter(QObject * obj, QEvent * event) override { //qDebug()<<obj<<event->type(); if(event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); //eventFilter is installed on table viewport, because mousePressEvents are not captured if the eventFilter is installed on the table directly //The table could be accessed using viewport->parent() QTableWidget *tableWidget = static_cast<QTableWidget*>(obj->parent()); //if it's an RMB event, disable selection if(mouseEvent->button() == Qt::RightButton) { tableWidget->setSelectionMode(QAbstractItemView::NoSelection); } //else, get it back to normal else { tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); } } return QObject::eventFilter(obj, event); } }; #endif // MYEVENTFILTER_H
I hope this helps.
@Abderrahmene_Rayene
This is a reasonable/clever solution. However, you leave the table inNoSelection
state upon any right mouse click, and only restore it to previous mode on next (non-right) click. This may not be acceptable, e.g. after right-click the keyboard selection keys will no longer workNote that the above table assumes that the selection mode allows the operations. For instance, you cannot select items if the selection mode is
QAbstractItemView::NoSelection
.till next click is done.
What we really want is only temporary disablement of selection on this click. Maybe your right-click evet filter could handle the content menu without passing the click onto the underlying system which will select? But I am not offering code for this :) Or, maybe when right-click after setting
NoSelection
one could do aQTimer::singleShot(0)
(or other small number) which will restore theExtendedSelection
? -
@Abderrahmene_Rayene
This is a reasonable/clever solution. However, you leave the table inNoSelection
state upon any right mouse click, and only restore it to previous mode on next (non-right) click. This may not be acceptable, e.g. after right-click the keyboard selection keys will no longer workNote that the above table assumes that the selection mode allows the operations. For instance, you cannot select items if the selection mode is
QAbstractItemView::NoSelection
.till next click is done.
What we really want is only temporary disablement of selection on this click. Maybe your right-click evet filter could handle the content menu without passing the click onto the underlying system which will select? But I am not offering code for this :) Or, maybe when right-click after setting
NoSelection
one could do aQTimer::singleShot(0)
(or other small number) which will restore theExtendedSelection
?@JonB Thank you! That is a serious problem which I had not noticed.
and I made a quick fix , here it is:
bool eventFilter(QObject * obj, QEvent * event) override { qDebug()<<obj<<event->type(); if(event->type() == QEvent::ContextMenu) { QTableWidget *tableWidget = static_cast<QTableWidget*>(obj->parent()); //restore selection when contextMenu is called tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); } if(event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); //eventFilter is installed on table viewport, because mousePressEvents are not captured... //...if the eventFilter is installed on the table directly //The table could be accessed using viewport->parent() QTableWidget *tableWidget = static_cast<QTableWidget*>(obj->parent()); //if it's an RMB event, disable selection if(mouseEvent->button() == Qt::RightButton) { tableWidget->setSelectionMode(QAbstractItemView::NoSelection); } } return QObject::eventFilter(obj, event); }
Thank you for you feedback! any further feedback is appreciated!