Изменить положение подменю в QMenu

В моем проекте у меня есть QMenu с элементом подменю. Подменю имеет много элементов, поэтому его высота относительно велика.

Я хочу вертикально центрировать подменю относительно элемента, который выполнил подменю.

Я уже создал подкласс подменю, которое хочу изменить, и попытался изменить геометрию на «aboutToShow» просто для проверки, но это не дало никакого эффекта:

class MySubMenu : public QMenu
{
    Q_OBJECT
public:
    QuickMod();
    ~QuickMod();

private slots:
    void centerMenu();
};



MySubMenu::MySubMenu()
{
    connect(this, SIGNAL(aboutToShow()), this, SLOT(centerMenu()));
}

MySubMenu::~MySubMenu()
{
}

void MySubMenu::centerMenu()
{
    qDebug() << x() << y() << width() << height();
    setGeometry(x(), y()-(height()/2), width(), height());
}

Вот изображение, которое я быстро нарисовал в MS Paint, которое, я надеюсь, наглядно объясняет, чего я пытаюсь достичь: (до и после) введите здесь описание изображения

Спасибо за ваше время!


person mrg95    schedule 18.03.2018    source источник


Ответы (1)


aboutToShow выдается перед обновлением геометрии, поэтому изменения перезаписываются позже. Решение состоит в том, чтобы изменить позицию сразу после их отображения, для этого мы можем использовать QTimer с небольшим временем.

Пример:

#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QTimer>

class CenterMenu: public QMenu{
    Q_OBJECT
public:
    CenterMenu(QWidget *parent = Q_NULLPTR):QMenu{parent}{
        connect(this, &CenterMenu::aboutToShow, this, &CenterMenu::centerMenu);
    }
    CenterMenu(const QString &title, QWidget *parent = Q_NULLPTR): QMenu{title, parent}{
        connect(this, &CenterMenu::aboutToShow, this, &CenterMenu::centerMenu);
    }
private slots:
    void centerMenu(){
        QTimer::singleShot(0, [this](){
            move(pos() + QPoint(0, -height()/2));
        });
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QMainWindow w;

    auto fileMenu = new QMenu("Menu1");
    w.menuBar()->addMenu(fileMenu);
    fileMenu->addAction("action1");
    fileMenu->addAction("action2");
    auto children_menu = new CenterMenu("children menu");
    children_menu->addAction("action1");
    children_menu->addAction("action2");
    children_menu->addAction("action3");
    children_menu->addAction("action4");
    children_menu->addAction("action5");
    children_menu->addAction("action6");
    fileMenu->addMenu(children_menu);
    w.show();
    return a.exec();
}

#include "main.moc"
person eyllanesc    schedule 18.03.2018
comment
Спасибо! Это помогло. Обратите внимание, что мне пришлось изменить код таймера на традиционную нотацию SLOT() вместо [this](), чтобы он скомпилировался для моей среды. Странный трюк :) - person mrg95; 18.03.2018
comment
@ mrg95 Вы используете Qt4? - person eyllanesc; 18.03.2018
comment
Неа. Qt 5.6.2, но компилируется с помощью msvc2010 - person mrg95; 18.03.2018
comment
@ mrg95 в Qt5 нотация SLOT устарела, это считается плохой практикой, рекомендуется использовать новый синтаксис, если вы используете Qt5, добавьте CONFIG += c++11 в свой .pro, wiki.qt.io/New_Signal_Slot_Syntax - person eyllanesc; 18.03.2018