mrg95
mrg95

Reputation: 2418

Change position of submenus in a QMenu

In my project, I have a QMenu with a submenu item. The submenu has a lot of items so it's height is relatively large.

I want to vertically center the submenu relative to the item that executed the submenu.

I have already subclassed the submenu I want to reposition and tried changing the geometry on "aboutToShow" just to test things, but this has no effect:

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

Here is an image I quickly MS Painted that I hope visually explains what I'm trying to achieve: (Before and After) enter image description here

Thanks for your time!

Upvotes: 1

Views: 1371

Answers (1)

eyllanesc
eyllanesc

Reputation: 243897

aboutToShow is emited before the geometry is updated so the changes are overwritten later. The solution is to change the position an instant after they are displayed, for this we can use a QTimer with a small time.

Example:

#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"

Upvotes: 1

Related Questions