Multiple QAction and using sender() to get which got selected?
-
Howdy fellow QT'ers, hope your days are going well so far. Wonder if you experts know why I'm getting these results? I've been reading the QT docs for the past 3 days and not getting anywhere with my test app. I noticed that QT has the QMenu class to create menus and that's so cool. Is there a way to use QObject::sender() to get what menu selection was selected as it uses a set of QActions? I'm using Action01 and Action02 as my 2 menu choices, can getAction() get that info without literally using a parameter to set it and send it to other methods? I also see that the action variable gets a QAction returned with all sorts of info set in it, how can I pull that data out?
Thanks again and to many successful compiles!
void App::menu() { QMenu actionMenu("ActionMenu", this); QAction action01("Action01", this); QAction action02("Action02", this); connect(&action01, &QAction::triggered, this, [=]() {getAction(); }); connect(&action02, &QAction::triggered, this, [=]() {getAction(); }); actionMenu.addAction(&action01); actionMenu.addAction(&action02); actionMenu.exec(QCursor::pos()); } void App::getAction() { if (sender() != nullptr) { QAction* newAction = new QAction(sender()); QAction* action = qobject_cast<QAction*>(sender()); qDebug() << sender(); // returns QAction(0x47bcf699c0) qDebug() << newAction; // returns QAction(0x1db458dd800 text="" menuRole=TextHeuristicRole visible=true) qDebug() << action; // returns QAction(0x47bcf699c0 text="Action01" toolTip="Action01" menuRole=TextHeuristicRole visible=true) or QAction(0x47bcf699c0 text="Action02" toolTip="Action02" menuRole=TextHeuristicRole visible=true) qDebug() << action->data(); // returns QVariant(Invalid) } }
-
@Calicoder said in Multiple QAction and using sender() to get which got selected?:
connect(&action01, &QAction::triggered, this, = {getAction(); });
connect(&action02, &QAction::triggered, this, = {getAction(); });connect(&action01, &QAction::triggered, this, [&action01,=]() {getAction(action01); }); connect(&action02, &QAction::triggered, this, [&action02,=]() {getAction(action02); });
Also, adjust the void App::getAction() signature accordingly.
-
Hi,
When using a lambda like you do, yes you have to.
Otherwise connect triggered directly to the slot and use sender. -
@SGaist Ok I'm starting to see the bigger picture here, thanks. I always figured this type of connection does connect triggered directly to the slot?
connect(&action01, &QAction::triggered, this, [=]() {getAction(); }); connect(&action02, &QAction::triggered, this, [=]() {getAction(); });
-
SGaist is right. In this case, lamba is not needed. Simply use slot onActionClicked and
connect(&action01, &QAction::triggered, this, &App::onActionClicked);
connect(&action02, &QAction::triggered, this, &App::onActionClicked);make action01 and action02 global.
Inside onActionClicked simply compare
if (sender() ==action01 )
else if (sender() ==action02 )The following variables are not pointers?
QMenu actionMenu("ActionMenu", this);
QAction action01("Action01", this);
QAction action02("Action02", this);The right way to create them is
auto actionMenu = new QMenu ("ActionMenu", this);
auto action01 = new QAction ("Action01", this);
auto action02 = new QAction ("Action02", this); -
@Calicoder said in Multiple QAction and using sender() to get which got selected?:
directly to the slot
Would mean with no lambda, just method:
connect(&action01, &QAction::triggered, this, &ThisClass::getAction });
So no chance to pass your own parameters, and
ThisClass::getAction()
's signature must (more or less, it can have less parameters but not more) matchQAction::triggered
's signature.so I have to pass the action as a parameter to the getAction() method? Is there a way to avoid that, just curious?
What you would like is that all
connect()
s automatically pass the signalling object as the first parameter to any slot. But Qt takes a "minimal" approach, and just does not bother to do that. Often you don't need to know the signaller. When you do, in the old days you had to usesender()
, which has some issues; after C++ lambdas andconnect()
support for new-style syntax, if you want the signaller/sender do the lambda with the explicit parameter, that's just how it is. -
@JoeCFD said in Multiple QAction and using sender() to get which got selected?:
make action01 and action02 global.
Inside onActionClicked simply compare
if (sender() ==action01 )
else if (sender() ==action02 )But why use
sender()
now that we have lambdas? This approach has problems when the coder does choose to use a lambda to connect a signal to the slot, for whatever reason. -
@Calicoder said in Multiple QAction and using sender() to get which got selected?:
qDebug() << action->data(); // returns QVariant(Invalid)
Suppose you want to call a method with the value (here an int) of the QVariant for each action, you can do:
void App::menu() { QMenu actionMenu("ActionMenu"); QAction* action=actionMenu.addAction("Action01"); action->setData(1); action=actionMenu.addAction("Action02"); action->setData(2); connect(&actionMenu, &QMenu::triggered, [this] (QAction* a) { qDebug()<<a; getAction(a->data().toInt()); }); actionMenu.exec(QCursor::pos()); } void App::getAction(const int p) { qDebug()<<p; }
-