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.0.5 edited Oct 12 2001 $ ** ** Definition of simple flow layout for custom layout example ** ** Created : 979899 ** ** Copyright (C) 1997 by Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #ifndef FLOW_H #define FLOW_H #include <qlayout.h> #include <qptrlist.h> class SimpleFlow : public QLayout { public: SimpleFlow( QWidget *parent, int border=0, int space=-1, const char *name=0 ) : QLayout( parent, border, space, name ), cached_width(0) {} SimpleFlow( QLayout* parent, int space=-1, const char *name=0 ) : QLayout( parent, space, name ), cached_width(0) {} SimpleFlow( int space=-1, const char *name=0 ) : QLayout( space, name ), cached_width(0) {} ~SimpleFlow(); void addItem( QLayoutItem *item); bool hasHeightForWidth() const; int heightForWidth( int ) const; QSize sizeHint() const; QSize minimumSize() const; QLayoutIterator iterator(); QSizePolicy::ExpandData expanding() const; protected: void setGeometry( const QRect& ); private: int doLayout( const QRect&, bool testonly = FALSE ); QPtrList<QLayoutItem> list; int cached_width; int cached_hfw; }; #endif
Implementation of the flow layout:
/**************************************************************************** ** $Id: qt/flow.cpp 3.0.5 edited Oct 12 2001 $ ** ** Implementing your own layout: flow example ** ** Copyright (C) 1996 by Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #include "flow.h" class SimpleFlowIterator :public QGLayoutIterator { public: SimpleFlowIterator( QPtrList<QLayoutItem> *l ) :idx(0), list(l) {} uint count() const; QLayoutItem *current(); QLayoutItem *next(); QLayoutItem *takeCurrent(); private: int idx; QPtrList<QLayoutItem> *list; }; uint SimpleFlowIterator::count() const { return list->count(); } QLayoutItem *SimpleFlowIterator::current() { return idx < int(count()) ? list->at(idx) : 0; } QLayoutItem *SimpleFlowIterator::next() { idx++; return current(); } QLayoutItem *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( QRect(0,0,w,0), TRUE ); mthis->cached_hfw = h; return h; } return cached_hfw; } void SimpleFlow::addItem( QLayoutItem *item) { list.append( item ); } bool SimpleFlow::hasHeightForWidth() const { return TRUE; } QSize SimpleFlow::sizeHint() const { return minimumSize(); } QSizePolicy::ExpandData SimpleFlow::expanding() const { return QSizePolicy::NoDirection; } QLayoutIterator SimpleFlow::iterator() { return QLayoutIterator( new SimpleFlowIterator( &list ) ); } void SimpleFlow::setGeometry( const QRect &r ) { QLayout::setGeometry( r ); doLayout( r ); } int SimpleFlow::doLayout( const QRect &r, bool testonly ) { int x = r.x(); int y = r.y(); int h = 0; //height of this line so far. QPtrListIterator<QLayoutItem> it(list); QLayoutItem *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( QRect( QPoint( x, y ), o->sizeHint() ) ); x = nextX; h = QMAX( h, o->sizeHint().height() ); } return y + h - r.y(); } QSize SimpleFlow::minimumSize() const { QSize s(0,0); QPtrListIterator<QLayoutItem> it(list); QLayoutItem *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.0.5 edited Oct 12 2001 $ ** ** Definition of simple flow layout for custom layout example ** ** Created : 979899 ** ** Copyright (C) 1997 by Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #ifndef BORDER_H #define BORDER_H #include <qlayout.h> #include <qptrlist.h> class BorderWidgetItem : public QWidgetItem { public: BorderWidgetItem( QWidget *w ) : QWidgetItem( w ) {} void setGeometry( const QRect &r ) { widget()->setGeometry( r ); } }; class BorderLayout : public QLayout { public: enum Position { West = 0, North, South, East, Center }; struct BorderLayoutStruct { BorderLayoutStruct( QLayoutItem *i, Position p ) { item = i; pos = p; } QLayoutItem *item; Position pos; }; enum SizeType { Minimum = 0, SizeHint }; BorderLayout( QWidget *parent, int border = 0, int autoBorder = -1, const char *name = 0 ) : QLayout( parent, border, autoBorder, name ), cached( 0, 0 ), mcached( 0, 0 ), sizeDirty( TRUE ), msizeDirty( TRUE ) {} BorderLayout( QLayout* parent, int autoBorder = -1, const char *name = 0 ) : QLayout( parent, autoBorder, name ), cached( 0, 0 ), mcached( 0, 0 ), sizeDirty( TRUE ), msizeDirty( TRUE ) {} BorderLayout( int autoBorder = -1, const char *name = 0 ) : QLayout( autoBorder, name ), cached( 0, 0 ), mcached( 0, 0 ), sizeDirty( TRUE ), msizeDirty( TRUE ) {} ~BorderLayout(); void addItem( QLayoutItem *item ); void addWidget( QWidget *widget, Position pos ); void add( QLayoutItem *item, Position pos ); bool hasHeightForWidth() const; QSize sizeHint() const; QSize minimumSize() const; QLayoutIterator iterator(); QSizePolicy::ExpandData expanding() const; protected: void setGeometry( const QRect &rect ); private: void doLayout( const QRect &rect, bool testonly = FALSE ); void calcSize( SizeType st ); QPtrList<BorderLayoutStruct> list; QSize cached, mcached; bool sizeDirty, msizeDirty; }; #endif
Implementation of the border layout:
/**************************************************************************** ** $Id: qt/border.cpp 3.0.5 edited Oct 12 2001 $ ** ** Implementing your own layout: flow example ** ** Copyright (C) 1996 by Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #include "border.h" class BorderLayoutIterator : public QGLayoutIterator { public: BorderLayoutIterator( const QPtrList<BorderLayout::BorderLayoutStruct> *l ) : idx( 0 ) , list( (QPtrList<BorderLayout::BorderLayoutStruct>*)l ) {} uint count() const; QLayoutItem *current(); BorderLayout::BorderLayoutStruct *currentStruct(); void toFirst(); QLayoutItem *next(); QLayoutItem *takeCurrent(); BorderLayoutIterator &operator++(); private: int idx; QPtrList<BorderLayout::BorderLayoutStruct> *list; }; uint BorderLayoutIterator::count() const { return list->count(); } QLayoutItem *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; } QLayoutItem *BorderLayoutIterator::next() { idx++; return current(); } QLayoutItem *BorderLayoutIterator::takeCurrent() { BorderLayout::BorderLayoutStruct *b = idx < int( list->count() ) ? list->take( idx ) : 0; QLayoutItem *item = b ? b->item : 0; delete b; return item; } BorderLayoutIterator &BorderLayoutIterator::operator++() { next(); return *this; } BorderLayout::~BorderLayout() { deleteAllItems(); } void BorderLayout::addItem( QLayoutItem *item ) { add( item, West ); } void BorderLayout::addWidget( QWidget *widget, Position pos ) { add( new BorderWidgetItem( widget ), pos ); } void BorderLayout::add( QLayoutItem *item, Position pos ) { list.append( new BorderLayoutStruct( item, pos ) ); sizeDirty = TRUE; msizeDirty = TRUE; calcSize( SizeHint ); calcSize( Minimum ); } bool BorderLayout::hasHeightForWidth() const { return FALSE; } QSize BorderLayout::sizeHint() const { return cached; } QSize BorderLayout::minimumSize() const { return cached; } QSizePolicy::ExpandData BorderLayout::expanding() const { return QSizePolicy::BothDirections; } QLayoutIterator BorderLayout::iterator() { return QLayoutIterator( new BorderLayoutIterator( &list ) ); } void BorderLayout::setGeometry( const QRect &rct ) { QLayout::setGeometry( rct ); doLayout( rct ); } void BorderLayout::doLayout( const QRect &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( QRect( rct.x(), nh, rct.width(), o->item->sizeHint().height() ) ); nh += o->item->geometry().height() + spacing(); } if ( o->pos == South ) { o->item->setGeometry( QRect( o->item->geometry().x(), o->item->geometry().y(), rct.width(), o->item->sizeHint().height() ) ); sh += o->item->geometry().height() + spacing(); o->item->setGeometry( QRect( 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( QRect( rct.x() + ww, nh, o->item->sizeHint().width(), h ) ); ww += o->item->geometry().width() + spacing(); } if ( o->pos == East ) { o->item->setGeometry( QRect( o->item->geometry().x(), o->item->geometry().y(), o->item->sizeHint().width(), h ) ); ew += o->item->geometry().width() + spacing(); o->item->setGeometry( QRect( rct.x() + rct.width() - ew + spacing(), nh, o->item->geometry().width(), o->item->geometry().height() ) ); } } if ( center ) center->item->setGeometry( QRect( 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 = QSize( w, h ); } else { sizeDirty = FALSE; cached = QSize( w, h ); } return; }
Header file of the card layout:
/**************************************************************************** ** $Id: qt/card.h 3.0.5 edited Oct 12 2001 $ ** ** Definition of simple flow layout for custom layout example ** ** Created : 979899 ** ** Copyright (C) 1997 by Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #ifndef CARD_H #define CARD_H #include <qlayout.h> #include <qptrlist.h> class CardLayout : public QLayout { public: CardLayout( QWidget *parent, int dist ) : QLayout( parent, 0, dist ) {} CardLayout( QLayout* parent, int dist) : QLayout( parent, dist ) {} CardLayout( int dist ) : QLayout( dist ) {} ~CardLayout(); void addItem( QLayoutItem *item ); QSize sizeHint() const; QSize minimumSize() const; QLayoutIterator iterator(); void setGeometry( const QRect &rect ); private: QPtrList<QLayoutItem> list; }; #endif
Implementation of the card layout:
/**************************************************************************** ** $Id: qt/card.cpp 3.0.5 edited Oct 12 2001 $ ** ** Implementing your own layout: flow example ** ** Copyright (C) 1996 by Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #include "card.h" class CardLayoutIterator :public QGLayoutIterator { public: CardLayoutIterator( QPtrList<QLayoutItem> *l ) : idx( 0 ), list( l ) {} QLayoutItem *current(); QLayoutItem *next(); QLayoutItem *takeCurrent(); private: int idx; QPtrList<QLayoutItem> *list; }; QLayoutItem *CardLayoutIterator::current() { return idx < int( list->count() ) ? list->at( idx ) : 0; } QLayoutItem *CardLayoutIterator::next() { idx++; return current(); } QLayoutItem *CardLayoutIterator::takeCurrent() { return idx < int( list->count() ) ?list->take( idx ) : 0; } QLayoutIterator CardLayout::iterator() { return QLayoutIterator( new CardLayoutIterator( &list ) ); } CardLayout::~CardLayout() { deleteAllItems(); } void CardLayout::addItem( QLayoutItem *item ) { list.append( item ); } void CardLayout::setGeometry( const QRect &rct ) { QLayout::setGeometry( rct ); QPtrListIterator<QLayoutItem> it( list ); if ( it.count() == 0 ) return; QLayoutItem *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; QRect geom( rct.x() + i * spacing(), rct.y() + i * spacing(), w, h ); o->setGeometry( geom ); ++i; } } QSize CardLayout::sizeHint() const { QSize s(0,0); int n = list.count(); if ( n > 0 ) s = QSize(100,70); //start with a nice default size QPtrListIterator<QLayoutItem> it(list); QLayoutItem *o; while ( (o=it.current()) != 0 ) { ++it; s = s.expandedTo( o->minimumSize() ); } return s + n*QSize(spacing(),spacing()); } QSize CardLayout::minimumSize() const { QSize s(0,0); int n = list.count(); QPtrListIterator<QLayoutItem> it(list); QLayoutItem *o; while ( (o=it.current()) != 0 ) { ++it; s = s.expandedTo( o->minimumSize() ); } return s + n*QSize(spacing(),spacing()); }
Main:
/**************************************************************************** ** $Id: qt/main.cpp 3.0.5 edited Oct 12 2001 $ ** ** Main for custom layout example ** ** Copyright (C) 1996 by Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #include "flow.h" #include "border.h" #include "card.h" #include <qapplication.h> #include <qlabel.h> #include <qcolor.h> #include <qgroupbox.h> #include <qpushbutton.h> #include <qmultilineedit.h> #include <qcolor.h> int main( int argc, char **argv ) { QApplication a( argc, argv ); QWidget *f = new QWidget; QBoxLayout *gm = new QVBoxLayout( f, 5 ); SimpleFlow *b1 = new SimpleFlow( gm ); b1->add( new QPushButton( "Short", f ) ); b1->add( new QPushButton( "Longer", f ) ); b1->add( new QPushButton( "Different text", f ) ); b1->add( new QPushButton( "More text", f ) ); b1->add( new QPushButton( "Even longer button text", f ) ); QPushButton* qb = new QPushButton( "Quit", f ); a.connect( qb, SIGNAL( clicked() ), SLOT( quit() ) ); b1->add( qb ); QWidget *wid = new QWidget( f ); BorderLayout *large = new BorderLayout( wid ); large->setSpacing( 5 ); large->addWidget( new QPushButton( "North", wid ), BorderLayout::North ); large->addWidget( new QPushButton( "West", wid ), BorderLayout::West ); QMultiLineEdit* m = new QMultiLineEdit( wid ); m->setText( "Central\nWidget" ); large->addWidget( m, BorderLayout::Center ); QWidget *east1 = new QPushButton( "East", wid ); large->addWidget( east1, BorderLayout::East ); QWidget *east2 = new QPushButton( "East 2", wid ); large->addWidget( east2 , BorderLayout::East ); large->addWidget( new QPushButton( "South", wid ), BorderLayout::South ); //Left-to-right tab order looks better: QWidget::setTabOrder( east2, east1 ); gm->addWidget( wid ); wid = new QWidget( f ); CardLayout *card = new CardLayout( wid, 10 ); QWidget *crd = new QWidget( wid ); crd->setBackgroundColor( Qt::red ); card->add( crd ); crd = new QWidget( wid ); crd->setBackgroundColor( Qt::green ); card->add( crd ); crd = new QWidget( wid ); crd->setBackgroundColor( Qt::blue ); card->add( crd ); crd = new QWidget( wid ); crd->setBackgroundColor( Qt::white ); card->add( crd ); crd = new QWidget( wid ); crd->setBackgroundColor( Qt::black ); card->add( crd ); crd = new QWidget( wid ); crd->setBackgroundColor( Qt::yellow ); card->add( crd ); gm->addWidget( wid ); QLabel* s = new QLabel( f ); s->setText( "outermost box" ); s->setFrameStyle( QFrame::Panel | QFrame::Sunken ); s->setAlignment( Qt::AlignVCenter | Qt::AlignHCenter ); gm->addWidget( s ); a.setMainWidget( f ); f->setCaption("Qt Example - Custom Layout"); f->show(); int result = a.exec(); delete f; return result; }
See also Examples.
Copyright © 2002 Trolltech | Trademarks | Qt version 3.0.5
|