qboxlayout与qt布局(二)

一直被QLayout::setSizeConstraint()搞得很头大。其实,很大部分原因只能怪小弟我英文水平不过关,因为qt文档里已经说明得够清楚的了。如下:
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()则反而需要看父窗口的窗口属性。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值