一. 缺陷信息
缺陷:当QMenu使用QMenu::addMenu(QMenu *menu)添加一个子菜单后。想隐藏子菜单时,调用hide()或者setVisible()时,子菜单依然会显示
二.根因分析
Qt在加入子菜单的时候,在菜单中只加了子菜单的action
QAction *QMenu::addMenu(QMenu *menu) { QAction *action = menu->menuAction(); addAction(action); return action; } void QWidget::addAction(QAction *action) { insertAction(nullptr, action); } void QWidget::insertAction(QAction *before, QAction *action) { if (Q_UNLIKELY(!action)) { qWarning("QWidget::insertAction: Attempt to insert null action"); return; } Q_D(QWidget); if (d->actions.contains(action)) removeAction(action); int pos = d->actions.indexOf(before); if (pos < 0) { before = nullptr; pos = d->actions.size(); } d->actions.insert(pos, action); QActionPrivate *apriv = action->d_func(); apriv->associatedObjects.append(this); QActionEvent e(QEvent::ActionAdded, action, before); QCoreApplication::sendEvent(this, &e); }
并且在QMenu的hideEvent中并没有进行隐藏action的操作
void QMenu::hideEvent(QHideEvent *) { Q_D(QMenu); emit aboutToHide(); if (d->eventLoop) d->eventLoop->exit(); d->setCurrentAction(nullptr); #ifndef QT_NO_ACCESSIBILITY QAccessibleEvent event(this, QAccessible::PopupMenuEnd); QAccessible::updateAccessibility(&event); #endif #if QT_CONFIG(menubar) if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget)) mb->d_func()->setCurrentAction(nullptr); #endif if (QMenuPrivate::mouseDown == this) QMenuPrivate::mouseDown = nullptr; d->hasHadMouse = false; if (d->activeMenu) d->hideMenu(d->activeMenu); d->causedPopup.widget = nullptr; d->causedPopup.action = nullptr; if (d->scroll) d->scroll->scrollTimer.stop(); //make sure the timer stops }
所以我们调用QMenu的hide()或者setVisible()是没有用的
三.修复方案
隐藏时需要调用子菜单的QMenu::menuAction()->setVisible(false);