Search code examples
c++qtqgraphicsitem

QActions in QGraphicsSceneContextMenuEvent


I want to make a program that shows the info of a QGraphicsItem (width and height) by clicking the option "info" inside a context menu I created with the QGraphicsSceneContextMenuEvent. Right now I´m just trying to call a function with a qDebug in it called info.

Here's my code

dialog.h:

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include "QtCore"
#include "QtGui"
#include "mysquare.h"
namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QGraphicsScene *scene;
    MySquare *square;

};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"
#include <QWidget>

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    scene = new QGraphicsScene(this);
    ui->graphicsView->setScene(scene);

    square=new MySquare();
    scene->addItem(square);

}

Dialog::~Dialog()
{
    delete ui;
}

mysquare.h

#ifndef MYSQUARE_H
#define MYSQUARE_H
#include <QPainter>
#include <QGraphicsItem>
#include <QDebug>
#include <QMenu>

class MySquare: public QGraphicsItem
{

public:
    MySquare();
    QRectF boundingRect() const;
    void paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    QMenu *menu;
    QAction *heightAct;
    QAction *widthAct;
    QAction *color;

private slots:
    void info();

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
    void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);

};

#endif // MYSQUARE_H

mysquare.cpp

#include "mysquare.h"
#include<QMenu>
#include <string>
using namespace std;
MySquare::MySquare()
{

}

QRectF MySquare::boundingRect() const
{
    return QRectF(100,100,50,50);
}

void MySquare::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QRectF rec  = boundingRect();
    QBrush brushy(Qt::green);
    painter->fillRect(rec,brushy);
    painter->drawRect(rec);

}

void MySquare::info()
{
    qDebug()<<"HERE'S MY INFO!!!";
}


void MySquare::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{

    QString height = "Height: "+QString::number(boundingRect().height());
    QString width = "Width: "+QString::number(boundingRect().width());

    menu = new QMenu();
    heightAct = menu->addAction(height);
    widthAct = menu->addAction(width);
    color = menu->addAction("Change color");

    menu->exec(QCursor::pos());

}

Solution

  • To make a "link" between a click on an action in your menu and your slot info(), you need to use the signal/slot mechanism.

    You only have to add a QObject::connect(...) in your QMenu initialization.

    void MySquare::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
    {
        QString height = "Height: "+QString::number(boundingRect().height());
        QString width = "Width: "+QString::number(boundingRect().width());
    
        menu = new QMenu();
        heightAct = menu->addAction(height);
        widthAct = menu->addAction(width);
        color = menu->addAction("Change color");
    
        QObject::connect(heightAct, SIGNAL(triggered()), this, SLOT(info()));
    
        menu->exec(QCursor::pos());
    }
    

    However, the above code will not compile because signal/slot mechanism work only with subclasses of QObject and QGraphicsItem isn't. So you have to change it to a QGraphicsObject. (Don't forget the Q_OBJECT macro though)

    Also, a little out of subject:

    Use

    #include <QtCore>
    

    instead of

    #include "QtCore"
    

    but I really advise you to just include what you need, not the whole QtCore library.

    Also, put your includes in your source files instead of your header files except when it's impossible.

    Don't mix standard C++ library such as

    #include <string>
    

    except when it's absolutely needed. In this case you have to include

    #include <QString>
    

    And just simply remove

    using namespace std;