14

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);

Austin
  • 791
  • 1
  • 7
  • 14
  • It returns the parent window. – Austin Mar 09 '10 at 14:15
  • @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 Mar 09 '10 at 14:16
  • oh I see. Now I get the question. – Ronny Brendel Mar 09 '10 at 14:18
  • 1
    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 Mar 09 '10 at 14:23
  • 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 Mar 09 '10 at 14:57
  • What is the real goal here? Accessing the layout a widget is in without going through the parent seems like a bad idea. – Adam W Mar 09 '10 at 16:44

7 Answers7

7

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;
}
MGamsby
  • 386
  • 4
  • 13
Ivan Babulic
  • 71
  • 1
  • 2
5

(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.

BastiBen
  • 19,679
  • 11
  • 56
  • 86
  • That returns the layout contained inside your widget (if any), not the layout containing your widget. – Austin Mar 09 '10 at 14:16
  • This returns the layout installed on the widget, not the parent layout of the widget (that is, the layout in which this widget is sitting). – Lucas Mar 09 '10 at 14:17
  • 1
    But parent().layout() should do what they want. – McBeth Mar 09 '10 at 14:19
  • @McBeth, it doesn't. The widget is still a child of the window, not the layout. – BastiBen Mar 09 '10 at 14:21
  • @BastiBense Of course the widget is a child of its parent widget. But that parent widget has a layout (as asserted by the OP), which may have further layouts, but the original widget will be in there somewhere. – McBeth Mar 09 '10 at 14:37
  • @BastiBense, in fact, you can find out if you have the right layout by calling indexOf(widget *) on the layout. It is a little tedious, but it will work. I'm not sure easy or clean is the operative word any more. Everything will be generic enough that you could write it once as a separate function, and will just work however. – McBeth Mar 09 '10 at 14:41
  • @McBeth, technically you are correct. But since you can't be 100% sure about the layout structure, I suggest using a simpler, and more secure approach instead of brute-force-searching through everything. – BastiBen Mar 12 '10 at 15:48
2

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.

waldyrious
  • 3,683
  • 4
  • 33
  • 41
Otto V.
  • 169
  • 4
  • 11
  • 2
    Note that this does not work in the general case. This caveat is implicit in this answer (*"I assume button is a child of the widget which contains the layout which contains the button."*), but @BastiBen says it explicitly in his answer: *"a widget can be technically contained in multiple layouts (a horizontal layout which is aligned inside a vertical layout, for instance)."* So keep that in mind if you're planning on using this solution. – waldyrious Dec 16 '16 at 13:31
1

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.

Austin
  • 791
  • 1
  • 7
  • 14
0

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

Ronny Brendel
  • 4,777
  • 5
  • 35
  • 55
-3

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.

Lucas
  • 6,328
  • 8
  • 37
  • 49
  • I'm positive the widget has a parent layout. – Austin Mar 09 '10 at 14:21
  • 1
    [See doc](http://qt-project.org/doc/qt-4.8/layout.html#tips-for-using-layouts): "The layout will automatically reparent the widgets (using QWidget::setParent()) so that they are children of the widget on which the layout is installed." – Marek R Feb 03 '14 at 14:22
-3

Have you tried QWidget::layout() ?

Paul
  • 13,042
  • 3
  • 41
  • 59
  • Somebody else already suggested this, but edited it out. This one won't work--the reason being that it returns the layout installed on the widget, not the layout containing your widget. – Austin Mar 09 '10 at 14:35
  • What do you mean by parent layout then? When you put widget inside a layout in Designer, you actually install that layout on the widget, that layout does not become `QObject::parent()` of that widget. You can easily see that if you look at .h file produced by `uic` from .ui file. – Paul Mar 09 '10 at 14:48
  • What I meant is, after placing my widget in layout A, is it possible, with Qt's API, to retrieve layout A later in the code? – Austin Mar 09 '10 at 14:59
  • 1
    How exactly do you "place" your widget into layout? If you call `A->addWidget(widget)`, then `widget->layout()` should return `A`. If you create widget like `widget = new QWidget(A)`, then `qobject_cast(widget->parent())` should return A. – Paul Mar 09 '10 at 15:02
  • I'm doing A->addWidget(widget). I have tried it and it returns a null pointer (0). Also, widget = new QWidget(A) is not possible, since a layout is not a QWidget and the constructor of QWidget takes a pointer to a QWidget. – Austin Mar 09 '10 at 23:13