How to pass a QString to a Qt slot from a QMenu via QSignalMapper or otherwise
Asked Answered
T

1

6

I have a QMenu with many submenus. These are dynamically created i.e. the names menus come from a db and created in a loop. Now i wanted to fire the same slot triggered() or similar when a menu is clicked, but i needed the QString menu name to be passed to slot so i could perform menu specific actions. I have tried this i.e. passing a QAction * to the triggered event and used setData but i am getting the run time error.

object::connect: No such signal QAction::triggered(QAction *)

for(int j=0; j<channelTypes[i].getNumChannels() ; j++){
        QAction *subMenuAct = subMenu->addAction(tr(c_name)); // c_name the menu name
        subMenuAct->setData(ch_name);
        connect(subMenuAct, SIGNAL(triggered(QAction *)), this, SLOT(playChannel(QAction *))); // playChannel is the slot
}

void <ClassName>::playChannel(QAction *channelAction)
{
     QString str = channelAction->data().toString();
    qDebug() << "Selected - " << str;
}

Alternately, i have also tried QSignalMapper where signalMapper is a data member initialized in the constructor

signalMapper = new QSignalMapper(this);

and

for(int j=0; j<channelTypes[i].getNumChannels() ; j++){
       QAction *subMenuAct = subMenu->addAction(tr(c_name));

       connect(subMenuAct, SIGNAL(triggered()), signalMapper, SLOT(map()));
       signalMapper->setMapping(subMenu, ch_name);
       connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(playChannel(QString)));
}

In the second case, i don't get any error, however the slot function playChannel is not being called. Would really appreciate if some one could help resolving it.

Update 1: The only difference that i see from other examples i have seen is that usually people are connecting signals from several widgets to a single slot (say different buttons). In my case i am connecting several sub menus (with different names) to a single slot. Should this make any difference?

Update 2: It worked after the correction suggested in the solution below for QSignalMapper. Also the fact that i was using SubMenu as argument to setMapping , where as MenuAction item should have been used instead. But now i am getting event fired multiple times i.e. as many times as there are entries in the main menu for the selected sub menu category. If channel type is English (main menu) with four entries), HBO, star movies etc. (sub menu), and i choose HBO, then event is fired four times with string HBO. It works fine if i create a separate signal mapper for each submenu. But i was hoping a single mapper should be used and i am doing something incorrectly here. Some more details in the comments to the answer.

Theologue answered 4/1, 2013 at 5:15 Comment(3)
You need to narrow down problematic code and post minimal code example that will reproduce the problem. Except that you don't need to connect signalMapper to a slot in every iteration, everything looks fine. Are you sure that you changed slot signature?Labyrinthodont
Thank you - these are two separate bare minimum code samples which reproduce the problem either way. I don't see a way to narrow it down. One tries via signal mapper where as the other used QAction *. First shows run time error and the second does not at all, but none works. And yes i am sure slot signature was changed for each of them i.e. QString in one case and QAction * in the other. If it is not the case, i run into compilation error.Theologue
Regarding connecting signalMapper in each iteration, how would i specify that each iteration of ch_name has a different name and should produce the same when selected from menu?Theologue
R
5

After adding the QAction to the menu, you only have to connect QMenu to the slot. You don't connect each action individually to the slot:

for(int j=0; j<channelTypes[i].getNumChannels() ; j++){
    ch_name = <name from the database for the channel j>;
    QAction *subMenuAct = subMenu->addAction(tr(ch_name));
    subMenuAct->setData(ch_name);
}

connect(subMenu, SIGNAL(triggered(QAction *)), 
        this, SLOT(playChannel(QAction *)), Qt::UniqueConnection);

As I don't know how you if you delete subMenu each time the dynamic menu is filled, the Qt::UniqueConnection ensure that the slot won't be reconnected multiple times.


For the signal mapper version, you should only connect the actions to the mapper in the loop. The connection from the mapper to the slot should only be done once.
for(int j=0; j<channelTypes[i].getNumChannels() ; j++){
   ch_name = <name from the database for the channel j>;
   QAction *subMenuAct = subMenu->addAction(tr(ch_name));
   connect(subMenuAct, SIGNAL(triggered()), signalMapper, SLOT(map()));
   signalMapper->setMapping(subMenuAct, ch_name);   
}
connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(playChannel(QString)));

And for that case, the slot playChannel should accept a QString instead of a QAction*.

Roper answered 4/1, 2013 at 12:47 Comment(4)
Thanks - One mistake on my part was signalMapper->setMapping(subMenu, ch_name); i.e. i was mapping on subMenu, not subMenuAct. Rest works, but now the issue was that signal is being called four times against a single click. To be clear, i have an outer loop which creates the main menu. The above posted loop is the inner loop with sub menus. For one selection of sub menu, event should be fired once, but it is called as many times as there are entries for that sub menu in the main.Theologue
Say if english channel has four different channel names, and i chose "HBO", it calls HBO four times, rather than one. Currently, it is resolved if i created multiple signal mappers with each mapper created in side the submenu loop, but i dont think this is the right way. Would appreciate if can be correctedTheologue
@fayyazkl You should move the last connect call outside any loop, and/or add Qt::UniqueConnection to the connect call to avoid multiple connections of the same signal to the same slot (if a connection is made N times, one trigger of the signal will call the slot N times).Roper
Thank you - that worked as well as improved my understanding of qt signals and slots.Theologue

© 2022 - 2024 — McMap. All rights reserved.