首先看一下布局器大概的类关系及数据信息
以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中的各个对象。