代码之家  ›  专栏  ›  技术社区  ›  HiFile.app - best file manager

QToolButton在按下Alt键后显示菜单

  •  1
  • HiFile.app - best file manager  · 技术社区  · 7 年前

    我有一个带有相关菜单的工具按钮。

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

    我希望当用户按下并释放Alt时显示此菜单。这样 QMenuBar 在Windows上激活(我希望使用此工具按钮而不是 ). 我试过这个:

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

    但当按下并释放Alt时,它不会显示菜单。或者这个:

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

    也没什么用。我试图覆盖按键按下和释放事件,但后来发现它干扰了其他按键快捷键,这些快捷键使用键Alt作为修改器,例如“Alt+Left”。

    有什么办法吗?

    #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();
    }
    
    2 回复  |  直到 7 年前
        1
  •  0
  •   king_nak    7 年前

    以下是一个受Qt在 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();
    }
    

        2
  •  0
  •   Vladimir Neustroev    7 年前

    尝试使用QObject::installEventFilter

    例如

    QtStackOverflow.h

    #pragma once
    
    #include <QtWidgets/QMainWindow>
    #include <QToolButton>
    #include "ui_QtStackOverflow.h"
    
    class QtStackOverflow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        QtStackOverflow(QWidget *parent = Q_NULLPTR);
    
    private:
        Ui::QtStackOverflowClass ui;
    };
    
    class KeyPressEater : public QObject
    {
       Q_OBJECT
    
    public:
       KeyPressEater(QToolButton*btn) : keyOtherPush(false), keyAltPush(false) { _btn = btn; }
    
    protected:
       bool eventFilter(QObject *obj, QEvent *event);
    
    private:
       QToolButton * _btn;
       bool keyOtherPush;
       bool keyAltPush;
    };
    

    主.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);
       }
    }
    

    在这种情况下,你将得到所有的按键在任何时候。

    然后需要检查QObject*senderObj=sender()