Trolltech | Documentation | Qt Quarterly | « Internationalization Q & A | Providing Context-Sensitive Help »

Laying out MDI Children
by Mark Summerfield
Qt provides support for MDI (Multiple Document Interface) through its QWorkspace widget. The workspace provides two strategies for laying out its child widgets. In this article we will show how easy it is to add new layout strategies to QWorkspace.

The layout strategies available from QWorkspace are cascading (cascade()) and tiling (tile()).

mdi1

The tiling strategy takes account of how many child windows there are, and tries to make optimal use of the available space.

mdi2

We can easily create our own layout strategies by subclassing QWorkspace. Here, we'll create two new strategies, vertical tiling and horizontal tiling. Let's start with the definition of our subclass:

    #include <qworkspace.h>
    
    class Workspace : public QWorkspace
    {
        Q_OBJECT
    
    public:
        Workspace(QWidget *parent = 0, const char *name = 0)
            : QWorkspace(parent, name)
	{}
    
    public slots:
        void tileVertically();
        void tileHorizontally();
    };
    

The implementation of the slots is straightforward:

    void Workspace::tileVertically()
    {
        QWidgetList windows = windowList();
        if (windows.count() < 2) {
            tile();
            return;
        }
        int wHeight = height() / windows.count();
        int y = 0;
        for (QWidget *widget = windows.first(); widget; widget = windows.next()) {
            widget->parentWidget()->resize(width(), wHeight);
            widget->parentWidget()->move(0, y);
            y += wHeight;
        }
    }
    

If there are less than two child widgets we simply call the normal tile() function. This will do nothing if there are no windows, and will maximize a single window. We calculate the height that each widget will get and then iterate over the list of child widgets.

Notice that geometry changes to an MDI child widget must be applied to its parentWidget(), not to the widget itself. Similarly, if you want to find out the geometry of an MDI child widget you must use its parentWidget(). This also applies to intercepting events for MDI child widgets: you must install your event filter on the parentWidget().

mdi3

The code for horizontal tiling is almost the same:

    void Workspace::tileHorizontally()
    {
        QWidgetList windows = windowList();
        if (windows.count() < 2) {
            tile();
            return;
        }
        int wWidth = width() / windows.count();
        int x = 0;
        for (QWidget *widget = windows.first(); widget; widget = windows.next()) {
            widget->parentWidget()->resize(wWidth, height());
            widget->parentWidget()->move(x, 0);
            x += wWidth;
        }
    }
    

mdi4

Vertical and horizontal tiling are simple to understand and implement, but what really makes these two little functions interesting are the other possibilities that they open up. For example, we might have an MDI application that had different kinds of child widgets, each with their own layout preferences. For this situation we could create a QWorkspace subclass that iterated over the list of child windows as we've done here, but which accounted for each type of widget (using ::qt_cast<>), and sized and moved them accordingly.


This document is licensed under the Creative Commons Attribution-Share Alike 2.5 license.

Copyright © 2003 Trolltech Trademarks Providing Context-Sensitive Help »