How to connect "menu action" with existing slot programatically
-
Hi qt pros.
I try to add a menu entry programatically and connect this one with a slot.
I get the menu entry - but when I trigger the entry nothing happens.
pls give me a hint what's wrong in my code. thx in advance.QFileInfo fi(fileName); recentFileList.append(fileName); QAction* recentFileAction = new QAction(this); recentFileAction->setText(fi.baseName() +"."+ fi.suffix()); recentFileAction->setData(fileName); recentFileAction->setEnabled(true); ui->recentFilesMenu->addAction(recentFileAction); ui->recentFilesMenu->update(); QObject::connect(recentFileAction, SIGNAL(&QAction::triggered), this, SLOT(slotOpenRecentFile()));
-
-
@ademmler
Ah, yes, @Bonnie spotted it. You were mixing new & old style syntax attempt.Like I said, if you would change to the new style syntax as per his second solution --- don't ever use
SIGNAL
/SLOT()
macros and runtime behaviour --- you would have received a compile-time error and wouldn't have had to ask this question at all.... -
@ademmler
Purely OOI, with your originalSIGNAL(&QAction::triggered)
didn't you receive a runtime warning message (stderr, or debugger console) when it executed thatconnect()
?EDIT Ah, from https://doc.qt.io/qt-5/qobject.html#connect:
The function returns a QMetaObject::Connection that represents a handle to a connection if it successfully connects the signal to the slot. The connection handle will be invalid if it cannot create the connection, for example, if QObject is unable to verify the existence of either signal or method, or if their signatures aren't compatible. You can check if the handle is valid by casting it to a bool.
So the
connect()
return result should have told you it was invalid, and it's your responsibility to check, certainly if you're using the macros.This has inspired me to raise question https://forum.qt.io/topic/118029/connect-new-style-syntax-return-result ....
-
@JonB I did not got a runtime error.
Honestly I am really get confused by "old" and new" syntax and different styles of slots/signals ...
I have read this: https://wiki.qt.io/New_Signal_Slot_Syntax but still its a miracle to me.Would you tell me how to get informations like about the calling action (name, title, data) in the slot I call?
-
@ademmler
I edited my post above, when I came across that theconnect()
will have returned a "false" result at runtime which is your job to test, rather than issuing an error message.I don't know why you are confused, I find that link easy to understand. Look at @Bonnie's two different ways, and compare to your original "mixed" way. Simple rule: do not ever use
SIGNAL()
orSLOT()
macros! It won't compile till you have it right in your code then.Would you tell me how to get informations like about the calling action (name, title, data) in the slot I call?
If you mean you need to know the actual
QAction
, or some extra parameters from it, in the slot, for whatever purpose, you will want to use a C++ lambda for your slot, so that you can pass extra parameters to your method. In that link they show an example:connect( sender, &Sender::valueChanged, [=]( const QString &newValue ) { receiver->updateValue( "senderValue", newValue ); } );
Maybe also look at https://forum.qt.io/topic/96163/lambda-that-uses-signal-argument-to-connect-to-a-slot. Also an example in https://doc.qt.io/qt-5/signalsandslots.html#signals-and-slots-with-default-arguments
I know it looks a bit hairy, but this is what a C++ lambda looks like. You'll have to read up or look at other examples till you get the hang of it.
-
thx for your help again. I will have a look at it.
in the meantime I found this solution:
QObject* obj = sender();
QAction *action = qobject_cast<QAction *>(obj);
QString data = action->data().toString();
qDebug() <<"Action data: " << data; -
@ademmler
I know! But usingsender()
was really the only way to do it without using lambdas. I know it looks easier, but it's "naughty" :) I'm sure there will be references to this over the web. And actually it (quite possibly) will not work if the connection is using lambda. (And if you're not the only programmer you don't know how other people are doing theirconnect()
s to your slot.)As you please, but getting into the habit of using the lambda approach is better than
sender()
. Also you can do quite different things (pass different parameters, which you could not otherwise access) via lambda which you cannot viasender()
. "Trust Me" ;-)