Grid layout reordering after modifications
-
Hello,
For my button dial widget I have put a grid layout to hold my buttons. Since they are created based on the actions attached to the widget I've also intercepted theChildAdded
/ChildRemoved
events of the action objects and I'm creating/destroying buttons based on that. For more information on what exactly I'm doing you could look here.Currently, when a child is removed I destroy the corresponding button, but that button might be laid out in a place that's nether the beginning nor the ending of the grid. To have consistency (no holes in my layout) I'm removing all the buttons following the one I'm deleting and then reinserting them at their new positions, like this:
void AgDialPrivate::destroyButton(QObject * action) { ButtonHash::Iterator i = buttons.find(action); if (i == buttons.end()) return; // Remove the button QAction * parentAction = qobject_cast<QAction *>(action->parent()); if (parentAction && parentAction->findChildren<QAction *>(QString(), Qt::FindDirectChildrenOnly).count() <= 1) { destroyPage(parentAction); // If there's a parent page and there's no more children, remove it! return; } QToolButton * button = qobject_cast<QToolButton *>(i.value()); QGridLayout * layout = qobject_cast<QGridLayout *>(button->parentWidget()->layout()); qint32 index = layout->indexOf(button); if (index < 0) return; // Take out the remaining items from the layout QVector<QLayoutItem *> items; for (qint32 count = layout->count() - 1; count > index; count--) items.append(layout->takeAt(count)); // Remove the current button delete button; buttons.erase(i); // Reinsert the items in the layout for (qint32 i = items.size() - 1; i >= 0; i--) { QPoint position = newItemLayoutPosition(layout); layout->addItem(items[i], position.y(), position.x()); } }
Is there a smarter way to do this? Can I somehow instruct the layout to reorder the items without doing that manually?
As a side question, can I pre-determine the number of rows and columns for aQGridLayout
, I was not able to see anything like this in the documentation, but I might have missed something?Kind regards.
-
Hi
I was wondering.
If I make a layout in designer, say a grid layout and put buttons 1,2,3,4,5 in it,
then I delete 3. the others are rearranged so no holes.So I wonder what will happen if you call activate() on layout after u removed the
button(s). -
@mrjj
Hm, indeed, no need to callactivate
even. If I comment out the taking-out-and-reinserting code the layout is rearranged automatically after thedelete button
. This is however a bit strange for me, because how is the layout supposed to know the number of columns/rows I'm expecting?Nope, this seems to "work" only if I have a single row in the layout, otherwise I get a hole at the place the button was supposed to be.
-
Im not sure its expecting anything. just seems to start with
first Layoutitem and then then just position one by one.The number of rows seems to the height / items.
if I set minimum height to such degree they can not longer fit with
in layout_height, they start to overlap.Ahh. the hole is a "column"
-
-
@kshegunov
Yes pictures made it very clear.
Try to reproduce it in Creator. Its seems to
rearrange. -
@kshegunov
I know u cant use UI file.
Im just wondering why in creator,
if I create a grid 3x2 with buttons.
Then from code, i take() and delete say button 3, i
get no holes. But in AgDial there is.
I should get the same, shouldn't I? -
@mrjj
I suppose so. But I'm nottake
ing the item itself, maybe this is why the behavior differs.I'll try it out.
Nope, substituting the relevant reinsertion code with:delete layout->takeAt(index); delete button; buttons.erase(i);
Produces the same hole. I have no idea why this works in your case ...
-
Just to be sure, we are talking
about a normal gridlayout in a widget?
At runtime, there should be no difference between one from
UI files and one from code.
So your case must be different or mine too simple. -
Just to be sure, we are talking
about a normal gridlayout in a widget?Absolutely! Here's how a create a page:
bool AgDialPrivate::createPage(QAction * action) { Q_ASSERT(action); QList<QAction *> children = action->findChildren<QAction *>(QString(), Qt::FindDirectChildrenOnly); if (children.count() <= 0 || pages.value(action, NULL)) return false; // Create a page for this action AGUI_Q(AgDial); QWidget * page = new QWidget(q); new QGridLayout(page); pages.insert(action, page); q->addWidget(page); // Create a return button QAction * parent = qobject_cast<QAction *>(action->parent()); createReturnButton(page, parent); // If the action has any children, create their buttons and/or pages foreach (QAction * child, children) { createButton(child); if (child->children().count() > 0) createPage(child); } // Map the triggered signal of the child action QSignalMapper * mapper = new QSignalMapper(page); mapper->setMapping(action, page); QObject::connect(action, SIGNAL(triggered()), mapper, SLOT(map())); QObject::connect(mapper, SIGNAL(mapped(QWidget *)), q, SLOT(setCurrentWidget(QWidget *))); return true; }
-
Ok, i delete sample and tried again.
Now I get hole too! ?
only difference is that I had min/max heights in other test. -
Ok. now even in Creator it leaves holes.
my first sample must not been proper. -
@kshegunov
I agree . must been something like that as now the effect
is 100% as your experience. Even in designer.
Sorry for the confusion.