enum QLayout::SizeConstraint
The possible values are:
Constant ValueDescription:
QLayout::SetDefaultConstraint 0
The main widget's minimum size is set to minimumSize(), unless the widget already has a minimum size.
QLayout::SetFixedSize 3
The main widget's size is set to sizeHint(); it cannot be resized at all.
QLayout::SetMinimumSize 2
The main widget's minimum size is set to minimumSize(); it cannot be smaller.
QLayout::SetMaximumSize 4
The main widget's maximum size is set to maximumSize(); it cannot be larger.
QLayout::SetMinAndMaxSize 5
The main widget's minimum size is set to minimumSize() and its maximum size is set to maximumSize().
QLayout::SetNoConstraint 1
The widget is not constrained.
不過,這裏也有幾個問題是需要注意一下下的:
1)被QLayout::setSizeConstraint()所設置的約束,是對qlayout的父窗口而言的。譬如,當某qlayout設置了QLayout::SetMinimumSize約束屬性,則它的父窗口(mainW)的minimumSize則會設置爲qlayout的totalMinimumSize()值;相當於, mainW->setMinimumSize(qlayout->totalMinimumSize())。
2)QLayout::totalMinimumSize()的計算裏有點貓膩。
下面看看代碼的,
1)對於第一點,直接看QLayout::activate()函數就可以一目瞭然的。
bool QLayout::activate()
{
Q_D(QLayout);
if (!d->enabled || !parent())
return false;
if (!d->topLevel)
return static_cast<QLayout*>(parent())->activate();
if (d->activated)
return false;
QWidget *mw = static_cast<QWidget*>(parent());
if (mw == 0) {
qWarning("QLayout::activate: %s \"%s\" does not have a main widget",
QObject::metaObject()->className(), QObject::objectName().toLocal8Bit().data());
return false;
}
activateRecursiveHelper(this);
QWidgetPrivate *md = mw->d_func();
uint explMin = md->extra ? md->extra->explicitMinSize : 0;
uint explMax = md->extra ? md->extra->explicitMaxSize : 0;
// 此處根據不同的約束條件,來給qlayout的父窗口設置相應的Size約束條件
// *****************************************************************
switch (d->constraint) {
case SetFixedSize:
// will trigger resize
mw->setFixedSize(totalSizeHint());
break;
case SetMinimumSize:
mw->setMinimumSize(totalMinimumSize());
break;
case SetMaximumSize:
mw->setMaximumSize(totalMaximumSize());
break;
case SetMinAndMaxSize:
mw->setMinimumSize(totalMinimumSize());
mw->setMaximumSize(totalMaximumSize());
break;
case SetDefaultConstraint: {
bool widthSet = explMin & Qt::Horizontal;
bool heightSet = explMin & Qt::Vertical;
if (mw->isWindow()) {
QSize ms = totalMinimumSize();
if (widthSet)
ms.setWidth(mw->minimumSize().width());
if (heightSet)
ms.setHeight(mw->minimumSize().height());
if ((!heightSet || !widthSet) && hasHeightForWidth()) {
int h = minimumHeightForWidth(ms.width());
if (h > ms.height()) {
if (!heightSet)
ms.setHeight(0);
if (!widthSet)
ms.setWidth(0);
}
}
mw->setMinimumSize(ms);
} else if (!widthSet || !heightSet) {
QSize ms = mw->minimumSize();
if (!widthSet)
ms.setWidth(0);
if (!heightSet)
ms.setHeight(0);
mw->setMinimumSize(ms);
}
break;
}
case SetNoConstraint:
break;
}
d->doResize(mw->size());
if (md->extra) {
md->extra->explicitMinSize = explMin;
md->extra->explicitMaxSize = explMax;
}
// ideally only if sizeHint() or sizePolicy() has changed
mw->updateGeometry();
return true;
}
2)對於第二個問題,以SetMinimumSize爲例子,首先得從QLayout::totalMinimumSize()函數開始的:
QSize QLayout::totalMinimumSize() const
{
Q_D(const QLayout);
int side=0, top=0;
if (d->topLevel) {
QWidget *pw = parentWidget();
pw->ensurePolished();
QWidgetPrivate *wd = pw->d_func();
side += wd->leftmargin + wd->rightmargin;
top += wd->topmargin + wd->bottommargin;
}
// 這裏需要看這一行就行了:說明我們要再看minimumSize()這個函數。
QSize s = minimumSize();
#ifndef QT_NO_MENUBAR
top += menuBarHeightForWidth(d->menubar, s.width() + side);
#endif
return s + QSize(side, top);
}
好吧,順藤摸瓜,依次經歷了(注意我調試代碼時,是用QHBoxLayout作爲例子的)QBoxLayout::minimumSize() -> QBoxLayoutPrivate::setupGeom() -> QWidgetItemV2::minimumSize()
最後,發現了QWidgetItemV2::updateCacheIfNecessary()這個函數
void QWidgetItemV2::updateCacheIfNecessary() const
{
if (q_cachedMinimumSize.width() != Dirty)
return;
const QSize sizeHint(wid->sizeHint());
const QSize minimumSizeHint(wid->minimumSizeHint());
const QSize minimumSize(wid->minimumSize());
const QSize maximumSize(wid->maximumSize());
const QSizePolicy sizePolicy(wid->sizePolicy());
const QSize expandedSizeHint(sizeHint.expandedTo(minimumSizeHint));
// 於是那點貓開始浮出水面了~沒錯,就是qSmartMinSize()函數!
// layout item的大小計算都是經由qSmart*Size()函數來計算的。
const QSize smartMinSize(qSmartMinSize(sizeHint, minimumSizeHint, minimumSize, maximumSize, sizePolicy));
const QSize smartMaxSize(qSmartMaxSize(expandedSizeHint, minimumSize, maximumSize, sizePolicy, align));
const bool useLayoutItemRect = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect);
q_cachedMinimumSize = useLayoutItemRect
? toLayoutItemSize(wid->d_func(), smartMinSize)
: smartMinSize;
q_cachedSizeHint = expandedSizeHint;
q_cachedSizeHint = q_cachedSizeHint.boundedTo(maximumSize)
.expandedTo(minimumSize);
q_cachedSizeHint = useLayoutItemRect
? toLayoutItemSize(wid->d_func(), q_cachedSizeHint)
: q_cachedSizeHint;
if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
q_cachedSizeHint.setWidth(0);
if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
q_cachedSizeHint.setHeight(0);
q_cachedMaximumSize = useLayoutItemRect
? toLayoutItemSize(wid->d_func(), smartMaxSize)
: smartMaxSize;
}
可見,layout item的大小計算都是經由qSmart*Size()函數來計算的。於是,看一下下代碼,
Q_GUI_EXPORT QSize qSmartMinSize(const QSize &sizeHint, const QSize &minSizeHint,
const QSize &minSize, const QSize &maxSize,
const QSizePolicy &sizePolicy)
{
QSize s(0, 0);
// 根據不同大小策略,不同的考慮,但是,minSizeHint纔是影響大小的人
if (sizePolicy.horizontalPolicy() != QSizePolicy::Ignored) {
if (sizePolicy.horizontalPolicy() & QSizePolicy::ShrinkFlag)
s.setWidth(minSizeHint.width());
else
s.setWidth(qMax(sizeHint.width(), minSizeHint.width()));
}
if (sizePolicy.verticalPolicy() != QSizePolicy::Ignored) {
if (sizePolicy.verticalPolicy() & QSizePolicy::ShrinkFlag) {
s.setHeight(minSizeHint.height());
} else {
s.setHeight(qMax(sizeHint.height(), minSizeHint.height()));
}
}
// 這裏,只有當minSize大於0時,控件上所設置最小大小纔會有影響力。呃,所謂的貓膩就是指這個。是我故弄玄虛了~
s = s.boundedTo(maxSize);
if (minSize.width() > 0)
s.setWidth(minSize.width());
if (minSize.height() > 0)
s.setHeight(minSize.height());
return s.expandedTo(QSize(0,0));
}
相關的其它類型的大小計算,也一併貼上來吧。它們都是alayoutengine.cpp(layout計算引擎)代碼。
Q_GUI_EXPORT QSize qSmartMaxSize(const QSize &sizeHint,
const QSize &minSize, const QSize &maxSize,
const QSizePolicy &sizePolicy, Qt::Alignment align)
{
if (align & Qt::AlignHorizontal_Mask && align & Qt::AlignVertical_Mask)
return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
QSize s = maxSize;
QSize hint = sizeHint.expandedTo(minSize);
if (s.width() == QWIDGETSIZE_MAX && !(align & Qt::AlignHorizontal_Mask))
if (!(sizePolicy.horizontalPolicy() & QSizePolicy::GrowFlag))
s.setWidth(hint.width());
if (s.height() == QWIDGETSIZE_MAX && !(align & Qt::AlignVertical_Mask))
if (!(sizePolicy.verticalPolicy() & QSizePolicy::GrowFlag))
s.setHeight(hint.height());
if (align & Qt::AlignHorizontal_Mask)
s.setWidth(QLAYOUTSIZE_MAX);
if (align & Qt::AlignVertical_Mask)
s.setHeight(QLAYOUTSIZE_MAX);
return s;
}
// QSize qSmartMaxSize()會受到排列方向的影響
Q_GUI_EXPORT int qSmartSpacing(const QLayout *layout, QStyle::PixelMetric pm)
{
QObject *parent = layout->parent();
if (!parent) {
return -1;
} else if (parent->isWidgetType()) {
QWidget *pw = static_cast<QWidget *>(parent);
return pw->style()->pixelMetric(pm, 0, pw);
} else {
return static_cast<QLayout *>(parent)->spacing();
}
}
// int qSmartSpacing()則反而需要看父窗口的窗口屬性。