11
votes

quick question. Is there any way to (easily) retrieve the parent layout of a widget in Qt?

PS: QObject::parent() won't work, for logical reasons.

EDIT: I'm positive the widget has a parent layout, because I added it to a layout earlier in the code. Now, I have many other layouts in the window and while it is possible for me to keep track of them, I just want to know if there is an easy and clean way to get the parent layout.

EDIT2: Sorry, "easy and clean" was probably not the best way of putting. I meant using the Qt API.

EDIT3: I'm adding the widget to the layout like this:

QHBoxLayout* layout = new QHBoxLayout;

layout->addWidget(button);

7
It returns the parent window.Austin
@Ronny, because QLayouts are just managers. The managed objects within layouts are still the children of their respective parent (like the Window). This is so the Widgets do not depend on the layout (if any) they are being managed in.BastiBen
oh I see. Now I get the question.Ronny Brendel
Damnit, guys. What's with all the weird downvoting today? Seems the more crowded SO becomes, the more people want to play serious moderator business. :/BastiBen
Can you show how do you create widgets and set up your layouts? Or at least explain, what did you mean by saying "I added it to a layout earlier in the code".Paul

7 Answers

5
votes

(Updated answer)

I guess it is not easily possible then. Since a Widget can be technically contained in multiple layouts (a horizontal layout which is aligned inside a vertical layout, for instance).

Just remember that a QWidget's parent does not change if it is aligned in a layout.

You possibly have to keep track of that yourself, then.

4
votes

SOLVED! Usage: QLayout* parentLayout = findParentLayout(addedWidget)

QLayout* findParentLayout(QWidget* w, QLayout* topLevelLayout)
{
  for (QObject* qo: topLevelLayout->children())
  {
     QLayout* layout = qobject_cast<QLayout*>(qo);
     if (layout != nullptr)
     {
        if (layout->indexOf(w) > -1)
          return layout;
        else if (!layout->children().isEmpty())
        {
          layout = findParentLayout(w, layout);
          if (layout != nullptr)
            return layout;
        }
     }
  }
  return nullptr;
}

QLayout* findParentLayout(QWidget* w)
{
    if (w->parentWidget() != nullptr)
        if (w->parentWidget()->layout() != nullptr)
            return findParentLayout(w, w->parentWidget()->layout());
    return nullptr;
}
2
votes

Simply use:

QHBoxLayout* parentLayout = button->parentWidget()->layout();

I assume button is a child of the widget which contains the layout which contains button. button->parentWidget() returns a pointer to the widget of the button's parent and ->layout() returns the pointer to the layout of the parent.

1
votes

use widget.parent().layout() and search brute force (recursion included) is my only advice. Maybe you can search be "name".

1
votes

After some exploration, I found a "partial" solution to the problem.

If you are creating the layout and managing a widget with it, it is possible to retrieve this layout later in the code by using Qt's dynamic properties. Now, to use QWidget::setProperty(), the object you are going to store needs to be a registered meta type. A pointer to QHBoxLayout is not a registered meta type, but there are two workarounds. The simplest workaround is to register the object by adding this anywhere in your code:

Q_DECLARE_METATYPE(QHBoxLayout*)

The second workaround is to wrap the object:

struct Layout {
    QHBoxLayout* layout;
};
Q_DECLARE_METATYPE(Layout)

Once the object is a registered meta type, you can save it this way:

QHBoxLayout* layout = new QHBoxLayout;
QWidget* widget = new QWidget;
widget->setProperty("managingLayout", QVariant::fromValue(layout));
layout->addWidget(widget);

Or this way if you used the second workaround:

QHBoxLayout* layout = new QHBoxLayout;
QWidget* widget = new QWidget;
Layout l;
l.layout = layout;
widget->setProperty("managingLayout", QVariant::fromValue(l));
layout->addWidget(widget);

Later when you need to retrieve the layout, you can retrieve it this way:

QHBoxLayout* layout = widget->property("managingLayout").value<QHBoxLayout*>();

Or like this:

Layout l = widget->property("managingLayout").value<Layout>();
QHBoxLayout* layout = l.layout;

This approach is applicable only when you created the layout. If you did not create the layout and set it, then there is not a simple way of retrieving it later. Also you will have to keep track of the layout and update the managingLayout property when necessary.

-3
votes

Have you tried this? Don't forget to check for NULL.

QLayout *parent_layout = qobject_cast< QLayout* >( parent() );

If parent_layout equals NULL, then the parent widget is not a layout.

-3
votes

Have you tried QWidget::layout() ?