📄 customlayout.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Qt Toolkit - Writing your own layout manager</title><style type="text/css"><!--h3.fn,span.fn { margin-left: 1cm; text-indent: -1cm; }a:link { color: #004faf; text-decoration: none }a:visited { color: #672967; text-decoration: none }body { background: white; color: black; }--></style></head><body bgcolor="#ffffff"><p><table width="100%"><tr><td><a href="index.html"><img width="100" height="100" src="qtlogo.png"alt="Home" border="0"><img width="100"height="100" src="face.png" alt="Home" border="0"></a><td valign="top"><div align="right"><img src="dochead.png" width="472" height="27"><br><a href="classes.html"><b>Classes</b></a>- <a href="annotated.html">Annotated</a>- <a href="hierarchy.html">Tree</a>- <a href="functions.html">Functions</a>- <a href="index.html">Home</a>- <a href="topicals.html"><b>Structure</b> <font face="Arial,Helvetica,Geneva,Swiss,SunSans-Regular" align="center" size=32>Qte</font></a></div></table><h1 align="center"> Writing your own layout manager</h1><br clear="all">Here we go through an example in detail. The class <code>CardLayout</code> is inspired by the Java layout manager of the same name. Itlays out the items (widgets or nested layouts)on top of each other, each item offset by<a href="qlayout.html#372777">spacing()</a>.<p>To write your own layout class, you must define the following: <ul> <li>A data structure to store the items handle by the layout. Each item is a <a href="qlayoutitem.html">QLayoutItem</a>. We will just use a QList in this example. <li><a href="qlayout.html#db69d5">addItem()</a>, how to add items to the layout. <li><a href="qlayout.html#f1f752">setGeometry()</a>, how to do the layout. <li><a href="qlayoutitem.html#48b5b2">sizeHint()</a>, the preferred size of the layout. <li><a href="qlayout.html#3d3ab8">iterator()</a>, how to iterate over the layout. </ul><p>In most cases, you will also implement <a href="qlayout.html#8e1dc2">minimumSize()</a>.<p><h3> card.h </h3><p><pre>class CardLayout : public QLayout{public: CardLayout( <a href="qwidget.html">QWidget</a> *parent, int dist ) : <a href="qlayout.html">QLayout</a>( parent, 0, dist ) {} CardLayout( <a href="qlayout.html">QLayout</a>* parent, int dist) : <a href="qlayout.html">QLayout</a>( parent, dist ) {} CardLayout( int dist ) : <a href="qlayout.html">QLayout</a>( dist ) {} ~CardLayout(); void addItem(<a href="qlayoutitem.html">QLayoutItem</a> *item); <a href="qsize.html">QSize</a> sizeHint() const; <a href="qsize.html">QSize</a> minimumSize() const; <a href="qlayoutiterator.html">QLayoutIterator</a> iterator(); void setGeometry(const QRect &rect);private: <a href="qlist.html">QList</a><<a href="qlayoutitem.html">QLayoutItem</a>> list;};</pre><p><h3> card.cpp </h3><pre></pre><p>We first define an iterator over the layout. Layout iterators areused internally by the layout system to handle deletion ofwidgets. They are also available for application programmers.<p>There are two different classes involved: QLayoutIterator is the classthat is visible to application programmers, it is explicitlyshared. The QLayoutIterator contains a QGLayoutIterator that does allthe work. We must create a subclass of QGLayoutIterator that knows howto iterate over our layout class.<p>In this case, we choose a simple implementation: we store an integerindex into the list and a pointer to the list. Every QGLayoutIteratorsubclass must implement <a href="qglayoutiterator.html#cdab98">current()</a>,<a href="qglayoutiterator.html#e03723">next()</a> and<a href="qglayoutiterator.html#fa72ce">takeCurrent()</a>, as well asa constructor. In our example we do not need a destructor.<p><pre>class CardLayoutIterator :public QGLayoutIterator{public: CardLayoutIterator(<a href="qlist.html">QList</a><<a href="qlayoutitem.html">QLayoutItem</a>> *l) : idx(0), list(l) {} <a href="qlayoutitem.html">QLayoutItem</a> *current() { return idx < int(list-><a href="qlist.html#359d9f">count</a>()) ? list-><a href="qlist.html#0e7e42">at</a>(idx) : 0; } <a href="qlayoutitem.html">QLayoutItem</a> *next() { idx++; return current(); } <a href="qlayoutitem.html">QLayoutItem</a> *takeCurrent() { return list-><a href="qlist.html#0639ad">take</a>( idx ); }private: int idx; <a href="qlist.html">QList</a><<a href="qlayoutitem.html">QLayoutItem</a>> *list;};</pre><p>We must implement QLayout:iterator() to return a QLayoutIterator overthis layout.<p><pre><a href="qlayoutiterator.html">QLayoutIterator</a> CardLayout::iterator(){ return QLayoutIterator( new CardLayoutIterator(&list) );}</pre><p>addItem() implements the default placement strategy for layout items. Itmust be implemented. It is used by QLayout::add(), by the QLayoutconstructor that takes a layout as parent, and it is used to implementthe <a href="qlayout.html#d02056">auto-add</a> feature. If your layouthas advanced placement options that require parameters, you will have toprovide extra access functions like eg. <a href="qgridlayout.html#67545e">QGridLayout::addMultiCell()</a>.<p><pre>void CardLayout::addItem( <a href="qlayoutitem.html">QLayoutItem</a> *item ){ list.append(item);}</pre><p>The layout takes over responsibility of the items added. SinceQLayoutItem does not inherit QObject, we must delete the itemsmanually. The function <a href="qlayout.html#3349c9">deleteAllItems()</a>uses the iterator we defined above to delete all items in the layout.<p><pre>CardLayout::~CardLayout(){ deleteAllItems();}</pre><p>The setGeometry() function actually performs the layout. The rectanglesupplied as an argument does not include margin(). If relevant, usespacing() as the distance between items.<p><pre>void CardLayout::setGeometry(const QRect &rect){ <a href="qlayout.html#f1f752">QLayout::setGeometry</a>(rect); <a href="qlistiterator.html">QListIterator</a><<a href="qlayoutitem.html">QLayoutItem</a>> it(list); if (it.<a href="qlistiterator.html#e61e8b">count</a>() == 0) return; <a href="qlayoutitem.html">QLayoutItem</a> *o; int i = 0; int w = rect.width() - (list.count() - 1) * spacing(); int h = rect.height() - (list.count() - 1) * spacing(); while ((o=it.<a href="qlistiterator.html#e58f06">current</a>()) != 0) { ++it; <a href="qrect.html">QRect</a> geom(rect.x() + i * spacing(), rect.y() + i * spacing(), w, h ); o-><a href="qlayoutitem.html#0c6928">setGeometry</a>( geom ); ++i; } }</pre><p>sizeHint() and minimumSize() are normally very similar inimplementation. The sizes returned by both functions should includespacing(), but not margin().<p><pre><a href="qsize.html">QSize</a> CardLayout::sizeHint() const{ <a href="qsize.html">QSize</a> s(0,0); int n = list.count(); if ( n > 0 ) s = QSize(100,70); //start with a nice default size <a href="qlistiterator.html">QListIterator</a><<a href="qlayoutitem.html">QLayoutItem</a>> it(list); <a href="qlayoutitem.html">QLayoutItem</a> *o; while ( (o=it.<a href="qlistiterator.html#e58f06">current</a>()) != 0 ) { ++it; s = s.<a href="qsize.html#a74829">expandedTo</a>( o-><a href="qlayoutitem.html#83838c">minimumSize</a>() ); } return s + n*QSize(spacing(),spacing());}<a href="qsize.html">QSize</a> CardLayout::minimumSize() const{ <a href="qsize.html">QSize</a> s(0,0); int n = list.count(); <a href="qlistiterator.html">QListIterator</a><<a href="qlayoutitem.html">QLayoutItem</a>> it(list); <a href="qlayoutitem.html">QLayoutItem</a> *o; while ( (o=it.<a href="qlistiterator.html#e58f06">current</a>()) != 0 ) { ++it; s = s.<a href="qsize.html#a74829">expandedTo</a>( o-><a href="qlayoutitem.html#83838c">minimumSize</a>() ); } return s + n*QSize(spacing(),spacing());}</pre><p><h2>Further comments</h2><p>This layout does not implement heightForWidth().<p>We ignore QLayoutItem::isEmpty(), this means that the layout will treathidden widgets as visible.<p>For complex layouts, speed can be greatly increased by caching calculatedvalues and/or data structures. In that case, implement <a href="qlayoutitem.html#91d950">invalidate()</a> to mark the cacheddata as dirty.<p>Calling QLayoutItem::sizeHint(), etc. may be expensive, so you shouldstore the value in a local variable if you need it again later in thesame function.<p>You should not call QLayoutItem::setGeometry() twice on the same itemin the same function. That can be very expensive if the item hasseveral child widgets, because it will have to do a complete layoutevery time. Instead, calculate the geometry and then set it. (Thisdoes not only apply to layouts, you should do the same if youimplement your own resizeEvent()).<p><address><hr><div align="center"><table width="100%" cellspacing="0" border="0"><tr><td>Copyright
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -