Qt: Изменить содержимое приложения QMenuBar на Mac OS X

Мое приложение использует QTabWidget для нескольких «страниц», где меню верхнего уровня изменяется в зависимости от того, на какой странице находится пользователь.

Моя проблема заключается в том, что попытка воссоздать содержимое строки меню приводит к серьезным проблемам с отображением. Он работает, как и ожидалось, с первым и третьим стилем (не тестировал второй, но я бы предпочел не использовать этот стиль) на всех платформах, кроме 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

Я создал минимальный пример для воспроизведения этого поведения на Mac OS X 10.9.4 с Qt 5.3.

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

1

Решение

Все это выглядит как ошибка Qt в OS X. И это на самом деле очень старая ошибка.

Вы можете обойти и не работать с QMenu через вызовы функций QMenuBar :: addMenu, как вы делаете здесь:

m_menuBar->addMenu("One");

Вместо этого работайте с QAction, полученным из QMenu, путем динамического создания экземпляра QMenu и последующего вызова QMenuBar :: addAction для экземпляра QAction, полученного с помощью QMenu :: menuAction, следующим образом:

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, используя QMenuBar :: setNativeMenuBar
  • Из-за включенного по умолчанию собственного поведения QMenuBar, QActions со стандартными заголовками OS X («About», «Quit») будут автоматически размещаться Qt предопределенным способом на экране; Пустые экземпляры QMenu не будут показаны вообще.
2

Другие решения

Я думаю, что ваша проблема в этой строке:

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

По вопросам рекламы [email protected]