From bd0f3345a938b35ce6a12f6150373b0955b8dd12 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 10 Jul 2011 15:24:15 -0500 Subject: Add Qt3 development HEAD version --- doc/html/customlayout.html | 246 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 doc/html/customlayout.html (limited to 'doc/html/customlayout.html') diff --git a/doc/html/customlayout.html b/doc/html/customlayout.html new file mode 100644 index 0000000..1a46c6d --- /dev/null +++ b/doc/html/customlayout.html @@ -0,0 +1,246 @@ + + + + + +Writing your own layout manager + + + + + + + +
+ +Home + | +All Classes + | +Main Classes + | +Annotated + | +Grouped Classes + | +Functions +

Writing your own layout manager

+ + +

Here we present an example in detail. The class CardLayout is inspired +by the Java layout manager of the same name. It lays out the items +(widgets or nested layouts) on top of each other, each item offset by +QLayout::spacing(). +

To write your own layout class, you must define the following: +

+

In most cases, you will also implement minimumSize(). +

card.h +

+

+#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
+
+ +

card.cpp +

+

+#include "card.h"
+
+ +

First we define an iterator over the layout. Layout iterators are used +internally by the layout system to handle deletion of widgets. They +are also available for application programmers. +

There are two different classes involved: QLayoutIterator is the class +that is visible to application programmers, it is explicitly shared. +The QLayoutIterator contains a QGLayoutIterator that does all the +work. We must create a subclass of QGLayoutIterator that knows how to +iterate over our layout class. +

In this case, we choose a simple implementation: we store an integer +index into the list and a pointer to the list. Every QGLayoutIterator subclass must implement current(), next() and takeCurrent(), as well as a +constructor. In our example we do not need a destructor. +

+class CardLayoutIterator : public QGLayoutIterator
+{
+public:
+    CardLayoutIterator( QPtrList<QLayoutItem> *l )
+        : idx( 0 ), list( l ) {}
+
+    QLayoutItem *current()
+    { return idx < int(list->count()) ? list->at(idx) : 0;  }
+
+    QLayoutItem *next()
+    { idx++; return current(); }
+
+    QLayoutItem *takeCurrent()
+    { return list->take( idx ); }
+
+private:
+    int idx;
+    QPtrList<QLayoutItem> *list;
+};
+
+ +

We must implement QLayout:iterator() to return a QLayoutIterator over +this layout. +

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

addItem() implements the default placement strategy for layout items. +It must be implemented. It is used by QLayout::add(), by the QLayout +constructor that takes a layout as parent, and it is used to implement +the auto-add feature. If your layout +has advanced placement options that require parameters, you must +provide extra access functions such as QGridLayout::addMultiCell(). +

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

The layout takes over responsibility of the items added. Since +QLayoutItem does not inherit QObject, we must delete the items +manually. The function QLayout::deleteAllItems() uses the iterator we +defined above to delete all the items in the layout. +

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

The setGeometry() function actually performs the layout. The rectangle +supplied as an argument does not include margin(). If relevant, use +spacing() as the distance between items. +

+void CardLayout::setGeometry( const QRect &rect )
+{
+    QLayout::setGeometry( rect );
+
+    QPtrListIterator<QLayoutItem> it( list );
+    if (it.count() == 0)
+        return;
+
+    QLayoutItem *item;
+
+    int i = 0;
+
+    int w = rect.width() - ( list.count() - 1 ) * spacing();
+    int h = rect.height() - ( list.count() - 1 ) * spacing();
+
+    while ( (item = it.current()) != 0 ) {
+        ++it;
+        QRect geom( rect.x() + i * spacing(), rect.y() + i * spacing(),
+                    w, h );
+        item->setGeometry( geom );
+        ++i;
+    }
+}
+
+ +

sizeHint() and minimumSize() are normally very similar in +implementation. The sizes returned by both functions should include +spacing(), but not margin(). +

+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 *item;
+    while ( (item = it.current()) != 0 ) {
+        ++it;
+        s = s.expandedTo( item->minimumSize() );
+    }
+    return s + n * QSize( spacing(), spacing() );
+}
+
+QSize CardLayout::minimumSize() const
+{
+    QSize s( 0, 0 );
+    int n = list.count();
+    QPtrListIterator<QLayoutItem> it( list );
+    QLayoutItem *item;
+    while ( (item = it.current()) != 0 ) {
+        ++it;
+        s = s.expandedTo( item->minimumSize() );
+    }
+    return s + n * QSize( spacing(), spacing() );
+}
+
+ +

Further Notes +

+

This layout does not implement heightForWidth(). +

We ignore QLayoutItem::isEmpty(), this means that the layout will +treat hidden widgets as visible. +

For complex layouts, speed can be greatly increased by caching +calculated values. In that case, implement QLayoutItem::invalidate() +to mark the cached data as dirty. +

Calling QLayoutItem::sizeHint(), etc. may be expensive, so you should +store the value in a local variable if you need it again later in the +same function. +

You should not call QLayoutItem::setGeometry() twice on the same item +in the same function. That can be very expensive if the item has +several child widgets, because it will have to do a complete layout +every time. Instead, calculate the geometry and then set it. (This +doesn't only apply to layouts, you should do the same if you implement +your own resizeEvent().) +

+ +


+ +
Copyright © 2007 +TrolltechTrademarks +
Qt 3.3.8
+
+ -- cgit v1.2.3