的Qt:在Mac OS X

问题描述:

我的应用程序,来改变应用QMenuBar内容使用QTabWidget多个“页”,其中取决于顶层菜单更改的用户是在什么页面。的Qt:在Mac OS X

我的问题是,试图重新创建在各大显示器问题菜单栏的结果内容。它的工作原理与第一和第三样式预期(没有第二次测试,但我宁愿不使用该样式)在所有平台上,除了针对Mac OS X

在我创作的方式创建的第一个菜单大部分在应用程序中,并且他们收到正确的标题,但只要菜单重新创建就会消失。

第二个菜单显示在两个初始人口和菜单栏的重新人口,但在这两种情况下的标签是“无题”。第二个菜单的样式只是在试图解决这个问题时才创建的,所以这是我唯一能够使用菜单的唯一方法。

第三动态菜单永远不会出现,期。我使用这种风格来动态填充即将显示的菜单。

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

m_menuBar = new QMenuBar(0); 

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

我没有足够的声誉在线发表图片,所以我会包括imgur链接:

发射行为http://i.imgur.com/ZEvvGKl.png

邮政按钮点击行为http://i.imgur.com/NzRmcYg.png

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

mainwindow.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"); 
} 

mainwindow.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 

这一切看起来Qt的错误在OS X上,这是非常老的bug,其实。

你可以做的解决办法,不通过QMenuBar :: addMenu函数调用与QMenu工作,因为你在这里做的:

m_menuBar->addMenu("One");

而是用的QAction这项工作由创作从QMenu检索到的QMenu例如动态,然后调用QMenuBar ::的addAction由QMenu :: menuAction检索的QAction实例,如下:

m_menuBar->addAction(oneMenu->menuAction()); 

除了QMenuBar ::的addAction可以使用QMenuBar :: removeAction和QMenuBar ::在sertAction,如果你只想创建一些特定的菜单项动态。

根据你的源代码,它是它的修改版本,它处理所有菜单动态创建每个按钮单击(你在源代码中这样做),菜单'动态'填充每次不同数量的项目你点击按钮。

#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实例将不会显示。
+2

我想指出,虽然增加'oneMenu-> menuAction()'是正确的,并且适用于前2个,它显然是**强制**(在Mac OS X上)菜单添加到“QMenuBar”时有现有的操作。由于我的动态菜单示例在发出'aboutToShow()'信号之前不会添加动作,因此我的解决方法是使用1'QAction'来填充动态菜单,除了使其初始显示外,其他任何功能都无用。在我的'updateDynamicMenu()'插槽中,我清除并重新填充动态菜单。 – syrius 2014-09-24 18:19:06

+0

@syrius,只是为了说明,通过使用QMenuBar :: setNativeMenuBar可以禁用菜单栏平台原生行为。但是这会带来更多令人头痛的问题。 同样在实际应用中,我们使用QActions来监听它们的信号。为避免开销,最佳解决方案转变为将所有QAction保留为私有成员,并在每次需要更改QMenu时为其填充动态菜单。 – 2014-09-24 19:00:35

+0

,但是在实际的应用程序中,例如编辑器的“窗口”菜单,对于当前打开的每个文件都不会有私有成员操作。这就是为什么我在连接到'aboutToShow()'信号的插槽中填充菜单的原因。我只是提到,在你的动态菜单的例子中,如果你没有填充它,直到'aboutToShow()'信号发出,它将永远不会出现在菜单栏中,这是我发布我的初始评论的原因需要一个空的QAction(因为你还不知道内容)。我认为将其纳入答案对其他人有所帮助。 – syrius 2014-09-24 19:02:15

我觉得你的问题是这一行:

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

要菜单添加到菜单栏你'd想要代码如下:

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();