Qt:在 Mac OS X 上更改应用程序 QMenuBar 内容



我的应用程序将QTabWidget用于多个"页面",其中顶级菜单根据用户所在的页面而变化。

我的问题是尝试重新创建菜单栏的内容会导致主要的显示问题。它按预期在所有平台上使用第一和第三种样式(尚未测试第二种样式,但我宁愿不使用该样式(,除了Mac OS X。

第一个菜单以我在应用程序中创建的方式创建,它们会收到正确的标题,但一旦重新创建菜单就会消失。

第二个菜单同时出现在菜单栏的初始填充和重新填充上,但在这两种情况下都有标签"无标题"。第二个菜单的样式是在尝试解决此问题时才创建的,因此这是我能够保留菜单的唯一方法。

第三个动态菜单永远不会出现,句号。我使用此样式动态填充即将显示的菜单。

我尝试删除 QMenuBar 并重新创建一个

m_menuBar = new QMenuBar(0);

并使用它而不是m_menuBar->clear()但它具有相同的行为。

我没有足够的声誉来内联发布图像,所以我将包含 imgur 链接:

启动行为:https://i.stack.imgur.com/V4N6O.png

发布按钮单击行为:https://i.stack.imgur.com/fytDc.png

我创建了一个最小示例,以在带有Qt 5.3的Mac OS X 10.9.4上重现此行为。

主窗口.cpp

#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    m_menuBar = new QMenuBar(0);
    m_dynamicMenu = new QMenu("Dynamic");
    connect(m_dynamicMenu, SIGNAL(aboutToShow()), this, SLOT(updateDynamicMenu()));
    changeMenuBar();
    QPushButton *menuBtn = new QPushButton("Test");
    connect(menuBtn, SIGNAL(clicked()), this, SLOT(changeMenuBar()));
    setCentralWidget(menuBtn);
}
void MainWindow::changeMenuBar() {
    m_menuBar->clear();
    // Disappears as soon as this is called a second time
    QMenu *oneMenu = m_menuBar->addMenu("One");
    oneMenu->addAction("foo1");
    oneMenu->addAction("bar1");
    oneMenu->addAction("baz1");
    // Stays around but has 'Untitled' for title in menu bar
    QMenu *twoMenu = new QMenu("Two");
    twoMenu->addAction("foo2");
    twoMenu->addAction("bar2");
    twoMenu->addAction("baz2");
    QAction *twoMenuAction = m_menuBar->addAction("Two");
    twoMenuAction->setMenu(twoMenu);
    // Never shows up
    m_menuBar->addMenu(m_dynamicMenu);
}
void MainWindow::updateDynamicMenu() {
    m_dynamicMenu->clear();
    m_dynamicMenu->addAction("foo3");
    m_dynamicMenu->addAction("bar3");
    m_dynamicMenu->addAction("baz3");
}

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtWidgets>
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
private slots:
    void changeMenuBar();
    void updateDynamicMenu();
private:
    QMenuBar *m_menuBar;
    QMenu *m_dynamicMenu;
};
#endif // MAINWINDOW_H

所有这些看起来都像OS X上的Qt错误。实际上,这是非常古老的错误。

您可以执行解决方法,并且不要通过QMenuBar::addMenu函数调用使用QMenu,就像您在此处所做的那样:

m_menuBar->addMenu("One");

而不是通过动态创建 QMenu 实例,然后为 QMenu::menuAction 检索的 QAction 实例调用 QMenuBar::addAction,而不是使用从 QMenu 检索的 QAction

,如下所示:
m_menuBar->addAction(oneMenu->menuAction());

在 QMenuBar::addAction 旁边,如果您只想动态创建某些特定的菜单项,您可以使用 QMenuBar::removeAction 和 QMenuBar::insertAction。

根据你这里的源代码,它是它的修改版本,它处理每次点击按钮时的所有菜单动态创建(你在源代码中这样做(,并且菜单"动态"每次你点击按钮时都会填充不同的项目计数。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtWidgets>
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
private slots:
    void changeMenuBar();
private:
    QMenuBar *m_menuBar;
    QMenu *m_dynamicMenu;
    int m_clickCounter;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
      m_clickCounter(1)
{
    m_menuBar = new QMenuBar(this);
    connect(m_dynamicMenu, SIGNAL(aboutToShow()), this, SLOT(updateDynamicMenu()));
    changeMenuBar();
    QPushButton *menuBtn = new QPushButton("Test");
    connect(menuBtn, SIGNAL(clicked()), this, SLOT(changeMenuBar()));
    setCentralWidget(menuBtn);
}
void MainWindow::changeMenuBar() {
    ++m_clickCounter;
    m_menuBar->clear();
    QMenu *oneMenu = new QMenu("One");
    oneMenu->addAction("bar1");
    oneMenu->addAction("baz1");
    m_menuBar->addAction(oneMenu->menuAction());
    QMenu *twoMenu = new QMenu("Two");
    twoMenu->addAction("foo2");
    twoMenu->addAction("bar2");
    twoMenu->addAction("baz2");
    m_menuBar->addAction(twoMenu->menuAction());
    m_dynamicMenu = new QMenu("Dynamic");
    for (int i = 0; i < m_clickCounter; ++i) {
        m_dynamicMenu->addAction(QString("foo%1").arg(i));
    }
    m_menuBar->addAction(m_dynamicMenu->menuAction());
}

此外,在为 OS X 开发菜单逻辑时,最好记住:

  • 可以使用 QMenuBar::setNativeMenuBar 禁用 QMenuBar 本机行为
  • 由于默认打开QMenuBar本机行为,具有标准OS X标题("关于","退出"(的QActions将由Qt以预定义的方式自动放置在屏幕上;空的 QMenu 实例根本不会显示。

我认为你的问题是这一行:

QMenu *oneMenu = m_menuBar->addMenu("One");

要将菜单添加到菜单栏,您需要按如下方式编写代码:

QMenuBar *m = new QMenuBar;
m->addMenu( new QMenu("Hmmm") );
m->show();
创建菜单,

然后添加操作,然后将菜单添加到菜单栏:

QMenu *item = new QMenu( "Test1" );
item->addAction( "action1" );
QMenuBar *t = new QMenuBar;
t->addMenu( item );
t->show();

最新更新