与 QMainWindow 的 GUI 命令交互时,QDockWidget 无法正确调整大小
Posted
技术标签:
【中文标题】与 QMainWindow 的 GUI 命令交互时,QDockWidget 无法正确调整大小【英文标题】:QDockWidget does not resize properly when interacting with GUI commands of QMainWindow 【发布时间】:2019-03-12 00:39:08 【问题描述】:我有一个关于 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_
我经常在here 和in this post 阅读有关此问题的信息。但是我一直在阅读有关此特定对象可能有一些bugs 的可能性,建议覆盖resiveEvent
。然而,这些都没有奏效。
经过大量研究,我终于找到了this useful post,它几乎复制了我遇到的问题,并且承载了class QFluidGridLayout
和class QDockResizeEventFilter
以上两个类中的大部分。
虽然我使用相同的方法,但我仍然无法实现该对象的正常行为。
我还包括调试器的快照:
谁能解释我做错了什么?非常感谢您阐明这个问题。
【问题讨论】:
【参考方案1】:@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);
【讨论】:
@Linds,感谢您抽出宝贵时间阅读问题。是的,这行得通!这比我想象的要容易得多:)以上是关于与 QMainWindow 的 GUI 命令交互时,QDockWidget 无法正确调整大小的主要内容,如果未能解决你的问题,请参考以下文章