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();
–
–
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.
–
–
–
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()
–
–
–
–
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.