📄 t10.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 Tutorial - Chapter 10: Smooth as Silk</title></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><p><h1 align=center>Chapter 10: Smooth as Silk</h1><br clear="all"><p><center><img src="t10.png" alt="Screenshot of tutorial ten"></center><p>In this example, we introduce painting in a pixmap to remove flickering.We also add a force control.<p><ul><li><a href="t10-lcdrange-h.html">lcdrange.h</a> contains the LCDRangeclass definition<li><a href="t10-lcdrange-cpp.html">lcdrange.cpp</a> contains the LCDRangeimplementation<li><a href="t10-cannon-h.html">cannon.h</a> contains the CannonField classdefinition<li><a href="t10-cannon-cpp.html">cannon.cpp</a> contains the CannonFieldimplementation<li><a href="t10-main-cpp.html">main.cpp</a> contains MyWidget and main.<li><a href="t10-makefile.html">Makefile</a> contains some rules forgenerating the meta object information necessary for<a href="signalsandslots.html">signal/slot creation.</a></ul><p><h2>Line by Line Walk-Through</h2><p><h3><a href="t10-cannon-h.html">cannon.h</a></h3><p>The CannonField now has a force value in addition to the angle. <pre> int angle() const { return ang; } int force() const { return f; } public slots: void setAngle( int degrees ); void setForce( int newton ); signals: void angleChanged( int ); void forceChanged( int );</pre><p>The interface to the force follows the same practice as for angle. <pre> private: <a href="qrect.html">QRect</a> cannonRect() const;</pre><p>We have put the definition of the cannon's enclosing rectangle in aseparate function. <pre> int ang; int f; };</pre><p>The force is stored in the integer f.<p><h3><a href="t10-cannon-cpp.html">cannon.cpp</a></h3> <pre> #include <<a href="qpixmap-h.html">qpixmap.h</a>></pre><p>We include the QPixmap class definition. <pre> CannonField::CannonField( <a href="qwidget.html">QWidget</a> *parent, const char *name ) : <a href="qwidget.html">QWidget</a>( parent, name ) { ang = 45; f = 0; <a href="qwidget.html#d7e4b9">setPalette</a>( <a href="qpalette.html">QPalette</a>( <a href="qcolor.html">QColor</a>( 250, 250, 200) ) ); }</pre><p>The force (f) is initialized to zero. <pre> void CannonField::setAngle( int degrees ) { if ( degrees < 5 ) degrees = 5; if ( degrees > 70 ) degrees = 70; if ( ang == degrees ) return; ang = degrees; <a href="qwidget.html#7569b1">repaint</a>( cannonRect(), FALSE ); emit angleChanged( ang ); }</pre><p>We have made a slight change in the setAngle() function. It repaintsonly the portion of the widget that contains the cannon. The FALSEargument indicates that the specified rectangle should not be erasedbefore a paint event is sent to the widget. This speeds up and smoothsdrawing a little bit. <pre> void CannonField::setForce( int newton ) { if ( newton < 0 ) newton = 0; if ( f == newton ) return; f = newton; emit forceChanged( f ); }</pre><p>The implementation of setForce() is quite similar to that ofsetAngle(). The only difference is that since we don't show the forcevalue, we don't need to repaint the widget. <pre> void CannonField::paintEvent( <a href="qpaintevent.html">QPaintEvent</a> *e ) { if ( !e-><a href="qpaintevent.html#2d6e18">rect</a>().intersects( cannonRect() ) ) return;</pre><p>We have now optimized the paint event to repaint only the parts of thewidget that need updating. First we check whether we have to paintanything at all, and return if we don't. <pre> <a href="qrect.html">QRect</a> cr = cannonRect(); <a href="qpixmap.html">QPixmap</a> pix( cr.<a href="qrect.html#507cd9">size</a>() );</pre><p>Then we create a temporary pixmap, which we use for flicker-freepainting. All the painting operations are done into this pixmap, andthen the pixmap is drawn on the screen in a single operation.<p>This is the essence of flicker-free drawing: Draw on each pixelprecisely once. Less, and you get drawing errors. More, and you getflicker. It doesn't matter much in this example - when the code waswritten there were still machines slow enough for it to flicker, butnot any more. We've kept the code for educational purposes. <pre> pix.<a href="qpixmap.html#6910a0">fill</a>( this, cr.<a href="qrect.html#349186">topLeft</a>() );</pre><p>We fill the pixmap with the background from this widget. <pre> <a href="qpainter.html">QPainter</a> p( &pix ); p.<a href="qpainter.html#3e0cc8">setBrush</a>( blue ); p.<a href="qpainter.html#0183e4">setPen</a>( NoPen ); p.<a href="qpainter.html#eb778c">translate</a>( 0, pix.<a href="qpixmap.html#d5bb33">height</a>() - 1 ); p.<a href="qpainter.html#3ca7a2">drawPie</a>( <a href="qrect.html">QRect</a>( -35,-35, 70, 70 ), 0, 90*16 ); p.<a href="qpainter.html#b5205c">rotate</a>( -ang ); p.<a href="qpainter.html#4c0077">drawRect</a>( <a href="qrect.html">QRect</a>(33, -4, 15, 8) ); p.<a href="qpainter.html#365784">end</a>();</pre><p>We paint, as in chapter 9, but now we paint in the pixmap.<p>At this point, we have a painter variable and a pixmap that looksprecisely right, but we still haven't painted on the screen. <pre> p.<a href="qpainter.html#02ed5d">begin</a>( this ); p.<a href="qpainter.html#c64b89">drawPixmap</a>( cr.<a href="qrect.html#349186">topLeft</a>(), pix );</pre><p>So we open the painter on the CannonField itself and then draw the pixmap.<p>That's all. A couple of extra lines at the top and a couple at thebottom, and the code is 100% flicker-free. <pre> <a href="qrect.html">QRect</a> CannonField::cannonRect() const { <a href="qrect.html">QRect</a> r( 0, 0, 50, 50 ); r.<a href="qrect.html#8df149">moveBottomLeft</a>( <a href="qwidget.html#75ae71">rect</a>().bottomLeft() ); return r; }</pre><p>This function returns the rectangle enclosing the cannon in widgetcoordinates. First we create a rectangle with the size 50x50, thenmove it so its bottom left corner is equal to the widget's own bottomleft corner.<p>The <a href="qwidget.html#75ae71">QWidget::rect()</a> function returns the widget's enclosingrectangle in the widget's own coordinates (where the top left corneris 0,0).<p><h3><a href="t10-main-cpp.html">main.cpp</a></h3> <pre> MyWidget::MyWidget( <a href="qwidget.html">QWidget</a> *parent, const char *name ) : <a href="qwidget.html">QWidget</a>( parent, name ) {</pre><p>The constructor is mostly the same, but some new bits have been added. <pre> LCDRange *force = new LCDRange( this, "force" ); force->setRange( 10, 50 );</pre><p>We add a second LCDRange which will be used to set the force. <pre> <a href="qobject.html#fbde73">connect</a>( force, SIGNAL(valueChanged(int)), cannonField, SLOT(setForce(int)) ); <a href="qobject.html#fbde73">connect</a>( cannonField, SIGNAL(forceChanged(int)), force, SLOT(setValue(int)) );</pre><p>We connect the <code>force</code> widget and the <code>cannonField</code> widget just likewe did for the <code>angle</code> widget. <pre> <a href="qvboxlayout.html">QVBoxLayout</a> *leftBox = new <a href="qvboxlayout.html">QVBoxLayout</a>; grid-><a href="qgridlayout.html#a409bc">addLayout</a>( leftBox, 1, 0 ); leftBox-><a href="qboxlayout.html#ebba99">addWidget</a>( angle ); leftBox-><a href="qboxlayout.html#ebba99">addWidget</a>( force );</pre><p>In chapter 9, we put <code>angle</code> in the lower-left cell of the layout.Now, we want to have two widgets in that cell, so we make a verticalbox, put the vertical box in the grid cell, and put each of <code>angle</code>and <code>range</code> in the vertical box. <pre> force->setValue( 25 );</pre><p>We initialize the force value to 25.<p><h2>Behavior</h2><p>The flicker has gone and we have a force control.<p><h2>Exercises</h2><p>Make the size of the cannon barrel be dependent on the force.<p>Put the cannon in the bottom right corner.<p>Try adding a better keyboard interface. For example, make + and -increase and decrease the force and enter shoot. Hint: <a href="qaccel.html">QAccel</a> andnew addStep() and subtractStep() slots in LCDRange, like <a href="qslider.html#f8da10">QSlider::addStep()</a>. If you're bothered by the way the left and rightkeys work (I am!), change that too.<p>You may now go on to <a href="t11.html">chapter eleven.</a><p>[<a href="t9.html">Previous tutorial</a>][<a href="t11.html">Next tutorial</a>][<a href="tutorial.html">Main tutorial page</a>]<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 + -