Anchor layout joins the family of QGraphicsLayout

Published Thursday November 26th, 2009
16 Comments on Anchor layout joins the family of QGraphicsLayout
Posted in Graphics View, Kinetic, Layouts

For a long time the standard layouts shipped with Qt’s have been built around the concepts of linear and grid layouts. In the QLayout regime they are represented as QBoxLayout and QGridLayout. In the QGraphicsLayout regime they are represented as QGraphicsLinearLayout and QGraphicsGridLayout. We therefore started early this year with research on a new layout. The efforts of that culiminated into the QGraphicsAnchorLayout.

Motivation

We have quite often seen that the existing layouts in Qt can not always do what you want with just one layout. Take for instance Qt Linguist’s “Find dialog”.
The dialog is made up of four box layouts and one grid layout for the checkboxes inside the groupbox.
Qt Linguist’s Find Dialog
(note that Qt Designer does not illustrate the layout inside the groupbox or the toplevel layout)

In addition, in order to achieve this simple arrangement it uses three levels of nested layouts.
Luckilly, if you design it in Qt Designer it is quite easy, but you might not get it right at first attempt. Of course, doing it programmatically makes it even worse. The result are probably far from how a UI designer would specify the arrangement. We think that an anchor layout will narrow that gap in a lot of cases.

Concept

The QGraphicsAnchorLayout is a very flexible layout, yet the concept is simple. By creating an anchor between two edges of two layout items you are giving the anchor layout a constraint to fulfill. In the simplest case you are just saying that the distance between the two layout edges should be a fixed distance. You can do this with the left, right, top, bottom and the “center edges” of any layout item. You can also have an edge that has several anchors connected to it. This is not possible with linear layout and it is partly possible with a grid layout. This allows you to build up the structure the layout should have. The layout will then try to fulfill the constraints you have given it by potentially growing or shrinking the layout items. You can also configure each anchor to grow or shrink if that is preferred.

The API for configuring the layout structure reflects this concept. The addAnchor() function is all that you need to configure the structure of the layout, but we added some convenience functions for anchoring corners (surprise, addCornerAnchors()) and for fitting the size of an item to another (addAncors()). Thus, the following code will ensure that the left edge of item findEdit is always connected to the right edge of the item findLabel. In this case it means that there will typically be a bit spacing between the items, and the spacing will always be the same.

   anchorLayout->addAnchor(findLabel, Qt::RightAnchor, findEdit, Qt::LeftAnchor);

You can also anchor an item to a layout edge. If the edge of an item is anchored directly or indirectly to a layout edge, it’s geometry will react to changes in the layout geometry:

   anchorLayout->addAnchor(anchorLayout, Qt::LeftAnchor, findLabel, Qt::LeftAnchor);
   anchorLayout->addAnchor(findLabel, Qt::RightAnchor, findEdit, Qt::LeftAnchor);

Of course, you can also anchor items the same way in the vertical dimension.

Now, with this brief introduction we can go back to Qt Linguist’s “Find Dialog” example as I gave above.
It turns out we can make the same arrangement with just one anchor layout.

This is how the code could look like:

    QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout;
    QGraphicsWidget *w = new QGraphicsWidget(0, Qt::Window);
    w->setLayout(l);

    // label, line edit and "Find Next" button
    l->addCornerAnchors(l, Qt::TopLeftCorner, findLabel, Qt::TopLeftCorner);
    l->addCornerAnchors(findLabel, Qt::TopRightCorner, findEdit, Qt::TopLeftCorner);
    l->addCornerAnchors(findEdit, Qt::TopRightCorner, findButton, Qt::TopLeftCorner);
    l->addCornerAnchors(findButton, Qt::TopRightCorner, l, Qt::TopRightCorner);
    // group box
    l->addCornerAnchors(l, Qt::BottomLeftCorner, groupBox, Qt::BottomLeftCorner);
    l->addCornerAnchors(groupBox, Qt::TopRightCorner, findEdit, Qt::BottomRightCorner);
    // cancel button
    l->addCornerAnchors(findButton, Qt::BottomLeftCorner, cancelButton, Qt::TopLeftCorner);
    QGraphicsAnchor *anchor = l->addAnchor(cancelButton, Qt::AnchorBottom, l, Qt::AnchorBottom);
    anchor->setSizePolicy(QSizePolicy::Minimum);
    l->addAnchor(cancelButton, Qt::AnchorRight, l, Qt::AnchorRight);

    // Done!
    scene.addItem(w);

Note, for simplicity the code does not populate the group box with items, since that is easier done with a grid layout. Thus, the anchor layout reduced 4 layouts into one.

There’s a lot of interesting things I could mention here, but I would then be just repeating what’s already written in the documentation, so if you are interested I suggest you take a look at that.

Conclusion

The anchor layout has some attractive properties. For some setups it provides a more intuitive API that is closer to how the UI designer would specify it. It is also very flexible: You can construct free-form graphs of anchors where one edge might be anchored to several other edges. You can modify size policy of each anchor, which means there is little use for a spacer item. You can also modify the spacing to be both a positive and negative value.

Of course, the anchor layout is not the silver bullet and in a lot of cases you are better off with just using a linear or a grid layout. The anchor layout is a flexible layout, and there is a price you have to pay for that: For some arrangements it can be very verbose compared to a linear layout, since you don’t have to anchor each item together (the “anchoring” is implicit by the order of the items).


Of course, I must not forget that this could not have been accomplished by the excellent work done by the openbossa guys from Brazil, which I had the pleasure to work together with (and more importantly got to know)!

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Graphics View, Kinetic, Layouts

16 comments

Philippe says:

I was waiting for this kind of layout concept for a long time (being used with something a little bit similar in Borland OWL).
Unfortunatly, this seems to be limited to widgets in Graphics View 🙁
Why?

Enrico Ros says:

Really nice. It may get verbose for some use cases, but in the end this opens new possibilities.
A graphical editor, with the “pin points” will help much though 😉

Max Howell says:

Great! I was getting fed up with the “explosive” nature of the current layout system, where every label button and spacer is just desperate to increase its size as much as possible at the earliest opportunity.

I’ve done a lot of work with Interface Builder (ie. Cocoa/Mac dev) lately. It’s layout system is very similar to this. It is really good, so I’m glad you’ve decided to go this route. Thanks.

Andre says:

Any chance of seeing this for normal layouts as well?

Antoine says:

Very interesting stuff. This idea comes in very handy for my problem. I’m on a software with a MDI interface and I need a way to flexibly describe in a config file the default arrangement of the many QMDISubWindows in have (which offer various view on some complex, time-variying data structure). I’m going to implement this anchor mechanism, which lends itself well for a generic description in a config file.

andre says:

only 10 years to create something that remdinds to the motif form layout. and it is still not competitive…

why limit it to graphics view ?

why not realy create something that is as powefull as the morif form layout was ?

girish says:

Very nice stuff! I would really like to see this in QWidget based layouts and have designer integration.

Also, Shouldn’t QGraphicsAnchor be QGraphicsLayoutAnchor (heh hee, swap words and you end up with another class )? In the case where 1 is implemented we end up with QAnchor which is not ideal :).

William Stokes says:

Since 99% of my code uses traditional layouts and widgets I’m also interested in seeing this implemented along side QGridLayout for normal widgets as well. I’m also interested in seeing if Designer can be enhanced to use these types of layouts since I suspect using them will be easier in a graphical sense. I actually find massive QGridLayout hierarchies written by hand not so hard to maintain. In fact, I find them easier to maintain then going the Designer route. Maybe I’m strange. 🙂

Jan-Arve says:

@Philippe, @girish, @Andre, @William: Yes, we want to make this available in the classic QLayout world too – we had to begin with one of them and the choice we made was to base it on QGraphicsLayout.

@Enrico, @girish, @William: Yeah, we also want a designer integration, but first we have to make it available for classic QLayouts.

@girish: QGraphicsLayoutAnchor would be too long :-). Yeah, QAnchor is not ideal, but we can always call the other anchor class QLayoutAnchor.

Thanks for all the positive feedback!

panzi says:

The best layout+layout editor I know is the default layout used in NetBeans. (Called “Free Layout” in the GUI but is actually “javax.swing.GroupLayout”.) It is really easy to design. You can define all constraints just by D’n’D and resizing of the widgets. They dock with about 3 different margin widths to anything and automatically align to anything when you drag them at the right place. While doing so lines are displayed indicating what will happen if you drop it. Once you’ve understood how it works (play with it for 30min for that) you’ll love it. No more manual setting of min size/max size/preferred size, it just works as you expect (well as I expect at least). All the other Java layout managers: forget them! I’m not sure how easy it’s to use programmatically, though.

matthewl says:

Nice work!

What does the “magnitude” of an anchor mean? It’s mentioned in the function docs for addAnchor() but I don’t see it anywhere else.

eSKon says:

Long time ago i was using Borland C++ Builder (6.0 – last version as i remember). Their layout system was very convenience for me and when i started work with qt (also long time ago) i was very frustrated by qt layouts. Of course it might be just habit in using VCL layout methods but even now, after many years working with qt, sometime qt layouts get me angry. New AnchorLayout may solve many problems and it’s closer to VCL layout system

Daniel says:

Not only do the Qt layouts get me angry by sizing things in unexpected ways, they leave the code looking like a dog’s breakfast in many cases (for complex layouts). I can’t say that I find the anchor layout code much clearer, even for the very simple example given above.

It would be great if someone could port something like JGoodies FormLayout or MigLayout from Java-land to Qt. These layout managers result in code that almost looks like the on-screen layout and is very easy to update and maintain.

Craig Ringer says:

Are you aware of MigLayout (for Java): http://www.miglayout.com/ ?

Its design is pretty flexible and isn’t tied to any particular widget set. It’d be fantastic to have available for C++/Qt.

fleury says:

Hi
@andre, @panzi, @Craig Ringer: While reading the comments on Jan-Arve’s blog I got curious to further look at the layouts you mentioned, thanks for sharing this knowledge 🙂

Below I summarize my very personal impressions about the layouts mentioned.

I’m not used to Motif, but from what I read, XmForm resembles a simplified version of the layout system used in EFL / Evas. It supports relative positioning to the parent widget as well as side-by-side arrangements. However I don’t know how easy it is to use and neither how well it can handle off-screen items, overlapping elements, center-binding or per-item size restrictions (min, pref, and max sizeHints).

MigLayout seems to focus form-based applications, with a goal of being easy to use for those creating interfaces using Java code (not editors).

GroupLayout resambles QGraphicsAnchorLayout to some extent in the sense it separates the horizontal and vertical axis, for instance one can arrange the items in a diagonal line adding them to sequential horizontal group and a sequential vertical group at the same time.

I’m not sure either whether these two latter layouts can handle off-screen items, overlapping or center-binding. It is also important to note that there is a group of arrangements which I call “complex” that are simply not simplify-able to a nested group of parallel or sequential groups. These layouts are required in fluid UI applications and are handled by QGAL.

@matthewl
Magnitude is the size of an anchor. If you anchor two items side-by-side, this will be the distance between them, and in QGAL that’s usually read from the style applied to the widget the layout is installed into. One can also change that using QGraphicsAnchor::setSpacing().

Daniel says:

@fleury Regarding your MigLayout comments, it is not only focused on form-based applications. While form layouts are a major feature of MigLayout, it can also do things like flow layouts with the “nogrid” constraint, border layouts with the “north/west/south/east” constraints, absolute positioning, offscreen positioning, overlapping components, etc. The White Paper contains details on all these goodies.

I agree that MigLayout is optimized for creating UIs in code as opposed to in a UI designer. This is its main advantage for me, as I find coding layouts by hand with MigLayout to be more productive and maintainable than using something like Qt Designer.

For those of us who prefer to code layouts by hand, the current Qt layouts are quite painful to use, and unfortunately it doesn’t look like Anchor layout will do anything to address this.

Commenting closed.

Get started today with Qt Download now