Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. One method to handle all menu items?
Forum Updated to NodeBB v4.3 + New Features

One method to handle all menu items?

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 3 Posters 2.1k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    Publicnamer
    wrote on last edited by
    #1

    Currently the way that I'm aware to set up a menu callback is to connect it to a method e.g.

                        connect(action1, &QAction::triggered, this, &onMenuA); 
                        connect(action2, &QAction::triggered, this, &onMenuB);
    

    However I'm wondering, rather than create an onMenu callback for each and every menu item,
    how can I have one callback that handles all of them?
    i.e. how can I identify in my callback which menu item it was that was chosen by the user?
    Thanks.

    1 Reply Last reply
    0
    • P Offline
      P Offline
      Publicnamer
      wrote on last edited by
      #2

      To answer my own question, a slot method can call sender() to learn who "sent" the message (in OO parlance) i.e. who called the slot method.

      Using that you can get the QAction that was triggered:

              QAction *actionThatUserChose = qobject_cast<QAction *>(sender());
      

      Voila.

      JonBJ 1 Reply Last reply
      0
      • P Publicnamer

        To answer my own question, a slot method can call sender() to learn who "sent" the message (in OO parlance) i.e. who called the slot method.

        Using that you can get the QAction that was triggered:

                QAction *actionThatUserChose = qobject_cast<QAction *>(sender());
        

        Voila.

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #3

        @Publicnamer
        You can achieve it this way, but there are two alternatives.

        QSignalMapper Class:

        This class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object that sent the signal. Note that in most cases you can use lambdas for passing custom parameters to slots. This is less costly and will simplify the code.

        As mentioned there, instead of using this or your sender() approach which is frowned upon, the "modern" way of doing what you want is to use C++ lambdas for your connections, passing an additional parameter of the sender into the slot method:

        connect(action1, &QAction::triggered, this, [this, action1](bool checked = false) { onMenu(action1); }); 
        connect(action2, &QAction::triggered, this, [this, action2](bool checked = false) { onMenu(action2); }); 
        
        // slot definition
        void Class::onMenu(const QAction &action)
        {
        }
        

        Once you start using lambdas you will find you can do a lot more powerful/flexible things than via sender or signal mapper approaches.

        P 1 Reply Last reply
        2
        • M Offline
          M Offline
          mpergand
          wrote on last edited by
          #4

          All the actions in the same level (not submenus) can be connected in one shot.
          I'm using this:

          connect(menuBar, &QMenuBar::triggered, this, &Application::menuAction);
          
          JonBJ 1 Reply Last reply
          1
          • M mpergand

            All the actions in the same level (not submenus) can be connected in one shot.
            I'm using this:

            connect(menuBar, &QMenuBar::triggered, this, &Application::menuAction);
            
            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by
            #5

            @mpergand
            I didn't know about this. I see it says:

            Normally, you connect each menu action to a single slot using QAction::triggered(), but sometimes you will want to connect several items to a single slot (most often if the user selects from an array). This signal is useful in such cases.

            and I see it passes the triggering QAction as a parameter to the slot. This is good. Whether the OP uses this or the lambda approach those are the best way to get at the trigger.

            1 Reply Last reply
            0
            • M Offline
              M Offline
              mpergand
              wrote on last edited by
              #6

              @JonB To go a little bit further.
              When you use lambda, it's useless to call another function like onMenu(), because you lose the kind of action is it !
              Why not doing this:

              action=menu->addAction(tr("Copy"));
              action->setShortcut(QKeySequence::Copy);
              connect(action, &QAction::triggered, [this, action]() { // do copy here}); 
              
              JonBJ 1 Reply Last reply
              0
              • M mpergand

                @JonB To go a little bit further.
                When you use lambda, it's useless to call another function like onMenu(), because you lose the kind of action is it !
                Why not doing this:

                action=menu->addAction(tr("Copy"));
                action->setShortcut(QKeySequence::Copy);
                connect(action, &QAction::triggered, [this, action]() { // do copy here}); 
                
                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by
                #7

                @mpergand
                I named it onMenu() purely because that is what the OP was using in his code.

                Of course you could do the specific action in each lambda. Just as the OP could have written separate slots for each QAction. But that was not his question, which (as per the title) is "One method to handle all menu items?". He perhaps has many related items which he wants to channel through some shared code.

                1 Reply Last reply
                0
                • JonBJ JonB

                  @Publicnamer
                  You can achieve it this way, but there are two alternatives.

                  QSignalMapper Class:

                  This class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object that sent the signal. Note that in most cases you can use lambdas for passing custom parameters to slots. This is less costly and will simplify the code.

                  As mentioned there, instead of using this or your sender() approach which is frowned upon, the "modern" way of doing what you want is to use C++ lambdas for your connections, passing an additional parameter of the sender into the slot method:

                  connect(action1, &QAction::triggered, this, [this, action1](bool checked = false) { onMenu(action1); }); 
                  connect(action2, &QAction::triggered, this, [this, action2](bool checked = false) { onMenu(action2); }); 
                  
                  // slot definition
                  void Class::onMenu(const QAction &action)
                  {
                  }
                  

                  Once you start using lambdas you will find you can do a lot more powerful/flexible things than via sender or signal mapper approaches.

                  P Offline
                  P Offline
                  Publicnamer
                  wrote on last edited by
                  #8

                  @JonB said in One method to handle all menu items?:

                  connect(action1, &QAction::triggered, this, [this, action1](bool checked = false) { onMenu(action1); });

                  Thanks, that helps.
                  I do need the onMenu call as it happens, because there is a lot that I need to do in response to the menu invocation and putting it all in a lambda would be unseemly. Just curious what is the checked parameter for? I omitted it and things work fine.

                  JonBJ 1 Reply Last reply
                  0
                  • P Publicnamer

                    @JonB said in One method to handle all menu items?:

                    connect(action1, &QAction::triggered, this, [this, action1](bool checked = false) { onMenu(action1); });

                    Thanks, that helps.
                    I do need the onMenu call as it happens, because there is a lot that I need to do in response to the menu invocation and putting it all in a lambda would be unseemly. Just curious what is the checked parameter for? I omitted it and things work fine.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #9

                    @Publicnamer said in One method to handle all menu items?:

                    putting it all in a lambda would be unseemly

                    Absolutely! You can write a multiline lambda as big as you like, but I keep them to one line, calling some other method to do big stuff but with whatever extra parameters I need from any variables where the connect() appears.

                    Just curious what is the checked parameter for? I omitted it and things work fine.

                    You obviously have never noticed, but the QAction::triggered signal actually passes this: void QAction::triggered(bool checked = false):

                    If the action is checkable, checked is true if the action is checked, or false if the action is unchecked.

                    I only put it in in case you were using it, to match the original signal signature. Here I could have omitted it, and I received the parameter in my lambda but didn't actually bother to pass it onto onMenu(). I too would probably have left it out here.

                    1 Reply Last reply
                    0

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved