Important: Please read the Qt Code of Conduct -

How to change QMenu behavior

  • Hi, I'm a bit stuck with quite specific problem and will appreciate any suggestions.
    First of all I'd like to say that I'm developing small module in the big project, so I can't change some basic things and have to deal with it.
    So, this project is big cross-platform application which has a variety of features and some of them are presented in a big toolbar. My target is to add a couple of buttons in it and provide them needed functionality.

    Main requirements are:

    • button must be checkable;
    • button must have dropdown menu;
    • it must be icon with small arrow on the right side (as it usually appears in applications).

    It looks like quite easy: we can take QAction, add it to toolbar, create QMenu, pack it with some other QActions and set this menu for QAction from toolbar.

    But the problem is that dropdown menu must have specific view and it already designed and developed, and it is presented as QDialog. So, when I click the black arrow near the icon in toolbar this QDialog should appear.

    For now I have found following solution:

    1. Create my own QCustomMenu class which is inherited from QMenu.
    2. In this custom class override showEvent(...) method.
    3. Create QAction, add it to toolbar.
    4. Create object of my custom menu class and insert it as a menu for this QAction.
    5. Connect to aboutToShow() signal of my custom menu.
    6. In connected slot exec() given QDialog and perform all needed actions.

    This is how my custom class looks like:

    class QCustomMenu : public QMenu
    QCustomMenu(QObject *parent = 0){};
    void showEvent(QShowEvent *)
    this->hide(); // close() also possible

    In Windows it works great and performs as I expected.

    But in Linux here's a small problem: when I press button in created QDialog and it disappears I can't press any button in the whole application (but when I hover mouse to icons in toolbar their description appears in status bar and so on, they are simply unclickable ). It looks like QCustomMenu wasn't closed or smth like that, but I can't catch what I have missed. May be I should override other events or something else. I have been trying to figure it out for three days now and absolutely stuck (it looks like that QMenu perform different with X11 ) .
    Everything I want is to close this QCustomMenu programmatically when it try to appear.
    Hope someone could help me with some good suggestions.

  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Since you don't use it at all, why the QMenu ?
    Why not connect the triggered signal of your action to a custom slot that would show your dialog ?

  • @SGaist the problem is that I need this toolbar button being able to press (or check like on/off state) that's why I can't do it in this way.

  • Lifetime Qt Champion

    A checkable QAction ?

  • @SGaist yes, when you add a QAction into QToolBar you can set it checkable and if you press it you will see the button which represents QAction being hold in the toolbar.
    For example, in this picture "align left" button is checked in the QAction meaning.

  • Lifetime Qt Champion

    Before going further, what do you need to show in that dialog ?

  • @SGaist actually it is some kind of a treeview with a bunch of buttons, due to specifications I need to use only this dialog.

  • Lifetime Qt Champion

    Then I'd rather go with a checkable action, show the dialog in triggered(true) and hide it again on triggered(false)

  • @SGaist unfortunately, i don't have an option. I have to show given dialog.

  • For now I found following solution to prevent GUI from freeze:

    QCustomMenu(QObject *parent = 0){};
    void showEvent(QShowEvent *)
    emit show();
    QMenu::closeEvent(new QCloseEven());
    QMenu::hideEvent(new QHideEvent());
    void show();

    And also now I've changed logic: on show() signal I exec() my dialog:

    QCustomMenu *menu = new QCustomMenu(toolbar);
    connect(menu, SIGNAL(show()), this, SLOT(execMyMenu()));

    But after closing my dialog UI waits for mouse click somewhere to start responding for further actions.

    May be it is possible to make programmatically click somewhere ? I didn't find any solution yet.