?? tutorial1-14.html
字號(hào):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- /home/reggie/tmp/qt-3.0-reggie-5401/qt-win-commercial-3.0.5/doc/tutorial.doc:2381 -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="Translator" content="Cavendish">
<meta name="Qt zh_CN Documents Website" content="http://www.qiliang.net/qt">
<title>Qt教程一 —— 第十四章:面對(duì)墻壁</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: #ffffff; color: black; font-family: "Times New Roman" }
--></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">主頁(yè)</font></a>
| <a href="classes.html">
<font color="#004faf">所有的類</font></a>
| <a href="mainclasses.html">
<font color="#004faf">主要的類</font></a>
| <a href="annotated.html">
<font color="#004faf">注釋的類</font></a>
| <a href="groups.html">
<font color="#004faf">分組的類</font></a>
| <a href="functions.html">
<font color="#004faf">函數(shù)</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教程一 —— 第十四章:面對(duì)墻壁</h1>
<p> <center><img src="t14.png" alt="Screenshot of tutorial fourteen"></center>
<p> 這是最后的例子:一個(gè)完整的游戲。
<p> 我們添加鍵盤快捷鍵并引入鼠標(biāo)事件到CannonField。我們?cè)贑annonField周圍放一個(gè)框架并添加一個(gè)障礙物(墻)使這個(gè)游戲更富有挑戰(zhàn)性。
<p> <ul>
<li> <a href="t14-lcdrange-h.html">t14/lcdrange.h</a>包含LCDRange類定義。
<li> <a href="t14-lcdrange-cpp.html">t14/lcdrange.cpp</a>包含LCDRange類實(shí)現(xiàn)。
<li> <a href="t14-cannon-h.html">t14/cannon.h</a>包含CannonField類定義。
<li> <a href="t14-cannon-cpp.html">t14/cannon.cpp</a>包含CannonField類實(shí)現(xiàn)。
<li> <a href="t14-gamebrd-h.html">t14/gamebrd.h</a>包含GameBoard類定義。
<li> <a href="t14-gamebrd-cpp.html">t14/gamebrd.cpp</a>包含GameBoard類實(shí)現(xiàn)。
<li> <a href="t14-main-cpp.html">t14/main.cpp</a>包含MyWidget和main。
</ul>
<p> <h2> 一行一行地解說
</h2>
<a name="1"></a><p> <h3> <a href="t14-cannon-h.html">t14/cannon.h</a>
</h3>
<a name="1-1"></a><p> CannonField現(xiàn)在可以接收鼠標(biāo)事件,使得用戶可以通過點(diǎn)擊和拖拽炮筒來瞄準(zhǔn)。CannonField也有一個(gè)障礙物的墻。
<p>
<p> <pre> protected:
void paintEvent( <a href="qpaintevent.html">QPaintEvent</a> * );
void mousePressEvent( <a href="qmouseevent.html">QMouseEvent</a> * );
void mouseMoveEvent( <a href="qmouseevent.html">QMouseEvent</a> * );
void mouseReleaseEvent( <a href="qmouseevent.html">QMouseEvent</a> * );
</pre>
<p> 除了常見的事件處理器,CannonField實(shí)現(xiàn)了三個(gè)鼠標(biāo)事件處理器。名稱說明了一切。
<p> <pre> void paintBarrier( <a href="qpainter.html">QPainter</a> * );
</pre>
<p> 這個(gè)私有函數(shù)繪制了障礙物墻。
<p> <pre> <a href="qrect.html">QRect</a> barrierRect() const;
</pre>
<p> 這個(gè)私有寒暑返回封裝障礙物的矩形。
<p> <pre> bool barrelHit( const <a href="qpoint.html">QPoint</a> & ) const;
</pre>
<p> 這個(gè)私有函數(shù)檢查是否一個(gè)點(diǎn)在加農(nóng)炮炮筒的內(nèi)部。
<p> <pre> bool barrelPressed;
</pre>
<p> 當(dāng)用戶在炮筒上點(diǎn)擊鼠標(biāo)并且沒有放開的話,這個(gè)私有變量為TRUE。
<p> <h3> <a href="t14-cannon-cpp.html">t14/cannon.cpp</a>
</h3>
<a name="1-2"></a><p>
<p> <pre> barrelPressed = FALSE;
</pre>
<p> 這一行被添加到構(gòu)造函數(shù)中。最開始的時(shí)候,鼠標(biāo)沒有在炮筒上點(diǎn)擊。
<p> <pre> <a name="x2361"></a><a name="x2360"></a> } else if ( shotR.<a href="qrect.html#x">x</a>() > width() || shotR.<a href="qrect.html#y">y</a>() > height() ||
shotR.<a href="qrect.html#intersects">intersects</a>(barrierRect()) ) {
</pre>
<p> 現(xiàn)在我們有了一個(gè)障礙物,這樣就有了三種射失的方法。我們來測(cè)試一下第三種。
<p> <pre> void CannonField::<a href="qwidget.html#mousePressEvent">mousePressEvent</a>( <a href="qmouseevent.html">QMouseEvent</a> *e )
{
if ( e-><a href="qmouseevent.html#button">button</a>() != LeftButton )
return;
<a name="x2350"></a> if ( barrelHit( e-><a href="qmouseevent.html#pos">pos</a>() ) )
barrelPressed = TRUE;
}
</pre>
<p> 這是一個(gè)Qt事件處理器。當(dāng)鼠標(biāo)指針在窗口部件上,用戶按下鼠標(biāo)的按鍵時(shí),它被調(diào)用。
<p> 如果事件不是由鼠標(biāo)左鍵產(chǎn)生的,我們立即返回。否則,我們檢查鼠標(biāo)指針是否在加農(nóng)炮的炮筒內(nèi)。如果是的,我們?cè)O(shè)置<tt>barrelPressed</tt>為TRUE。
<p> 注意pos()函數(shù)返回的是窗口部件坐標(biāo)系統(tǒng)中的點(diǎn)。
<p> <pre> void CannonField::<a href="qwidget.html#mouseMoveEvent">mouseMoveEvent</a>( <a href="qmouseevent.html">QMouseEvent</a> *e )
{
if ( !barrelPressed )
return;
<a href="qpoint.html">QPoint</a> pnt = e-><a href="qmouseevent.html#pos">pos</a>();
<a name="x2356"></a> if ( pnt.<a href="qpoint.html#x">x</a>() <= 0 )
<a name="x2354"></a> pnt.<a href="qpoint.html#setX">setX</a>( 1 );
<a name="x2357"></a> if ( pnt.<a href="qpoint.html#y">y</a>() >= <a href="qwidget.html#height">height</a>() )
<a name="x2355"></a> pnt.<a href="qpoint.html#setY">setY</a>( <a href="qwidget.html#height">height</a>() - 1 );
double rad = atan(((double)<a href="qwidget.html#rect">rect</a>().bottom()-pnt.<a href="qpoint.html#y">y</a>())/pnt.<a href="qpoint.html#x">x</a>());
setAngle( qRound ( rad*180/3.14159265 ) );
}
</pre>
<p> 這是另外一個(gè)Qt事件處理器。當(dāng)用戶已經(jīng)在窗口部件中按下了鼠標(biāo)按鍵并且移動(dòng)/拖拽鼠標(biāo)時(shí),它被調(diào)用。(你可以讓Qt在沒有鼠標(biāo)按鍵被按下的時(shí)候發(fā)送鼠標(biāo)移動(dòng)事件。請(qǐng)看<a href="qwidget.html#setMouseTracking">QWidget::setMouseTracking</a>()。)
<p> 這個(gè)處理器根據(jù)鼠標(biāo)指針的位置重新配置加農(nóng)炮的炮筒。
<p> 首先,如果炮筒沒有被按下,我們返回。接下來,我們獲得鼠標(biāo)指針的位置。如果鼠標(biāo)指針到了窗口部件的左面或者下面,我們調(diào)整鼠標(biāo)指針使它返回到窗口部件中。
<p> 然后我們計(jì)算在鼠標(biāo)指針和窗口部件的左下角所構(gòu)成的虛構(gòu)的線和窗口部件下邊界的角度。最后,我們把加農(nóng)炮的角度設(shè)置為我們新算出來的角度。
<p> 記住要用setAngle()來重新繪制加農(nóng)炮。
<p> <pre> <a name="x2364"></a>void CannonField::<a href="qwidget.html#mouseReleaseEvent">mouseReleaseEvent</a>( <a href="qmouseevent.html">QMouseEvent</a> *e )
{
<a name="x2349"></a> if ( e-><a href="qmouseevent.html#button">button</a>() == LeftButton )
barrelPressed = FALSE;
}
</pre>
<p> 只要用戶釋放鼠標(biāo)按鈕并且它是在窗口部件中按下的時(shí)候,這個(gè)Qt事件處理器就會(huì)被調(diào)用。
<p> 如果鼠標(biāo)左鍵被釋放,我們就會(huì)確認(rèn)炮筒不再被按下了。
<p> 繪畫事件包含了下述額外的兩行:
<p> <pre> <a name="x2359"></a> if ( updateR.<a href="qrect.html#intersects">intersects</a>( barrierRect() ) )
paintBarrier( &p );
</pre>
<p> paintBarrier()做的和paintShot()、paintTarget()和paintCannon()是同樣的事情。
<p> <pre> void CannonField::paintBarrier( <a href="qpainter.html">QPainter</a> *p )
{
p-><a href="qpainter.html#setBrush">setBrush</a>( yellow );
p-><a href="qpainter.html#setPen">setPen</a>( black );
p-><a href="qpainter.html#drawRect">drawRect</a>( barrierRect() );
}
</pre>
<p> 這個(gè)私有函數(shù)用一個(gè)黑色邊界黃色填充的矩形作為障礙物。
<p> <pre> QRect CannonField::barrierRect() const
{
return QRect( 145, height() - 100, 15, 100 );
}
</pre>
<p> 這個(gè)私有函數(shù)返回障礙物的矩形。我們把障礙物的下邊界和窗口部件的下邊界放在了一起。
<p> <pre> bool CannonField::barrelHit( const <a href="qpoint.html">QPoint</a> &p ) const
{
<a href="qwmatrix.html">QWMatrix</a> mtx;
<a name="x2368"></a> mtx.<a href="qwmatrix.html#translate">translate</a>( 0, height() - 1 );
<a name="x2367"></a> mtx.<a href="qwmatrix.html#rotate">rotate</a>( -ang );
<a name="x2365"></a> mtx = mtx.<a href="qwmatrix.html#invert">invert</a>();
<a name="x2366"></a><a name="x2358"></a> return barrelRect.<a href="qrect.html#contains">contains</a>( mtx.<a href="qwmatrix.html#map">map</a>(p) );
}
</pre>
<p> 如果點(diǎn)在炮筒內(nèi),這個(gè)函數(shù)返回TRUE;否則它就返回FALSE。
<p> 這里我們使用<a href="qwmatrix.html">QWMatrix</a>類。它是在頭文件qwmatrix.h中定義的,這個(gè)頭文件被qpainter.h包含。
<p> <a href="qwmatrix.html">QWMatrix</a>定義了一個(gè)坐標(biāo)系統(tǒng)映射。它可以執(zhí)行和<a href="qpainter.html">QPainter</a>中一樣的轉(zhuǎn)換。
<p> 這里我們實(shí)現(xiàn)同樣的轉(zhuǎn)換的步驟就和我們?cè)趐aintCannon()函數(shù)中繪制炮筒的時(shí)候所作的一樣。首先我們轉(zhuǎn)換坐標(biāo)系統(tǒng),然后我們旋轉(zhuǎn)它。
<p> 現(xiàn)在我們需要檢查點(diǎn)<tt>p</tt>(在窗口部件坐標(biāo)系統(tǒng)中)是否在炮筒內(nèi)。為了做到這一點(diǎn),我們倒置這個(gè)轉(zhuǎn)換矩陣。倒置的矩陣就執(zhí)行了我們?cè)诶L制炮筒時(shí)使用的倒置的轉(zhuǎn)換。我們通過使用倒置矩陣來映射點(diǎn)<tt>p</tt>,并且如果它在初始的炮筒矩形內(nèi)就返回TRUE。
<p> <h3> <a href="t14-gamebrd-cpp.html">t14/gamebrd.cpp</a>
</h3>
<a name="1-3"></a><p>
<p> <pre> #include <<a href="qaccel-h.html">qaccel.h</a>>
</pre>
<p> 我們包含<a href="qaccel.html">QAccel</a>的類定義。
<p> <pre> <a href="qvbox.html">QVBox</a> *box = new <a href="qvbox.html">QVBox</a>( this, "cannonFrame" );
box-><a href="qframe.html#setFrameStyle">setFrameStyle</a>( QFrame::WinPanel | QFrame::Sunken );
cannonField = new CannonField( box, "cannonField" );
</pre>
<p> 我們創(chuàng)建并設(shè)置一個(gè)<a href="qvbox.html">QVBox</a>,設(shè)置它的框架風(fēng)格,并在之后創(chuàng)建<tt>CannonField</tt>作為這個(gè)盒子的子對(duì)象。因?yàn)闆]有其它的東西在這個(gè)盒子里了,效果就是<a href="qvbox.html">QVBox</a>會(huì)在CannonField周圍生成了一個(gè)框架。
<p> <pre> <a href="qaccel.html">QAccel</a> *accel = new <a href="qaccel.html">QAccel</a>( this );
<a name="x2370"></a><a name="x2369"></a> accel-><a href="qaccel.html#connectItem">connectItem</a>( accel-><a href="qaccel.html#insertItem">insertItem</a>( Key_Enter ),
this, SLOT(fire()) );
accel-><a href="qaccel.html#connectItem">connectItem</a>( accel-><a href="qaccel.html#insertItem">insertItem</a>( Key_Return ),
this, SLOT(fire()) );
</pre>
<p> 現(xiàn)在我們創(chuàng)建并設(shè)置一個(gè)加速鍵。加速鍵就是在應(yīng)用程序中截取鍵盤事件并且如果特定的鍵被按下的時(shí)候調(diào)用相應(yīng)的槽。這種機(jī)制也被稱為快捷鍵。注意快捷鍵是窗口部件的子對(duì)象并且當(dāng)窗口部件被銷毀的時(shí)候銷毀。<a href="qaccel.html">QAccel</a><em>不是</em>窗口部件,并且在它的父對(duì)象中沒有任何可見的效果。
<p> 我們定義兩個(gè)快捷鍵。我們希望在Enter鍵被按下的時(shí)候調(diào)用fire()槽,在Ctrl+Q鍵被按下的時(shí)候,應(yīng)用程序退出。因?yàn)镋nter有時(shí)又被稱為Return,并且有時(shí)鍵盤中<em>兩個(gè)</em>鍵都有,所以我們讓這兩個(gè)鍵都調(diào)用fire()。
<p> <pre> accel-><a href="qaccel.html#connectItem">connectItem</a>( accel-><a href="qaccel.html#insertItem">insertItem</a>( CTRL+Key_Q ),
qApp, SLOT(<a href="qapplication.html#quit">quit</a>()) );
</pre>
<p> 并且之后我們?cè)O(shè)置Ctrl+Q和Alt+Q做同樣的事情。一些人通常使用Ctrl+Q更多一些(并且無論如何它顯示了如果做到它)。
<p> CTRL、Key_Enter、Key_Return和Key_Q都是Qt提供的常量。它們實(shí)際上就是Qt::Key_Enter等等,但是實(shí)際上所有的類都繼承了<a href="qt.html">Qt</a>這個(gè)命名空間類。
<p> <pre> <a href="qgridlayout.html">QGridLayout</a> *grid = new <a href="qgridlayout.html">QGridLayout</a>( this, 2, 2, 10 );
<a name="x2373"></a> grid-><a href="qgridlayout.html#addWidget">addWidget</a>( quit, 0, 0 );
grid-><a href="qgridlayout.html#addWidget">addWidget</a>( box, 1, 1 );
<a name="x2374"></a> grid-><a href="qgridlayout.html#setColStretch">setColStretch</a>( 1, 10 );
</pre>
<p> 我們放置<tt>box</tt>(<a href="qvbox.html">QVBox</a>),不是CannonField,在右下的單元格中。
<p> <h2> 行為
</h2>
<a name="2"></a><p> 現(xiàn)在當(dāng)你按下Enter的時(shí)候,加農(nóng)炮就會(huì)發(fā)射。你也可以用鼠標(biāo)來確定加農(nóng)炮的角度。障礙物會(huì)使你在玩游戲的時(shí)候獲得更多一點(diǎn)的挑戰(zhàn)。我們還會(huì)在CannnonField周圍看到一個(gè)好看的框架。
<p> (請(qǐng)看<a href="tutorial1-07.html#compiling">編譯</a>來學(xué)習(xí)如何創(chuàng)建一個(gè)makefile和連編應(yīng)用程序。)
<p> <h2> 練習(xí)
</h2>
<a name="3"></a><p> 寫一個(gè)空間入侵者的游戲。
<p> (這個(gè)練習(xí)首先被<a href="mailto:igorr@ifi.uio.no">Igor Rafienko</a>作出來了。你可以<a href="http://www.stud.ifi.uio.no/~igorr/download.html">下載他的游戲</a>。)
<p> 新的練習(xí)是:寫一個(gè)突圍游戲。
<p> 最后的勸告:現(xiàn)在向前進(jìn),創(chuàng)造<em>編程藝術(shù)的杰作</em>!
<p>
<p> [<a href="tutorial1-13.html">上一章</a>]
[<a href="tutorial1-01.html">第一章</a>]
[<a href="tutorial.html">教程一主頁(yè)</a>]
<p>
<!-- eof -->
<p><address><hr><div align=center>
<table width=100% cellspacing=0 border=0><tr>
<td>Copyright © 2002
<a href="http://www.trolltech.com">Trolltech</a>
<td><a href="http://www.trolltech.com/trademarks.html">Trademarks</a>
<td><a href="zh_CN.html">譯者:Cavendish</a>
<td align=right><div align=right>Qt 3.0.5版</div>
</table></div></address></body>
</html>
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -