PDA

View Full Version : Custom QLayout 'FlowLayout' in QScrollArea, can't update layout



ComServant
13th August 2011, 04:52
I am using the FlowLayout (http://doc.qt.nokia.com/latest/layouts-flowlayout.html) custom layout example, with one small modification, inside a QScrollLayout.

The custom modification is that I'm adding a 'insertWidgetAt' function (alongside the normal 'addWidget' function), but try as I might, I can't seem to get the inserted widget to display.

void FlowLayout::insertWidgetAt(QWidget *widget, int index)
{
this->itemList.insert(index, new QWidgetItem(widget));

//What function do I need to call here, to make the inserted widget show up?
}

I've tried:
this->invalidate();
this->update();
this->activate();
this->parentWidget()->updateGeometry();
this->parentWidget()->update();

And: (from the Qt FlowLayout example)
doLayout(QLayout::geometry(), false);
doLayout(QRect(0, 0, 0, 0), false);

Calling the regular customLayout->addWidget() works fine. The customLayout->insertWidgetAt() never shows up, even if I call addWidget() afterward.

My guess at the problem: I never inform the QScrollArea of the widget... only the QScrollArea's layout. Does the layout somehow inform the parent widget of added widgets? How is my custom layout supposed to do that?

QLayout::addWidget() calls the FlowLayout::addItem(). Clearly something happens in QLayout::addWidget() that is significant, that I'm not aware of. I've looked in the Qt source, but I can't find the QLayout source file.
I've also looked at QBoxLayout::insertWidgetAt() source code, and it doesn't seem to be doing anything special, though I can't be sure because of the heavy use of unfamiliar macros.

norobro
13th August 2011, 16:00
Works fine here:

flowcontrol.cpp
flowLayout->insertWidgetAt(new QPushButton(tr("INSERTED ITEM")),2);
main.cpp

Window window;
QScrollArea *sa = new QScrollArea;
sa->setWidget(&window);
sa->setMaximumHeight(100);
sa->show();

ComServant
13th August 2011, 17:57
Wierd. I just knocked together a minimalistic example, and it's still not working.

main.cpp: http://pastebin.com/hABZSjxj
FlowLayout.h: http://pastebin.com/fB4yi4sB
FlowLayout.cpp: http://pastebin.com/iVwEzjJa

Specifically, insertWidgetAt: (from FlowWidget.cpp)

void FlowLayout::insertWidgetAt(QWidget *widget, int index)
{
this->itemList.insert(index, new QWidgetItem(widget));
}

Am I missing something?

Where I inserted another QPushButton, it creates a bulge, but doesn't show the inserted button:
http://img232.imageshack.us/img232/5029/flowexample.png

Could you post your example, so I can compare it to mine?

norobro
13th August 2011, 18:14
Try this:
// frame->setLayout(layout);
layout->addWidget(new QPushButton("One"));
layout->addWidget(new QPushButton("Two"));
layout->addWidget(new QPushButton("Three"));
layout->addWidget(new QPushButton("Four"));
layout->insertWidgetAt(new QPushButton("2.5"), 2);
frame->setLayout(layout);

ComServant
13th August 2011, 18:19
Okay, I've gotten it working by going like this:

void FlowLayout::insertWidgetAt(QWidget *widget, int index)
{
widget->setParent(this->parentWidget());
this->itemList.insert(index, new QWidgetItem(widget));
}

So all I needed to do was make sure the widget being added actually knows who its parent is.
I suppose 'QLayout::addWidget()' normally does it, before passing the widget as a item to 'myCustomLayout::addItem()', but since I couldn't find the source for QLayout, I can't be sure.

[Edit:] Found the QLayout source. Apparently the proper and safer call is 'QLayout::addChildWidget()':

void FlowLayout::insertWidgetAt(QWidget *widget, int index)
{
QLayout::addChildWidget(widget);
this->itemList.insert(index, new QWidgetItem(widget));
}
This is what QLayout::addWidget() calls internally, and it checks for a number of different circumstances making the code more robust.

norobro
13th August 2011, 18:26
Your code worked fine after moving the "setLayout" statement.

6760

ComServant
13th August 2011, 18:31
Cool, but "QLayout::addChildWidget(widget)" is the proper way to do it, (or at least the way QLayout itself does it).
It works fine this way, even after calls to setLayout(), which gives the programmer (me) more flexibility.

It wouldn't be cool to have to call setLayout() after I insert the widgets... the whole point of 'inserting' the widgets, is to add widgets after the layout is already filled and created.