Task: to implement the ability to hide and show the main menu by pressing Alt, as well as highlight the menu after the appearance (such as the FireFox menu also works). Actually, I know how to hide / show, but the menu is always highlighted only by the second Alt press after the menu is shown. I tried to move the focus to menuBar and to a specific menu, tried menuBar()->actions()[0].hover() , tried to activateWindow() , setActiveAction() , activate(QAction::Hover)

We intercept the message on the pressed Alt

 bool MainWindow::event(QEvent *event){ if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast<QKeyEvent*>(event); if (ke->key() == Qt::Key_Alt) { keyReleaseEvent(ke); return true; } } return QMainWindow::event(event); } 

Process Alt

 void MainWindow::keyReleaseEvent (QKeyEvent* event) { if (event->key() == Qt::Key_Alt){ if (menuBar()->isHidden()){ menuBar()->show(); menuBar()->setFocus(Qt::MenuBarFocusEvent); //Здесь пробовал всё вышеперечисленное } else{ menuBar()->hide(); { } } 
  • Please provide the code that performs the specified functions - Cerbo
  • @Cerbo led, do you need anything else? - Dimanesson
  • My little research has shown that the menu is highlighted in a very tricky way. The QMenuBar object temporarily registers itself with the event filter of the application object, that is, literally qApp->installEventFilter(this) . In this filter, it handles keystrokes (it does a lot of things in general) and, via Alt, enters the keyboard control mode, which, in fact, means backlighting. The solution was to send a fictitious event about pressing Alt, but in connection with the chemistry described above it is not clear where to send this event. - Cerbo
  • @Cerbo Thanks for the hint, in fact, you need to send two dummy messages: keyPressed and keyReleased, then the backlight works. In my case, you need to send them in menuBar() . I did it like this: QApplication::sendEvent(menuBar(), altPress); and QApplication::sendEvent(menuBar(), altRelease); where altPress and altRelease are QKeyEvent objects - Dimanesson
  • I checked it first thing and did not work. Qt 5.5 on Windows 7 compiled by Visual Studio 2012. - Cerbo am

1 answer 1

A crutch solution found. First you need to make sure that the focusPolicy parameter of all widgets is Qt::StrongFocus .

Next, you need to write your focus switching handler so that QMenu processed as part of the QMenuBar

 void MainWindow::onFocusChanging(QWidget* old, QWidget* now){ if(now != menuBar() && now != menuBar()->findChild<QMenu*>() && old == menuBar()) { menuBar()->hide(); } else{ QKeyEvent* altPress = new QKeyEvent(QEvent::KeyPress, Qt::Key_Alt, Qt::NoModifier); QKeyEvent* altRelease = new QKeyEvent(QEvent::KeyRelease, Qt::Key_Alt, Qt::NoModifier); QApplication::sendEvent(menuBar(), altPress); QApplication::sendEvent(menuBar(), altRelease); } } 

and link it with the QApplication signal about switching focus, I did it in right in main:

 QObject::connect(&a, SIGNAL(focusChanged(QWidget*, QWidget*)), &w, SLOT(onFocusChanging(QWidget*, QWidget*))); 

Well, then everything was as it was:

We intercept the message on the pressed Alt

 bool MainWindow::event(QEvent *event){ if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast<QKeyEvent*>(event); if (ke->key() == Qt::Key_Alt) { keyReleaseEvent(ke); return true; } } return QMainWindow::event(event); } 

Process Alt

 void MainWindow::keyReleaseEvent (QKeyEvent* event) { if (event->key() == Qt::Key_Alt){ if (menuBar()->isHidden()){ menuBar()->show(); menuBar()->setFocus(); } } else menuBar()->hide(); } 

I hope those who look will forgive me such an ugly solution and a bad description, but this is the only thing that I managed to come up with to solve this problem.

  • Why not send bogus messages right after menuBar()->setFocus() - Cerbo 2:26 pm
  • @Cerbo application crashes with StackOverflow, I don’t know why, but it also creates a huge number of threads. Maybe this is a Qt - Dimanesson bug