与QMainWindow的GUI命令交互时,QDockWidget不会正确调整大小

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

关于QDockWidget的非正确调整大小,我有一个问题。特别是当我启动GUI时,QDockWidget就像下图中的错误一样。我也在使用.ui时调整QDockWidget的大小,但是一旦我与.ui交互(例如使用QPushButton或使用QCheckBox),QDockWidget会再次变大:

预期的行为是下面的行为,它不会在与.ui的交互过程中突然增加维度,而是保持在下面的位置:

下面是我正在为这个项目使用的代码中最重要的部分,我签署了编译器通过// <-- ERROR HERE通知的3个调试错误,如果这可能有用:

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    mDockWidget_A = new QDockWidget(QLatin1String("Command Log"));
    mDockWidget_A->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    mNewText = new QPlainTextEdit;
    mNewText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    mDockWidget_A->setWidget(mNewText);

    mDockWidget_A->installEventFilter(new QDockResizeEventFilter(mNewText,dynamic_cast<QFluidGridLayout*>(mNewText->layout())));
    addDockWidget(Qt::BottomDockWidgetArea, mDockWidget_A);
}

qdockresizeeventfilter.h

#include <QObject>
#include <QLayout>
#include <QEvent>
#include <QDockWidget>
#include <QResizeEvent>
#include <QCoreApplication>
#include <QMouseEvent>
#include "qfluidgridlayout.h"
#include "mainwindow.h"

class QDockResizeEventFilter : public QObject
{

public:
    friend QMainWindow;
    friend QLayoutPrivate;
    QDockResizeEventFilter(QWidget* dockChild, QFluidGridLayout* layout, QObject* parent = nullptr)
        : QObject(parent), m_dockChild(dockChild), m_layout(layout)
    {

    }

protected:

    bool eventFilter(QObject *p_obj, QEvent *p_event)
    {  
        if (p_event->type() == QEvent::Resize)
        {
            QResizeEvent* resizeEvent   = static_cast<QResizeEvent*>(p_event);
            QMainWindow* mainWindow     = dynamic_cast<QMainWindow*>(p_obj->parent());              
            QDockWidget* dock           = static_cast<QDockWidget*>(p_obj);

            // determine resize direction
            if (resizeEvent->oldSize().height() != resizeEvent->size().height())
            {
                // vertical expansion
                QSize fixedSize(m_layout->widthForHeight(m_dockChild->size().height()), m_dockChild->size().height()); // <-- ERROR HERE
                if (dock->size().width() != fixedSize.width())
                {
                    m_dockChild->setFixedWidth(fixedSize.width());
                    dock->setFixedWidth(fixedSize.width());

                    // cause mainWindow dock layout recalculation
                    QDockWidget* dummy = new QDockWidget;
                    mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dummy);
                    mainWindow->removeDockWidget(dummy);

                    // adding dock widgets causes the separator move event to end
                    // restart it by synthesizing a mouse press event
                    QPoint mousePos = mainWindow->mapFromGlobal(QCursor::pos());
                    mousePos.setY(dock->rect().bottom());
                    QCursor::setPos(mainWindow->mapToGlobal(mousePos));
                    QMouseEvent* grabSeparatorEvent = new QMouseEvent(QMouseEvent::MouseButtonPress,mousePos,Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);
                    qApp->postEvent(mainWindow, grabSeparatorEvent);
                }
            }
            if (resizeEvent->oldSize().width() != resizeEvent->size().width())
            {
                // Do nothing
            }           
        }   
        return false;
    }

private:

    QWidget* m_dockChild;
    QFluidGridLayout* m_layout;
};

#endif // QDockResizeEventFilter_h_

最后是qfluidgridlayout.h

#ifndef QFluidGridLayout_h_
#define QFluidGridLayout_h_

#include <QLayout>
#include <QGridLayout>
#include <QRect>
#include <QStyle>
#include <QWidgetItem>

class QFluidGridLayout : public QLayout
{
public:

    enum Direction { downToUp, UpToDown };
    QFluidGridLayout(QWidget *parent = nullptr)
        : QLayout(parent)
    {
        setContentsMargins(8,8,8,8);
        setSizeConstraint(QLayout::SetMinAndMaxSize);
    }

    ~QFluidGridLayout() {
        QLayoutItem *item;
        while ((item = takeAt(0)))
            delete item;
    }

    void addItem(QLayoutItem *item) {
        itemList.append(item);
    }

    Qt::Orientations expandingDirections() const {
        return nullptr;
    }

    bool hasHeightForWidth() const {
        return false;
    }

    int heightForWidth(int width) const {
        int height = doLayout(QRect(0, 0, width, 0), true, true);
        return height;
    }

    bool hasWidthForHeight() const {
        return true;
    }

    int widthForHeight(int height) const {  // <-- ERROR HERE
        int width = doLayout(QRect(0, 0, 0, height), true, false);
        return width;
    }

    int count() const {
        return itemList.size();
    }

    QLayoutItem *itemAt(int index) const {
        return itemList.value(index);
    }

    QSize minimumSize() const {
        QSize size;
        QLayoutItem *item;
        foreach (item, itemList)
            size = size.expandedTo(item->minimumSize());
        size += QSize(2*margin(), 2*margin());
        return size;
    }

    void setGeometry(const QRect &rect) {
        QLayout::setGeometry(rect);
        doLayout(rect); 
    }

    QSize sizeHint() const {
        return minimumSize();
    }

    QLayoutItem *takeAt(int index) {
        if (index >= 0 && index < itemList.size())
            return itemList.takeAt(index);
        else
            return nullptr; }
private:
    int doLayout(const QRect &rect, bool testOnly = false, bool width = false) const
    {
        int left, top, right, bottom;
        getContentsMargins(&left, &top, &right, &bottom); // <-- ERROR HERE
        QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
        int x = effectiveRect.x();
        int y = effectiveRect.y();
        int lineHeight = 0;
        int lineWidth = 0;
        QLayoutItem* item;
        foreach(item,itemList)
        {
            QWidget* widget = item->widget();   
            if (y + item->sizeHint().height() > effectiveRect.bottom() && lineWidth > 0) {
                y = effectiveRect.y();
                x += lineWidth + right;
                lineWidth = 0;
            }
            if (!testOnly) {
                item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
            }
            y += item->sizeHint().height() + top;
            lineHeight = qMax(lineHeight, item->sizeHint().height());
            lineWidth = qMax(lineWidth, item->sizeHint().width());
        } 
        if (width) {
            return y + lineHeight - rect.y() + bottom;
        }
        else {
            return x + lineWidth - rect.x() + right;
        }
    }
    QList<QLayoutItem *> itemList;
    Direction dir;
};

#endif // QFluidGridLayout_h_

我经常阅读herein this post这个问题。然而,我一直在阅读这个特定对象可能有一些bugs的可能性,并建议覆盖resiveEvent。然而,这一切都没有奏效。

最后,经过大量的研究,我发现this useful post几乎复制了我所拥有的问题,并且在class QFluidGridLayoutclass QDockResizeEventFilter之上的两个类中占据了大部分。

虽然我使用相同的方法,但我仍然无法实现此对象的正常行为。

我还包括调试器的快照:

有人可以解释我做错了什么吗?非常感谢您对这个问题的阐述。

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

@Emanuele,你看到的post主要用于将QDockWidget分类为小孩,因此该解决方案必须手动实施。我想如果你看看this alternative solution,你会发现它很有用。

尝试修改你的构造函数,在帖子中添加resizeDocks({dock}, {100}, Qt::Horizontal);,以便:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    mDockWidget_A = new QDockWidget(QLatin1String("Command Log"));
    mDockWidget_A->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    mNewText = new QPlainTextEdit;
    mNewText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    mDockWidget_A->setWidget(mNewText);
    mDockWidget_A->installEventFilter(new QDockResizeEventFilter(mNewText,dynamic_cast<QFluidGridLayout*>(mNewText->layout())));
    addDockWidget(Qt::BottomDockWidgetArea, mDockWidget_A);

    resizeDocks({mDockWidget_A}, {100}, Qt::Horizontal);

}
© www.soinside.com 2019 - 2024. All rights reserved.