c++qtqt5qgraphicsvieweventfilter

How to create Mouse right click menu option using eventFilter in Qt?


I have a QGraphicsView which contains many QGraphicsItem. If I click mouse right click on any QGraphicsItem, the item should get select and right menu options should appear and then I will choose one of the options among them.To do that I have installed eventFilter and through it, I am using ContextMenu to create right click menu. Right click menu are getting cretaed properly. But propblem is I am not getting how to connect them to some function so that I can write logic for it.

It means if I clicked on save option that particular QGraphicsItem should get select and I should be able to go to some function where I will write logic for saving.

bool myClass::eventFilter(QObject *watched, QEvent *event)
{
    switch(event->type())
    {
       case QEvent::ContextMenu:
       {
          QMouseEvent *mouseEvent = static_cast<QMouseEvent*> (event);
          menu = new QMenu(this);
          option = menu->addMenu("CopyOption");
          option->addAction("save");
          menu->exec(mouseEvent->globalPos());
          break;
       }
        default:
          break;
   }
}

Solution

  • In your approach you show a context menu when you have no information if any item is selected. It is rather bad idea. You don't want to show the context menu in any location of view. You have to check if a cursor mouse is over an item.

    Why not to derive from QGraphicsItem and just overload mousePressEvent method. Inside this method check if right button of mouse is clicked. If so, show context menu and test which action is clicked. Minimal code would be:

    class TItem : public QGraphicsItem
    {
        bool _selected = false;
    public:
        TItem(QGraphicsItem* parent = nullptr) : QGraphicsItem(parent) {}
        QRectF  boundingRect() const override { return QRectF(0,0,20,20); }
        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override {
            painter->fillRect(QRectF(0,0,20,20),_selected ? QColor(0,255,255) : QColor(255,255,0));
        }
        void mousePressEvent(QGraphicsSceneMouseEvent* e) override {
            QGraphicsItem::mousePressEvent(e);
            if (e->button() & Qt::RightButton) {
                QMenu menu;
                QAction* a1 = menu.addAction(QString("test1"));
                QAction* a2 = menu.addAction(QString("test2"));
                if(a2 == menu.exec(e->screenPos())) {
                    test2();
                    _selected = true;
                    update();
                }
            }
        }
        void test2() {
            QMessageBox::information(nullptr,"test2","test2");
        }
    };
    

    All the job with checking is an item is under mouse is done by QT, mousePressEvent is invoked only if it is necessary.


    Another approach would be override mousePressEvent on QGraphicsView. Inside which:

    1. get all items belonging to the scene
    2. iterate over them, checking if an item is under mouse -> QGraphicsItem has isUnderMouse method
    3. if any item is under mouse, create QMenu and show it
    4. check selected QAction, if it is save call a proper method which doing the save and mark the item as selected