Установить положение (вправо) всплывающего меню Qt QPushButton

Я пишу всплывающее меню для виджета кнопки Qt. При каждом нажатии кнопки всплывает меню (под кнопкой).

По умолчанию всплывающее меню находится внизу слева.

Есть ли способы сделать так, чтобы всплывающее меню появлялось справа под кнопкой?

Нет функции установки позиции, поэтому мне интересно, есть ли какой-нибудь изощренный способ сделать это?

Вот код (для всплывающего меню):

QMenu *menuMode = new QMenu(this);
    min = menu ->addAction("In");
    mout = menu ->addAction("out");
ui->pushButtonMode->setMenu(menuMode);   //I am writing in MainWindow, that's there is ui

person Ryan    schedule 28.07.2015    source источник


Ответы (3)


Это можно сделать, создав подкласс QMenu и переместив всплывающее меню туда, где вы хотите его разместить в showEvent:

popupmenu.h

#ifndef POPUPMENU_H
#define POPUPMENU_H

#include <QMenu>

class QPushButton;
class QWidget;

class PopupMenu : public QMenu
{
    Q_OBJECT
public:
    explicit PopupMenu(QPushButton* button, QWidget* parent = 0);
    void showEvent(QShowEvent* event);
private:
    QPushButton* b;
};

#endif // POPUPMENU_H

popupmenu.cpp

#include "popupmenu.h"
#include <QPushButton>

PopupMenu::PopupMenu(QPushButton* button, QWidget* parent) : QMenu(parent), b(button)
{
}

void PopupMenu::showEvent(QShowEvent* event)
{
    QPoint p = this->pos();
    QRect geo = b->geometry();
    this->move(p.x()+geo.width()-this->geometry().width(), p.y());
}

mainwindow.cpp

...
PopupMenu* menu = new PopupMenu(ui->pushButton, this);
...
ui->pushButton->setMenu(menu);

Выглядит это так:

введите описание изображения здесь

person m.s.    schedule 28.07.2015
comment
Спасибо, я над этим работаю! Могу я спросить, почему QPushButton* b в классе PopupMenu? И это функция showEvent будет вызываться каждый раз, когда я нажимаю кнопку для всплывающего меню? - person Ryan; 29.07.2015
comment
Кроме того, я сталкивался с этими ошибками: popupmenu.obj : error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __cdecl PopupMenu::metaObject(void)const " `popupmenu.obj : error LNK2001: unresolved external symbol "public: virtual void * __cdecl PopupMenu::qt_metacast(char const *)" popupmenu.obj : error LNK2001: unresolved external symbol "public: virtual int __cdecl PopupMenu::qt_metacall(enum QMetaObject::Call,int,void * *)" Я сталкивался с подобными ошибками раньше, но я также не знаю, почему это связано с QMetaObject. - person Ryan; 29.07.2015
comment
@Ryan QPushButton* b используется, чтобы сообщить PopupMenu, к какому экземпляру кнопки он должен выровняться. да, showEvent будет вызываться каждый раз при нажатии кнопки. о своих ошибках: взгляните на этот вопрос и ответы на SO < / а> - person m.s.; 29.07.2015
comment
Спасибо за ссылку!! Я попытался добавить .h обратно в cmakelist, чтобы сгенерировать moc, решит этот LNK2001 (вдохновленный одним из ответчиков). - person Ryan; 29.07.2015

Вы должны реализовать eventFilter для своего QMenu. В методе eventFilter вам необходимо рассчитать позицию, в которой будет отображаться ваше меню.

Вот вам пример:

.pro

TEMPLATE = app

QT     += widgets
SOURCES += main.cpp \
           dialog.cpp

HEADERS += dialog.h

FORMS   += dialog.ui

main.cpp

#include <QtWidgets/QApplication>

#include "dialog.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog dia;
    return dia.exec();
}

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QtWidgets/QDialog>
#include <QMenu>
#include "ui_dialog.h"

class Dialog : public QDialog
{
    Q_OBJECT
public:
    Dialog();

protected:
    bool eventFilter(QObject * obj, QEvent *event);

private:
    QMenu *menu;
    Ui::Dialog m_ui;
};

#endif

dialog.cpp

#include "dialog.h"

Dialog::Dialog()
{
    m_ui.setupUi(this);

    menu = new QMenu("menu", this);
    menu->installEventFilter(this);
    QAction *action = new QAction("action#1", this);
    menu->addAction(action);
    m_ui.pushButton->setMenu(menu);
}

bool Dialog::eventFilter(QObject * obj, QEvent *event)
{
    if (event->type() == QEvent::Show && obj == m_ui.pushButton->menu())
    {
        int menu_x_pos = m_ui.pushButton->menu()->pos().x();
        int menu_width = m_ui.pushButton->menu()->size().width();
        int button_width = m_ui.pushButton->size().width();

        QPoint pos = QPoint(menu_x_pos - menu_width + button_width,
                            m_ui.pushButton->menu()->pos().y());

        m_ui.pushButton->menu()->move(pos);
        return true;
    }
    return false;
}
person Tarod    schedule 28.07.2015

Другой (имхо) более простой подход:

void MainFrame::Slot_ShowMenu()
{
    auto pMenu = new QMenu(this);

    connect(pMenu, &QMenu::aboutToHide, pMenu, &QMenu::deleteLater);

    ...

    // Retrieve a valid width of the menu. (It's not the same as using "pMenu->width()"!)
    int menuWidth = pMenu->sizeHint().width();

    int x = mUI.myQPushButton->width() - menuWidth;
    int y = mUI.myQPushButton->height();

    QPoint pos(mUI.myQPushButton->mapToGlobal(QPoint(x, y)));

    pMenu->popup(pos);
}
person Gediminas    schedule 24.02.2018