[190] | 1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
---|
| 2 | <!-- /home/espenr/tmp/qt-3.3.8-espenr-2499/qt-x11-free-3.3.8/doc/tutorial.doc:1711 -->
|
---|
| 3 | <html>
|
---|
| 4 | <head>
|
---|
| 5 | <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
---|
| 6 | <title>Qt Tutorial - Chapter 12: Hanging in the Air the Way Bricks Don't</title>
|
---|
| 7 | <style type="text/css"><!--
|
---|
| 8 | fn { margin-left: 1cm; text-indent: -1cm; }
|
---|
| 9 | a:link { color: #004faf; text-decoration: none }
|
---|
| 10 | a:visited { color: #672967; text-decoration: none }
|
---|
| 11 | body { background: #ffffff; color: black; }
|
---|
| 12 | --></style>
|
---|
| 13 | </head>
|
---|
| 14 | <body>
|
---|
| 15 |
|
---|
| 16 | <table border="0" cellpadding="0" cellspacing="0" width="100%">
|
---|
| 17 | <tr bgcolor="#E5E5E5">
|
---|
| 18 | <td valign=center>
|
---|
| 19 | <a href="index.html">
|
---|
| 20 | <font color="#004faf">Home</font></a>
|
---|
| 21 | | <a href="classes.html">
|
---|
| 22 | <font color="#004faf">All Classes</font></a>
|
---|
| 23 | | <a href="mainclasses.html">
|
---|
| 24 | <font color="#004faf">Main Classes</font></a>
|
---|
| 25 | | <a href="annotated.html">
|
---|
| 26 | <font color="#004faf">Annotated</font></a>
|
---|
| 27 | | <a href="groups.html">
|
---|
| 28 | <font color="#004faf">Grouped Classes</font></a>
|
---|
| 29 | | <a href="functions.html">
|
---|
| 30 | <font color="#004faf">Functions</font></a>
|
---|
| 31 | </td>
|
---|
| 32 | <td align="right" valign="center"><img src="logo32.png" align="right" width="64" height="32" border="0"></td></tr></table><h1 align=center>Qt Tutorial - Chapter 12: Hanging in the Air the Way Bricks Don't</h1>
|
---|
| 33 |
|
---|
| 34 |
|
---|
| 35 | <p> <center><img src="t12.png" alt="Screenshot of tutorial twelve"></center>
|
---|
| 36 | <p> In this example, we extend our LCDRange class to include a text label.
|
---|
| 37 | We also provide something to shoot at.
|
---|
| 38 | <p> <ul>
|
---|
| 39 | <li> <a href="t12-lcdrange-h.html">t12/lcdrange.h</a> contains the LCDRange
|
---|
| 40 | class definition.
|
---|
| 41 | <li> <a href="t12-lcdrange-cpp.html">t12/lcdrange.cpp</a> contains the LCDRange
|
---|
| 42 | implementation.
|
---|
| 43 | <li> <a href="t12-cannon-h.html">t12/cannon.h</a> contains the CannonField class
|
---|
| 44 | definition.
|
---|
| 45 | <li> <a href="t12-cannon-cpp.html">t12/cannon.cpp</a> contains the CannonField
|
---|
| 46 | implementation.
|
---|
| 47 | <li> <a href="t12-main-cpp.html">t12/main.cpp</a> contains MyWidget and main.
|
---|
| 48 | </ul>
|
---|
| 49 | <p> <h2> Line-by-line Walkthrough
|
---|
| 50 | </h2>
|
---|
| 51 | <a name="1"></a><p> <h3> <a href="t12-lcdrange-h.html">t12/lcdrange.h</a>
|
---|
| 52 | </h3>
|
---|
| 53 | <a name="1-1"></a><p> The LCDRange now has a text label.
|
---|
| 54 | <p>
|
---|
| 55 |
|
---|
| 56 | <p> <pre> class QLabel;
|
---|
| 57 | </pre>
|
---|
| 58 | <p> We name declare <a href="qlabel.html">QLabel</a> because we want to use a pointer to it in the class
|
---|
| 59 | definition.
|
---|
| 60 | <p> <pre> class LCDRange : public <a href="qvbox.html">QVBox</a>
|
---|
| 61 | {
|
---|
| 62 | <a href="metaobjects.html#Q_OBJECT">Q_OBJECT</a>
|
---|
| 63 | public:
|
---|
| 64 | LCDRange( <a href="qwidget.html">QWidget</a> *parent=0, const char *name=0 );
|
---|
| 65 | LCDRange( const char *s, QWidget *parent=0,
|
---|
| 66 | const char *name=0 );
|
---|
| 67 | </pre>
|
---|
| 68 | <p> We have added a new constructor that sets the label text in addition to
|
---|
| 69 | the parent and name.
|
---|
| 70 | <p> <pre> const char *text() const;
|
---|
| 71 | </pre>
|
---|
| 72 | <p> This function returns the label text.
|
---|
| 73 | <p> <pre> void setText( const char * );
|
---|
| 74 | </pre>
|
---|
| 75 | <p> This slot sets the label text.
|
---|
| 76 | <p> <pre> private:
|
---|
| 77 | void init();
|
---|
| 78 | </pre>
|
---|
| 79 | <p> Because we now have two constructors, we have chosen to put the common
|
---|
| 80 | initialization in the private init() function.
|
---|
| 81 | <p> <pre> <a href="qlabel.html">QLabel</a> *label;
|
---|
| 82 | </pre>
|
---|
| 83 | <p> We also have a new private variable: a QLabel. QLabel is one of Qt's
|
---|
| 84 | standard widgets and can show a text or a pixmap with or without a
|
---|
| 85 | frame.
|
---|
| 86 | <p> <h3> <a href="t12-lcdrange-cpp.html">t12/lcdrange.cpp</a>
|
---|
| 87 | </h3>
|
---|
| 88 | <a name="1-2"></a><p>
|
---|
| 89 |
|
---|
| 90 | <p> <pre> #include <<a href="qlabel-h.html">qlabel.h</a>>
|
---|
| 91 | </pre>
|
---|
| 92 | <p> Here we include the <a href="qlabel.html">QLabel</a> class definition.
|
---|
| 93 | <p> <pre> LCDRange::LCDRange( <a href="qwidget.html">QWidget</a> *parent, const char *name )
|
---|
| 94 | : <a href="qvbox.html">QVBox</a>( parent, name )
|
---|
| 95 | {
|
---|
| 96 | init();
|
---|
| 97 | }
|
---|
| 98 | </pre>
|
---|
| 99 | <p> This constructor calls the init() function, which contains the common
|
---|
| 100 | initialization code.
|
---|
| 101 | <p> <pre> LCDRange::LCDRange( const char *s, QWidget *parent,
|
---|
| 102 | const char *name )
|
---|
| 103 | : <a href="qvbox.html">QVBox</a>( parent, name )
|
---|
| 104 | {
|
---|
| 105 | init();
|
---|
| 106 | setText( s );
|
---|
| 107 | }
|
---|
| 108 | </pre>
|
---|
| 109 | <p> This constructor first calls init() and then sets the label text.
|
---|
| 110 | <p> <pre> void LCDRange::init()
|
---|
| 111 | {
|
---|
| 112 | <a href="qlcdnumber.html">QLCDNumber</a> *lcd = new <a href="qlcdnumber.html">QLCDNumber</a>( 2, this, "lcd" );
|
---|
| 113 | slider = new <a href="qslider.html">QSlider</a>( Horizontal, this, "slider" );
|
---|
| 114 | <a name="x2387"></a> slider-><a href="qrangecontrol.html#setRange">setRange</a>( 0, 99 );
|
---|
| 115 | <a name="x2388"></a> slider-><a href="qslider.html#setValue">setValue</a>( 0 );
|
---|
| 116 |
|
---|
| 117 | label = new <a href="qlabel.html">QLabel</a>( " ", this, "label" );
|
---|
| 118 | <a name="x2383"></a> label-><a href="qlabel.html#setAlignment">setAlignment</a>( AlignCenter );
|
---|
| 119 |
|
---|
| 120 | <a name="x2389"></a> <a href="qobject.html#connect">connect</a>( slider, SIGNAL(<a href="qslider.html#valueChanged">valueChanged</a>(int)),
|
---|
| 121 | <a name="x2386"></a> lcd, SLOT(<a href="qlcdnumber.html#display">display</a>(int)) );
|
---|
| 122 | <a href="qobject.html#connect">connect</a>( slider, SIGNAL(<a href="qslider.html#valueChanged">valueChanged</a>(int)),
|
---|
| 123 | SIGNAL(valueChanged(int)) );
|
---|
| 124 |
|
---|
| 125 | <a href="qwidget.html#setFocusProxy">setFocusProxy</a>( slider );
|
---|
| 126 | }
|
---|
| 127 | </pre>
|
---|
| 128 | <p> The setup of <tt>lcd</tt> and <tt>slider</tt> is the same as in the previous
|
---|
| 129 | chapter. Next we create a <a href="qlabel.html">QLabel</a> and tell it to align the contents
|
---|
| 130 | centered (both vertically and horizontally). The connect() statements
|
---|
| 131 | have also been taken from the previous chapter.
|
---|
| 132 | <p> <pre> const char *LCDRange::text() const
|
---|
| 133 | {
|
---|
| 134 | <a name="x2385"></a> return label-><a href="qlabel.html#text">text</a>();
|
---|
| 135 | }
|
---|
| 136 | </pre>
|
---|
| 137 | <p> This function returns the label text.
|
---|
| 138 | <p> <pre> void LCDRange::setText( const char *s )
|
---|
| 139 | {
|
---|
| 140 | <a name="x2384"></a> label-><a href="qlabel.html#setText">setText</a>( s );
|
---|
| 141 | }
|
---|
| 142 | </pre>
|
---|
| 143 | <p> This function sets the label text.
|
---|
| 144 | <p> <h3> <a href="t12-cannon-h.html">t12/cannon.h</a>
|
---|
| 145 | </h3>
|
---|
| 146 | <a name="1-3"></a><p> The CannonField now has two new signals: hit() and missed(). In addition
|
---|
| 147 | it contains a target.
|
---|
| 148 | <p>
|
---|
| 149 |
|
---|
| 150 | <p> <pre> void newTarget();
|
---|
| 151 | </pre>
|
---|
| 152 | <p> This slot creates a target at a new position.
|
---|
| 153 | <p> <pre> signals:
|
---|
| 154 | void hit();
|
---|
| 155 | void missed();
|
---|
| 156 | </pre>
|
---|
| 157 | <p> The hit() signal is emitted when a shot hits the target. The missed()
|
---|
| 158 | signal is emitted when the shot moves beyond the right or bottom edge
|
---|
| 159 | of the widget (i.e., it is certain that it has not and will not
|
---|
| 160 | hit the target).
|
---|
| 161 | <p> <pre> void paintTarget( <a href="qpainter.html">QPainter</a> * );
|
---|
| 162 | </pre>
|
---|
| 163 | <p> This private function paints the target.
|
---|
| 164 | <p> <pre> <a href="qrect.html">QRect</a> targetRect() const;
|
---|
| 165 | </pre>
|
---|
| 166 | <p> This private function returns the enclosing rectangle of the target.
|
---|
| 167 | <p> <pre> <a href="qpoint.html">QPoint</a> target;
|
---|
| 168 | </pre>
|
---|
| 169 | <p> This private variable contains the center point of the target.
|
---|
| 170 | <p> <h3> <a href="t12-cannon-cpp.html">t12/cannon.cpp</a>
|
---|
| 171 | </h3>
|
---|
| 172 | <a name="1-4"></a><p>
|
---|
| 173 |
|
---|
| 174 | <p> <pre> #include <<a href="qdatetime-h.html">qdatetime.h</a>>
|
---|
| 175 | </pre>
|
---|
| 176 | <p> We include the <a href="qdate.html">QDate</a>, <a href="qtime.html">QTime</a>, and <a href="qdatetime.html">QDateTime</a> class definitions.
|
---|
| 177 | <p> <pre> #include <stdlib.h>
|
---|
| 178 | </pre>
|
---|
| 179 | <p> We include the stdlib library because we need the rand() function.
|
---|
| 180 | <p> <pre> newTarget();
|
---|
| 181 | </pre>
|
---|
| 182 | <p> This line has been added to the constructor. It creates a "random"
|
---|
| 183 | position for the target. In fact, the newTarget() function will try
|
---|
| 184 | to paint the target. Because we are in a constructor, the CannonField
|
---|
| 185 | widget is invisible. Qt guarantees that no harm is done when calling
|
---|
| 186 | repaint() on a hidden widget.
|
---|
| 187 | <p> <pre> void CannonField::newTarget()
|
---|
| 188 | {
|
---|
| 189 | static bool first_time = TRUE;
|
---|
| 190 | if ( first_time ) {
|
---|
| 191 | first_time = FALSE;
|
---|
| 192 | <a href="qtime.html">QTime</a> midnight( 0, 0, 0 );
|
---|
| 193 | <a name="x2399"></a><a name="x2398"></a> srand( midnight.<a href="qtime.html#secsTo">secsTo</a>(QTime::<a href="qtime.html#currentTime">currentTime</a>()) );
|
---|
| 194 | }
|
---|
| 195 | <a href="qregion.html">QRegion</a> r( targetRect() );
|
---|
| 196 | target = QPoint( 200 + rand() % 190,
|
---|
| 197 | 10 + rand() % 255 );
|
---|
| 198 | <a name="x2395"></a> <a href="qwidget.html#repaint">repaint</a>( r.<a href="qrect.html#unite">unite</a>( targetRect() ) );
|
---|
| 199 | }
|
---|
| 200 | </pre>
|
---|
| 201 | <p> This private function creates a target center point at a new "random"
|
---|
| 202 | position.
|
---|
| 203 | <p> We use the rand() function to fetch random integers. The rand() function
|
---|
| 204 | normally returns the same series of numbers each time you run a program.
|
---|
| 205 | This would make the target appear at the same position every time. To
|
---|
| 206 | avoid this, we must set a random seed the first time this function is
|
---|
| 207 | called. The random seed must also be random in order to avoid equal random
|
---|
| 208 | number series. The solution is to use the number of seconds that have
|
---|
| 209 | passed since midnight as a pseudo-random value.
|
---|
| 210 | <p> First we create a static bool local variable. A static variable like
|
---|
| 211 | this one is guaranteed to keep its value between calls to the function.
|
---|
| 212 | <p> The <tt>if</tt> test will succeed only the first time this function is called
|
---|
| 213 | because we set <tt>first_time</tt> to FALSE inside the <tt>if</tt> block.
|
---|
| 214 | <p> Then we create the <a href="qtime.html">QTime</a> object <tt>midnight</tt>, which represents the time
|
---|
| 215 | 00:00:00. Next we fetch the number of seconds from midnight until
|
---|
| 216 | now and use it as a random seed. See the documentation for <a href="qdate.html">QDate</a>,
|
---|
| 217 | <a href="qtime.html">QTime</a>, and <a href="qdatetime.html">QDateTime</a> for more information.
|
---|
| 218 | <p> Finally we calculate the target's center point. We keep it within
|
---|
| 219 | the rectangle (x=200, y=35, width=190, height=255), (i.e., the
|
---|
| 220 | possible x and y values are x = 200..389 and y = 35..289) in a
|
---|
| 221 | coordinate system where we put y position 0 at the bottom edge of the
|
---|
| 222 | widget and let y values increase upwards X is as normal, with 0 at
|
---|
| 223 | the left edge and with x values increasing to the right.
|
---|
| 224 | <p> By experimentation we have found this to always be in reach of the shot.
|
---|
| 225 | <p> Note that rand() returns a random integer >= 0.
|
---|
| 226 | <p> <pre> void CannonField::moveShot()
|
---|
| 227 | {
|
---|
| 228 | <a href="qregion.html">QRegion</a> r( shotRect() );
|
---|
| 229 | timerCount++;
|
---|
| 230 |
|
---|
| 231 | <a href="qrect.html">QRect</a> shotR = shotRect();
|
---|
| 232 | </pre>
|
---|
| 233 | <p> This part of the timer event has not changed from the previous chapter.
|
---|
| 234 | <p> <pre> if ( shotR.<a href="qrect.html#intersects">intersects</a>( targetRect() ) ) {
|
---|
| 235 | <a name="x2400"></a> autoShootTimer-><a href="qtimer.html#stop">stop</a>();
|
---|
| 236 | emit hit();
|
---|
| 237 | </pre>
|
---|
| 238 | <p> This <tt>if</tt> statement checks whether the shot rectangle intersects the
|
---|
| 239 | target rectangle. If it does, the shot has hit the target (ouch!).
|
---|
| 240 | We stop the shoot timer and emit the hit() signal to tell the outside
|
---|
| 241 | world that a target was destroyed, and return.
|
---|
| 242 | <p> Note that we could have created a new target on the spot, but because the
|
---|
| 243 | CannonField is a component we leave such decisions to the user of the
|
---|
| 244 | component.
|
---|
| 245 | <p> <pre> <a name="x2397"></a><a name="x2396"></a> } else if ( shotR.<a href="qrect.html#x">x</a>() > width() || shotR.<a href="qrect.html#y">y</a>() > height() ) {
|
---|
| 246 | autoShootTimer-><a href="qtimer.html#stop">stop</a>();
|
---|
| 247 | emit missed();
|
---|
| 248 | </pre>
|
---|
| 249 | <p> This <tt>if</tt> statement is the same as in the previous chapter, except that
|
---|
| 250 | it now emits the missed() signal to tell the outside world about the
|
---|
| 251 | failure.
|
---|
| 252 | <p> <pre> } else {
|
---|
| 253 | </pre>
|
---|
| 254 | <p> And the rest of the function is as before.
|
---|
| 255 | <p> CannonField::paintEvent() is as before, except that this has been
|
---|
| 256 | added:
|
---|
| 257 | <p> <pre> <a name="x2393"></a> if ( updateR.<a href="qrect.html#intersects">intersects</a>( targetRect() ) )
|
---|
| 258 | paintTarget( &p );
|
---|
| 259 | </pre>
|
---|
| 260 | <p> These two lines make sure that the target is also painted when necessary.
|
---|
| 261 | <p> <pre> void CannonField::paintTarget( <a href="qpainter.html">QPainter</a> *p )
|
---|
| 262 | {
|
---|
| 263 | p-><a href="qpainter.html#setBrush">setBrush</a>( red );
|
---|
| 264 | p-><a href="qpainter.html#setPen">setPen</a>( black );
|
---|
| 265 | p-><a href="qpainter.html#drawRect">drawRect</a>( targetRect() );
|
---|
| 266 | }
|
---|
| 267 | </pre>
|
---|
| 268 | <p> This private function paints the target; a rectangle filled with red and
|
---|
| 269 | with a black outline.
|
---|
| 270 | <p> <pre> QRect CannonField::targetRect() const
|
---|
| 271 | {
|
---|
| 272 | <a href="qrect.html">QRect</a> r( 0, 0, 20, 10 );
|
---|
| 273 | <a name="x2394"></a> r.<a href="qrect.html#moveCenter">moveCenter</a>( QPoint(target.x(),height() - 1 - target.y()) );
|
---|
| 274 | return r;
|
---|
| 275 | }
|
---|
| 276 | </pre>
|
---|
| 277 | <p> This private function returns the enclosing rectangle of the target.
|
---|
| 278 | Remember from newTarget() that the <tt>target</tt> point uses y coordinate 0 at
|
---|
| 279 | the bottom of the widget. We calculate the point in widget coordinates
|
---|
| 280 | before we call <a href="qrect.html#moveCenter">QRect::moveCenter</a>().
|
---|
| 281 | <p> The reason we have chosen this coordinate mapping is to fix the distance
|
---|
| 282 | between the target and the bottom of the widget. Remember that the widget
|
---|
| 283 | can be resized by the user or the program at any time.
|
---|
| 284 | <p> <h3> <a href="t12-main-cpp.html">t12/main.cpp</a>
|
---|
| 285 | </h3>
|
---|
| 286 | <a name="1-5"></a><p>
|
---|
| 287 |
|
---|
| 288 | <p> There are no new members in the MyWidget class, but we have slightly
|
---|
| 289 | changed the constructor to set the new LCDRange text labels.
|
---|
| 290 | <p> <pre> LCDRange *angle = new LCDRange( "ANGLE", this, "angle" );
|
---|
| 291 | </pre>
|
---|
| 292 | <p> We set the angle text label to "ANGLE".
|
---|
| 293 | <p> <pre> LCDRange *force = new LCDRange( "FORCE", this, "force" );
|
---|
| 294 | </pre>
|
---|
| 295 | <p> We set the force text label to "FORCE".
|
---|
| 296 | <p> <h2> Behavior
|
---|
| 297 | </h2>
|
---|
| 298 | <a name="2"></a><p> The LCDRange widgets look a bit strange - the built-in layout
|
---|
| 299 | management in <a href="qvbox.html">QVBox</a> gives the labels too much space and the rest not
|
---|
| 300 | enough. We'll fix that in the next chapter.
|
---|
| 301 | <p> (See <a href="tutorial1-07.html#compiling">Compiling</a> for how to create a
|
---|
| 302 | makefile and build the application.)
|
---|
| 303 | <p> <h2> Exercises
|
---|
| 304 | </h2>
|
---|
| 305 | <a name="3"></a><p> Make a cheat button that, when pressed, makes the CannonField display
|
---|
| 306 | the shot trajectory for five seconds.
|
---|
| 307 | <p> If you did the "round shot" exercise from the previous chapter, try
|
---|
| 308 | changing the shotRect() to a shotRegion() that returns a <a href="qregion.html">QRegion</a> so
|
---|
| 309 | you can have really accurate collision detection.
|
---|
| 310 | <p> Make a moving target.
|
---|
| 311 | <p> Make sure that the target is always created entirely on-screen.
|
---|
| 312 | <p> Make sure that the widget cannot be resized so that the target isn't
|
---|
| 313 | visible. Hint: <a href="qwidget.html#setMinimumSize">QWidget::setMinimumSize</a>() is your friend.
|
---|
| 314 | <p> Not easy; make it possible to have several shots in the air at the
|
---|
| 315 | same time. Hint: make a Shot object.
|
---|
| 316 | <p> You're now ready for <a href="tutorial1-13.html">Chapter 13.</a>
|
---|
| 317 | <p> [<a href="tutorial1-11.html">Previous tutorial</a>]
|
---|
| 318 | [<a href="tutorial1-13.html">Next tutorial</a>]
|
---|
| 319 | [<a href="tutorial.html">Main tutorial page</a>]
|
---|
| 320 | <p>
|
---|
| 321 | <!-- eof -->
|
---|
| 322 | <p><address><hr><div align=center>
|
---|
| 323 | <table width=100% cellspacing=0 border=0><tr>
|
---|
| 324 | <td>Copyright © 2007
|
---|
| 325 | <a href="troll.html">Trolltech</a><td align=center><a href="trademarks.html">Trademarks</a>
|
---|
| 326 | <td align=right><div align=right>Qt 3.3.8</div>
|
---|
| 327 | </table></div></address></body>
|
---|
| 328 | </html>
|
---|