如何使用 Qt 聚焦 menuBar()
我有一个可用的应用程序.我向带有一些菜单的主窗口添加了一个 menuBar().然后,我将其隐藏以释放屏幕空间.我写了下面的代码,这样当用户按下 ALT 键时,菜单栏如果隐藏就会出现,如果显示则隐藏.
void MainWindow::keyPressEvent( QKeyEvent *k ) {if(k->modifiers() & Qt::AltModifier) {menuBar()->setHidden(!menuBar()->isHidden());if(menuBar()->hasFocus()) {QMessageBox::information(this, "Info", "Focus !");}}}
如你所见,我还添加了一个 QMessageBox 来查看 menuBar 何时获得焦点.而这个框只出现一半的时间.它是这样的:
- 应用启动,菜单栏隐藏
- 我按下 ALT,显示菜单栏,没有消息框,没有焦点
- 我按下 ALT,隐藏菜单栏
- 我按下 ALT,显示菜单栏,消息框,焦点
- 我按下 ALT,隐藏菜单栏
- 我按下 ALT,显示菜单栏,没有消息框,没有焦点
- 我按下 ALT,隐藏菜单栏
- 我按下 ALT,显示菜单栏,消息框,焦点
- 等
如何确保menuBar在显示时始终有焦点?
解决方案我想做同样的事情.我的解决方案,完整示例,作为要点:
https://gist.github.com/xim/ee56564f425151ea2fa70f7830d
针对 Qt 5.9.4 进行测试.
因为它包含很多其他垃圾,一个最小的例子:
class AutoHidingMenuBar : public QMenuBar {Q_OBJECT上市:AutoHidingMenuBar() : QMenuBar() {设置最大高度(0);连接(qApp, &QApplication::focusChanged, this, &AutoHidingMenuBar::focusChanged);}私人插槽:void focusChanged(QWidget *from, QWidget *to) {bool inFocus = hasFocus() ||isAncestorOf(focus) ||hasFocusedChild();if (inFocus &&maximumHeight() == 0) {自动动作 = activeAction();设置最大高度(100);如果(动作){//XXX 这是一个小技巧.我们可以做//QCoreApplication::processEvents();//setActiveAction(action);//效果几乎相同,但随后我们*打开*了单次按下 alt 时的第一个菜单...auto evt = new QMouseEvent(QEvent::MouseMove, actionGeometry(action).center(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);QCoreApplication::postEvent(this, evt);}} else if (!inFocus &&maximumHeight() != 0)) {设置最大高度(0);}}私人的:bool hasFocusedChild() {QObjectList 队列{children()};而 (!queue.empty()) {auto child = queue.takeFirst();自动小部件 = dynamic_cast<QWidget *>(child);if (widget && widget->hasFocus())返回真;queue.append(child->children());}返回假;}};
I have a working application. I added a menuBar() to the main window with some menus. Then, I hid it to free screen space. I wrote the code below so that when user presses ALT key, the menu bar appears if it's hidden, and it hides if it's displayed.
void MainWindow::keyPressEvent( QKeyEvent *k ) {
if(k->modifiers() & Qt::AltModifier) {
menuBar()->setHidden(!menuBar()->isHidden());
if(menuBar()->hasFocus()) {
QMessageBox::information(this, "Info", "Focus !");
}
}
}
As you can see, I also added a QMessageBox to see when the menuBar has the focus. And this box appears only half of the time. It goes like this :
- Application launched, menubar hidden
- I press ALT, menubar displayed, no message box, no focus
- I press ALT, menubar hidden
- I press ALT, menubar displayed, message box, focus
- I press ALT, menubar hidden
- I press ALT, menubar displayed, no message box, no focus
- I press ALT, menubar hidden
- I press ALT, menubar displayed, message box, focus
- etc.
How to make sure when the menuBar is displayed, it always has focus ?
解决方案I wanted to do the same thing. My solution, complete example, as a gist:
https://gist.github.com/xim/ee56564f425151ea2fa70f730d644873
Tested against Qt 5.9.4.
As it contains a lot of other junk, a minimal example:
class AutoHidingMenuBar : public QMenuBar {
Q_OBJECT
public:
AutoHidingMenuBar() : QMenuBar() {
setMaximumHeight(0);
connect(qApp, &QApplication::focusChanged, this, &AutoHidingMenuBar::focusChanged);
}
private slots:
void focusChanged(QWidget *from, QWidget *to) {
bool inFocus = hasFocus() || isAncestorOf(focus) || hasFocusedChild();
if (inFocus && maximumHeight() == 0) {
auto action = activeAction();
setMaximumHeight(100);
if (action) {
// XXX This is a bit of a hack. We could do
// QCoreApplication::processEvents();
// setActiveAction(action);
// with almost the same effect, but then we *open* the first menu on single alt press...
auto evt = new QMouseEvent(QEvent::MouseMove, actionGeometry(action).center(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
QCoreApplication::postEvent(this, evt);
}
} else if (!inFocus && maximumHeight() != 0)) {
setMaximumHeight(0);
}
}
private:
bool hasFocusedChild() {
QObjectList queue{children()};
while (!queue.empty()) {
auto child = queue.takeFirst();
auto widget = dynamic_cast<QWidget *>(child);
if (widget && widget->hasFocus())
return true;
queue.append(child->children());
}
return false;
}
};
相关文章