Sometimes it occurs that keypresses act like the Alt-key has been pressed also, which means that the key event is only sent to the menubar and not to the application. I encountered this in our own application, but I could reproduce this with Qt Designer. Please follow the next recipe exactly and come back to me if you can't reproduce.
簡單地說:菜單欄原本須要ALT+'M'(或其餘字符)來激活並彈出某個菜單,如今直接按'M'就能夠激活了。 ide
初次看到感受頗有意思,後來發現問題還算簡單。咱們能夠用下面的程序來重現這個問題:工具
#include <QApplication> #include <QMainWindow> #include <QMenuBar> class MainWindow : public QMainWindow { public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(){} }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QMenu * menu = menuBar()->addMenu("&Menu"); menu->addAction("&Item"); menu->addAction("I&tem"); } int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
void QMenuBarPrivate::handleReparent() { Q_Q(QMenuBar); QWidget *newParent = q->parentWidget(); //Note: if parent is reparented, then window may change even if parent doesn't // we need to install an event filter on parent, and remove the old one if (oldParent != newParent) { if (oldParent) oldParent->removeEventFilter(q); if (newParent) newParent->installEventFilter(q); } //we also need event filter on top-level (for shortcuts) QWidget *newWindow = newParent ? newParent->window() : 0; if (oldWindow != newWindow) { if (oldParent && oldParent != oldWindow) oldWindow->removeEventFilter(q); if (newParent && newParent != newWindow) newWindow->installEventFilter(q); } oldParent = newParent; oldWindow = newWindow;
void QMenuBarPrivate::updateGeometries() { ... for(int i = 0; i < actions.count(); i++) shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actions.at(i)->text())));
注意:一旦遇到包含Alt鍵值的QEvent::ShortcutOverride事件,它會將本身安裝成QApplication的事件過濾器this
bool QMenuBar::eventFilter(QObject *object, QEvent *event) { if (style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this)) { if (d->altPressed) { 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) // Alt-press does not interest us, we have the shortcut-override event break; d->setKeyboardMode(!d->keyboardState); } } // fall through case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: case QEvent::FocusIn: case QEvent::FocusOut: case QEvent::ActivationChange: d->altPressed = false; 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) { d->altPressed = true; qApp->installEventFilter(this); } } } } return false;
bool QMenuBar::event(QEvent *e) { Q_D(QMenuBar); switch (e->type()) { case QEvent::Shortcut: { QShortcutEvent *se = static_cast<QShortcutEvent *>(e); int shortcutId = se->shortcutId(); for(int j = 0; j < d->shortcutIndexMap.size(); ++j) { if (shortcutId == d->shortcutIndexMap.value(j)) d->_q_internalShortcutActivated(j); } } break;
void QMenuBar::keyPressEvent(QKeyEvent *e) { Q_D(QMenuBar); d->updateGeometries(); int key = e->key(); if(isRightToLeft()) { // in reverse mode open/close key for submenues are reversed if(key == Qt::Key_Left) key = Qt::Key_Right; else if(key == Qt::Key_Right) key = Qt::Key_Left; } if(key == Qt::Key_Tab) //means right key = Qt::Key_Right; else if(key == Qt::Key_Backtab) //means left key = Qt::Key_Left; bool key_consumed = false; switch(key) { case Qt::Key_Up: case Qt::Key_Down: case Qt::Key_Enter: case Qt::Key_Space: case Qt::Key_Return: { if(!style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this) || !d->currentAction) break; if(d->currentAction->menu()) { d->popupAction(d->currentAction, true); } else if(key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Space) { d->activateAction(d->currentAction, QAction::Trigger); d->setCurrentAction(d->currentAction, false); d->setKeyboardMode(false); } key_consumed = true; break; } case Qt::Key_Right: case Qt::Key_Left: { if(d->currentAction) { int index = d->actions.indexOf(d->currentAction); if (QAction *nextAction = d->getNextAction(index, key == Qt::Key_Left ? -1 : +1)) { d->setCurrentAction(nextAction, d->popupState, true); key_consumed = true; } } break; } case Qt::Key_Escape: d->setCurrentAction(0); d->setKeyboardMode(false); key_consumed = true; break; default: key_consumed = false; } if(!key_consumed && (!e->modifiers() || (e->modifiers()&(Qt::MetaModifier|Qt::AltModifier))) && e->text().length()==1 && !d->popupState) { int clashCount = 0; QAction *first = 0, *currentSelected = 0, *firstAfterCurrent = 0; { QChar c = e->text()[0].toUpper(); for(int i = 0; i < d->actions.size(); ++i) { if (d->actionRects.at(i).isNull()) continue; QAction *act = d->actions.at(i); QString s = act->text(); if(!s.isEmpty()) { int ampersand = s.indexOf(QLatin1Char('&')); if(ampersand >= 0) { if(s[ampersand+1].toUpper() == c) { clashCount++; if(!first) first = act; if(act == d->currentAction) currentSelected = act; else if (!firstAfterCurrent && currentSelected) firstAfterCurrent = act; } } } } } QAction *next_action = 0; if(clashCount >= 1) { if(clashCount == 1 || !d->currentAction || (currentSelected && !firstAfterCurrent)) next_action = first; else next_action = firstAfterCurrent; } if(next_action) { key_consumed = true; d->setCurrentAction(next_action, true, true); } } if(key_consumed) e->accept(); else e->ignore(); }
void QMenuBarPrivate::setKeyboardMode(bool b) { Q_Q(QMenuBar); if (b && !q->style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, q)) { setCurrentAction(0); return; } keyboardState = b; if(b) { QWidget *fw = QApplication::focusWidget(); if (fw != q) keyboardFocusWidget = fw; focusFirstAction(); q->setFocus(Qt::MenuBarFocusReason); } else { if(!popupState) setCurrentAction(0); if(keyboardFocusWidget) { if (QApplication::focusWidget() == q) keyboardFocusWidget->setFocus(Qt::MenuBarFocusReason); keyboardFocusWidget = 0; } } q->update(); }