更改QDockWidget内容时的行为

3
我遇到了一个关于我的QDockWidget的问题。我在一个QDockWidget中有几个QWidget项目,有时可见,有时不可见。
我希望我的QDockWidget可以根据其内容自动调整大小......不仅在QWidgets出现时,而且在它们消失时也能调整大小......
目前,当我在QDockWidget中显示更多QWidgets时,它会自动调整大小,但是当我让它们消失时,QDockWidget保持原来的大小...
有什么想法可以帮忙吗?
提前感谢!
2个回答

7
多年来,关于在QMainWindow的停靠区域中控制QDockWidget大小的帖子层出不穷。我也一直在努力解决这个问题,但只能实现部分、有些令人不满意的解决方案。主要问题在于无法从管理其停靠区域的QMainWindow上下文中掌握停靠机制。使用布局管理(尺寸策略和尺寸提示控件)的尝试并不有效;当改变停靠区域大小时,QMainWindow会按照自己的方式进行操作。
首先,我取得了一些有限的成功:
QMainWindow子类(MW)和QDockWidget子类(DW)开始。 DW有一个QWidget,其中包含一个QHBoxLayout,并在DW中设置了setWidget。该布局有两个小部件 - 我将它们称为面板 - 其中一个面板根据上下文意图显示或隐藏:当DW位于底部或顶部停靠区域或浮动时显示,否则隐藏。构建后另一个面板的sizeHint(以及适当的边距间距)用于设置DW的“基本尺寸”,而将改变可见性的面板的构造sizeHint宽度提供了增量,从而在适当时提供了基本尺寸的增量:DW实现提供了一个panel_visible方法,该方法用于通过对面板应用setVisible并更改增量值的sizeHint值来启用或禁用可变面板。DW及其面板的大小策略设置为Minimum。
在MW中,DW的dockLocationChanged和topLevelChanged信号连接到DW_resize插槽。在此情况下,当DW可见时,isWindow为false,并且MW::dockWidgetArea报告LeftDockWidgetArea或RightDockWidgeArea时,将调用DW::panel_visible(false)以更改有效的DW大小(当不满足上述条件时,当然会调用DW::panel_visible(true))。调用DW::resize,在MW中调用updateGeometry和update对停靠区域大小没有影响。但是,如果调用DW::setMaximumSize(DW::sizeHint()),则可以正确调整停靠区域的大小(不需要updateGeometry或update)。当DW浮动(通过拖动或双击其标题栏)然后重新停靠(通过双击其标题栏或将其拖回侧面停靠区域)时,这起作用得很好。
现在问题来了:
已经强制MW适应其停靠区域的预定DW大小,因此需要释放DW的固定大小限制,以便用户可以通过拖动MW提供的分隔手柄来调整停靠区域和中心区域之间的宽度。显然的答案是只需调用DW::setMaximumSize(0xFFFFFF, 0xFFFFFF)来“释放”DW约束即可。是的,除了幕后进行的更新绘画优化合并两个大小调整事件的结果导致初始停靠缩小操作丢失。通过在两个setMaxmimumSize调用之间放置qApp->sendPostedEvents()和qApp->flush(),可以避免这种优化效果,将停靠区域适应DW大小,然后释放停靠区域,以便用户可以调整停靠区域的大小...有时。
这个解决方案适用于通过双击 DW 标题栏将其从浮动状态变为停靠状态的情况,但不适用于将 DW 拖到 MW 的侧边停靠区域。例如,如果用户将 DW 从左侧停靠区域拖到右侧停靠区域,则右侧停靠区域的大小不会按预期调整;接收停靠区域仍保持拖动过程中产生的浮动 DW 的大小。如果在接收停靠区域中的 DW 标题栏上双击(使其再次浮动),然后再次双击(将其返回到相同的停靠区域),则 MW 现在符合预期的停靠区域大小。经过仔细检查 - 通过监视 MW::paintEvent - 我发现当停靠区域达到预期大小时,flush() 立即跟随一个 paintEvent,其中 DW 报告具有预期大小,并且在取消限制 DW 的第二个 setMaximumSize 后,DW 发生了一个 paintEvent,大小仍然是预期的。但是,当 DW 被拖入停靠区域时,flush() 再次立即跟随 paintEvent,其中 DW 报告具有预期大小,但在这种情况下,在第二个 setMaximumSize 后有两个 paintEvent,而 DW 突然具有其先前的浮动大小!

我还没有找到防止正确调整大小后未经解释地覆盖 DW 大小的方法。显然,MWDW_resize 槽处理返回后从信号发出导致槽的信息中保持了尺寸信息,并生成了一个附加的调整大小事件。监视 MW::eventFilter 确实显示,在 DW_resize 返回后会发生调整大小事件,将 DW 的大小从在槽代码中设置的大小更改回其浮动状态时的大小。当使用双击 DW 标题栏将 DW 从浮动状态移回侧边停靠区域时,DW_resize 槽返回后不会发生其他调整大小事件。

因此,挑战在于如何防止在 DW_resize 槽中正确调整 DW 大小后发生意外的大小调整。也许在 DW::resizeEvent 中进行某些强制转换可以避免这个问题....

当然,更好的方式是Qt开发人员在QMainWindow API中提供应用程序开发人员对其停靠区域管理活动(特别是停靠区域大小)以及/或者访问其用于停靠区域管理的小部件的全面控制。
我目前在Linux、OS X和MS/Windows上使用Qt 4.6.2。上述调试报告是在Intel OS X 10.6.7系统上完成的;在不同平台上结果略有不同,但基本问题相同。也许这些QMainWindow/QDockWidget问题已经在Qt的较新版本中得到解决?也许有人对此有更深入的了解并能提供简单的解决方案?

Qt 5.15.2,MacOs 12.6.1 Monterey仍然存在同样的问题。在Linux和Windows上没有遇到过(可能会有更接近的例外情况揭示任何事情,但似乎是一个特定于Mac的问题)。 - Mykola Tetiuk

1

我一直遇到同样的问题。不知何故,将restoreState()调用两次对我有用。
我正在使用Qt 4.7.0。

void MainWnd::showEvent(QShowEvent *se){
QMainWindow::showEvent(se);

static bool first = true;

if (first){
   restoreState(...);
   restoreState(...);
   first = false;
}
}

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