1

I'm creating a multi window gui program, in c++ with Qt Widgets. I do have many custom gui elements, which usually are c++ classes inherited from QWidget or other Qt elements. When foo is the main window, it often looks like this:

Foo = new Foo();
Bar1 *widget1(foo);
Bar2 *widget2(widget1);
Bar3 *widget3(widget2);
Bar4 *widget4(widget3);

foo->addWidget(widget1);
widget1->addWidget(widget2);
widget2->addWidget(widget3);
widget3->addWidget(widget4);

Actually I use std::shared_ptr everywhere but I'm omitting that here for the sake of readability. Also this is simplified, the order is not always like this and there may be other Qt elements in between.

The argument in the constructors is the "parent" Window. Qt handles the deletion of all my Widgets using the parent structures.

My problem is, that sometimes, I need to access elements of my main window foo from some Bar widget down the road. E.g.: "If this is clicked, add another tab to the QTabwidget in foo. I do not always know, how many layers there are between foo and widgetX.

What's the best way to have a reference to foo in the lowest layer?

  1. The easiest way would be to make foo a singleton since I only ever have one foo window and once it get's closed, my program terminates anyway. But making the whole class static comes with it's own drawbacks.
  2. Add a reference to foo to all my constructors and pass it through them. I'd have a reference to foo in many places where I do not need one.
  3. I can access the parent reference that got passed through the constructors, but it's a pointer to QWidget. I'd have to cast it, check whether it's actually Foo and not Bar2, and then continue until I have found Foo.
  4. Set foo as a parent for everything, even if it is not really the parent (e.g. in a new Window). This would keep all my elements in memory until foo is destroyed.
  5. Use signals and slots. This sometimes works, but if I'm already 3 layers below foo when creating widget4, I can't connect them without foo.

Currently I have a mixed mess where I sometimes pass a reference to foo, have some static elements in foo and at some point cast the parent widget to foo.

What would be a good approach here?

4
  • 1
    Do you want to access grand parent because of the hierarchy? Or because it has some responsibilities and happen to be the grand parent by coincidence? Is it only about gui properties/behaviors or is it possible that you need grand partent access for a non gui reason?
    – Christophe
    Commented Mar 3, 2021 at 15:47
  • One use case is the modification of other gui elements the main windows holts. But it also holds some data I want to modify from a lower level element. Maybe that's where my problem originates, a gui element holding non-gui data. Commented Mar 3, 2021 at 15:53
  • Please clarify your issue with slots and signals. In your example the foo and any of the widgets are in same scope so you sure can connect them directly
    – max630
    Commented Mar 3, 2021 at 17:46
  • My example is oversimplified, e.g. widget3 would be created in widget2's constructor. Commented Mar 3, 2021 at 17:50

2 Answers 2

2

Assuming you have your own widget class that wraps the Qt widget or descends from it, you can add a GetGodfather() method who's implementation looks somewhat like this:

if (this.parent == NULL)
{
    return this;
}
else
{
    return this.parent.GetGodfather();
}

Or, if you want to be smart about it:

return (this.Parent == NULL) ? this : this.parent.GetGodfather();
7
  • I wondered if something like this would work, it should, shouldn't it? My idea was without the wrapper class but this makes this pretty straightforward I guess. Will play around with that a bit and test it, thanks! Commented Mar 3, 2021 at 16:19
  • 3
    I would caution against this. The moment your nested GUI element starts relying on the structure of the GUI "above" it, it's becomes non-reusable, and calcifies a dependency between that GUI component and the one particular context it's used in. Ideally, the parent should pass child components all the objects they need to collaborate with, in a way that prevents them from needing to "reach out" and access things themselves
    – Alexander
    Commented Mar 3, 2021 at 17:18
  • 1
    @Alexander It is a common way to produce a path to a node in a tree. The only dependency is the tree structure. Yes, a tree node is meaningless outside the scope of a tree structure, this is by design so I don't see any merit in the statement that it is not reusable independent from the tree structure. Any node has a parent (or not if it is a root). That is as far as reaching out goes, it gets all it wants to know directly from its parent and remains unaware of the ultimate source of the information returned or the route taken to obtain it. That looks pretty elegant to me. [...] Commented Mar 3, 2021 at 19:12
  • 1
    If it only queries for the immediate parent, and not siblings, cousins or ancestors, that can be OK. But going up more than 1 level (which is what I though GetGodfather() was doing, but now I'm not sure) is a really mad idea, IMO. Instead, I would pass the child a reference to a collaborator object which is stable over the lifetime of the GUI (regardless of the movement of elements within the GUI), which can be a stable source for data. Perhaps the parent can be that collaborator, but I still rather inject that then have the child access it directly
    – Alexander
    Commented Mar 3, 2021 at 19:42
  • 1
    @Alexander: it is not a "mad idea", quite the opposite, we have used this technique to find the "uppermost window" of an application for years in several desktop applications, and the potential drawbacks were acceptable. It was actually Winforms/C#, but relying on the tree structure of a form and its controls or widgets will work in most GUI frameworks I know and not induce any unacceptable constraints to reusability.
    – Doc Brown
    Commented Mar 4, 2021 at 6:46
1

I encountered this same problem and solved it via a static member function of Foo that traverses parents of a child widget until one of type Foo is found:

class Foo : public QWidget {

public:
    // static member function to find Foo parent
    static Foo* findFrom(QWidget* widget) {
        while (widget) {
            Foo* foo = qobject_cast<Foo*>(widget);
            if (foo) {
                return foo; // found a Foo parent
            }
            widget = widget->parentWidget();
        }
        return nullptr; // no Foo parent found
    }
};

In some child widget's member method, you can then call Foo* parentFoo = Foo::findFrom(this) to get the Foo-pointer.

2
  • I've been out of c++ for a while, does this work if widget is another custom class that inherits from QWidget too? I like toe idea to search for a specific type of widget though. Commented Sep 19, 2023 at 9:02
  • Yes, this works flawlessly, since the CustomWidget* to a derived class that you pass to this method is implicitly cast to a QWidget*.
    – MrJ
    Commented Sep 19, 2023 at 13:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.