Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have a tool button with an associated menu.

m_mainMenuButton = new ToolButton("menu.png", tr("Open menu"));
m_mainMenuButton->setMenu(m_mainMenu);
m_mainMenuButton->setPopupMode(QToolButton::InstantPopup);

I want this menu to be shown when the user presses and releases Alt. This way the normal QMenuBar gets activated on Windows (and I want to have this tool button instead of QMenuBar). I tried this:

m_mainMenuButton->setShortcut(QKeySequence(Qt::Key_Alt));

but it does not show the menu when Alt is pressed and released. Or this:

auto shortcut = new QShortcut(QKeySequence(Qt::Key_Alt), this);
connect(shortcut, &QShortcut::activated, m_mainMenuButton, &QToolButton::showMenu);

which does not do anything too. I tried to override key press and release events but then I found it interferes with other key shortcuts which are using key Alt as a modifier, e.g "Alt+Left".

Any ideas how to do this?

UPDATE a minimal example which shows that Alt does not work as a shortcut.

#include <QAction>
#include <QApplication>
#include <QLabel>
#include <QMainWindow>
#include <QMenu>
#include <QShortcut>
#include <QToolButton>
#include <QVBoxLayout>
int main(int argc, char *argv[])
    QApplication a(argc, argv);
    QMainWindow w;
    auto label = new QLabel();
    auto menu = new QMenu(&w);
    // intentionally added a shortcut which contains Alt as modifier to test it does not interfere with the menu
    menu->addAction("Action", [label]{ label->setText("Trigered!"); }, QKeySequence("Alt+Left"));
    auto btn = new QToolButton();
    btn->setMenu(menu);
    btn->setPopupMode(QToolButton::InstantPopup);
    // the following lines do not have any effect, the menu is not shown when Alt is pressed and released
    auto shortcut = new QShortcut(QKeySequence(Qt::Key_Alt), &w);
    QObject::connect(shortcut, &QShortcut::activated, btn, &QToolButton::showMenu);
    auto container = new QWidget();
    auto layout = new QVBoxLayout(container);
    layout->addWidget(btn);
    layout->addWidget(label);
    w.setCentralWidget(container);
    w.show();
    return a.exec();
                this is in my case the main window, which is set as the parent of the shortcut. It does not matter, it could be the button as well.
– HiFile.app - best file manager
                Aug 13, 2018 at 9:15
                I am suspecting that ALT being a modifier is not a valid shorcut, as I have tried so far the valid shorcuts are MODIFIER + KEY or just KEY.
– eyllanesc
                Aug 13, 2018 at 10:17

Here is a version inspired by Qt's implementation in QMenuBar:

class AltButton : public QToolButton {
public:
    AltButton(QWidget *parent) : QToolButton(parent)
        // To handle initial ALT-press in parent
        parent->installEventFilter(this);
        // If reparenting should be possible, override changeEvent
        // You can also make an app-wide event filter if the button should catch all alt presses
protected:
    bool altPressed = false;
    bool eventFilter(QObject *watched, QEvent *event)
        if (altPressed) {
            // Alt-press registered before, check alt-Release
            switch (event->type())
            case QEvent::KeyPress:
            case QEvent::KeyRelease:
                QKeyEvent *kev = static_cast<QKeyEvent*>(event);
                if (kev->key() == Qt::Key_Alt || kev->key() == Qt::Key_Meta) {
                    if (event->type() == QEvent::KeyPress)
                        break; // Alt-Press handled below by shortcut override
                    // Alt-Release. Toggle button
                    this->showMenu();
            // fallthrough
            case QEvent::MouseButtonPress:
            case QEvent::MouseButtonRelease:
            case QEvent::MouseMove:
            case QEvent::FocusIn:
            case QEvent::FocusOut:
            case QEvent::ActivationChange:
            case QEvent::Shortcut:
                // These events cancel a alt-trigger
                altPressed = false;
                // Stop listening for global alt-releas
                qApp->removeEventFilter(this);
                break;
            default:
                break;
        } else if (isVisible()) {
            if (event->type() == QEvent::ShortcutOverride) {
                QKeyEvent *kev = static_cast<QKeyEvent*>(event);
                if ((kev->key() == Qt::Key_Alt || kev->key() == Qt::Key_Meta) && kev->modifiers() == Qt::AltModifier) {
                    // Alt-Press. Listen globally for alt-release
                    altPressed = true;
                    qApp->installEventFilter(this);
        return false;
int main(int argc, char**argv) {
    QApplication a(argc,argv);
        QMainWindow w;
        auto label = new QLabel();
        auto menu = new QMenu(&w);
        // intentionally added a shortcut which contains Alt as modifier to test it does not interfere with the menu
        menu->addAction("Action", [label]{ label->setText("Trigered!"); }, QKeySequence("Alt+Left"));
        auto btn = new AltButton(&w);
        btn->setMenu(menu);
        btn->setPopupMode(QToolButton::InstantPopup);
        // the following lines do not have any effect, the menu is not shown when Alt is pressed and released
        //auto shortcut = new QShortcut(QKeySequence(Qt::Key_Alt), &w);
        //QObject::connect(shortcut, &QShortcut::activated, btn, &QToolButton::showMenu);
        auto container = new QWidget();
        auto layout = new QVBoxLayout(container);
        layout->addWidget(btn);
        layout->addWidget(label);
        w.setCentralWidget(container);
        w.show();
        return a.exec();

The Alt-Left shortcut works as expected, and the buttons menu is toggled by a Alt-Pres-Release.

Works well. I only need to find out how to install the event filter for the top level window. changeEvent() does not always work because this button can be a child of widget X which can be reparented to Y which can be then reparented to top level window Z. And if I want to install the event filter for Z, then the button's changeEvent() will not be triggered when Y gets reparented to Z. Maybe I am doing something wrong... Anyway, I can call installFilter() manually from the top level window and it works. – HiFile.app - best file manager Aug 13, 2018 at 17:11 In the linked QMenuBar implementation, I saw something about a grand-parent change (I think in the event-filter). Maybe you can use this approach for your case, too. – king_nak Aug 14, 2018 at 7:43 Finally I ended up with passing the scope widget (the widget in which Tab key is handled by this menu button) in the constructor. Works very well so far. Thanks. – HiFile.app - best file manager Aug 14, 2018 at 8:19 public: KeyPressEater(QToolButton*btn) : keyOtherPush(false), keyAltPush(false) { _btn = btn; } protected: bool eventFilter(QObject *obj, QEvent *event); private: QToolButton * _btn; bool keyOtherPush; bool keyAltPush;

main.cpp

#include "QtStackOverflow.h"
#include <QtWidgets/QApplication>
#include <QObject>
#include <QEvent>
#include <QKeyEvent>
#include <QLabel>
#include <QMainWindow>
#include <QMenu>
#include <QShortcut>
#include <QToolButton>
#include <QVBoxLayout>
int main(int argc, char *argv[])
   QApplication a(argc, argv);
   QMainWindow w;
   auto label = new QLabel();
   auto menu = new QMenu(&w);
   // intentionally added a shortcut which contains Alt as modifier to test it does not interfere with the menu
   int number = 0;
   menu->addAction("Action", [label, &number] {
      label->setText(QString("%1 %2 ").arg("Trigered!").arg(number));
      number++;
   }, QKeySequence("Alt+Left"));
   auto btn = new QToolButton();
   btn->setMenu(menu);
   btn->setPopupMode(QToolButton::InstantPopup);
   // the following lines do not have any effect, the menu is not shown when Alt is pressed and released
   auto shortcut = new QShortcut(QKeySequence(Qt::Key_Alt), &w);
   QObject::connect(shortcut, &QShortcut::activated, btn, &QToolButton::showMenu);
   KeyPressEater *m_keyPressEater;
   m_keyPressEater = new KeyPressEater(btn);
   qApp->installEventFilter(m_keyPressEater);
   auto container = new QWidget();
   auto layout = new QVBoxLayout(container);
   layout->addWidget(btn);
   layout->addWidget(label);
   w.setCentralWidget(container);
   w.show();
   return a.exec();
bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
   if (event->type() == QEvent::KeyPress)
      int key = static_cast<QKeyEvent *>(event)->key();
      if (key == Qt::Key_Alt)
         keyAltPush = true;
      else {
         keyOtherPush = true;
      return QObject::eventFilter(obj, event);
   else if (event->type() == QEvent::KeyRelease)
      int key = static_cast<QKeyEvent *>(event)->key();
      if (key == Qt::Key_Alt) {
         if (keyAltPush == true && keyOtherPush == false) {
            _btn->showMenu();
      else {
         keyAltPush = false;
         keyOtherPush = false;
      return true;
   else {
      return QObject::eventFilter(obj, event);

In this case you will get all key press at any time.

Then you need check QObject *senderObj = sender()

But this would trigger even if I press, for example, "Alt+Left", which is a valid shortcut for another action. The problem with shortcut is that you first press "Alt" (which is when the menu would be opened - and I do not want this) and then "Left". – HiFile.app - best file manager Aug 13, 2018 at 9:20 I've corrected my code. You need check QObject *senderObj = sender() - who send key "Alt+Left" – Vladimir Neustroev Aug 13, 2018 at 10:08 I think you misunderstood the question. My problem is not to trigger "Alt+Left", I can do this with normal shortcuts. My problem is to trigger just a shortcut "Alt". The problem is that this cannot be handled as a normal shortcut because it cannot react to key press event (at that moment you do not know whether any more keys will be pressed to form a shortcut like Alt+Left). So it needs to react to key release event. But then it gets triggered when a shortcut like Alt+Left is relased. – HiFile.app - best file manager Aug 13, 2018 at 10:14 Your code (UPDATE: minimal example ) is working very well ! If I push "Alt+Left" I will see "Trigered!" – Vladimir Neustroev Aug 13, 2018 at 10:25

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.