[Solved] QAction + QMenu: How to trigger the menu from within the code?



  • You can set a popup-menu for a QAction (e.g. for when it is in a toolbar) via "QAction::setMenu":http://qt-project.org/doc/qt-5.1/qtwidgets/qaction.html#setMenu .

    In my case the action itself is pretty useless, so I want the menu to show up even when the action is triggered, not only that little arrow next to it. Just calling exec() for its menu doesn't position it properly, though. Is there some way to either get the global position of the action, or directly trigger that arrow (I assume that's a QAction on its own)?



  • menu.exec(event->globalPos());
    use this command it will position the menu at the point of click



  • Sorry, but that doesn't help. I don't have an event, and even if I had: globalPos() is not the correct position. If I click the little menu-arrow next to the action, it is positioned exactly where you would expect it. And that position is not the same as globalPos() in nearly all cases.

    And just to be clear: I tried using QCursor::pos(), but it has the same problems event->globalPos() has.



  • well i actually used a context menu event and it works in that case so maybe it is for that only


  • Moderators

    when i understood you right you want to open the sub-menu on click on the action. So no event and no position is involved.

    But why do you want to do this? This is against the default behavior and may not be what the user expects.
    And as you said the action is useless in the first place, why do you want it to be included at all then?



  • The action itself is useless, it's popup-menu isn't. So I want the action to trigger said menu, like the small arrow next to the action does.


  • Moderators

    sry..my fault...i thought we are talking about a context menu.

    What happens when you do this (once after you've added the action to the toolbar):
    @
    QWidget * widget = toolBar->widgetForAction ( action );
    QToolButton* button = qobject_cast<QToolButton*>(widget);
    if( button )
    {
    connect( action, SIGNAL(triggered(bool)), button, SLOT(showMenu()) );
    }
    @



  • The action is added dynamically, so I can't really pinpoint when or where it is added.
    To me this feels like an insufficiency of Qt, since every action has a trigger() slot, but not a "showMenu()" slot (in case it has a menu).

    Is there any other "standard behavior" I could implement for the action? As it is now, it looks like button, it acts like a button, but it doesn't do anything.


  • Moderators

    [quote author="thEClaw" date="1381844627"]
    To me this feels like an insufficiency of Qt, since every action has a trigger() slot, but not a "showMenu()" slot (in case it has a menu).[/quote]
    Not in my opinion. The QAction design is abstract. The specific behavior depends on how you visualize the action. The action is displayed as a QToolButton in a QToolBar. And as an menu item in QMenu.

    Ok ... other approach then. Subclass QToolBar and reimplement the actionEvent() handler.
    @
    void MyToolBar::actionEvent( QActionEvent* event )
    {
    QToolBar::actionEvent(event);

    if( event->type() == QEvent::ActionAdded )
    {
         QAction* action = event->action();
         QWidget * widget = toolBar->widgetForAction ( action );
         QToolButton* button = qobject_cast<QToolButton*>(widget);
         if( button )
         {
              connect( action, SIGNAL(triggered(bool)), button, SLOT(showMenu()) );
          }
    }
    

    }
    @

    If you only want to do this for a specific action you can set a property to the action and check for the property before doing the connection, or use QAction's data-property.



  • That idea was great, thanks a lot!

    I did the connection like this in the end:
    @connect(button, &QToolButton::clicked, button, &QToolButton::showMenu);@

    since the action may be part of different widgets, but overall this seems to work great. Thanks once more, on to the next problem! ;)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.