C++ 以编程方式调整停靠的 Qt QDockWidget 的大小?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2722939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:29:50  来源:igfitidea点击:

C++ resize a docked Qt QDockWidget programmatically?

c++qtresizeqdockwidget

提问by Zac

I've just started working on a new C++/Qt project. It's going to be an MDI-based IDE with docked widgets for things like the file tree, object browser, compiler output, etc. One thing is bugging me so far though: I can't figure out how to programmatically make a QDockWidgetsmaller. For example, this snippet creates my bottom dock window, "Build Information":

我刚刚开始从事一个新的 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);

When launched, my program looks like this (bear in mind the early stage of development):

启动时,我的程序看起来像这样(记住开发的早期阶段):

Actual

实际的

However, I want it to appear like this:

但是,我希望它看起来像这样:

Expected

预期的

I can't seem to get this to happen. The Qt Reference on QDockWidget says this:

我似乎无法让这发生。QDockWidget 上的 Qt 参考是这样说的:

Custom size hints, minimum and maximum sizes and size policies should be implemented in the child widget. QDockWidget will respect them, adjusting its own constraints to include the frame and title. Size constraints should not be set on the QDockWidget itself, because they change depending on whether it is docked

自定义大小提示、最小和最大大小以及大小策略应在子小部件中实现。QDockWidget 会尊重它们,调整自己的约束以包含框架和标题。不应在 QDockWidget 本身上设置大小约束,因为它们会根据是否停靠而改变

Now, this suggests that one method of going about doing this would be to sub-class QTextEditand override the sizeHint()method. However, I would prefer not to do this just for that purpose, nor have I tried it to find that to be a working solution.

现在,这表明进行此操作的一种方法是子类化QTextEdit并覆盖该sizeHint()方法。但是,我不想仅仅为了这个目的而这样做,我也没有尝试找到它是一个可行的解决方案。

I have tried calling dock->resize(m_compilerOutput->width(), m_compilerOutput->minimumHeight()), calling m_compilerOutput->setSizePolicy()with each of its options... Nothing so far has affected the size. Like I said, I would prefer a simple solution in a few lines of code to having to create a sub-class just to change sizeHint(). All suggestions are appreciated.

我试过调用dock->resize(m_compilerOutput->width(), m_compilerOutput->minimumHeight()),调用m_compilerOutput->setSizePolicy()它的每个选项......到目前为止没有任何影响大小。就像我说的,我更喜欢在几行代码中的简单解决方案,而不必创建一个子类来更改sizeHint(). 所有建议表示赞赏。

采纳答案by Charl Botha

I just went through this same process. After trying far too many permutations of resize(), adjustSize()and friends on dock widgets and their contained widget, none of which worked, I ended up subclassing QListViewand adding that sizeHint()method.

我刚刚经历了同样的过程。在尝试了太多的resize(),adjustSize()和停靠小部件及其包含的小部件上的朋友的排列后,没有一个起作用,我最终子类化QListView并添加了该sizeHint()方法。

Now it works like a charm.

现在它就像一个魅力。

回答by semenvx

I made it easy: HEADER:

我让它变得简单:标题:

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

SOURCE:

来源:

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);
}

回答by TreDubZedd

It sounds like the dock widget re-sizes itself to the proper size, considering its child widget. From the QDockWidget documentation (emphasis mine):

考虑到它的子小部件,这听起来像是停靠小部件将自身重新调整为适当的大小。从 QDockWidget 文档(强调我的):

A QDockWidget acts as a wrapper for its child widget, set with setWidget(). Custom size hints, minimum and maximum sizes and size policies should be implemented in the child widget. QDockWidget will respect them, adjusting its own constraints to include the frame and title. Size constraints should not be set on the QDockWidget itself, because they change depending on wether it is docked; a docked QDockWidget has no frame and a smaller title bar.

QDockWidget 充​​当其子小部件的包装器,使用 setWidget() 设置。自定义大小提示、最小和最大大小以及大小策略应在子小部件中实现。QDockWidget 会尊重它们,调整自己的约束以包含框架和标题。不应在 QDockWidget 本身上设置大小约束,因为它们会根据它是否停靠而改变;停靠的 QDockWidget 没有框架和较小的标题栏。

In order to change the size, then, you must re-size the child widget.

为了更改大小,您必须重新调整子小部件的大小。

EDIT: The Qt documentation can sometimes be misleading when it discusses size hints. Often, it's referring to any kind of resizing, whether performed automatically by the widget or programatically.

编辑:Qt 文档在讨论大小提示时有时会产生误导。通常,它指的是任何类型的调整大小,无论是由小部件自动执行还是以编程方式执行。

回答by Alex Goldberg

This is an old question, but I wanted to chime in to mention that Qt 5.6 introduced the QMainWindow::resizeDocksfunction to handle this.

这是一个老问题,但我想插一句,Qt 5.6 引入了QMainWindow::resizeDocks函数来处理这个问题。

Unfortunately, it doesn't work for my use case(moving separator between two QDockWidgets that have been split with QMainWindows::splitDockWidget)

不幸的是,它不适用于我的用例(在使用 QMainWindows::splitDockWidget 拆分的两个 QDockWidget 之间移动分隔符)

回答by thuga

You could do this:

你可以这样做:

Set a maximum height for your QTextEdit:

为您设置最大高度QTextEdit

m_compilerOutput = new QTextEdit;
m_compilerOutput->setMaximumHeight(100);

And then in the show eventof your main window set it back to the old size or something high:

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

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

That is all you should need.

这就是你所需要的。

回答by Kitsune

Have you tried calling resize()on the QTextEditinside your dock widget? You could also try temporarily setting the dock widget's maximum & minimum sizes to the size you want it to be, then restore the original values.

您是否尝试过调用Dock 小部件resize()QTextEdit内部?您还可以尝试将停靠小部件的最大和最小尺寸临时设置为您想要的尺寸,然后恢复原始值。

回答by user674263

Tests using resize on the QDockWidget::widget()(i.e. the widget that the QDockWidgetis managing) do not consistently work as expected.

QDockWidget::widget()(即QDockWidget正在管理的小部件)上使用调整大小的测试并不能始终如预期地工作。

With a QDockWidgetsubclass (DW) in which a QWidgetwith a QHBoxLayoutthat has two widgets (left-panel and right-panel) added, all of which have had their size policies set to QSizePolicy::Minimum, the DW normally has both panel widgets visible. When the DW is positioned in a side dock an application (QMainWindow) slot handling the DW's dockLocationChangedsignal hides left-panel and re-sizes the DW->widget()to the size right-panel. When the DW is programmatically moved to the bottom dock area leftPanel is set visible and the DW fills the full width of the main window (of course). When the DW is then programmatically moved to a side dock area the left-panel is hidden and the DW is re-sized down. This works as intended. However, if the DW is dragged from the bottom dock area to a side dock area, though the left-panel is hidden and the re-size applied as before, the DW is not re-sized down as when the repositioning is done programatically. The DW can be manually re-sized down by dragging the splitter handele between the DW and main window central area. Note that the main window central area is a QWidgethaving a QHBoxLayoutwith size polices QSizePolicy::Expanding.

QDockWidget子类 (DW) 中,QWidget添加了QHBoxLayout两个小部件(左面板和右面板)的子类 (DW),所有这些小部件的大小策略都设置为QSizePolicy::Minimum,DW 通常使两个面板小部件都可见。当 DW 位于侧板时,QMainWindow处理 DWdockLocationChanged信号的应用程序 ( ) 插槽会隐藏左侧面板并重新调整其大小DW->widget()到大小右侧面板。当 DW 以编程方式移动到底部停靠区域时,leftPanel 设置为可见并且 DW 填充主窗口的整个宽度(当然)。当 DW 然后以编程方式移动到侧停靠区域时,左侧面板被隐藏并且 DW 被重新调整大小。这按预期工作。但是,如果将 DW 从底部停靠区域拖到侧停靠区域,尽管左侧面板被隐藏并且像以前一样应用了重新调整大小,但在重新定位以编程方式完成时,DW 不会重新调整大小。DW 可以通过拖动 DW 和主窗口中央区域之间的分隔手柄手动重新调整大小。请注意,主窗口中央区域是QWidget一个QHBoxLayout带有大小的策略QSizePolicy::Expanding

Calling adjustSizeon the main window after the DW has been re-sized has no effect. This despite the DW having reimplemented sizeHintto return its minimum size depending on whether left-panel is visible or not.

adjustSize在重新调整 DW 大小后调用主窗口无效。尽管 DW 已重新实现sizeHint以根据左面板是否可见来返回其最小大小。

Either I am missing something in how to control the size of QDockWidget(which, given the difficulty I've had understanding all the interactions amongst the parts of the layout management system, is quite likely), or the QMainWindowis ignoring or overriding the layout instructions that it is being given. Closely examining the event stream during the QDockWidgetrepositioning operations suggests the latter: After the slot handling the dockLocationChangedsignal has done its resizing work and returned to the event loop I can see that the QMainWindow, when user repositioning is done, applies additional re-size operations on the affected QDockWidgetthus undoing the application logic that attempts to control the dock size. Something seems amiss in the QMainWindow....

要么我在如何控制大小方面遗漏了一些东西QDockWidget(鉴于我很难理解布局管理系统各部分之间的所有交互,这很可能),或者QMainWindow忽略或覆盖布局说明它正在被给予。在QDockWidget重新定位操作期间仔细检查事件流表明后者:在处理dockLocationChanged信号的槽完成其调整大小工作并返回到事件循环后,我可以看到QMainWindow,当用户重新定位完成后,在影响QDockWidget从而撤消尝试控制停靠栏大小的应用程序逻辑。似乎有些不对劲QMainWindow......

回答by momo

If the dockWidgets are docked, the sizes are control by their parent. In such cases you can use the QMainWindow::resizeDocksfunction.

如果停靠dockWidgets,则大小由其父级控制。在这种情况下,您可以使用该QMainWindow::resizeDocks功能。

If floating, sizes are determined by their children.Resize childrento achieve your purpose.

如果浮动,尺寸由它们的孩子决定。调整孩子的大小以实现您的目的。

回答by vrogach

The resize of dock widgets problem when MainWindow is maximized is described in QTBUG-16252 (https://bugreports.qt.io/browse/QTBUG-16252)

在 QTBUG-16252 ( https://bugreports.qt.io/browse/QTBUG-16252) 中描述了 MainWindow 最大化时停靠小部件的大小调整问题

I've found another workaround on it. Works for me on QT 5.4.1 minGW on Windows7. It looks like some widget state restore operations are closely related to QApplication event loop.

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

DockWidget sizes are restored correctly ONLY when following conditions are met:

仅当满足以下条件时,DockWidget 大小才能正确恢复:

  1. restoreGeometry() is called BEFORE entering QApplication::exec() (e.g. in constructor of your MainWindow class)

  2. restoreState() is called AFTER exec() (e.g. via QTimer)

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

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

Here is my code:

这是我的代码:

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);

}