tuspazio
tuspazio

Reputation: 213

Qt: Context menu / connect with parameters

I have a problem connecting context menu actions in Qt. I know there are plenty of similar questions around, nevertheless I couldn't find a solution yet.

I have a series of plots built using QCustomplot.

What I want to do is to create a context menu when right-clicking on the background of each plot listing all the signal present in the graph. By clicking an entry of this menu, the corresponding signal should be hidden (if currently visible) or made visible (if hidden).

Now, I've defined a class called PlotHandler of which I paste the relevant parts here below:

plotHandler.cpp

#include "plothandler.h"

PlotHandler::PlotHandler(QStringList groupNames, int startIdx, QWidget *parent) :
    QWidget(parent), scrolling(false), refreshing(true)
{
    pPlot = new QCustomPlot(this);
    pPlot->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(pPlot, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequest(QPoint)));
}

void PlotHandler::contextMenuRequest(QPoint pos)
{
    int i;
    QMenu *menu = new QMenu(this);
    for(i=0; i<pGroup->getDataLength(); i++)
        {
            QAction *menuEntry;
            menuEntry = new QAction(pPlot->graph(i)->name(), this);
            menuEntry->setProperty("graphIdx", i);
            menu->addAction(menuEntry);
            connect(menuEntry, SIGNAL(triggered()), this, SLOT(addRemoveGraph()));
        }
        menu->popup(pPlot->mapToGlobal(pos));    
}

void PlotHandler::addRemoveGraph()
{
    QAction *selectedSignal = qobject_cast<QAction *>(sender());
    int tmp = selectedSignal->property("graphIdx").toInt();

    if (pPlot->graph(tmp)->visible())
    {
        pPlot->graph(tmp)->setVisible(false);
    }
    else
    {
        pPlot->graph(tmp)->setVisible(true);
    }
}

plotHandler.h

class PlotHandler : public QWidget
{
    Q_OBJECT
public:
    explicit PlotHandler(QStringList groupNames, int startIdx, QWidget *parent = 0);
    QString groupRequested();

private:
    QCustomPlot *pPlot;

public slots:
   void contextMenuRequest(QPoint pos);
   void addRemoveGraph();
}

The menu is correctly showed with the right entries and when I click on an action addRemoveGraph is called. In debug it gives back the following message:

The inferior stopped because it triggered an exception. Stopped in thread 0 by: Exception at 0x5d6c2f9a, code: 0xc0000005: read access violation at: 0x0, flags=0x0.

trying to execute

int tmp = selectedSignal->property("graphIdx").toInt();

Could anyone point me towards the right direction?

Thanks in advance

Upvotes: 0

Views: 1802

Answers (2)

You use QObject::setProperty but QAction doesn't have a property named "graphIdx". When you attempt to read the "graphIdx" property from QAction you will always get an invalid QVariant.

int tmp = selectedSignal->property("graphIdx").toInt();
// tmp always is 0;

You can use QAction::setData if you need to store only one property. Otherwise, use QObject::setProperty to set a custom property on any QObject. QAction is a QObject.

Upvotes: 2

tuspazio
tuspazio

Reputation: 213

Here below the solution that solved the issue.

plotHandler.cpp

#include "plothandler.h"

PlotHandler::PlotHandler(QStringList groupNames, int startIdx, QWidget *parent) :
    QWidget(parent), scrolling(false), refreshing(true)
{
    pPlot = new QCustomPlot(this);
    pPlot->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(pPlot, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequest(QPoint)));
}

void PlotHandler::contextMenuRequest(QPoint pos)
{
    int i;
    QMenu *menu = new QMenu(this);
    for(i=0; i<pGroup->getDataLength(); i++)
        {
            QAction *menuEntry;
            menuEntry = new QAction(pPlot->graph(i)->name(), this);
            menuEntry->setData(i);
            menu->addAction(menuEntry);
        }

    connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(addRemoveGraph(QAction*)));    
    menu->popup(pPlot->mapToGlobal(pos));    
}

void PlotHandler::addRemoveGraph(QAction *selectedSignal)
{

    int tmp = selectedSignal->property("graphIdx").toInt();

    if (pPlot->graph(tmp)->visible())
    {
        pPlot->graph(tmp)->setVisible(false);
    }
    else
    {
        pPlot->graph(tmp)->setVisible(true);
    }
    pPlot->replot();
}

plotHandler.h

class PlotHandler : public QWidget
{
    Q_OBJECT
public:
    explicit PlotHandler(QStringList groupNames, int startIdx, QWidget *parent = 0);
    QString groupRequested();

private:
    QCustomPlot *pPlot;

public slots:
   void contextMenuRequest(QPoint pos);
   void addRemoveGraph();
}

Thanks everyone for your help.

Upvotes: 0

Related Questions