3
votes

I want to create a QMenu that contains QAction objects that are checkable. Once an action is checked, it will fire and enable drawing of some 3D object. However, the number of 3D objects depends on what files to be loaded. Thus, this QMenu have dynamic number of QAction objects. Suppose we have 10 3D objects with names "1", "2", ... "10" and thus the QAction objects in the QMenu would be displayed as "1", "2", ... "10". When one of these are checked, 3D object of that name will be enabled to display.

Code to generate dynamic QAction objects:

QStringList labels = defaultScene->getLabels();
for(int i=0; i<labels.size(); i++){
     QAction* labelAction = new QAction(labels[i], this);
     labelAction->setToolTip("Trace Marker " + labels[i]);
     labelAction->setStatusTip("Trace Marker " + labels[i]);
     labelAction->setCheckable(true);
     traceMenu->addAction(labelAction);
}

My question is, how do I connect these QAction objects? Specifically, I have an array of bool in defaultScene that will be toggled as the QAction are toggled. How am I to know which QAction is firing? The SIGNAL of QAction on toggle only passes through a bool. Ideally, I would have a single function in defaultScene:

void toggleObject3D(int index){
     if(index >= 0 && index < visibleSize){
          visible[index] = !visible[index];
     }
}

So to make this work, I would need some sort of SIGNAL from traceMenu that would fire an int variable. I am unaware of such SIGNAL.

1

1 Answers

6
votes

You can use QSignalMapper (Link in the documentation)

The idea is to associate each QAction with an index, and then use the mapped(int) signal from QSignalMapper. Of course, we need to map the toggled signal.

So first, define your method toggleObject3D as a slot.

Then, when generating the instances of QAction, create the QSignalMapper and associate each action with it:

QStringList labels = defaultScene->getLabels();
QSignalMapper *mapper = new QSignalMapper(this);
for(int i=0; i<labels.size(); i++){
   QAction* labelAction = new QAction(labels[i], this);
   labelAction->setToolTip("Trace Marker " + labels[i]);
   labelAction->setStatusTip("Trace Marker " + labels[i]);
   labelAction->setCheckable(true);
   traceMenu->addAction(labelAction);

   // Map this action to index i
   mapper->setMapping(labelAction, i);
   // Associate the toggled signal to map slot from the mapper
   // (it does not matter if we don't use the bool parameter from the signal)
   connect(action, SIGNAL(toggled(bool)), mapper, SLOT(map()));
}

// Connect the QSignalMapper map() signal to your method
connect(mapper, SIGNAL(mapped(int)), this, SLOT(toggleObject3D(int)));

And it should work :)