qboxlayout与qt布局(一)

说实在的,qlayout的确很好用。不过,发觉用得越多就越是疑惑。例如动不动,它里面的控件就迭在一起了。唉,忍无可忍了,只好去分析下下它的源码罗~
qt有个叫做qGeomCalc()的函数,qboxlayout里面的控件的大小与位置就是通它来计算的(注意,可不是全由它说了算的,这就是叫人疑惑的原因之一吧)。此函数主要是处理传进来的QLayoutStruct链的,QLayoutStruct主要定义如下
struct QLayoutStruct
{
    ... ...
    // parameters(参数, 传进qGeomCalc()时就已经初始化好的了)
    int stretch;
    int sizeHint;
    int maximumSize;
    int minimumSize;
    bool expansive;
    bool empty;
    int spacing;
    // temporary storage(临时变量,用来标志是否已经算出了结果)
    bool done;
    // result(qGeomCalc()的计算结果)
    int pos;
    int size;
};
可见,qGeomCalc()其它就是计算子控件的大小与位置的。但是,主要的计算还是大小,想想,大小都出来了,放的位置不就明显得很了吗?
而qGeomCalc()计算大小主要分为三种情况来进行的,这其中也隐藏了它的控制规则,三种情况如下:
1)所分配的总空间大小 < 所有子控件的minimumSize总和
此时,会根据控件size由大到小的顺序,减小控件的size。
2)所分配的总空间大小 < 所有子控件的smartSizeHint总和
此时,会先保证满足固定大小的控件的minimumSize,然后再通过逐一地平均地减小各控件的smartSizeHint()来得到size值。
3)所分配的总空间大小 > 所有子控件的smartSizeHint的总和(即,需要扩展子控件大小)

此时, 会先设置好固定大小的子控件,然后再平均地分配剩下的子控件的大小,再看平均分配大小后的子控件是否能够满足条件(大于smartSizeHint 且小于maximumSize),且进行调整(怎么调整,觉得好难说清楚,还是直接看源码吧)
当qboxlayout中各子控件的大小计算出来后,就是通过QWidgetPrivate::setGeometry_sys()来设置各子控件的大小了。QWidgetPrivate::setGeometry_sys()中有几行,可让我傻眼了:
if (extra) {                                // any size restrictions?
        w = qMin(w,extra->maxw);
        h = qMin(h,extra->maxh);
        w = qMax(w,extra->minw);
        h = qMax(h,extra->minh);
    }
这样,qGeomCalc()中第一种情况计算出来的大小就完全被无视了,但是再看之后的代码,计算出来的位置却被沿用了。我的天,难怪,缩小主窗口时,子控件会叠在一起了。

附上qt相关源码
void qGeomCalc(QVector<QLayoutStruct> &chain, int start, int count,
               int pos, int space, int spacer)
{
    int cHint = 0;
    int cMin = 0;
    int cMax = 0;
    int sumStretch = 0;
    int sumSpacing = 0;
    bool wannaGrow = false; // anyone who really wants to grow?
    //    bool canShrink = false; // anyone who could be persuaded to shrink?
    bool allEmptyNonstretch = true;
    int pendingSpacing = -1;
    int spacerCount = 0;
    int i;
    for (i = start; i < start + count; i++) {
        QLayoutStruct *data = &chain[i];
        data->done = false;
        cHint += data->smartSizeHint();
        cMin += data->minimumSize;
        cMax += data->maximumSize;
        sumStretch += data->stretch;
        if (!data->empty) {
            if (pendingSpacing >= 0) {
                sumSpacing += pendingSpacing;
                ++spacerCount;
            }
            pendingSpacing = data->effectiveSpacer(spacer);
        }
        wannaGrow = wannaGrow || data->expansive || data->stretch > 0;
        allEmptyNonstretch = allEmptyNonstretch && !wannaGrow && data->empty;
    }
    int extraspace = 0;
// sumSpacing子项间的间隔总和
    if (space < cMin + sumSpacing) {
        /*
          Less space than minimumSize; take from the biggest first
        */
        int minSize = cMin + sumSpacing;
// 按比例缩小子项间隔
        if (spacer >= 0) {
            spacer = minSize > 0 ? spacer * space / minSize : 0;
            sumSpacing = spacer * spacerCount;
        }
// 取出子链的最小值,并排序
        QList<int> list;
        for (i = start; i < start + count; i++)
            list << chain.at(i).minimumSize;
        qSort(list);
// 剩下的可用于分配给各个子项的空间
        int space_left = space - sumSpacing;
        int sum = 0;
        int idx = 0;
        int space_used=0;
        int current = 0;
// 从小到大向后查找,看哪一项开始,以它作为它后面各项的平均值时,会空间不足
        while (idx < count && space_used < space_left) {
            current = list.at(idx);
            space_used = sum + current * (count - idx);
            sum += current;
            ++idx;
        }
        --idx;
// 不足的空间大小, 以及相关的子项数目
        int deficit = space_used - space_left;
        int items = count - idx;
        /*
// 真正移去的空间为deficitPerItem + remainder/items
         * If we truncate all items to "current", we would get "deficit" too many pixels. Therefore, we have to remove
         * deficit/items from each item bigger than maxval. The actual value to remove is deficitPerItem + remainder/items
         * "rest" is the accumulated error from using integer arithmetic.
        */
        int deficitPerItem = deficit/items;
        int remainder = deficit % items;
        int maxval = current - deficitPerItem;
        int rest = 0;
        for (i = start; i < start + count; i++) {
            int maxv = maxval;
            rest += remainder;
            if (rest >= items) {
                maxv--;
                rest-=items;
            }
            QLayoutStruct *data = &chain[i];
            data->size = qMin(data->minimumSize, maxv);
            data->done = true;
        }
    } else if (space < cHint + sumSpacing) {
        /*
          Less space than smartSizeHint(), but more than minimumSize.
          Currently take space equally from each, as in Qt 2.x.
          Commented-out lines will give more space to stretchier
          items.
        */
        int n = count;
        int space_left = space - sumSpacing;
        int overdraft = cHint - space_left;
        // first give to the fixed ones:
// 先处理固定大小的子项
        for (i = start; i < start + count; i++) {
            QLayoutStruct *data = &chain[i];
            if (!data->done
                 && data->minimumSize >= data->smartSizeHint()) {
                data->size = data->smartSizeHint();
                data->done = true;
                space_left -= data->smartSizeHint();
                // sumStretch -= data->stretch;
                n--;
            }
        }
        bool finished = n == 0;
// 除去那个固定值,以及不符合最小值要求的值,平均地从每项中的smartSizeHint减去超出的空间
        while (!finished) {
            finished = true;
            Fixed64 fp_over = toFixed(overdraft);
            Fixed64 fp_w = 0;
            for (i = start; i < start+count; i++) {
                QLayoutStruct *data = &chain[i];
                if (data->done)
                    continue;
                // if (sumStretch <= 0)
                fp_w += fp_over / n;
                // else
                //    fp_w += (fp_over * data->stretch) / sumStretch;
                int w = fRound(fp_w);
                data->size = data->smartSizeHint() - w;
                fp_w -= toFixed(w); // give the difference to the next
                if (data->size < data->minimumSize) {
                    data->done = true;
                    data->size = data->minimumSize;
                    finished = false;
                    overdraft -= data->smartSizeHint() - data->minimumSize;
                    // sumStretch -= data->stretch;
                    n--;
                    break;
                }
            }
        }
    } else { // extra space
// 需要扩展空间的情况
        int n = count;
        int space_left = space - sumSpacing;
        // first give to the fixed ones, and handle non-expansiveness
// 先处理固定大小以及没有扩展属性的子项
        for (i = start; i < start + count; i++) {
            QLayoutStruct *data = &chain[i];
            if (!data->done
                && (data->maximumSize <= data->smartSizeHint()
                    || (wannaGrow && !data->expansive && data->stretch == 0)
                    || (!allEmptyNonstretch && data->empty &&
                        !data->expansive && data->stretch == 0))) {
                data->size = data->smartSizeHint();
                data->done = true;
                space_left -= data->size;
                sumStretch -= data->stretch;
                n--;
            }
        }
        extraspace = space_left;
        /*
          Do a trial distribution and calculate how much it is off.
          If there are more deficit pixels than surplus pixels, give
          the minimum size items what they need, and repeat.
          Otherwise give to the maximum size items, and repeat.
          Paul Olav Tvete has a wonderful mathematical proof of the
          correctness of this principle, but unfortunately this
          comment is too small to contain it.
        */
        int surplus, deficit;
        do {
            surplus = deficit = 0;
            Fixed64 fp_space = toFixed(space_left);
            Fixed64 fp_w = 0;
// 按照各自的扩展因子stretch成比例分配剩余空间的大小
            for (i = start; i < start + count; i++) {
                QLayoutStruct *data = &chain[i];
                if (data->done)
                    continue;
                extraspace = 0;
                if (sumStretch <= 0)
                    fp_w += fp_space / n;
                else
                    fp_w += (fp_space * data->stretch) / sumStretch;
                int w = fRound(fp_w);
                data->size = w;
                fp_w -= toFixed(w); // give the difference to the next
                if (w < data->smartSizeHint()) {
                    deficit +=  data->smartSizeHint() - w;
                } else if (w > data->maximumSize) {
                    surplus += w - data->maximumSize;
                }
            }
// 如果不足的空间比较多,则把不足项设置为smartSizeHint值
            if (deficit > 0 && surplus <= deficit) {
                // give to the ones that have too little
                for (i = start; i < start+count; i++) {
                    QLayoutStruct *data = &chain[i];
                    if (!data->done && data->size < data->smartSizeHint()) {
                        data->size = data->smartSizeHint();
                        data->done = true;
                        space_left -= data->smartSizeHint();
                        sumStretch -= data->stretch;
                        n--;
                    }
                }
            }
// 如果是富余的空间比较多,则把富余项设置为其最大值
            if (surplus > 0 && surplus >= deficit) {
                // take from the ones that have too much
                for (i = start; i < start + count; i++) {
                    QLayoutStruct *data = &chain[i];
                    if (!data->done && data->size > data->maximumSize) {
                        data->size = data->maximumSize;
                        data->done = true;
                        space_left -= data->maximumSize;
                        sumStretch -= data->stretch;
                        n--;
                    }
                }
            }
        } while (n > 0 && surplus != deficit);
        if (n == 0)
            extraspace = space_left;
    }
    /*
      As a last resort, we distribute the unwanted space equally
      among the spacers (counting the start and end of the chain). We
      could, but don't, attempt a sub-pixel allocation of the extra
      space.
    */
    int extra = extraspace / (spacerCount + 2);
    int p = pos + extra;
    for (i = start; i < start+count; i++) {
        QLayoutStruct *data = &chain[i];
        data->pos = p;
        p += data->size;
        if (!data->empty)
            p += data->effectiveSpacer(spacer) + extra;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值