防止QMainWindow在切换中央widget时放大QDockWidget

问题描述 投票:0回答:1

我有一个带有停靠小部件和中央小部件的主窗口。中央小部件可以根据用户的选择进行更改,但停靠小部件保留。 当用户没有调整停靠小部件的大小时,一切都很好,并且更改中央小部件不会影响停靠小部件的大小(保持大小提示)。然而,当用户调整停靠小部件的大小时,它会异常放大并占据中央小部件空间。

这是问题的动画 gif:

Qt Bug dock widget

这是重现问题的代码(使用 Qt5.15):

#include <QApplication>
#include <QLayout>
#include <QLabel>
#include <QMainWindow>
#include <QDockWidget>
#include <QToolBar>
#include <QTimer>

class Widget : public QWidget
{
public:
    Widget(const QString& aName, QSize aSize, QWidget * parent = nullptr)
        : QWidget(parent), size(aSize)
    {
        static int COUNT = 0;
        static QStringList COLORS = { "LightBlue", "LightGreen", "LightSalmon" };

        auto label = new QLabel(tr("%1 (%2x%3)").arg(aName).arg(size.width()).arg(size.height()), this);
        label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        label->setAlignment(Qt::AlignCenter);
        label->setWordWrap(true);
        label->setStyleSheet(QString("QLabel { background-color: %1 }").arg(COLORS.value(COUNT++ % COLORS.size())));

        auto mainLayout = new QVBoxLayout(this);
        mainLayout->addWidget(label);
    }

    QSize sizeHint() const override
    {
        return size;
    }

private:
    QSize size;
};

class MainWindow : public QMainWindow
{

public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        // Creating toolbar
        addToolBar("Tool bar")->addAction("Switch central Widget", this, &MainWindow::switchCentralWidget);

        // Creating main widget
        switchCentralWidget();

        // Creating dock widget
        auto dockWidget = new QDockWidget("My dock widget");
        dockWidget->setWidget(new Widget("DOCK WIDGET", {200, 400}, this));
        addDockWidget(Qt::RightDockWidgetArea, dockWidget);
    }

private slots:

    void switchCentralWidget()
    {
        setCentralWidget(new Widget("CENTRAL WIDGET", {300, 400}, this));
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

我尝试(未成功)修改中央和停靠小部件的大小策略。 我发现防止扩展坞扩大的唯一方法是设置临时最大尺寸(见下文)。

void switchCentralWidget()
{
    // Dirty hack
    for (auto dock : findChildren<QDockWidget *>()) {
        int width = dock->widget()->width();
        int maxWidth = dock->widget()->maximumWidth();
        dock->setMaximumWidth(width);
        QTimer::singleShot(1000, dock, [=] { dock->setMaximumWidth(maxWidth); });
    }

    setCentralWidget(new Widget("CENTRAL WIDGET", {300, 400}, this));
}

但是它很脏,并且在修改停靠小部件的大小提示时会给我带来问题(一个用户操作是放置另一个中央小部件并修改停靠小部件字体大小)。

我想要的是停靠小部件保持与中央小部件切换之前相同的大小。

c++ qt qmainwindow qdockwidget
1个回答
0
投票

我无法阻止 QMainWindow 在调用时放大停靠小部件

setCentralWidget()
。解决方案是为中央小部件创建一个包装器:

class WidgetWrapper : public QWidget
{
public:
    WidgetWrapper(QWidget *parent = nullptr)
        : QWidget(parent),
        layout(new QVBoxLayout(this)),
        widget(nullptr)
    {
        layout->setContentsMargins(0, 0, 0, 0);
    }

    void setWidget(QWidget *aWidget) {
        // Remove the current widget if it exists
        if (widget) {
            layout->removeWidget(widget);
            widget->hide();
            widget->deleteLater();
            widget = nullptr;
        }

        // Add the new widget
        if (aWidget) {
            layout->addWidget(aWidget);
            widget = aWidget;
        }
    }

private:
    QVBoxLayout * layout;
    QWidget * widget;
};

并像这样使用它:

class MainWindow : public QMainWindow
{

public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent), centralWidget(new WidgetWrapper(this))
    {
        // Creating toolbar
        addToolBar("Tool bar")->addAction("Switch central Widget", this, &MainWindow::switchCentralWidget);

        // Init central widget
        setCentralWidget(centralWidget);
        switchCentralWidget();

        // Creating dock widget
        auto dockWidget = new QDockWidget("My dock widget");
        dockWidget->setWidget(new Widget("DOCK WIDGET", {200, 400}, this));
        addDockWidget(Qt::RightDockWidgetArea, dockWidget);
    }

private slots:

    void switchCentralWidget()
    {
        centralWidget->setWidget(new Widget("CENTRAL WIDGET", {300, 400}, this));
    }

    WidgetWrapper * centralWidget;
};
© www.soinside.com 2019 - 2024. All rights reserved.