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