I’m working on a simple widget system (single window, fixed size). Each widget gets its parent (i.e. the widget containing it) passed into its constructor – except for the root widget, which I called Screen.
I have some doubts if that approach makes sense. I did it because most of the widget systems I used before do it (Qt, GTK, …), but I realised that these are quite a bit more complex than mine:
- I have no window resizing
- I don’t plan to size containers based on their children’s sizes
- I don’t think I need it for memory management (I’m using C++), I can use shared pointers instead (basically how it would work in Java)
Is there any reason why a widget would need a reference to its parent?
It’s a major refactoring to change this. So before I go ahead and implement containers and layouts, I want to have a good idea of whether or not I’m going to need that parent.
Edit: Please note that the parent does know all its children anyway, I’m just wondering if the children need to know the parent as well.
As you pointed out, the child itself seldomly if at all needs to access the parent, as long as the parent does all the work and keeps track of its children. However, the classic getParent
is most useful when you use the framework from outside.
Scenario
A simple operation that may cause problems is the following: given two concrete widgets that are somewhere in your overall widget tree and a use-case that requires you to swap these two, how does the swapping work?
Option 1: Tell the children
Tell your child widget to swap(withOtherChild)
. But swapping involves updating the parent’s children datastructure in some way. As your child does not know its parent, how do you achieve this?
Option 2: Tell the parents
Tell the parent of a child to remove it and add the other one. Oh wait, same problem. You only have the children objects and there’s no getParent
on those.
Option 3: Grunt work
As a final option, you can traverse your whole widget tree in order to find a parent with hasChild(x)
and one with hasChild(y)
and then fall back to option 2.
Solution
You should keep the parent if you ever want to build large widget trees and perform operations that require moving a widget’s position in the tree. If your widget trees are very small, or only have a very small depth, but fast hasChild
accessors, then Option 3 may be acceptable for you and you could omit the parent reference.
References in Datastructures in general
What you are planning to do here is to build up a datastructure for a tree. Let’s consider a simplification and for the sake of argument assume that every widget can only have one child. The result, of course, is a list and your question now becomes “should I have a single-linked or double-linked list?”.
And just like lists, there is no definite answer, but only pros and cons. Obvious pros for the single-linked (i.e., no parent reference) are a) easier to implement and b) less memory. But the cons include a) some operations become slow as they have to traverse the structure and b) not having easy access to those operations may mean that the datastructure is cumbersome to use, and c) it uses more memory.
On the other hand, the double-linked variant, i.e. with parent reference, pretty much reverses these pros and cons.
In terms of a GUI library/framework though, the memory limits are usually not a problem that prohibits parent pointers. If you rule that out, and realize that it’s a library/framework, and hence, it is preferrable for it to be hard to implement, but easy to use, then you essentially rule out the above pros of a single-linked approach.
I am not aware of the peculiarities of your project, so I want to refrain from telling you to keep the parent reference, as some of my above reasoning may well not apply in your case. In general, however, I consider parent references in a widget datastructure to be worthwhile for the above reasons.
In most of these cases there is quite some communication going on between parent and children in case of events, signals or state change (or simply to destroy children when necessary). For example a grouping box may handle it’s contained radio buttons to ensure only one of them is “on” at a given time.
You may or may not plan to have functionality of this kind. Personally I would doubt if a widget system without it is worth the time since it wouldn’t offer much. But then I would simply use one of the existing solution anyway.
6
I would say that, when the children know their parents, a widget and all its ancestors form a chain of responsibility. A typical example is a mouse event received by a widget : the widget can either consume the event (and react accordingly), or pass the event to its parent, who can either consume or pass to its parent, etc…
In the case of Qt, each widget is given its parent by constructor, and this indicates that the widget is owned by the parent. In particular, the deletion of the parent triggers the deletion of the widget.