diff options
Diffstat (limited to 'src/quicktemplates/qquickmenubar.cpp')
-rw-r--r-- | src/quicktemplates/qquickmenubar.cpp | 563 |
1 files changed, 484 insertions, 79 deletions
diff --git a/src/quicktemplates/qquickmenubar.cpp b/src/quicktemplates/qquickmenubar.cpp index 62c7680d0d..5bc6995670 100644 --- a/src/quicktemplates/qquickmenubar.cpp +++ b/src/quicktemplates/qquickmenubar.cpp @@ -42,16 +42,27 @@ QT_BEGIN_NAMESPACE \l {removeMenu}{remove}, and \l {takeMenu}{take} menus dynamically. The menus in a menu bar can be accessed using \l menuAt(). + \note Since Qt 6.8, MenuBar is implemented as a native menu bar on \macos. As a + result, all Menus, MenuItems and MenuBarItems within a MenuBar will also be native. + While this has the advantage that everything will look native, it also comes with the + disadvantage that the delegates set on the mentioned controls will not be used + for rendering. + If a native MenuBar is not wanted, you can set + \l {Qt::AA_DontUseNativeMenuBar}{QGuiApplication::setAttribute(Qt::AA_DontUseNativeMenuBar)} + to disable it. + \sa {Customizing MenuBar}, Menu, MenuBarItem, {Menu Controls}, {Focus Management in Qt Quick Controls} */ -QQuickItem *QQuickMenuBarPrivate::beginCreateItem(QQuickMenu *menu) +Q_LOGGING_CATEGORY(lcMenuBar, "qt.quick.controls.menubar") + +static const char* kCreatedFromDelegate = "_qt_createdFromDelegate"; + +QQuickItem *QQuickMenuBarPrivate::createItemFromDelegate() { Q_Q(QQuickMenuBar); - if (!delegate) - return nullptr; - + Q_ASSERT(delegate); QQmlContext *context = delegate->creationContext(); if (!context) context = qmlContext(q); @@ -63,45 +74,94 @@ QQuickItem *QQuickMenuBarPrivate::beginCreateItem(QQuickMenu *menu) return nullptr; } - if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) - menuBarItem->setMenu(menu); - item->setParentItem(q); QQml_setParent_noEvent(item, q); + delegate->completeCreate(); return item; } -void QQuickMenuBarPrivate::completeCreateItem() +QQuickMenuBarItem *QQuickMenuBarPrivate::createMenuBarItem(QQuickMenu *menu) { - if (!delegate) - return; + Q_Q(QQuickMenuBar); - delegate->completeCreate(); + QQuickMenuBarItem *menuBarItem = nullptr; + if (delegate) { + QQuickItem *item = createItemFromDelegate(); + menuBarItem = qobject_cast<QQuickMenuBarItem *>(item); + if (!menuBarItem) { + qmlWarning(q) << "cannot insert menu: the delegate is not a MenuBarItem."; + delete item; + } + } + + if (!menuBarItem) { + // When we fail to create a delegate item, create a hidden placeholder + // instead. This is needed, since we store the menus inside the container + // using MenuBarItem. And without a MenuBarItem, we would therefore lose + // the menu, even if the delegate is changed later. + qCDebug(lcMenuBar) << "creating hidden placeholder MenuBarItem for:" << menu->title(); + menuBarItem = new QQuickMenuBarItem(q); + menuBarItem->setParentItem(q); + menuBarItem->setVisible(false); + } + + menuBarItem->setMenu(menu); + + // Tag the menuBarItem, so that we know which container items to change if the + // delegate is changed. This is needed since you can add MenuBarItems directly + // to the menu bar, which should not change when the delegate changes. + menuBarItem->setProperty(kCreatedFromDelegate, true); + + return menuBarItem; } -QQuickItem *QQuickMenuBarPrivate::createItem(QQuickMenu *menu) +void QQuickMenuBarPrivate::openCurrentMenu() { - QQuickItem *item = beginCreateItem(menu); - completeCreateItem(); - return item; + if (!currentItem || currentMenuOpen) + return; + QQuickMenu *menu = currentItem->menu(); + if (!menu || menu->isOpened()) + return; + +#ifdef Q_OS_MACOS + // On macOS, the menu should open underneath the MenuBar + Q_Q(QQuickMenuBar); + const QPointF posInParentItem = q->mapToItem(currentItem, {currentItem->x(), q->height()}); +#else + // On other platforms, it should open underneath the MenuBarItem + const QPointF posInParentItem{0, currentItem->y() + currentItem->height()}; +#endif + + // Store explicit if the current menu is logically supposed to be open. + // menu->isVisible() is async when using top-level menus, and will not become + // "true" before the menu is actually shown by the OS. This will cause us to + // lose track of if a menu is (supposed to be) open, if relying on menu->isVisible(). + currentMenuOpen = true; + + // The position should be the coordinate system of the parent item. Note that + // the parentItem() of a menu will be the MenuBarItem (currentItem), and not the + // MenuBar (even if parent() usually points to the MenuBar). + menu->popup(posInParentItem); } -void QQuickMenuBarPrivate::toggleCurrentMenu(bool visible, bool activate) +void QQuickMenuBarPrivate::closeCurrentMenu() { - if (!currentItem || visible == popupMode) + if (!currentItem || !currentMenuOpen) return; - + currentMenuOpen = false; QQuickMenu *menu = currentItem->menu(); + QScopedValueRollback triggerRollback(closingCurrentMenu, true); + menu->dismiss(); +} - triggering = true; - popupMode = visible; - if (menu) - menu->setVisible(visible); - if (!visible) - currentItem->forceActiveFocus(); - else if (menu && activate) - menu->setCurrentIndex(0); - triggering = false; +void QQuickMenuBarPrivate::activateMenuItem(int index) +{ + if (!currentItem) + return; + QQuickMenu *menu = currentItem->menu(); + if (!menu) + return; + menu->setCurrentIndex(index); } void QQuickMenuBarPrivate::activateItem(QQuickMenuBarItem *item) @@ -109,23 +169,20 @@ void QQuickMenuBarPrivate::activateItem(QQuickMenuBarItem *item) if (currentItem == item) return; + const bool stayOpen = currentMenuOpen; + if (currentItem) { currentItem->setHighlighted(false); - if (popupMode) { - if (QQuickMenu *menu = currentItem->menu()) - menu->dismiss(); - } - } - - if (item) { - item->setHighlighted(true); - if (popupMode) { - if (QQuickMenu *menu = item->menu()) - menu->open(); - } + closeCurrentMenu(); } currentItem = item; + + if (currentItem) { + currentItem->setHighlighted(true); + if (stayOpen) + openCurrentMenu(); + } } void QQuickMenuBarPrivate::activateNextItem() @@ -162,19 +219,34 @@ void QQuickMenuBarPrivate::onItemTriggered() return; if (item == currentItem) { - toggleCurrentMenu(!popupMode, false); + if (currentMenuOpen) { + closeCurrentMenu(); + currentItem->forceActiveFocus(); + } else { + openCurrentMenu(); + } } else { - popupMode = true; activateItem(item); + openCurrentMenu(); } } -void QQuickMenuBarPrivate::onMenuAboutToHide() +void QQuickMenuBarPrivate::onMenuAboutToHide(QQuickMenu *menu) { - if (triggering || !currentItem || !currentItem->isHighlighted()) + if (closingCurrentMenu) { + // We only react on a menu closing if it's + // initiated from outside of QQuickMenuBar. + return; + } + + if (!currentItem || currentItem->menu() != menu) + return; + + currentMenuOpen = false; + + if (!currentItem->isHighlighted() || currentItem->isHovered()) return; - popupMode = false; activateItem(nullptr); } @@ -220,14 +292,32 @@ void QQuickMenuBarPrivate::itemImplicitHeightChanged(QQuickItem *item) void QQuickMenuBarPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj) { - QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object); - if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(obj)) - obj = QQuickMenuBarPrivate::get(menuBar)->createItem(menu); + auto menuBar = static_cast<QQuickMenuBar *>(prop->object); + auto menuBarPriv = QQuickMenuBarPrivate::get(menuBar); + + if (auto *menu = qobject_cast<QQuickMenu *>(obj)) { + QQuickMenuBarItem *delegateItem = menuBarPriv->createMenuBarItem(menu); + menuBarPriv->insertMenu(menuBar->count(), menu, delegateItem); + QQuickContainerPrivate::contentData_append(prop, delegateItem); + return; + } + + if (auto *menuBarItem = qobject_cast<QQuickMenuBarItem *>(obj)) { + menuBarPriv->insertMenu(menuBar->count(), menuBarItem->menu(), menuBarItem); + QQuickContainerPrivate::contentData_append(prop, menuBarItem); + return; + } + QQuickContainerPrivate::contentData_append(prop, obj); } void QQuickMenuBarPrivate::menus_append(QQmlListProperty<QQuickMenu> *prop, QQuickMenu *obj) { + // This function is only called if the application assigns a list of menus + // directly to the 'menus' property. Otherwise, contentData_append is used. + // Since the functions belonging to the 'menus' list anyway returns data from + // the menuBar, calls such as "menuBar.menus.length" works as expected + // regardless of how the menus were added. QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object); menuBar->addMenu(obj); } @@ -255,6 +345,283 @@ QPalette QQuickMenuBarPrivate::defaultPalette() const return QQuickTheme::palette(QQuickTheme::MenuBar); } +QWindow* QQuickMenuBarPrivate::window() const +{ + Q_Q(const QQuickMenuBar); + QObject *obj = q->parent(); + while (obj) { + if (QWindow *window = qobject_cast<QWindow *>(obj)) + return window; + QQuickItem *item = qobject_cast<QQuickItem *>(obj); + if (item && item->window()) + return item->window(); + obj = obj->parent(); + } + return nullptr; +} + +int QQuickMenuBarPrivate::menuIndex(QQuickMenu *menu) const +{ + Q_Q(const QQuickMenuBar); + for (int i = 0; i < q->count(); ++i) { + if (q->menuAt(i) == menu) + return i; + } + + return -1; +} + +QPlatformMenuBar* QQuickMenuBarPrivate::nativeHandle() const +{ + return handle.get(); +} + +void QQuickMenuBarPrivate::insertNativeMenu(QQuickMenu *menu) +{ + Q_Q(QQuickMenuBar); + Q_ASSERT(handle); + Q_ASSERT(menu); + + QPlatformMenu *insertBeforeHandle = nullptr; + + // This function assumes that the QQuickMenuBarItem that corresponds to \a menu + // has already been added to the container at the correct index. So we search for + // it, to determine where to insert it in the native menubar. Since the QPA API + // expects a pointer to the QPlatformMenu that comes after it, we need to search + // for that one as well, since some MenuBarItems in the container can be hidden. + bool foundInContainer = false; + for (int i = 0; i < q->count(); ++i) { + if (q->menuAt(i) != menu) + continue; + foundInContainer = true; + + for (int j = i + 1; j < q->count(); ++j) { + insertBeforeHandle = QQuickMenuPrivate::get(q->menuAt(j))->maybeNativeHandle(); + if (insertBeforeHandle) + break; + } + + break; + } + + Q_ASSERT(foundInContainer); + QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu); + if (QPlatformMenu *menuHandle = menuPrivate->nativeHandle()) { + qCDebug(lcMenuBar) << "insert native menu:" << menu->title() << menuHandle << "before:" << insertBeforeHandle; + handle->insertMenu(menuPrivate->nativeHandle(), insertBeforeHandle); + } else { + qmlWarning(q) << "failed to create native menu for:" << menu->title(); + } +} + +void QQuickMenuBarPrivate::removeNativeMenu(QQuickMenu *menu) +{ + Q_ASSERT(handle); + Q_ASSERT(menu); + + QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu); + if (!menuPrivate->maybeNativeHandle()) + return; + + qCDebug(lcMenuBar) << "remove native menu:" << menu << menu->title(); + handle->removeMenu(menuPrivate->nativeHandle()); + menuPrivate->removeNativeMenu(); +} + +void QQuickMenuBarPrivate::syncMenuBarItemVisibilty(QQuickMenuBarItem *menuBarItem) +{ + if (!handle) { + // We only need to update visibility on native menu bar items + return; + } + + QQuickMenu *menu = menuBarItem->menu(); + if (!menu) + return; + QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu); + + if (menuBarItem->isVisible()) { + Q_ASSERT(!menuPrivate->maybeNativeHandle()); + insertNativeMenu(menu); + } else { + if (menuPrivate->maybeNativeHandle()) + removeNativeMenu(menu); + } +} + +void QQuickMenuBarPrivate::insertMenu(int index, QQuickMenu *menu, QQuickMenuBarItem *menuBarItem) +{ + Q_Q(QQuickMenuBar); + if (!menu) { + qmlWarning(q) << "cannot insert menu: menu is null."; + return; + } + + auto menuPrivate = QQuickMenuPrivate::get(menu); + menuPrivate->menuBar = q; + + QObject::connect(menuBarItem, &QQuickMenuBarItem::visibleChanged, [this, menuBarItem]{ + syncMenuBarItemVisibilty(menuBarItem); + }); + + // Always insert menu into the container, even when using a native + // menubar, so that container API such as 'count' and 'itemAt' + // continues to work as expected. + q->insertItem(index, menuBarItem); + + // Create or remove a native (QPlatformMenu) menu. Note that we should only create + // a native menu if it's supposed to be visible in the menu bar. + if (menuBarItem->isVisible()) { + if (handle) + insertNativeMenu(menu); + } else { + if (menuPrivate->maybeNativeHandle()) { + // If the menu was added from an explicit call to addMenu(m), it will have been + // created before we enter here. And in that case, QQuickMenuBar::useNativeMenu(m) + // was never called, and a QPlatformMenu might have been created for it. In that + // case, we remove it again now, since the menu is not supposed to be visible in + // the menu bar. + menuPrivate->removeNativeMenu(); + } + } +} + +QQuickMenu *QQuickMenuBarPrivate::takeMenu(int index) +{ + Q_Q(QQuickMenuBar); + QQuickItem *item = q->itemAt(index); + Q_ASSERT(item); + QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item); + if (!menuBarItem) { + qmlWarning(q) << "cannot take/remove menu: item at index " << index << " is not a MenuBarItem."; + return nullptr; + } + QQuickMenu *menu = menuBarItem->menu(); + if (!menu) { + qmlWarning(q) << "cannot take/remove menu: MenuBarItem.menu at index " << index << " is null."; + return nullptr; + } + + // Dismiss the menu if it's open. Otherwise, when we now remove it from + // the menubar, it will stay open without the user being able to dismiss + // it (at least if it's non-native). + menu->dismiss(); + + if (item == currentItem) + activateItem(nullptr); + + if (QQuickMenuPrivate::get(menu)->maybeNativeHandle()) + removeNativeMenu(menu); + + removeItem(index, item); + + // Delete the MenuBarItem. This will also cause the menu to be deleted by + // the garbage collector, unless other QML references are being held to it. + // Note: We might consider leaving it to the garbage collector to also + // delete the MenuBarItem in the future. + item->deleteLater(); + + QQuickMenuPrivate::get(menu)->menuBar = nullptr; + menuBarItem->disconnect(q); + + return menu; +} + +bool QQuickMenuBarPrivate::useNativeMenuBar() const +{ + // We current only use native menu bars on macOS. Especially, the + // QPA menu bar for Windows is old and unused, and looks broken and non-native. +#ifdef Q_OS_MACOS + return !QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuBar); +#else + return false; +#endif +} + +bool QQuickMenuBarPrivate::useNativeMenu(const QQuickMenu *menu) const +{ + Q_Q(const QQuickMenuBar); + if (!useNativeMenuBar()) + return false; + + // Since we cannot hide a QPlatformMenu, we have to avoid + // creating it if it shouldn't be visible in the menu bar. + for (int i = 0; i < q->count(); ++i) { + if (q->menuAt(i) == menu) + return itemAt(i)->isVisible(); + } + + return true; +} + +void QQuickMenuBarPrivate::syncNativeMenuBarVisible() +{ + Q_Q(QQuickMenuBar); + if (!componentComplete) + return; + + const bool shouldBeVisible = q->isVisible() && useNativeMenuBar(); + qCDebug(lcMenuBar) << "syncNativeMenuBarVisible called - q->isVisible()" << q->isVisible() + << "useNativeMenuBar()" << useNativeMenuBar() << "handle" << handle.get(); + if (shouldBeVisible && !handle) + createNativeMenuBar(); + else if (!shouldBeVisible && handle) + removeNativeMenuBar(); +} + +void QQuickMenuBarPrivate::createNativeMenuBar() +{ + Q_Q(QQuickMenuBar); + Q_ASSERT(!handle); + qCDebug(lcMenuBar) << "creating native menubar"; + + handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar()); + if (!handle) { + qCDebug(lcMenuBar) << "QPlatformTheme failed to create a QPlatformMenuBar!"; + return; + } + + handle->handleReparent(window()); + qCDebug(lcMenuBar) << "native menubar parented to window:" << handle->parentWindow(); + + // Add all the native menus. We need to do this right-to-left + // because of the QPA API (insertBefore). + for (int i = q->count() - 1; i >= 0; --i) { + if (QQuickMenu *menu = q->menuAt(i)) { + if (useNativeMenu(menu)) + insertNativeMenu(menu); + } + } + + // Hide the non-native menubar and set it's height to 0. The + // latter will cause a relayout to happen in ApplicationWindow + // which effectively removes the menubar from the contentItem. + setCulled(true); + q->setHeight(0); +} + +void QQuickMenuBarPrivate::removeNativeMenuBar() +{ + Q_Q(QQuickMenuBar); + Q_ASSERT(handle); + qCDebug(lcMenuBar) << "removing native menubar"; + + // Remove all native menus. + for (int i = 0; i < q->count(); ++i) { + if (QQuickMenu *menu = q->menuAt(i)) + removeNativeMenu(menu); + } + + // Delete the menubar + handle.reset(); + + // Show the non-native menubar and reset it's height. The + // latter will cause a relayout to happen in ApplicationWindow + // which will effectively add the menubar to the contentItem. + setCulled(false); + q->resetHeight(); +} + QQuickMenuBar::QQuickMenuBar(QQuickItem *parent) : QQuickContainer(*(new QQuickMenuBarPrivate), parent) { @@ -264,6 +631,13 @@ QQuickMenuBar::QQuickMenuBar(QQuickItem *parent) setFocusPolicy(Qt::ClickFocus); } +QQuickMenuBar::~QQuickMenuBar() +{ + Q_D(QQuickMenuBar); + if (d->handle) + d->removeNativeMenuBar(); +} + /*! \qmlproperty Component QtQuick.Controls::MenuBar::delegate @@ -285,6 +659,21 @@ void QQuickMenuBar::setDelegate(QQmlComponent *delegate) return; d->delegate = delegate; + + for (int i = count() - 1; i >= 0; --i) { + auto item = itemAt(i); + if (!item->property(kCreatedFromDelegate).toBool()) + continue; + + QQuickMenuBarItem *menuBarItem = static_cast<QQuickMenuBarItem *>(item); + if (QQuickMenu *menu = menuBarItem->menu()) { + removeMenu(menu); + d->insertMenu(i, menu, d->createMenuBarItem(menu)); + } else { + removeItem(menuBarItem); + } + } + emit delegateChanged(); } @@ -310,7 +699,12 @@ QQuickMenu *QQuickMenuBar::menuAt(int index) const void QQuickMenuBar::addMenu(QQuickMenu *menu) { Q_D(QQuickMenuBar); - addItem(d->createItem(menu)); + if (d->menuIndex(menu) >= 0) { + qmlWarning(this) << "cannot add menu: '" << menu->title() << "' is already in the MenuBar."; + return; + } + + d->insertMenu(count(), menu, d->createMenuBarItem(menu)); } /*! @@ -321,54 +715,52 @@ void QQuickMenuBar::addMenu(QQuickMenu *menu) void QQuickMenuBar::insertMenu(int index, QQuickMenu *menu) { Q_D(QQuickMenuBar); - insertItem(index, d->createItem(menu)); + if (d->menuIndex(menu) >= 0) { + qmlWarning(this) << "cannot insert menu: '" << menu->title() << "' is already in the MenuBar."; + return; + } + + d->insertMenu(index, menu, d->createMenuBarItem(menu)); } /*! \qmlmethod void QtQuick.Controls::MenuBar::removeMenu(Menu menu) - Removes and destroys the specified \a menu. + Removes specified \a menu. If the menu is \l {QQuickMenu::popup(QQmlV4Function *)}{open}, + it will first be \l {QQuickMenu::dismiss()}{dismissed.} + The \a menu will eventually be deleted by the garbage collector when the + application no longer holds any QML references to it. */ void QQuickMenuBar::removeMenu(QQuickMenu *menu) { Q_D(QQuickMenuBar); - if (!menu) + const int index = d->menuIndex(menu); + if (index < 0) { + qmlWarning(this) << "cannot remove menu: '" << menu->title() << "' is not in the MenuBar."; return; - - const int count = d->contentModel->count(); - for (int i = 0; i < count; ++i) { - QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(itemAt(i)); - if (!item || item->menu() != menu) - continue; - - removeItem(item); - break; } - menu->deleteLater(); + d->takeMenu(index); } /*! \qmlmethod Menu QtQuick.Controls::MenuBar::takeMenu(int index) - Removes and returns the menu at \a index. - - \note The ownership of the item is transferred to the caller. + Removes and returns the menu at \a index. If the menu is + \l {QQuickMenu::popup(QQmlV4Function *)}{open}, it will first be + \l {QQuickMenu::dismiss()}{dismissed.} + The menu will eventually be deleted by the garbage collector when the + application no longer holds any QML references to it. */ QQuickMenu *QQuickMenuBar::takeMenu(int index) { Q_D(QQuickMenuBar); - QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(itemAt(index)); - if (!item) - return nullptr; - - QQuickMenu *menu = item->menu(); - if (!menu) + if (index < 0 || index > count() - 1) { + qmlWarning(this) << "index out of range: " << index; return nullptr; + } - d->removeItem(index, item); - item->deleteLater(); - return menu; + return d->takeMenu(index); } /*! @@ -488,11 +880,12 @@ void QQuickMenuBar::keyPressEvent(QKeyEvent *event) switch (event->key()) { case Qt::Key_Up: - d->toggleCurrentMenu(false, false); + d->closeCurrentMenu(); break; case Qt::Key_Down: - d->toggleCurrentMenu(true, true); + d->openCurrentMenu(); + d->activateMenuItem(0); break; case Qt::Key_Left: @@ -517,7 +910,8 @@ void QQuickMenuBar::keyPressEvent(QKeyEvent *event) if (auto *item = qobject_cast<QQuickMenuBarItem *>(d->itemAt(i))) { if (item->shortcut() == mnemonic) { d->activateItem(item); - d->toggleCurrentMenu(true, true); + d->openCurrentMenu(); + d->activateMenuItem(0); } } } @@ -550,7 +944,7 @@ void QQuickMenuBar::hoverLeaveEvent(QHoverEvent *event) { Q_D(QQuickMenuBar); QQuickContainer::hoverLeaveEvent(event); - if (!d->popupMode && d->currentItem) + if (!d->currentMenuOpen && d->currentItem) d->activateItem(nullptr); } @@ -573,6 +967,10 @@ void QQuickMenuBar::itemChange(QQuickItem::ItemChange change, const QQuickItem:: d->windowContentItem->installEventFilter(this); } break; + case ItemVisibleHasChanged: + qCDebug(lcMenuBar) << "visibility of" << this << "changed to" << isVisible(); + d->syncNativeMenuBarVisible(); + break; default: break; } @@ -587,7 +985,7 @@ void QQuickMenuBar::itemAdded(int index, QQuickItem *item) QObjectPrivate::connect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered); QObjectPrivate::connect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered); if (QQuickMenu *menu = menuBarItem->menu()) - QObjectPrivate::connect(menu, &QQuickPopup::aboutToHide, d, &QQuickMenuBarPrivate::onMenuAboutToHide); + connect(menu, &QQuickPopup::aboutToHide, [this, menu]{ d_func()->onMenuAboutToHide(menu); }); } d->updateImplicitContentSize(); emit menusChanged(); @@ -608,12 +1006,19 @@ void QQuickMenuBar::itemRemoved(int index, QQuickItem *item) QObjectPrivate::disconnect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered); QObjectPrivate::disconnect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered); if (QQuickMenu *menu = menuBarItem->menu()) - QObjectPrivate::disconnect(menu, &QQuickPopup::aboutToHide, d, &QQuickMenuBarPrivate::onMenuAboutToHide); + menu->disconnect(this); } d->updateImplicitContentSize(); emit menusChanged(); } +void QQuickMenuBar::componentComplete() +{ + Q_D(QQuickMenuBar); + QQuickContainer::componentComplete(); + d->syncNativeMenuBarVisible(); +} + QFont QQuickMenuBar::defaultFont() const { return QQuickTheme::font(QQuickTheme::MenuBar); |