源码是这样子做的:
QLayout删除或增加layoutitem时候,会调用invalidate函数,setDirty为false,把rect置为空。再调用update函数。update函数会判断下当前界面是不是active的,然后发送一个LayoutRequest事件。事件循环器在QApplication的notify_helper中分配这个事件到QLayout。QLayout再调用active函数。active根据QLayout的sizeConstraint模式,
SetFixedSize, SetMinimumSize,SetMaximumSize,SetMinAndMaxSize,SetDefaultConstraint约束父控件的最大最小尺寸。 QLayout默认是SetDefaultConstraint,
这个模式下,会通过totalMininumSize()这个函数得到当前的最小尺寸。然后根据Layout的方向,把父控件的最小尺寸设置到size中去。最好把这个尺寸设置到父控件的minimunsize中去。
接着调用doResize,拿到当前父控件的size,根据是否有menubar,重新计算一遍Geometry。
最后updateGeometry。
总之,重点就是layout更新之后只是设置了最小的尺寸,而父控件的更新size的策略会先和最小尺寸比较下。再跟新自己的尺寸。
也就解释了为什么增加会刷新父控件的尺寸,而减少不会更新父控件的尺寸。
那么怎么去解决这个问题呢。
我们就要去分析QWidget的sizeHinit函数。这个函数是通过父控件的totalSizeHint()去获得QLayout的尺寸的。
在totalSizeHint中,会先或者QLayout的sizeHint的尺寸。然后那个父控件的Margin。把size和margin相加返回。
分析QLayout的 sizeHint函数发现会判断下当前的Layout是不是dirty的,然后调用setupGeom函数,setupGeom会计算Layout中的各个子控件,的最大值最小值以及默认的size,汇总以后保存。也就是说可以拿到layout的sizeHint尺寸去resize父控件。
还有一个问题,增加子控件之后,更新layout尺寸会发出一个Layout异步事件,会导致sizihint和miniSize的尺寸跟不及时。需要在处理完事件之后再刷新尺寸。
所以我们要等到父控件处理完LayoutRequest事件之后再去刷新尺寸。研究Layout源码发现。处理LayoutRequest时候之后,会调用一边setGeometry这个虚函数函数,于是重写这个最后的解决发难就是重写这个虚函数,再setGeometry之后发送一个刷新的信号,刷新主界面。