You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
329 lines
15 KiB
329 lines
15 KiB
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
<!-- /home/espenr/tmp/qt-3.3.8-espenr-2499/qt-x11-free-3.3.8/doc/tutorial.doc:1711 -->
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<title>Qt Tutorial - Chapter 12: Hanging in the Air the Way Bricks Don't</title>
|
|
<style type="text/css"><!--
|
|
fn { margin-left: 1cm; text-indent: -1cm; }
|
|
a:link { color: #004faf; text-decoration: none }
|
|
a:visited { color: #672967; text-decoration: none }
|
|
body { background: #ffffff; color: black; }
|
|
--></style>
|
|
</head>
|
|
<body>
|
|
|
|
<table border="0" cellpadding="0" cellspacing="0" width="100%">
|
|
<tr bgcolor="#E5E5E5">
|
|
<td valign=center>
|
|
<a href="index.html">
|
|
<font color="#004faf">Home</font></a>
|
|
| <a href="classes.html">
|
|
<font color="#004faf">All Classes</font></a>
|
|
| <a href="mainclasses.html">
|
|
<font color="#004faf">Main Classes</font></a>
|
|
| <a href="annotated.html">
|
|
<font color="#004faf">Annotated</font></a>
|
|
| <a href="groups.html">
|
|
<font color="#004faf">Grouped Classes</font></a>
|
|
| <a href="functions.html">
|
|
<font color="#004faf">Functions</font></a>
|
|
</td>
|
|
<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>
|
|
|
|
|
|
<p> <center><img src="t12.png" alt="Screenshot of tutorial twelve"></center>
|
|
<p> In this example, we extend our LCDRange class to include a text label.
|
|
We also provide something to shoot at.
|
|
<p> <ul>
|
|
<li> <a href="t12-lcdrange-h.html">t12/lcdrange.h</a> contains the LCDRange
|
|
class definition.
|
|
<li> <a href="t12-lcdrange-cpp.html">t12/lcdrange.cpp</a> contains the LCDRange
|
|
implementation.
|
|
<li> <a href="t12-cannon-h.html">t12/cannon.h</a> contains the CannonField class
|
|
definition.
|
|
<li> <a href="t12-cannon-cpp.html">t12/cannon.cpp</a> contains the CannonField
|
|
implementation.
|
|
<li> <a href="t12-main-cpp.html">t12/main.cpp</a> contains MyWidget and main.
|
|
</ul>
|
|
<p> <h2> Line-by-line Walkthrough
|
|
</h2>
|
|
<a name="1"></a><p> <h3> <a href="t12-lcdrange-h.html">t12/lcdrange.h</a>
|
|
</h3>
|
|
<a name="1-1"></a><p> The LCDRange now has a text label.
|
|
<p>
|
|
|
|
<p> <pre> class QLabel;
|
|
</pre>
|
|
<p> We name declare <a href="qlabel.html">QLabel</a> because we want to use a pointer to it in the class
|
|
definition.
|
|
<p> <pre> class LCDRange : public <a href="qvbox.html">QVBox</a>
|
|
{
|
|
<a href="metaobjects.html#Q_OBJECT">Q_OBJECT</a>
|
|
public:
|
|
LCDRange( <a href="qwidget.html">QWidget</a> *parent=0, const char *name=0 );
|
|
LCDRange( const char *s, QWidget *parent=0,
|
|
const char *name=0 );
|
|
</pre>
|
|
<p> We have added a new constructor that sets the label text in addition to
|
|
the parent and name.
|
|
<p> <pre> const char *text() const;
|
|
</pre>
|
|
<p> This function returns the label text.
|
|
<p> <pre> void setText( const char * );
|
|
</pre>
|
|
<p> This slot sets the label text.
|
|
<p> <pre> private:
|
|
void init();
|
|
</pre>
|
|
<p> Because we now have two constructors, we have chosen to put the common
|
|
initialization in the private init() function.
|
|
<p> <pre> <a href="qlabel.html">QLabel</a> *label;
|
|
</pre>
|
|
<p> We also have a new private variable: a QLabel. QLabel is one of Qt's
|
|
standard widgets and can show a text or a pixmap with or without a
|
|
frame.
|
|
<p> <h3> <a href="t12-lcdrange-cpp.html">t12/lcdrange.cpp</a>
|
|
</h3>
|
|
<a name="1-2"></a><p>
|
|
|
|
<p> <pre> #include <<a href="qlabel-h.html">qlabel.h</a>>
|
|
</pre>
|
|
<p> Here we include the <a href="qlabel.html">QLabel</a> class definition.
|
|
<p> <pre> LCDRange::LCDRange( <a href="qwidget.html">QWidget</a> *parent, const char *name )
|
|
: <a href="qvbox.html">QVBox</a>( parent, name )
|
|
{
|
|
init();
|
|
}
|
|
</pre>
|
|
<p> This constructor calls the init() function, which contains the common
|
|
initialization code.
|
|
<p> <pre> LCDRange::LCDRange( const char *s, QWidget *parent,
|
|
const char *name )
|
|
: <a href="qvbox.html">QVBox</a>( parent, name )
|
|
{
|
|
init();
|
|
setText( s );
|
|
}
|
|
</pre>
|
|
<p> This constructor first calls init() and then sets the label text.
|
|
<p> <pre> void LCDRange::init()
|
|
{
|
|
<a href="qlcdnumber.html">QLCDNumber</a> *lcd = new <a href="qlcdnumber.html">QLCDNumber</a>( 2, this, "lcd" );
|
|
slider = new <a href="qslider.html">QSlider</a>( Horizontal, this, "slider" );
|
|
<a name="x2387"></a> slider-><a href="qrangecontrol.html#setRange">setRange</a>( 0, 99 );
|
|
<a name="x2388"></a> slider-><a href="qslider.html#setValue">setValue</a>( 0 );
|
|
|
|
label = new <a href="qlabel.html">QLabel</a>( " ", this, "label" );
|
|
<a name="x2383"></a> label-><a href="qlabel.html#setAlignment">setAlignment</a>( AlignCenter );
|
|
|
|
<a name="x2389"></a> <a href="qobject.html#connect">connect</a>( slider, SIGNAL(<a href="qslider.html#valueChanged">valueChanged</a>(int)),
|
|
<a name="x2386"></a> lcd, SLOT(<a href="qlcdnumber.html#display">display</a>(int)) );
|
|
<a href="qobject.html#connect">connect</a>( slider, SIGNAL(<a href="qslider.html#valueChanged">valueChanged</a>(int)),
|
|
SIGNAL(valueChanged(int)) );
|
|
|
|
<a href="qwidget.html#setFocusProxy">setFocusProxy</a>( slider );
|
|
}
|
|
</pre>
|
|
<p> The setup of <tt>lcd</tt> and <tt>slider</tt> is the same as in the previous
|
|
chapter. Next we create a <a href="qlabel.html">QLabel</a> and tell it to align the contents
|
|
centered (both vertically and horizontally). The connect() statements
|
|
have also been taken from the previous chapter.
|
|
<p> <pre> const char *LCDRange::text() const
|
|
{
|
|
<a name="x2385"></a> return label-><a href="qlabel.html#text">text</a>();
|
|
}
|
|
</pre>
|
|
<p> This function returns the label text.
|
|
<p> <pre> void LCDRange::setText( const char *s )
|
|
{
|
|
<a name="x2384"></a> label-><a href="qlabel.html#setText">setText</a>( s );
|
|
}
|
|
</pre>
|
|
<p> This function sets the label text.
|
|
<p> <h3> <a href="t12-cannon-h.html">t12/cannon.h</a>
|
|
</h3>
|
|
<a name="1-3"></a><p> The CannonField now has two new signals: hit() and missed(). In addition
|
|
it contains a target.
|
|
<p>
|
|
|
|
<p> <pre> void newTarget();
|
|
</pre>
|
|
<p> This slot creates a target at a new position.
|
|
<p> <pre> signals:
|
|
void hit();
|
|
void missed();
|
|
</pre>
|
|
<p> The hit() signal is emitted when a shot hits the target. The missed()
|
|
signal is emitted when the shot moves beyond the right or bottom edge
|
|
of the widget (i.e., it is certain that it has not and will not
|
|
hit the target).
|
|
<p> <pre> void paintTarget( <a href="qpainter.html">QPainter</a> * );
|
|
</pre>
|
|
<p> This private function paints the target.
|
|
<p> <pre> <a href="qrect.html">QRect</a> targetRect() const;
|
|
</pre>
|
|
<p> This private function returns the enclosing rectangle of the target.
|
|
<p> <pre> <a href="qpoint.html">QPoint</a> target;
|
|
</pre>
|
|
<p> This private variable contains the center point of the target.
|
|
<p> <h3> <a href="t12-cannon-cpp.html">t12/cannon.cpp</a>
|
|
</h3>
|
|
<a name="1-4"></a><p>
|
|
|
|
<p> <pre> #include <<a href="qdatetime-h.html">qdatetime.h</a>>
|
|
</pre>
|
|
<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.
|
|
<p> <pre> #include <stdlib.h>
|
|
</pre>
|
|
<p> We include the stdlib library because we need the rand() function.
|
|
<p> <pre> newTarget();
|
|
</pre>
|
|
<p> This line has been added to the constructor. It creates a "random"
|
|
position for the target. In fact, the newTarget() function will try
|
|
to paint the target. Because we are in a constructor, the CannonField
|
|
widget is invisible. Qt guarantees that no harm is done when calling
|
|
repaint() on a hidden widget.
|
|
<p> <pre> void CannonField::newTarget()
|
|
{
|
|
static bool first_time = TRUE;
|
|
if ( first_time ) {
|
|
first_time = FALSE;
|
|
<a href="qtime.html">QTime</a> midnight( 0, 0, 0 );
|
|
<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>()) );
|
|
}
|
|
<a href="qregion.html">QRegion</a> r( targetRect() );
|
|
target = QPoint( 200 + rand() % 190,
|
|
10 + rand() % 255 );
|
|
<a name="x2395"></a> <a href="qwidget.html#repaint">repaint</a>( r.<a href="qrect.html#unite">unite</a>( targetRect() ) );
|
|
}
|
|
</pre>
|
|
<p> This private function creates a target center point at a new "random"
|
|
position.
|
|
<p> We use the rand() function to fetch random integers. The rand() function
|
|
normally returns the same series of numbers each time you run a program.
|
|
This would make the target appear at the same position every time. To
|
|
avoid this, we must set a random seed the first time this function is
|
|
called. The random seed must also be random in order to avoid equal random
|
|
number series. The solution is to use the number of seconds that have
|
|
passed since midnight as a pseudo-random value.
|
|
<p> First we create a static bool local variable. A static variable like
|
|
this one is guaranteed to keep its value between calls to the function.
|
|
<p> The <tt>if</tt> test will succeed only the first time this function is called
|
|
because we set <tt>first_time</tt> to FALSE inside the <tt>if</tt> block.
|
|
<p> Then we create the <a href="qtime.html">QTime</a> object <tt>midnight</tt>, which represents the time
|
|
00:00:00. Next we fetch the number of seconds from midnight until
|
|
now and use it as a random seed. See the documentation for <a href="qdate.html">QDate</a>,
|
|
<a href="qtime.html">QTime</a>, and <a href="qdatetime.html">QDateTime</a> for more information.
|
|
<p> Finally we calculate the target's center point. We keep it within
|
|
the rectangle (x=200, y=35, width=190, height=255), (i.e., the
|
|
possible x and y values are x = 200..389 and y = 35..289) in a
|
|
coordinate system where we put y position 0 at the bottom edge of the
|
|
widget and let y values increase upwards X is as normal, with 0 at
|
|
the left edge and with x values increasing to the right.
|
|
<p> By experimentation we have found this to always be in reach of the shot.
|
|
<p> Note that rand() returns a random integer >= 0.
|
|
<p> <pre> void CannonField::moveShot()
|
|
{
|
|
<a href="qregion.html">QRegion</a> r( shotRect() );
|
|
timerCount++;
|
|
|
|
<a href="qrect.html">QRect</a> shotR = shotRect();
|
|
</pre>
|
|
<p> This part of the timer event has not changed from the previous chapter.
|
|
<p> <pre> if ( shotR.<a href="qrect.html#intersects">intersects</a>( targetRect() ) ) {
|
|
<a name="x2400"></a> autoShootTimer-><a href="qtimer.html#stop">stop</a>();
|
|
emit hit();
|
|
</pre>
|
|
<p> This <tt>if</tt> statement checks whether the shot rectangle intersects the
|
|
target rectangle. If it does, the shot has hit the target (ouch!).
|
|
We stop the shoot timer and emit the hit() signal to tell the outside
|
|
world that a target was destroyed, and return.
|
|
<p> Note that we could have created a new target on the spot, but because the
|
|
CannonField is a component we leave such decisions to the user of the
|
|
component.
|
|
<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() ) {
|
|
autoShootTimer-><a href="qtimer.html#stop">stop</a>();
|
|
emit missed();
|
|
</pre>
|
|
<p> This <tt>if</tt> statement is the same as in the previous chapter, except that
|
|
it now emits the missed() signal to tell the outside world about the
|
|
failure.
|
|
<p> <pre> } else {
|
|
</pre>
|
|
<p> And the rest of the function is as before.
|
|
<p> CannonField::paintEvent() is as before, except that this has been
|
|
added:
|
|
<p> <pre> <a name="x2393"></a> if ( updateR.<a href="qrect.html#intersects">intersects</a>( targetRect() ) )
|
|
paintTarget( &p );
|
|
</pre>
|
|
<p> These two lines make sure that the target is also painted when necessary.
|
|
<p> <pre> void CannonField::paintTarget( <a href="qpainter.html">QPainter</a> *p )
|
|
{
|
|
p-><a href="qpainter.html#setBrush">setBrush</a>( red );
|
|
p-><a href="qpainter.html#setPen">setPen</a>( black );
|
|
p-><a href="qpainter.html#drawRect">drawRect</a>( targetRect() );
|
|
}
|
|
</pre>
|
|
<p> This private function paints the target; a rectangle filled with red and
|
|
with a black outline.
|
|
<p> <pre> QRect CannonField::targetRect() const
|
|
{
|
|
<a href="qrect.html">QRect</a> r( 0, 0, 20, 10 );
|
|
<a name="x2394"></a> r.<a href="qrect.html#moveCenter">moveCenter</a>( QPoint(target.x(),height() - 1 - target.y()) );
|
|
return r;
|
|
}
|
|
</pre>
|
|
<p> This private function returns the enclosing rectangle of the target.
|
|
Remember from newTarget() that the <tt>target</tt> point uses y coordinate 0 at
|
|
the bottom of the widget. We calculate the point in widget coordinates
|
|
before we call <a href="qrect.html#moveCenter">QRect::moveCenter</a>().
|
|
<p> The reason we have chosen this coordinate mapping is to fix the distance
|
|
between the target and the bottom of the widget. Remember that the widget
|
|
can be resized by the user or the program at any time.
|
|
<p> <h3> <a href="t12-main-cpp.html">t12/main.cpp</a>
|
|
</h3>
|
|
<a name="1-5"></a><p>
|
|
|
|
<p> There are no new members in the MyWidget class, but we have slightly
|
|
changed the constructor to set the new LCDRange text labels.
|
|
<p> <pre> LCDRange *angle = new LCDRange( "ANGLE", this, "angle" );
|
|
</pre>
|
|
<p> We set the angle text label to "ANGLE".
|
|
<p> <pre> LCDRange *force = new LCDRange( "FORCE", this, "force" );
|
|
</pre>
|
|
<p> We set the force text label to "FORCE".
|
|
<p> <h2> Behavior
|
|
</h2>
|
|
<a name="2"></a><p> The LCDRange widgets look a bit strange - the built-in layout
|
|
management in <a href="qvbox.html">QVBox</a> gives the labels too much space and the rest not
|
|
enough. We'll fix that in the next chapter.
|
|
<p> (See <a href="tutorial1-07.html#compiling">Compiling</a> for how to create a
|
|
makefile and build the application.)
|
|
<p> <h2> Exercises
|
|
</h2>
|
|
<a name="3"></a><p> Make a cheat button that, when pressed, makes the CannonField display
|
|
the shot trajectory for five seconds.
|
|
<p> If you did the "round shot" exercise from the previous chapter, try
|
|
changing the shotRect() to a shotRegion() that returns a <a href="qregion.html">QRegion</a> so
|
|
you can have really accurate collision detection.
|
|
<p> Make a moving target.
|
|
<p> Make sure that the target is always created entirely on-screen.
|
|
<p> Make sure that the widget cannot be resized so that the target isn't
|
|
visible. Hint: <a href="qwidget.html#setMinimumSize">QWidget::setMinimumSize</a>() is your friend.
|
|
<p> Not easy; make it possible to have several shots in the air at the
|
|
same time. Hint: make a Shot object.
|
|
<p> You're now ready for <a href="tutorial1-13.html">Chapter 13.</a>
|
|
<p> [<a href="tutorial1-11.html">Previous tutorial</a>]
|
|
[<a href="tutorial1-13.html">Next tutorial</a>]
|
|
[<a href="tutorial.html">Main tutorial page</a>]
|
|
<p>
|
|
<!-- eof -->
|
|
<p><address><hr><div align=center>
|
|
<table width=100% cellspacing=0 border=0><tr>
|
|
<td>Copyright © 2007
|
|
<a href="troll.html">Trolltech</a><td align=center><a href="trademarks.html">Trademarks</a>
|
|
<td align=right><div align=right>Qt 3.3.8</div>
|
|
</table></div></address></body>
|
|
</html>
|