控制附加到 QToolButton 的弹出式 QWidget

Controlling a popup QWidget attached to a QToolButton

我想要在单击 QTool 按钮时显示弹出窗口小部件。

这可以通过向按钮本身添加一个动作来完成。 弹出窗口将包含三个按钮(更新、创建和取消)和一个文本输入字段。

我有一些示例代码,其中只有一个按钮,我已将其共享为 Github repository

代码中最相关的部分是:

    auto button = new QToolButton(this);
    button->setText(" AA ");

    auto popup = new Popup(button, this);
    auto popupAction = new QWidgetAction(this);
    popupAction->setDefaultWidget(popup);
    button->setPopupMode(QToolButton::InstantPopup);
    button->addAction(popupAction);

结果如下:

我有两个问题无法解决:

右对齐弹出窗口

已经有一个类似的问题:

我可以添加建议的代码:

void Popup::showEvent(QShowEvent*)
{
    QPoint p = this->pos();
    QRect geo = clickedButton->geometry();

    this->move(p.x()+geo.width()-this->geometry().width(), p.y());
}

但只有弹出窗口的内容与按钮右对齐,而不是弹出窗口本身:

关闭弹出窗口

如果我单击弹出窗口中的任意位置(小部件除外),它就会关闭。我对这个很好。

但是如果我无法点击按钮关闭弹出窗口。
我试图调用 close() 函数,但它只清除弹出窗口的内容而不关闭它。

我可以让按钮触发信号然后关闭弹出窗口吗?

我同时问这两个问题,因为它们看起来非常相似:两次都是内容而不是弹出窗口受到影响。

  • 当您使用布局时,它的边距会妨碍对齐。

  • Popup 的 QMenu 可以通过亲缘关系访问,但是必须在按下按钮时访问,因为它是在首次显示时创建的。

popup.h

#ifndef POPUP_H
#define POPUP_H

#include <QWidget>

class QToolButton;

class Popup : public QWidget
{
    Q_OBJECT
public:
    explicit Popup(QWidget* parent=nullptr);
Q_SIGNALS:
    void clicked();
};
#endif

popup.cpp

#include "popup.h"

#include<QWidget>
#include<QVBoxLayout>
#include<QPushButton>

Popup::Popup(QWidget* parent)
    : QWidget(parent)
{
    auto layout = new QVBoxLayout(this);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->addStretch();
    auto updateButton = new QPushButton("Update");
    layout->addWidget(updateButton);
    connect(updateButton, &QPushButton::clicked, this, &Popup::clicked);
}

mainwindow.h


MainWindow::MainWindow()
{
    auto widget = new QWidget;
    setCentralWidget(widget);
    auto layout = new QHBoxLayout(widget);
    layout->addStretch();

    auto button = new QToolButton;
    button->setText(" AA ");
    layout->addWidget(button);

    auto popup = new Popup;
    auto popupAction = new QWidgetAction(this);
    popupAction->setDefaultWidget(popup);
    button->setPopupMode(QToolButton::InstantPopup);
    button->addAction(popupAction);

    connect(popup, &Popup::clicked, [popup](){
        if(QWidget *p = popup->parentWidget())
            p->close();
    });
}
auto popup = new Popup(button, this);
auto popupAction = new QWidgetAction(this);
popupAction->setDefaultWidget(popup);
button->setPopupMode(QToolButton::InstantPopup);
button->addAction(popupAction);

您的 Popup 小部件不是实际的弹出窗口,而只是真正的弹出窗口中的一个小部件。 所以你要移动的是真正弹出窗口中的小部件,而不是弹出窗口本身。

您链接到的问题中的解决方案使用 QMenu,并且它适用于 QMenu。

在您的代码中替换

connect(button, &QToolButton::clicked, this, &MainWindow::showPopup);

auto updateButton = new QPushButton("Update");
auto popupAction = new QWidgetAction(this);
popupAction->setDefaultWidget(updateButton);
button->setPopupMode(QToolButton::InstantPopup);
button->addAction(popupAction);

button->setPopupMode(QToolButton::InstantPopup);
auto menu = new Popup(button, this);
auto action = new QAction("Test");
menu->addAction(action);
button->setMenu(menu);

将 Popup class 更改为 extend/inherit QMenu,取消注释 showEvent 方法并从构造函数中删除所有内容。

编辑

您可以为 qmenu 设置布局并向其添加小部件。

auto menuLayout = new QGridLayout();
auto menuBtn1 = new QPushButton("Btn1");
auto menuBtn2 = new QPushButton("Btn2");
auto menuBtn3 = new QPushButton("Btn3");

menuLayout->addWidget(menuBtn1, 0, 0);
menuLayout->addWidget(menuBtn2, 0, 1);
menuLayout->addWidget(menuBtn3, 1, 0);

button->setPopupMode(QToolButton::InstantPopup);
auto menu = new Popup(button, this);
menu->setLayout(menuLayout);