Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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
    Looks fine to me. Show slotOpenRecentFile(), and put in a qDebug() to prove it's not being fired.

    Please consider moving over to signal/slot new style syntax, it will make life/error checking easier.



  • @ademmler
    Your syntax is wrong, either

    QObject::connect(recentFileAction, SIGNAL(triggered()), this, SLOT(slotOpenRecentFile()));
    

    or

    QObject::connect(recentFileAction, &QAction::triggered, this, &YourCurrentClass::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....



  • @Bonnie
    Both suggestion are working perfectly - thx to you !!!

    @JonB
    Thx for clarification



  • @ademmler
    Purely OOI, with your original SIGNAL(&QAction::triggered) didn't you receive a runtime warning message (stderr, or debugger console) when it executed that connect()?

    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 the connect() 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() or SLOT() 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.



  • @JonB

    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 using sender() 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 their connect()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 via sender(). "Trust Me" ;-)



  • @JonB I trust you and try this out - thx


Log in to reply