Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions |

# Customized Layoutmanager

This examples demonstrates how to write customized layout (geometry) managers like card layouts, border layout and flow layouts.

See also: Documentation of Geometry Management.

Header file of the flow layout:

    /****************************************************************************
    ** $Id: qt/flow.h   3.3.8   edited Jan 11 14:46 $
    **
    ** Definition of simple flow layout for custom layout example
    **
    ** Created : 979899
    **
    ** Copyright (C) 1997-2007 Trolltech ASA.  All rights reserved.
    **
    ** This file is part of an example program for TQt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #ifndef FLOW_H
    #define FLOW_H

    #include <ntqlayout.h>
    #include <ntqptrlist.h>

    class SimpleFlow : public TQLayout
    {
    public:
        SimpleFlow( TQWidget *parent, int border=0, int space=-1,
                    const char *name=0 )
            : TQLayout( parent, border, space, name ),
            cached_width(0) {}
        SimpleFlow( TQLayout* parent, int space=-1, const char *name=0 )
            : TQLayout( parent, space, name ),
            cached_width(0) {}
        SimpleFlow( int space=-1, const char *name=0 )
            : TQLayout( space, name ),
            cached_width(0) {}

        ~SimpleFlow();

        void addItem( TQLayoutItem *item);
        bool hasHeightForWidth() const;
        int heightForWidth( int ) const;
        TQSize sizeHint() const;
        TQSize minimumSize() const;
        TQLayoutIterator iterator();
        TQSizePolicy::ExpandData expanding() const;

    protected:
        void setGeometry( const TQRect& );

    private:
        int doLayout( const TQRect&, bool testonly = FALSE );
        TQPtrList<TQLayoutItem> list;
        int cached_width;
        int cached_hfw;

    };

    #endif

Implementation of the flow layout:

    /****************************************************************************
    ** $Id: qt/flow.cpp   3.3.8   edited Jan 11 14:46 $
    **
    ** Implementing your own layout: flow example
    **
    ** Copyright (C) 1996-2007 Trolltech ASA.  All rights reserved.
    **
    ** This file is part of an example program for TQt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #include "flow.h"

    class SimpleFlowIterator :public TQGLayoutIterator
    {
    public:
        SimpleFlowIterator( TQPtrList<TQLayoutItem> *l ) :idx(0), list(l)  {}
        uint count() const;
        TQLayoutItem *current();
        TQLayoutItem *next();
        TQLayoutItem *takeCurrent();

    private:
        int idx;
        TQPtrList<TQLayoutItem> *list;

    };

    uint SimpleFlowIterator::count() const
    {
        return list->count();
    }

    TQLayoutItem *SimpleFlowIterator::current()
    {
        return idx < int(count()) ? list->at(idx) : 0;
    }

    TQLayoutItem *SimpleFlowIterator::next()
    {
        idx++; return current();
    }

    TQLayoutItem *SimpleFlowIterator::takeCurrent()
    {
        return idx < int(count()) ? list->take( idx ) : 0;
    }

    SimpleFlow::~SimpleFlow()
    {
        deleteAllItems();
    }

    int SimpleFlow::heightForWidth( int w ) const
    {
        if ( cached_width != w ) {
            //Not all C++ compilers support "mutable" yet:
            SimpleFlow * mthis = (SimpleFlow*)this;
            int h = mthis->doLayout( TQRect(0,0,w,0), TRUE );
            mthis->cached_hfw = h;
            mthis->cached_width = w;
            return h;
        }
        return cached_hfw;
    }

    void SimpleFlow::addItem( TQLayoutItem *item)
    {
        list.append( item );
    }

    bool SimpleFlow::hasHeightForWidth() const
    {
        return TRUE;
    }

    TQSize SimpleFlow::sizeHint() const
    {
        return minimumSize();
    }

    TQSizePolicy::ExpandData SimpleFlow::expanding() const
    {
        return TQSizePolicy::NoDirection;
    }

    TQLayoutIterator SimpleFlow::iterator()
    {
        return TQLayoutIterator( new SimpleFlowIterator( &list ) );
    }

    void SimpleFlow::setGeometry( const TQRect &r )
    {
        TQLayout::setGeometry( r );
        doLayout( r );
    }

    int SimpleFlow::doLayout( const TQRect &r, bool testonly )
    {
        int x = r.x();
        int y = r.y();
        int h = 0;          //height of this line so far.
        TQPtrListIterator<TQLayoutItem> it(list);
        TQLayoutItem *o;
        while ( (o=it.current()) != 0 ) {
            ++it;
            int nextX = x + o->sizeHint().width() + spacing();
            if ( nextX - spacing() > r.right() && h > 0 ) {
                x = r.x();
                y = y + h + spacing();
                nextX = x + o->sizeHint().width() + spacing();
                h = 0;
            }
            if ( !testonly )
                o->setGeometry( TQRect( TQPoint( x, y ), o->sizeHint() ) );
            x = nextX;
            h = TQMAX( h,  o->sizeHint().height() );
        }
        return y + h - r.y();
    }

    TQSize SimpleFlow::minimumSize() const
    {
        TQSize s(0,0);
        TQPtrListIterator<TQLayoutItem> it(list);
        TQLayoutItem *o;
        while ( (o=it.current()) != 0 ) {
            ++it;
            s = s.expandedTo( o->minimumSize() );
        }
        return s;
    }

Header file of the border layout:

    /****************************************************************************
    ** $Id: qt/border.h   3.3.8   edited Jan 11 14:46 $
    **
    ** Definition of simple flow layout for custom layout example
    **
    ** Created : 979899
    **
    ** Copyright (C) 1997-2007 Trolltech ASA.  All rights reserved.
    **
    ** This file is part of an example program for TQt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #ifndef BORDER_H
    #define BORDER_H

    #include <ntqlayout.h>
    #include <ntqptrlist.h>

    class BorderWidgetItem : public TQWidgetItem
    {
    public:
        BorderWidgetItem( TQWidget *w )
            : TQWidgetItem( w )
        {}

        void setGeometry( const TQRect &r )
        { widget()->setGeometry( r ); }

    };

    class BorderLayout : public TQLayout
    {
    public:
        enum Position {
            West = 0,
            North,
            South,
            East,
            Center
        };

        struct BorderLayoutStruct
        {
            BorderLayoutStruct( TQLayoutItem *i, Position p ) {
                item = i;
                pos = p;
            }

            TQLayoutItem *item;
            Position pos;
        };

        enum SizeType {
            Minimum = 0,
            SizeHint
        };

        BorderLayout( TQWidget *parent, int border = 0, int autoBorder = -1,
                      const char *name = 0 )
            : TQLayout( parent, border, autoBorder, name ), cached( 0, 0 ), mcached( 0, 0 ),
              sizeDirty( TRUE ), msizeDirty( TRUE )
        {}

        BorderLayout( TQLayout* parent, int autoBorder = -1, const char *name = 0 )
            : TQLayout( parent, autoBorder, name  ), cached( 0, 0 ), mcached( 0, 0 ),
              sizeDirty( TRUE ), msizeDirty( TRUE )
        {}

        BorderLayout( int autoBorder = -1, const char *name = 0 )
            : TQLayout( autoBorder, name ), cached( 0, 0 ), mcached( 0, 0 ),
              sizeDirty( TRUE ), msizeDirty( TRUE )
        {}

        ~BorderLayout();

        void addItem( TQLayoutItem *item );

        void addWidget( TQWidget *widget, Position pos );
        void add( TQLayoutItem *item, Position pos );

        bool hasHeightForWidth() const;

        TQSize sizeHint() const;
        TQSize minimumSize() const;

        TQLayoutIterator iterator();

        TQSizePolicy::ExpandData expanding() const;

    protected:
        void setGeometry( const TQRect &rect );

    private:
        void doLayout( const TQRect &rect, bool testonly = FALSE );
        void calcSize( SizeType st );

        TQPtrList<BorderLayoutStruct> list;
        TQSize cached, mcached;
        bool sizeDirty, msizeDirty;

    };

    #endif

Implementation of the border layout:

    /****************************************************************************
    ** $Id: qt/border.cpp   3.3.8   edited Jan 11 14:46 $
    **
    ** Implementing your own layout: flow example
    **
    ** Copyright (C) 1996-2007 Trolltech ASA.  All rights reserved.
    **
    ** This file is part of an example program for TQt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #include "border.h"

    class BorderLayoutIterator : public TQGLayoutIterator
    {
    public:
        BorderLayoutIterator( const TQPtrList<BorderLayout::BorderLayoutStruct> *l )
            : idx( 0 ) , list( (TQPtrList<BorderLayout::BorderLayoutStruct>*)l )
        {}

        uint count() const;
        TQLayoutItem *current();
        BorderLayout::BorderLayoutStruct *currentStruct();
        void toFirst();
        TQLayoutItem *next();
        TQLayoutItem *takeCurrent();
        BorderLayoutIterator &operator++();

    private:
        int idx;
        TQPtrList<BorderLayout::BorderLayoutStruct> *list;

    };

    uint BorderLayoutIterator::count() const
    {
        return list->count();
    }

    TQLayoutItem *BorderLayoutIterator::current()
    {
        return idx < (int)count() ? list->at( idx )->item : 0;
    }

    BorderLayout::BorderLayoutStruct *BorderLayoutIterator::currentStruct()
    {
        return idx < (int)count() ? list->at( idx ) : 0;
    }

    void BorderLayoutIterator::toFirst()
    {
        idx = 0;
    }

    TQLayoutItem *BorderLayoutIterator::next()
    {
        idx++;
        return current();
    }

    TQLayoutItem *BorderLayoutIterator::takeCurrent()
    {
        BorderLayout::BorderLayoutStruct *b
            = idx < int( list->count() ) ? list->take(  idx  ) : 0;
        TQLayoutItem *item =  b ? b->item : 0;
        delete b;
        return item;
    }

    BorderLayoutIterator &BorderLayoutIterator::operator++()
    {
        next();
        return *this;
    }

    BorderLayout::~BorderLayout()
    {
        deleteAllItems();
    }

    void BorderLayout::addItem( TQLayoutItem *item )
    {
        add( item, West );
    }

    void BorderLayout::addWidget( TQWidget *widget, Position pos )
    {
        add( new BorderWidgetItem( widget ), pos );
    }

    void BorderLayout::add( TQLayoutItem *item, Position pos )
    {
        list.append( new BorderLayoutStruct( item, pos ) );
        sizeDirty = TRUE; msizeDirty = TRUE;
        calcSize( SizeHint ); calcSize( Minimum );
    }

    bool BorderLayout::hasHeightForWidth() const
    {
        return FALSE;
    }

    TQSize BorderLayout::sizeHint() const
    {
        return cached;
    }

    TQSize BorderLayout::minimumSize() const
    {
        return cached;
    }

    TQSizePolicy::ExpandData BorderLayout::expanding() const

    {
        return TQSizePolicy::BothDirections;
    }

    TQLayoutIterator BorderLayout::iterator()
    {
        return TQLayoutIterator( new BorderLayoutIterator( &list ) );
    }

    void BorderLayout::setGeometry( const TQRect &rct )
    {
        TQLayout::setGeometry( rct );
        doLayout( rct );
    }

    void BorderLayout::doLayout( const TQRect &rct, bool /*testonly*/ )
    {
        int ew = 0, ww = 0, nh = 0, sh = 0;
        int h = 0;

        BorderLayoutIterator it( &list );
        BorderLayoutStruct *o;
        BorderLayoutStruct *center = 0;
        while ( ( o = it.currentStruct() ) != 0 ) {
            ++it;

            if ( o->pos == North ) {
                o->item->setGeometry( TQRect( rct.x(), nh, rct.width(), o->item->sizeHint().height() ) );
                nh += o->item->geometry().height() + spacing();
            }
            if ( o->pos == South ) {
                o->item->setGeometry( TQRect( o->item->geometry().x(), o->item->geometry().y(),
                                             rct.width(), o->item->sizeHint().height() ) );
                sh += o->item->geometry().height() + spacing();
                o->item->setGeometry( TQRect( rct.x(), rct.y() + rct.height() - sh + spacing(),
                                             o->item->geometry().width(), o->item->geometry().height() ) );
            }
            if ( o->pos == Center )
                center = o;
        }

        h = rct.height() - nh - sh;

        it.toFirst();
        while ( ( o = it.currentStruct() ) != 0 ) {
            ++it;

            if ( o->pos == West ) {
                o->item->setGeometry( TQRect( rct.x() + ww, nh, o->item->sizeHint().width(), h ) );
                ww += o->item->geometry().width() + spacing();
            }
            if ( o->pos == East ) {
                o->item->setGeometry( TQRect( o->item->geometry().x(), o->item->geometry().y(),
                                             o->item->sizeHint().width(), h ) );
                ew += o->item->geometry().width() + spacing();
                o->item->setGeometry( TQRect( rct.x() + rct.width() - ew + spacing(), nh,
                                             o->item->geometry().width(), o->item->geometry().height() ) );
            }
        }

        if ( center )
            center->item->setGeometry( TQRect( ww, nh, rct.width() - ew - ww, h ) );
    }

    void BorderLayout::calcSize( SizeType st )
    {
        if ( ( st == Minimum && !msizeDirty ) ||
             ( st == SizeHint && !sizeDirty ) )
            return;

        int w = 0, h = 0;

        BorderLayoutIterator it( &list );
        BorderLayoutStruct *o;
        while ( ( o = it.currentStruct() ) != 0 ) {
            ++it;
            if ( o->pos == North ||
                 o->pos == South ) {
                if ( st == Minimum )
                    h += o->item->minimumSize().height();
                else
                    h += o->item->sizeHint().height();
            }
            else if ( o->pos == West ||
                      o->pos == East ) {
                if ( st == Minimum )
                    w += o->item->minimumSize().width();
                else
                    w += o->item->sizeHint().width();
            } else {
                if ( st == Minimum ) {
                    h += o->item->minimumSize().height();
                    w += o->item->minimumSize().width();
                }
                else {
                    h += o->item->sizeHint().height();
                    w += o->item->sizeHint().width();
                }
            }
        }

        if ( st == Minimum ) {
            msizeDirty = FALSE;
            mcached = TQSize( w, h );
        } else {
            sizeDirty = FALSE;
            cached = TQSize( w, h );
        }

        return;
    }

Header file of the card layout:

    /****************************************************************************
    ** $Id: qt/card.h   3.3.8   edited Jan 11 14:46 $
    **
    ** Definition of simple flow layout for custom layout example
    **
    ** Created : 979899
    **
    ** Copyright (C) 1997-2007 Trolltech ASA.  All rights reserved.
    **
    ** This file is part of an example program for TQt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #ifndef CARD_H
    #define CARD_H

    #include <ntqlayout.h>
    #include <ntqptrlist.h>

    class CardLayout : public TQLayout
    {
    public:
        CardLayout( TQWidget *parent, int dist )
            : TQLayout( parent, 0, dist ) {}
        CardLayout( TQLayout* parent, int dist)
            : TQLayout( parent, dist ) {}
        CardLayout( int dist )
            : TQLayout( dist ) {}
        ~CardLayout();

        void addItem( TQLayoutItem *item );
        TQSize sizeHint() const;
        TQSize minimumSize() const;
        TQLayoutIterator iterator();
        void setGeometry( const TQRect &rect );

    private:
        TQPtrList<TQLayoutItem> list;

    };

    #endif

Implementation of the card layout:

    /****************************************************************************
    ** $Id: qt/card.cpp   3.3.8   edited Jan 11 14:46 $
    **
    ** Implementing your own layout: flow example
    **
    ** Copyright (C) 1996-2007 Trolltech ASA.  All rights reserved.
    **
    ** This file is part of an example program for TQt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #include "card.h"

    class CardLayoutIterator :public TQGLayoutIterator
    {
    public:
        CardLayoutIterator( TQPtrList<TQLayoutItem> *l )
            : idx( 0 ), list( l )  {}

        TQLayoutItem *current();
        TQLayoutItem *next();
        TQLayoutItem *takeCurrent();

    private:
        int idx;
        TQPtrList<TQLayoutItem> *list;
    };

    TQLayoutItem *CardLayoutIterator::current()
    {
        return idx < int( list->count() ) ? list->at( idx ) : 0;
    }

    TQLayoutItem *CardLayoutIterator::next()
    {
        idx++; return current();
    }

    TQLayoutItem *CardLayoutIterator::takeCurrent()
    {
        return idx < int( list->count() ) ?list->take( idx ) : 0;
    }

    TQLayoutIterator CardLayout::iterator()
    {
        return TQLayoutIterator(  new CardLayoutIterator( &list )  );
    }

    CardLayout::~CardLayout()
    {
        deleteAllItems();
    }

    void CardLayout::addItem(  TQLayoutItem *item  )
    {
        list.append( item );
    }

    void CardLayout::setGeometry( const TQRect &rct )
    {
        TQLayout::setGeometry( rct );

        TQPtrListIterator<TQLayoutItem> it( list );
        if ( it.count() == 0 )
            return;

        TQLayoutItem *o;

        int i = 0;

        int w = rct.width() - ( list.count() - 1 ) * spacing();
        int h = rct.height() - ( list.count() - 1 ) * spacing();

        while ( ( o=it.current() ) != 0 ) {
            ++it;
            TQRect geom( rct.x() + i * spacing(), rct.y() + i * spacing(),
                        w, h  );
            o->setGeometry(  geom  );
            ++i;
        }
    }

    TQSize CardLayout::sizeHint() const
    {
        TQSize s(0,0);
        int n = list.count();
        if ( n > 0 )
            s = TQSize(100,70); //start with a nice default size
        TQPtrListIterator<TQLayoutItem> it(list);
        TQLayoutItem *o;
        while ( (o=it.current()) != 0 ) {
            ++it;
            s = s.expandedTo( o->minimumSize() );
        }
        return s + n*TQSize(spacing(),spacing());
    }

    TQSize CardLayout::minimumSize() const
    {
        TQSize s(0,0);
        int n = list.count();
        TQPtrListIterator<TQLayoutItem> it(list);
        TQLayoutItem *o;
        while ( (o=it.current()) != 0 ) {
            ++it;
            s = s.expandedTo( o->minimumSize() );
        }
        return s + n*TQSize(spacing(),spacing());
    }

Main:

    /****************************************************************************
    ** $Id: qt/main.cpp   3.3.8   edited Jan 11 14:46 $
    **
    ** Main for custom layout example
    **
    ** Copyright (C) 1996-2007 Trolltech ASA.  All rights reserved.
    **
    ** This file is part of an example program for TQt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #include "flow.h"
    #include "border.h"
    #include "card.h"

    #include <ntqapplication.h>
    #include <ntqlabel.h>
    #include <ntqcolor.h>
    #include <ntqgroupbox.h>
    #include <ntqpushbutton.h>
    #include <ntqmultilineedit.h>
    #include <ntqcolor.h>

    int main( int argc, char **argv )
    {
        TQApplication a( argc, argv );

        TQWidget *f = new TQWidget;
        TQBoxLayout *gm = new TQVBoxLayout( f, 5 );

        SimpleFlow *b1 = new SimpleFlow( gm );

        b1->add( new TQPushButton( "Short", f ) );
        b1->add( new TQPushButton( "Longer", f ) );
        b1->add( new TQPushButton( "Different text", f ) );
        b1->add( new TQPushButton( "More text", f ) );
        b1->add( new TQPushButton( "Even longer button text", f ) );
        TQPushButton* qb = new TQPushButton( "Quit", f );
        a.connect( qb, TQ_SIGNAL( clicked() ), TQ_SLOT( quit() ) );
        b1->add( qb );

        TQWidget *wid = new TQWidget( f );

        BorderLayout *large = new BorderLayout( wid );
        large->setSpacing( 5 );
        large->addWidget( new TQPushButton( "North", wid ), BorderLayout::North );
        large->addWidget( new TQPushButton( "West", wid ), BorderLayout::West );
        TQMultiLineEdit* m = new TQMultiLineEdit( wid );
        m->setText( "Central\nWidget" );
        large->addWidget( m, BorderLayout::Center );
        TQWidget *east1 = new TQPushButton( "East", wid );
        large->addWidget( east1, BorderLayout::East );
        TQWidget *east2 = new TQPushButton( "East 2", wid );
        large->addWidget( east2 , BorderLayout::East );
        large->addWidget( new TQPushButton( "South", wid ), BorderLayout::South );
        //Left-to-right tab order looks better:
        TQWidget::setTabOrder( east2, east1 );
        gm->addWidget( wid );

        wid = new TQWidget( f );
        CardLayout *card = new CardLayout( wid, 10 );

        TQWidget *crd = new TQWidget( wid );
        crd->setBackgroundColor( TQt::red );
        card->add( crd );
        crd = new TQWidget( wid );
        crd->setBackgroundColor( TQt::green );
        card->add( crd );
        crd = new TQWidget( wid );
        crd->setBackgroundColor( TQt::blue );
        card->add( crd );
        crd = new TQWidget( wid );
        crd->setBackgroundColor( TQt::white );
        card->add( crd );
        crd = new TQWidget( wid );
        crd->setBackgroundColor( TQt::black );
        card->add( crd );
        crd = new TQWidget( wid );
        crd->setBackgroundColor( TQt::yellow );
        card->add( crd );

        gm->addWidget( wid );

        TQLabel* s = new TQLabel( f );
        s->setText( "outermost box" );
        s->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
        s->setAlignment( TQt::AlignVCenter | TQt::AlignHCenter );
        gm->addWidget( s );
        a.setMainWidget( f );
        f->setCaption("TQt Example - Custom Layout");
        f->show();

        int result = a.exec();
        delete f;
        return result;
    }

See also Examples.