QT Layout源码解析

首先看一下布局器大概的类关系及数据信息


QT Layout源码解析_第1张图片

以GridLayout为例进行说明,我们一般使用additem方法,参数传入的是QLayoutItem对象,如添加QSpacerItem(继承自QLayoutItem,调用additem方法),它就没有widget相关信息了。

如果addwidget添加widget时,实际上是new的QWidgetItem,里面会保存wid信息,它是继承自QLayoutItem的,然后additem,传入刚才new的QWidgetItem。

void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment)

{

    addChildWidget(widget);   // 设置父对象,将widget的parent设置为layout的parent
    QWidgetItem *b = QLayoutPrivate::createWidgetItem(this, widget); // new一个QWidgetItem,QWidgetItem是继承自QLayoutItem的
    addItem(b, row, column, 1, 1, alignment);

}

后面会new一个QGridBox,new的时候会保存前面的QLayoutItem值到_item中,析构时也会析构掉QLayoutItem,但是如果调用了TakeAt,则会返回QLayoutItem,然后将QGridBox的_item赋值为0,由返回给外部来进行释放QLayoutItem了。所有添加的QGridBox,都会保存到QGridLayout的数据的List中,后面ItemAt获取数据也都是从这个list中遍历的。要注意各个TakeAt,widget方法的运行实际上都是到了List中,也会进行很多的比对。count也就是执行的thins.size()了.

void QGridLayout::addItem(QLayoutItem *item, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment)
{
    Q_D(QGridLayout);
    QGridBox *b = new QGridBox(item);   // new一个QGridBox,QGirdLayout最后保存的值都是QGirdBox的,即-  things: QList<QGridBox *> 
    b->setAlignment(alignment);
    d->add(b, row, (rowSpan < 0) ? -1 : row + rowSpan - 1, column, (columnSpan < 0) ? -1 : column + columnSpan - 1);
    invalidate();
}


另外注意,addwidget的rowcount之类的是一直自增的,如果为每个对象的rowindex或columnindex都改变,性能不好,所以QT是没有改变行,列索引的。使用中要注意。

如果layout中不断removewidget,addwidget,行,列信息会不确定是什么值的了。


如果我们继承Layout,并且重新实现setGeometry的话,可以自己实现布局中特殊的设置。流程大概如下

QWidget大小改变后

bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)

{

if (QLayout *layout=widget->d_func()->layout) {
            layout->widgetEvent(e); .//如果有布局器,布局器接受相关事件

}

// 布局器处理如下几个消息:

void QLayout::widgetEvent(QEvent *e)

{

switch (e->type()) {
case QEvent::Resize:

QResizeEvent *r = (QResizeEvent *)e;
            d->doResize(r->size())

break;

case QEvent::ChildRemoved

break;

case QEvent::ChildInserted:

break;

case QEvent::LayoutHint

break;

case QEvent::LayoutRequest:

}

void QLayoutPrivate::doResize(const QSize &r)

{

q->setGeometry(rect);

}

对于QGridLayout的setGeometry,具体实现大概如下:

int n = things.size();
    for (i = 0; i < n; ++i) {
        QGridBox *box = things.at(reverse ? n-i-1 : i);

。。。

 box->setGeometry(QRect(x, y, w, h));

对每个box设置大小位置

}


当然,我们也可以重载实现QLayout中的takeAt,insertItem等方法,使用自己的list来保存设置到layout中的各个对象。


你可能感兴趣的:(QT Layout源码解析)