Results 1 to 13 of 13

Thread: QToolButton: Menu in setMenu() overriding actions set in addAction!

  1. #1
    Join Date
    Jul 2007
    Posts
    35
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default QToolButton: Menu in setMenu() overriding actions set in addAction!

    Hi,
    I see this message every time I show a menu inside a QToolButton in a QToolBar:
    QToolButton: Menu in setMenu() overriding actions set in addAction!

    What I want to do is a button which can change function (to switch the selection mode of a QGraphicsView).
    In the code there is tool button for "scroll" mode and a tool button for "select" mode wich contains a menu with "select intersected" and "select contained".
    All the 3 actions are mutually exclusive.
    The code works very well and does exactly what I needed, but I don't like that message which is shown each time I click to show the menu (not when I click an action).

    Here is the code used to create them:
    Qt Code:
    1. // Create the toolbar
    2. m_selectionToolbar = new QToolBar;
    3. m_selectionToolbar->setOrientation(Qt::Horizontal);
    4. m_selectionToolbar->setWindowTitle(tr("Selection toolbar", "Toolbar"));
    5.  
    6. // Group mutually exclusive actions
    7. QActionGroup *actionGroup = new QActionGroup(this);
    8.  
    9. // Use mouse to scroll the view
    10. m_actionScrollHand = new QAction(actionGroup);
    11. m_actionScrollHand->setCheckable(true);
    12. m_actionScrollHand->setText(tr("&Scroll", "Action"));
    13. m_actionScrollHand->setStatusTip(tr("Drag to scroll the draw area", "Action"));
    14. m_actionScrollHand->setIcon(QIcon(":/images/move.png"));
    15. connect(m_actionScrollHand, SIGNAL(triggered()), this, SLOT(actionScrollHand_triggered()));
    16. m_selectionToolbar->addAction(m_actionScrollHand);
    17.  
    18. // Use mouse to select items
    19. m_selectionModeMenu = new QMenu;
    20.  
    21. m_actionIntersectsItem = new QAction(actionGroup);
    22. m_actionIntersectsItem->setCheckable(true);
    23. m_actionIntersectsItem->setText(tr("Select &intersected", "Action"));
    24. m_actionIntersectsItem->setStatusTip(tr("Drag to select items intersected by the rubber band", "Action"));
    25. m_actionIntersectsItem->setIcon(QIcon(":/images/selectintersected.png"));
    26. connect(m_actionIntersectsItem, SIGNAL(triggered()), this, SLOT(actionIntersectsItem_triggered()));
    27. m_selectionModeMenu->addAction(m_actionIntersectsItem);
    28.  
    29. m_actionContainsItem = new QAction(actionGroup);
    30. m_actionContainsItem->setCheckable(true);
    31. m_actionContainsItem->setText(tr("Select &contained", "Action"));
    32. m_actionContainsItem->setStatusTip(tr("Drag to select items contained by the rubber band", "Action"));
    33. m_actionContainsItem->setIcon(QIcon(":/images/selectcontained.png"));
    34. connect(m_actionContainsItem, SIGNAL(triggered()), this, SLOT(actionContainsItem_triggered()));
    35. m_selectionModeMenu->addAction(m_actionContainsItem);
    36.  
    37. m_selectionModeButton = new QToolButton;
    38. m_selectionModeButton->setPopupMode(QToolButton::MenuButtonPopup);
    39. m_selectionModeButton->setMenu(m_selectionModeMenu);
    40.  
    41. // Set default action
    42. m_selectionModeButton->setDefaultAction(m_actionIntersectsItem);
    43. m_actionIntersectsItem->setChecked(true);
    44.  
    45. m_selectionToolbar->addWidget(m_selectionModeButton);
    To copy to clipboard, switch view to plain text mode 

    And here are the slots:
    Qt Code:
    1. void GraphicsDrawView::actionScrollHand_triggered()
    2. {
    3. m_drawView->setDragMode(QGraphicsView::ScrollHandDrag);
    4. }
    5.  
    6. void GraphicsDrawView::actionIntersectsItem_triggered()
    7. {
    8. m_drawView->setDragMode(QGraphicsView::RubberBandDrag);
    9. m_drawView->setRubberBandSelectionMode(Qt::IntersectsItemShape);
    10. m_selectionModeButton->setDefaultAction(m_actionIntersectsItem);
    11. }
    12.  
    13. void GraphicsDrawView::actionContainsItem_triggered()
    14. {
    15. m_drawView->setDragMode(QGraphicsView::RubberBandDrag);
    16. m_drawView->setRubberBandSelectionMode(Qt::ContainsItemShape);
    17. m_selectionModeButton->setDefaultAction(m_actionContainsItem);
    18. }
    To copy to clipboard, switch view to plain text mode 

    Here instead are the variables (which are in the header):
    Qt Code:
    1. QPointer< DrawView > m_drawView; // Inherits QGraphicsView
    2. QPointer< QToolBar > m_selectionToolbar;
    3. QAction *m_actionScrollHand;
    4. QAction *m_actionIntersectsItem;
    5. QAction *m_actionContainsItem;
    6. QToolButton *m_selectionModeButton;
    7. QMenu *m_selectionModeMenu;
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,356
    Thanks
    3
    Thanked 5,010 Times in 4,789 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Blog Entries
    4
    Wiki edits
    10

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    How about not using QToolButton but a QAction and its setMenu() method instead and then adding the action to the toolbar like any other action?

  3. #3
    Join Date
    Jul 2007
    Posts
    35
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    Quote Originally Posted by wysota View Post
    How about not using QToolButton but a QAction and its setMenu() method instead and then adding the action to the toolbar like any other action?
    I tried adding this code:
    Qt Code:
    1. QAction *m_menuAction;
    2.  
    3. m_menuAction = new QAction(this);
    4. m_menuAction->setMenu(m_selectionModeMenu);
    5. m_drawToolbar->addAction(m_menuAction);
    To copy to clipboard, switch view to plain text mode 

    It works the same as what I was doing before, but I cannot set the visible action, I get an empty QToolButton with a menu. Is there something wrong with my code?
    I think the QToolButton is empty because it is showing m_menuAction which does not have any text or icon.

    I tried also to set the default action as I did before with this code:
    Qt Code:
    1. ((QToolButton*)(m_drawToolbar->widgetForAction(m_menuAction)))->setDefaultAction(m_actionIntersectsItem);
    To copy to clipboard, switch view to plain text mode 
    It works (with no strange messages), except for the problem that I get my 2 actions in a sub-menu + the default action in the main menu (what is happening???).

    Moreover I discovered that in my original code the message is shown only after I set the default action with:
    Qt Code:
    1. m_selectionModeButton->setDefaultAction(m_actionIntersectsItem);
    To copy to clipboard, switch view to plain text mode 
    If no default action is set, no message is shown, but in this case I have again an empty QToolButton!
    Last edited by iw2nhl; 17th August 2007 at 23:57.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,356
    Thanks
    3
    Thanked 5,010 Times in 4,789 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Blog Entries
    4
    Wiki edits
    10

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    The "default action" is the action you just created. Simply assign it an icon, text and whatever else you want. That's probably why you received the message in the first place - you tried to override the default action.

  5. #5
    Join Date
    Jul 2007
    Posts
    35
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    Quote Originally Posted by wysota View Post
    The "default action" is the action you just created. Simply assign it an icon, text and whatever else you want. That's probably why you received the message in the first place - you tried to override the default action.
    I don't create an action, but a toolbutton!
    The second test I did creating an action instead of the toolbutton did not show any more the message, but created an unwanted sub-menu.

    The default action must change depending on the user clicks in the menu.
    When a user clicks a menu item, the menu item's action become the default action, so that subsequent clicks on the toolbutton activate that action without using the menu.
    The menu is used to change the action performed by the toolbutton click.
    For this I don't want the toolbutton to have another action for himself.

    Here is what the documentation of QToolButton::setDefaultAction() says:
    void QToolButton::setDefaultAction ( QAction * action ) [slot]
    Sets the default action to action.
    If a tool button has a default action, the action defines the button's properties like text, icon, tool tip, etc.
    So it seems exactly what I'm doing: I set the button's properties using the default action.
    Last edited by iw2nhl; 19th August 2007 at 14:55.

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,356
    Thanks
    3
    Thanked 5,010 Times in 4,789 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Blog Entries
    4
    Wiki edits
    10

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    Quote Originally Posted by iw2nhl View Post
    I don't create an action, but a toolbutton!
    I meant the one in the second test. That's the "default action" for a tool button that will be created automatically by Qt when you add the action to the toolbar.

    The default action must change depending on the user clicks in the menu.
    I'm not sure I understand what you want then...

    Isn't this what you want?

    Qt Code:
    1. #include <QApplication>
    2. #include <QMainWindow>
    3. #include <QToolBar>
    4. #include <QToolButton>
    5. #include <QAction>
    6. #include <QMenu>
    7.  
    8. /*
    9.   Connecting POS1 and POS2 actions triggered signals to
    10.   a custom slot that will hide act and show POS1 or POS2
    11.   respectively and assign it the menu will switch the visible
    12.   action and retain the menu that allows to choose one of
    13.   the remaining actions.
    14. */
    15.  
    16. int main(int argc, char **argv){
    17. QApplication app(argc, argv);
    18. QToolBar *tb = mw.addToolBar("test");
    19. QAction *act = new QAction(&mw);
    20. act->setIcon(QPixmap("/usr/share/icons/crystalsvg/32x32/actions/exit.png"));
    21. act->setToolTip("Test menu");
    22. QMenu *menu = new QMenu(&mw);
    23. menu->addAction("POS1"); // real actions here
    24. menu->addAction("POS2"); // real actions here
    25. act->setMenu(menu);
    26. tb->addAction(act);
    27. QObject::connect(act, SIGNAL(triggered()), &mw, SLOT(close()));
    28. mw.show();
    29. return app.exec();
    30. }
    To copy to clipboard, switch view to plain text mode 

  7. #7
    Join Date
    Jul 2007
    Posts
    35
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    Yes, it is almost what I'm doing, but the idea is a little different:
    in the toolbar I want to have 2 buttons, say A (simple QToolButton) and B (QToolButton with arrow for menu) and the user 90% of the times clicks on A or B, but sometimes it wants to change what B does, so he clicks the B menu, change the action and B from now on performs the new action.
    The menu of B shows all the possible assignable actions to button B, while the button himself, when clicked, performs the last selected action. Button B also changes icon/text/tooltip depending on the selected action so that the user knows how it is working.

    Note that setDefaultAction() is doing exactly what I described above, just it shows the message in console every time the user clicks the arrow to show the menu of B.

    In your code, in the comment you say:
    "a custom slot that will hide act and show POS1 or POS2"
    What do you mean with "hide act", here act is the QToolButton, how can you hide the action and show POS1 or POS2? Sorry if it's a stupid question, may be I'm not understanding something...

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,356
    Thanks
    3
    Thanked 5,010 Times in 4,789 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Blog Entries
    4
    Wiki edits
    10

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    act is an action, not a toolbutton. It can be a menu entry as well. If you hide an action (set its visible property to false) all toolbuttons and menu entries associated with it will be hidden. The most trivial implementation of what you want is to have n actions in a toolbar (and each has the menu associated with it), but only show one of them at a time.

    I'm currently looking into the sources to find out exactly why you get that message, but it'll take some time - I have to download the latest Qt source archive.

  9. #9
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    OK. Here's what happens in 4.3.1( Sorry Wysota, I promise not to answer any posts until next Saturday ):

    A tool button has a list of assigned actions( inherited from QWidget).
    When you set the menu via setMenu:
    Qt Code:
    1. m_selectionModeButton->setMenu(m_selectionModeMenu);
    To copy to clipboard, switch view to plain text mode 
    the default(??) action of m_SelectionModeMenu will be added to m_SelectionModeButton's action list.

    Next, you added:
    Qt Code:
    1. m_selectionModeButton->setDefaultAction(m_actionIntersectsItem);
    To copy to clipboard, switch view to plain text mode 
    If m_actionIntersectsItem was not already the default action for the menu, it causes the tool button to add it to its action list.

    The message you were complaining about is outputted in QToolButton: popupTimerDone, called, for example when the menu is shown.
    Qt Code:
    1. if(menuAction) {
    2. actualMenu = menuAction->menu();
    3. if (q->actions().size() > 1)
    4. qWarning("QToolButton: Menu in setMenu() overriding actions set in addAction!");
    5. }
    To copy to clipboard, switch view to plain text mode 
    As you can see later in the function, if you set any menu with setMenu, then this menu will get displayed, rendering any actions that you add via addAction useless( they will be overwritten by the action you will select in the menu ).
    Basically the message is just a warning, so you should ignore it if you don't want to fix it.

    To fix it, use:
    Qt Code:
    1. m_selectionModeButton->setDefaultAction(m_actionIntersectsItem);
    To copy to clipboard, switch view to plain text mode 
    before setting the menu to the toolbutton with setMenu. This way you add only one action to the button( the current one).

    Regards
    Last edited by marcel; 19th August 2007 at 22:24.

  10. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,356
    Thanks
    3
    Thanked 5,010 Times in 4,789 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Blog Entries
    4
    Wiki edits
    10

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    If you mean this, then it also causes the warning to appear.
    Qt Code:
    1. #include <QtGui>
    2.  
    3. int main(int argc, char **argv){
    4. QApplication app(argc, argv);
    5. QToolBar *tb = mw.addToolBar("Test");
    6. QMenu *menu = new QMenu(&mw);
    7. QAction *act1 = new QAction(QPixmap("/usr/share/icons/crystalsvg/22x22/actions/filenew.png"), "ACT1", &mw);
    8. QAction *act2 = new QAction(QPixmap(), "ACT2", &mw);
    9. QAction *act3 = new QAction(QPixmap(), "ACT3", &mw);
    10. menu->addAction(act1);
    11. menu->addAction(act2);
    12. menu->addAction(act3);
    13. QToolButton *b = new QToolButton(&mw);
    14. b->setDefaultAction(act1);
    15. b->setMenu(menu);
    16. b->setPopupMode(QToolButton::MenuButtonPopup);
    17. tb->addWidget(b);
    18. mw.show();
    19. return app.exec();
    20. }
    To copy to clipboard, switch view to plain text mode 

    I'd ignore the "default action" and do the thing manually or just turn off debugging messages

  11. #11
    Join Date
    Jul 2007
    Posts
    35
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Thumbs up Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    Thank you marcel for your detailed explanation, it was very helpful!
    I could solve the problem!

    Although your solution did not work (changing the position of setDefaultAction() did not change anything, moreover I still needed to call it in the slots at user request), this sentence made me understand the problem:
    Quote Originally Posted by marcel View Post
    As you can see later in the function, if you set any menu with setMenu, then this menu will get displayed, rendering any actions that you add via addAction useless( they will be overwritten by the action you will select in the menu ).
    As you told, every QWidget has a list of actions, so adding a QMenu to it was not necessary and went to override the internal list of actions. The list was not empty because of setDefaultAction() which added the action to the list of widget actions in some way.
    The solutions now is very simple: instead of adding the actions to a QMenu and setting the menu to the QToolButton, you need only to add the actions directly to the QToolButton!
    In this way the menu is auto-generated with the list of the QWidget actions.
    Here is the code:
    Qt Code:
    1. m_selectionModeButton = new QToolButton;
    2. m_selectionModeButton->setPopupMode(QToolButton::MenuButtonPopup);
    3. m_selectionModeButton->addAction(m_actionIntersectsItem); // New line!
    4. m_selectionModeButton->addAction(m_actionContainsItem); // New line!
    5. m_selectionModeButton->setDefaultAction(m_actionIntersectsItem);
    6.  
    7. // Removed lines
    8. //m_selectionModeMenu = new QMenu;
    9. //m_selectionModeMenu->addAction(m_actionIntersectsItem);
    10. //m_selectionModeMenu->addAction(m_actionContainsItem);
    11. //m_selectionModeButton->setMenu(m_selectionModeMenu);
    To copy to clipboard, switch view to plain text mode 
    Now the code is even simpler!

    I hope this solution can help someone else too in the future!

    Thank you very much to every one for the help and thank you again marcel for the problem description which made me find the solution!

  12. #12
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    Although your solution did not work (changing the position of setDefaultAction() did not change anything,
    Well, I didn't test it... Seemed like it would work at the moment.

    Regards

  13. #13
    Join Date
    Nov 2008
    Posts
    1
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QToolButton: Menu in setMenu() overriding actions set in addAction!

    The solutions now is very simple: instead of adding the actions to a QMenu and setting the menu to the QToolButton, you need only to add the actions directly to the QToolButton!

    This is not always when one has to create a separate menu not only the action. One example of such case is when someone has to enable the tearing off on menu using "setTearOffEnabled(true)".

    So adding the actions to QMenu and setting the menu to QToolButton is needed int his case. How to overcome the problem here?

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.