PDA

View Full Version : QSignalMapper



Cremers
24th July 2013, 13:32
Hello,
I'm trying to make a menu with items that are checkable and send them to one slot:
This seemed to work but crashes the dialog when it's closed.


Diagram::Diagram(QWidget *parent) :
QDialog(parent)
{
menuBar = new QMenuBar(this);
planetsMenu = menuBar->addMenu("Planets");
QSignalMapper *mapper = new QSignalMapper(this);
for (int i = 0; i < 16; i++)
{
planet1Act[i] = new QAction(planetname[i], this);
planet1Act[i]->setCheckable(true);
mapper->setMapping(planet1Act[i], i);
connect(planet1Act[i], SIGNAL(toggled(bool)), mapper, SLOT(map()));
planetsMenu->addAction(planet1Act[i]);
}
connect(mapper, SIGNAL(mapped(int)), this, SLOT(toggleplanet(int)));
}
//---------------------------------------------
void Diagram::toggleplanet(int n)
{
QDebug()<< planet1Act[n]->isChecked()<<n;
}
//---------------------------------------------


This works but crashes afterwards, what am I doing wrong?

If I don't use an array for the actions:


for (int i = 0; i < 16; i++)
{
planet1Act = new QAction(planetname[i], this);
planet1Act->setCheckable(true);
mapper->setMapping(planet1Act, i);
connect(planet1Act, SIGNAL(toggled(bool)), mapper, SLOT(map()));
planetsMenu->addAction(planet1Act);
}
connect(mapper, SIGNAL(mapped(int)), this, SLOT(toggleplanet(int)));
}
//---------------------------------------------
void Diagram::toggleplanet(int n)
{
// how to get to the checked state of qaction number n ??
}


This works fine but then I don't know how I can see if the action is checked or not in toggleplanet() since the slot can only have one int or object etc. I don't know how to get to the corresponding action from that one int.

If it were checkboxes or something, I could get to them in toggelplanet() but how do I get to the actions?

Thanks for helping.

anda_skoa
24th July 2013, 14:54
Do you get any indication on the crash of your first code?

Anyway, one other option you have is to connect all actions to one slot directly and use QObject::sender() in the slot to get at the action which emitted the signal.

Cheers,
_

Cremers
24th July 2013, 15:12
Do you get any indication on the crash of your first code?
None.


Anyway, one other option you have is to connect all actions to one slot directly and use QObject::sender() in the slot to get at the action which emitted the signal.


I have a workaround, but surely there must be a better way.


for (int i = 0; i < PLANETS; i++)
{
planet1Act = new QAction(planetname[i], this);
planet1Act->setCheckable(true);
planet1Act->setWhatsThis(QString("%1").arg(i)); // put the number of the action into this qstring
.. etc

void Diagram::toggleplanet(QObject *w)
{
QAction *action = qobject_cast<QAction*>(w);
QDebug()<<action->whatsThis()<<action->isChecked();
}

Cremers
25th July 2013, 08:01
void Diagram::toggleplanet(int n)
{
// how to get to the checked state of qaction number n ??
}


Solution is QMenu::actions().at(n)->isChecked();

yeye_olive
25th July 2013, 16:10
None.


I have a workaround, but surely there must be a better way.


for (int i = 0; i < PLANETS; i++)
{
planet1Act = new QAction(planetname[i], this);
planet1Act->setCheckable(true);
planet1Act->setWhatsThis(QString("%1").arg(i)); // put the number of the action into this qstring
.. etc

void Diagram::toggleplanet(QObject *w)
{
QAction *action = qobject_cast<QAction*>(w);
QDebug()<<action->whatsThis()<<action->isChecked();
}


Please don't do that. There are better ways. You could subclass QAction to add an integer field that carries the information you need, but your original solution using QSignalMapper is quite elegant. We cannot help you more without seeing your whole program. What is the lifetime of the planet1Act array? Does the QDebug() give the expected output?

anda_skoa
25th July 2013, 21:54
You could subclass QAction to add an integer field that carries the information you need

QAction has setData() for that

Cheers,
_