C++如何通过编程方式调整Qt QDockWidget的大小?

27

我刚开始着手一个新的C++/Qt项目。它将是一个基于MDI的IDE,带有像文件树、对象浏览器、编译器输出等的停靠小部件。但目前有一件事情困扰着我:我无法弄清如何以编程方式使QDockWidget变小。例如,这个片段创建了我的底部停靠窗口“构建信息”:

m_compilerOutput = new QTextEdit;
m_compilerOutput->setReadOnly(true);
dock = new QDockWidget(tr("Build Information"), this);
dock->setWidget(m_compilerOutput);
addDockWidget(Qt::BottomDockWidgetArea, dock);
启动程序后,界面如下图所示(请注意开发早期的阶段): Actual 但是,我希望它看起来像这样: Expected 然而,我似乎无法做到这一点。Qt中QDockWidget参考文献上说:
“自定义大小提示、最小和最大尺寸以及尺寸策略应在子窗口小部件中实现。QDockWidget将尊重它们,并调整其自身的约束,以包括框架和标题。不应在QDockWidget本身上设置大小限制,因为它们会随着它是否停靠而改变。”
现在,这表明解决问题的一种方法是对QTextEdit进行子类化,并覆盖sizeHint()方法。然而,我宁愿不为此目的创建子类,也没有尝试过这个解决方案是否可行。
我已经尝试了调用dock->resize(m_compilerOutput->width(), m_compilerOutput->minimumHeight()),并使用m_compilerOutput->setSizePolicy()中的每个选项……到目前为止还没有影响大小的效果。正如我所说,我希望能够用几行简单的代码来解决问题,而不是创建一个子类来改变sizeHint()。感谢任何建议。
9个回答

11

我简化了它: 标题:

private void setDockSize(QDockWidget *dock, int, int);
  public slots:
  void returnToOldMaxMinSizes();

来源:

QSize oldMaxSize, oldMinSize;

void MainWindow::setDockSize(QDockWidget* dock, int setWidth,int setHeight)
{

    oldMaxSize=dock->maximumSize();
    oldMinSize=dock->minimumSize();

  if (setWidth>=0)
    if (dock->width()<setWidth)
        dock->setMinimumWidth(setWidth);
    else dock->setMaximumWidth(setWidth);
  if (setHeight>=0)
    if (dock->height()<setHeight)
        dock->setMinimumHeight(setHeight);
    else dock->setMaximumHeight(setHeight);

    QTimer::singleShot(1, this, SLOT(returnToOldMaxMinSizes()));
}

void MainWindow::returnToOldMaxMinSizes()
{
    ui->dockWidget->setMinimumSize(oldMinSize);
    ui->dockWidget->setMaximumSize(oldMaxSize);
}

3
可以将QTimer::singleShot的调用替换为qApp->processEvents(),两者的效果是一样的。虽然这是一种不良的 hack 手段,但这是我找到的唯一一种在 Qt 中调整停靠窗口小部件大小的方式。 - McLeary

9
这是一个旧问题,但我想提一下Qt 5.6引入了 QMainWindow::resizeDocks函数来处理这个问题。
不幸的是,它对于我的使用情况(在使用QMainWindows::splitDockWidget拆分两个QDockWidgets之间移动分隔符)无效。

如果我正确理解了您对答案的回复,只要在调用QMainWindow::show()之后调用resizeDocks,它就可以正常工作。 - titusjan

6
看起来 Dock Widget 会自动调整大小以适应其子部件。根据 QDockWidget 文档(重点在于子部件):
QDockWidget 充当其使用 setWidget() 设置的子部件的包装器。自定义大小提示、最小和最大大小以及大小策略应该在子部件中实现。QDockWidget 将尊重它们,调整自己的约束以包括框架和标题。不应在 QDockWidget 上设置大小约束,因为这些约束取决于它是否停靠;停靠的 QDockWidget 没有框架和较小的标题栏。
因此,要更改大小,您必须调整子部件的大小。
编辑:Qt 文档在讨论大小提示时有时可能会误导。通常,它是指任何由部件自动或程序化执行的大小调整。

5

我刚刚经历了同样的过程。在尝试了太多次对停靠窗口及其包含小部件使用resize()adjustSize()等方法之后,发现这些方法都没有用。最终,我选择子类化QListView并添加sizeHint()方法。

现在它工作得很好。


难道它不能像Python一样工作吗:创建一个新的Qwidget并调用dock.setWidget([your new Widget])。这样,您可以像这个例子中那样处理它:http://stackoverflow.com/questions/19760583/pyqt-resize-qdockwidget-in-maya?这样,您只需要覆盖QWidget一次,它就适用于每种情况。 - TheTrowser

2
你可以这样做:
为你的 QTextEdit 设置一个最大高度:
m_compilerOutput = new QTextEdit;
m_compilerOutput->setMaximumHeight(100);

然后在您的主窗口的显示事件中将其大小设置回旧的大小或更高的大小:

void MainWindow::showEvent(QShowEvent *)
{
   m_compilerOutput->setMaximumHeight(10000);
}

这就是你所需的全部内容。

2

你尝试过在你的停靠窗口小部件中调用resize()函数吗?你也可以尝试暂时将停靠窗口小部件的最大和最小尺寸设置为你想要的尺寸,然后恢复原始值。


你是正确的,设置停靠区域的最大和最小宽度/高度就足够了。此外,我们可以重新实现QMainWindow的“resizeEvent”事件,并在该事件中设置这两个值,以实现QDockWidget的动态调整大小。 - AshkanVZ

1

在使用QDockWidget::widget()上调整大小的测试中(即,QDockWidget正在管理的小部件),其结果并不总是如预期。

使用QDockWidget子类(DW),其中添加了一个具有两个小部件(left-panel和right-panel)的QHBoxLayoutQWidget,它们的大小策略均设置为QSizePolicy :: Minimum。 DW通常会显示两个面板小部件。当DW定位在侧面停靠时,应用程序(QMainWindow)插槽处理DW的dockLocationChanged信号隐藏左面板并将DW->widget()调整为右面板的大小。当DW以编程方式移动到底部停靠区域时,leftPanel设置为可见,并且DW填充主窗口的全宽度(当然)。然后,如果将DW从底部停靠区域拖动到侧面停靠区域,则虽然像以前一样隐藏了左面板并应用了重新调整大小,但DW未像在编程重新定位时那样重新调整大小。可以通过拖动DW和主窗口中央区域之间的分隔符手柄来手动调整DW的大小。请注意,主窗口中央区域是具有大小策略QSizePolicy :: ExpandingQWidget

在重新调整大小后,在主窗口上调用adjustSize没有任何效果。尽管DW已经重新实现了sizeHint,根据左侧面板是否可见返回其最小大小。

要么我在如何控制QDockWidget的大小方面缺少一些东西(考虑到我很难理解布局管理系统中所有部分之间的所有交互,这是相当可能的),要么QMainWindow正在忽略或覆盖它所接收到的布局指令。仔细检查QDockWidget重新定位操作期间的事件流表明后者:在处理dockLocationChanged信号的插槽完成其调整大小工作并返回事件循环后,当用户重新定位完成时,可以看到QMainWindow对受影响的QDockWidget应用额外的重新调整大小操作,从而撤消试图控制停靠大小的应用程序逻辑。 QMainWindow中似乎有问题....


1
如果dockWidgets被停靠,它们的大小由其父级控制。在这种情况下,您可以使用QMainWindow::resizeDocks函数。

如果浮动,大小取决于它们的子级。调整子级大小以实现您的目的。


0

当MainWindow最大化时,dock widgets的调整大小问题在QTBUG-16252中有描述(https://bugreports.qt.io/browse/QTBUG-16252)。

我已经找到了另一个解决方法。在Windows7上的QT 5.4.1 minGW上对我有效。 看起来一些小部件状态恢复操作与QApplication事件循环密切相关。

只有满足以下条件,DockWidget大小才会正确恢复:

  1. 在进入QApplication :: exec(例如,在MainWindow类的构造函数中)之前调用restoreGeometry()

  2. 在exec()之后调用restoreState(例如通过QTimer)

这是我的代码:

int main(int argc, char *argv[])
{
    QApplication application(argc, argv);

    //...

    MainWindow mainWindow;
    mainWindow.show();

    return application.exec();
}

MainWindow::MainWindow(...) 
{
    ui->setupUi(this);

    //...
    QTimer* nt = new QTimer(this);

    nt->setSingleShot(true);
    nt->setInterval( 100 );

    connect(nt, SIGNAL(timeout()), SLOT(restoreWidgetSettings()));
    nt->connect(nt, SIGNAL(timeout()), SLOT(deleteLater()));

    nt->start();

    restoreWidgetSettings(true);
}

void MainWindow::restoreWidgetSettings(bool geometryOnly) {

    //...
    QByteArray geometry = getSettings();

    restoreGeometry(geometry);

    if(geometryOnly)
        return;

    //... //create dock widgets here

    restoreState(mainWindowState);

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接