<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://techbase.kde.org/skins/common/feed.css?0.2"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://techbase.kde.org/api.php?action=feedcontributions&amp;user=Centerlink&amp;feedformat=atom</id>
		<title>KDE TechBase - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://techbase.kde.org/api.php?action=feedcontributions&amp;user=Centerlink&amp;feedformat=atom"/>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Special:Contributions/Centerlink"/>
		<updated>2013-06-18T22:37:42Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.20.2</generator>

	<entry>
		<id>http://techbase.kde.org/Edit_Markup/fi</id>
		<title>Edit Markup/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Edit_Markup/fi"/>
				<updated>2012-12-23T17:08:51Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
== Käytettävissä olevat työkalut ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* [[Special:MyLanguage/Typographical_Guidelines]] standardisoi kotoistamisessa käytettävät markup-merkinnät, joko virallisia käsikirjoja varten (DocBook) tai muille kielille. Viittaa tähän taajaan, koska markup-merkkejä määritellään uudelleen täsmäämään kotoistajien tarpeita.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Työnkulku vaihe 1 ==&lt;br /&gt;
&lt;br /&gt;
=== Vanhan markup-merkinnän korjaaminen ===&lt;br /&gt;
&lt;br /&gt;
* Tarkista, että jokaista lohkon tai alilohkon otsaketta seuraa tyhjä rivi.&lt;br /&gt;
&lt;br /&gt;
* Monille sivuille on asetettu useita sisennyksiä.  Tämä sisällytettiin aikaisempaan mediawiki-dokumentaatioon, mutta ei ole enää hyväksyttävää, koska se aiheuttaa pulmia muiden muotojen viennissä, joten järjestele uudelleen käyttäen vain yksittäisiä sisennyksiä.  Etumerkki-luettelot voivat edelleen olla sisäkkäisiä.&lt;br /&gt;
&lt;br /&gt;
* ASCII-hymiöt aiheuttavat pulmia ja ne on poistettava.  Ne voidaan korvata pienikokoisilla (11px?) oxygen-kuvakkeilla.  Monia muita on saatavilla Wikimedia Commons -sivustolta - lisätiedot lisätään tänne.&lt;br /&gt;
&lt;br /&gt;
* Muotoa &amp;lt;nowiki&amp;gt;[[Kotoistamistyökulku]]&amp;lt;/nowiki&amp;gt; olevat sisäiset linkit olisi muokattava täydelliseen muotoon, jotka näyttävät linkin, sitten näkyvän tekstin, kuten &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Translation_Workflow|Kotoistamistyökulku]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Syöttötekstin näyttämiseen on käytetty monia tyylejä, mukaan lukien &amp;lt;nowiki&amp;gt;&amp;lt;code&amp;gt;, &amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; ja taulukot ja laatikot. Käyttäjän syötteeksi tarkoitetun tekstin tulisi käyttää Input-mallinnetta, &amp;lt;nowiki&amp;gt;{{Input|1=syöteteksti (voi olla useita rivejä tai yksi rivi)}}&amp;lt;/nowiki&amp;gt;. Voit yhä käyttää &amp;lt;nowiki&amp;gt;&amp;lt;code&amp;gt;&amp;lt;/nowiki&amp;gt; hyvin lyhyelle syötteelle, jos et halua tekstin esiintyvän usealla rivillä. &lt;br /&gt;
&lt;br /&gt;
* Pääteikkunatulosteet ja virheilmoitusviestit on samalla tavalla merkitty vaihtelevasti.  Nämä tulisi korvata Output-mallinteella, &amp;lt;nowiki&amp;gt;{{Output|1=pääteikkunatuloste}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Jokaisen sivun tulisi päättyä Category-luokkalauseeseen.  Näiden on oltava standardisoituja luokkia.  Luokkien nykyinen luettelo löydetään miltä tahansa kotoistajan sivulta linkitettynä [[Translation_Help_Needed|tämä kielisivu]]&lt;br /&gt;
&lt;br /&gt;
* Varmista, että missään kappaleessa ei ole parittomia sulkeita. Jos löydät parittomia sulkeita, lisää puuttuvat sulkeet &amp;amp;mdash; mahdollisesti kommenteissa kuten tämä: {{Input|1=&amp;lt;nowiki&amp;gt;&amp;lt;!--(--&amp;gt; a)&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
* Luetteloissa pitäisi olla etumerkkirivien välissä tyhjä rivi. Katso kappeleita luetteloissa  [[Special:myLanguage/Toolbox#Bulleted Lists|Etumerkilliset luettelot]].&lt;br /&gt;
&lt;br /&gt;
* Taulukot pitäisi jakaa samalla tavalla niin että jokaisen rivin välissä on tyhjä rivi. Ensimmäisellä ja viimeisellä rivillä on oltava parilliset aaltosulkeet.&lt;br /&gt;
&lt;br /&gt;
== Vaihe 2 - Opas uuteen markup-merkintään ==&lt;br /&gt;
&lt;br /&gt;
=== Merkitään linkit kotoistamiseen ===&lt;br /&gt;
&lt;br /&gt;
* Yksittäisen linkin, sellaisen kuin sovelluksen nimi kohteessa Applications/Internet, pitäisi käyttää muotoa &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Ark|&amp;amp;lt;translate&amp;gt;Ark&amp;amp;lt;/translate&amp;gt;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* Siellä missä linkki on lauseen sisällä, koko linkki pitäisi pitää kotoistettavan viestin sisällä.&lt;br /&gt;
&lt;br /&gt;
=== Erityistunnisteet ===&lt;br /&gt;
&lt;br /&gt;
* Tunnista kaikki näppäimistön näppäinnimet, ja tagitunnisteet, esim.: &amp;lt;nowiki&amp;gt;&amp;lt;keycap&amp;gt;Enter&amp;lt;/keycap&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* Sisällytä samanaikaisen näppäinten painallukset &amp;lt;nowiki&amp;gt;&amp;lt;keycap&amp;gt;&amp;lt;/nowiki&amp;gt; -tagitunniste, esim.: &amp;lt;keycap&amp;gt;Ctrl + Alt + F1&amp;lt;/keycap&amp;gt;. Huomaa, että erotin on (välilyönti)+(välilyönti)&lt;br /&gt;
* Kohtele valikkosarjoja samalla tavalla käyttäen &amp;lt;nowiki&amp;gt;&amp;lt;menuchoice&amp;gt;&amp;lt;/nowiki&amp;gt; -tagitunnistetta, esim.: &amp;lt;menuchoice&amp;gt;System Settings -&amp;gt; Account Details -&amp;gt; Social Desktop&amp;lt;/menuchoice&amp;gt;.  Huomaa, että erotin on (välilyönti)-&amp;gt;(välilyönti)&lt;br /&gt;
&lt;br /&gt;
{{Warning|2=Varoitus|1=&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;ÄLÄ KOSKAAN&amp;lt;/span&amp;gt; lisää translate-lohkotagitunnisteita (niitä, jotka näyttävät seuraavilta &amp;lt;nowiki&amp;gt;&amp;lt; !--T:18-- &amp;gt;&amp;lt;/nowiki&amp;gt;).  Ohjelmisto tekee kaikkien vaadittujen tagitunnisteiden käsittelyn, ja manuaaliset muutokset rikkovat järjestelmän.}}&lt;br /&gt;
&lt;br /&gt;
=== Lihavoidut ===&lt;br /&gt;
&lt;br /&gt;
* Tunnista ohjelmanimet ja merkitse ne lihavoituna, esim.: '''Klipper'''&lt;br /&gt;
* Tunnista nimiöt ja nimet, joita käyttäjä ei voi muuttaa, ja merkitse ne lihavoiduiksi.&lt;br /&gt;
* Poista kaikki aikaisemmat lihavoinnit, jotka on kirjoitettu aiemmin, mutta jotka eivät täsmää tähän ohjeeseen.   (Katso alle sanan tai fraasin painottamisesta.)&lt;br /&gt;
* Ikkunan otsikkotekstit ja kuvakkeiden nimiöt merkitään myös lihavoiduiksi.&lt;br /&gt;
&lt;br /&gt;
=== Kursiivit ===&lt;br /&gt;
&lt;br /&gt;
* Kursivointia käytetään painottamiseen kuten tehdään ei-teknisessä kirjoittamisessa&lt;br /&gt;
* Käytä kursiivia epätavallisen sanan tai fraasin ensimmäisessä esiintymisessä, ja jos mahdollista, linkitä se kohteeseen #Glossary tai sanakirjasanaan.&lt;br /&gt;
* Kun viitataan muihin (ulkoisiin) teoksiin, otsikot kursivoidaan.&lt;br /&gt;
&lt;br /&gt;
=== Yhdistetty lihavointi ja kursivointi ===&lt;br /&gt;
&lt;br /&gt;
* Tätä pitäisi käyttää ainoastaan asiayhteydessä, jossa käyttäjä on korvannut tekstiä, esim.: &amp;quot;Uudet osoitekirjatietueesi ovat kohteessa &amp;lt;tt&amp;gt;/home/&amp;lt;/tt&amp;gt;'''''user'''''&amp;lt;tt&amp;gt;/share/contacts&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
{{Tip|2=Vihje|Yksinkertaistettuja määrittelyjä - käyttäjät käynnistävät ''Ohjelmia'', ohjelmat käyttävät ''komponentteja''}}&lt;br /&gt;
&lt;br /&gt;
== Kohteet, jotka aiheuttavat kotoistamispulmia ==&lt;br /&gt;
&lt;br /&gt;
Useat kohteet on tunnistettu ja niistä on keskusteltu, ja ehdotetut ratkaisut ovat seuraavassa kappaleessa:&lt;br /&gt;
&lt;br /&gt;
* [[Typographical_Guidelines#Lists|Luetteloiden jakaminen luettavuuden vuoksi]]&lt;br /&gt;
* [[Typographical_Guidelines#Keeping_things_together|Muut &amp;quot;luettavuus&amp;quot;katkokset]]&lt;br /&gt;
* [[Typographical_Guidelines#Unbalanced_brackets|Sulkeet jakavat lohkoja]]&lt;br /&gt;
&lt;br /&gt;
Nämä havaitaan tavallisesti ensimmäisen markup-merkinnän jälkeen ja saattaa olla välttämätöntä järjestää uudelleen välit ja/tai rakenne pulmien välttämiseksi.&lt;br /&gt;
&lt;br /&gt;
== Lähes valmis ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* Kirjoita lopussa olevaan yhteenvetokenttään, mitä olet tehnyt markup-muokkauksessa.&lt;br /&gt;
* Käytä &amp;lt;menuchoice&amp;gt;Esikatselu&amp;lt;/menuchoice&amp;gt; ja lue koko työsi lävitse.  Jos olet tyytyväinen, tallenna sivu.&lt;br /&gt;
* Käytä sivupalkin linkkiä julkaisun pyytämiseen - se ottaa sivusi, kun lisäät muokkaamasi sivun verkko-osoitteen.  Linkkisi liittäminen sinne kertoo meille, että uskot sivun olevan valmis kotoistajien työskentelyä varten.  Tutkimme sitä, ja jos olemme tyytyväisiä, otamme sen mukaan kotoistamiseen.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Translator_Help]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Edit_Markup/30/fi</id>
		<title>Translations:Edit Markup/30/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Edit_Markup/30/fi"/>
				<updated>2012-12-23T17:08:51Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[Typographical_Guidelines#Lists|Luetteloiden jakaminen luettavuuden vuoksi]]&lt;br /&gt;
* [[Typographical_Guidelines#Keeping_things_together|Muut &amp;quot;luettavuus&amp;quot;katkokset]]&lt;br /&gt;
* [[Typographical_Guidelines#Unbalanced_brackets|Sulkeet jakavat lohkoja]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Edit_Markup/fi</id>
		<title>Edit Markup/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Edit_Markup/fi"/>
				<updated>2012-12-23T17:06:30Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
== Käytettävissä olevat työkalut ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* [[Special:MyLanguage/Typographical_Guidelines]] standardisoi kotoistamisessa käytettävät markup-merkinnät, joko virallisia käsikirjoja varten (DocBook) tai muille kielille. Viittaa tähän taajaan, koska markup-merkkejä määritellään uudelleen täsmäämään kotoistajien tarpeita.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Työnkulku vaihe 1 ==&lt;br /&gt;
&lt;br /&gt;
=== Vanhan markup-merkinnän korjaaminen ===&lt;br /&gt;
&lt;br /&gt;
* Tarkista, että jokaista lohkon tai alilohkon otsaketta seuraa tyhjä rivi.&lt;br /&gt;
&lt;br /&gt;
* Monille sivuille on asetettu useita sisennyksiä.  Tämä sisällytettiin aikaisempaan mediawiki-dokumentaatioon, mutta ei ole enää hyväksyttävää, koska se aiheuttaa pulmia muiden muotojen viennissä, joten järjestele uudelleen käyttäen vain yksittäisiä sisennyksiä.  Etumerkki-luettelot voivat edelleen olla sisäkkäisiä.&lt;br /&gt;
&lt;br /&gt;
* ASCII-hymiöt aiheuttavat pulmia ja ne on poistettava.  Ne voidaan korvata pienikokoisilla (11px?) oxygen-kuvakkeilla.  Monia muita on saatavilla Wikimedia Commons -sivustolta - lisätiedot lisätään tänne.&lt;br /&gt;
&lt;br /&gt;
* Muotoa &amp;lt;nowiki&amp;gt;[[Kotoistamistyökulku]]&amp;lt;/nowiki&amp;gt; olevat sisäiset linkit olisi muokattava täydelliseen muotoon, jotka näyttävät linkin, sitten näkyvän tekstin, kuten &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Translation_Workflow|Kotoistamistyökulku]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Syöttötekstin näyttämiseen on käytetty monia tyylejä, mukaan lukien &amp;lt;nowiki&amp;gt;&amp;lt;code&amp;gt;, &amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; ja taulukot ja laatikot. Käyttäjän syötteeksi tarkoitetun tekstin tulisi käyttää Input-mallinnetta, &amp;lt;nowiki&amp;gt;{{Input|1=syöteteksti (voi olla useita rivejä tai yksi rivi)}}&amp;lt;/nowiki&amp;gt;. Voit yhä käyttää &amp;lt;nowiki&amp;gt;&amp;lt;code&amp;gt;&amp;lt;/nowiki&amp;gt; hyvin lyhyelle syötteelle, jos et halua tekstin esiintyvän usealla rivillä. &lt;br /&gt;
&lt;br /&gt;
* Pääteikkunatulosteet ja virheilmoitusviestit on samalla tavalla merkitty vaihtelevasti.  Nämä tulisi korvata Output-mallinteella, &amp;lt;nowiki&amp;gt;{{Output|1=pääteikkunatuloste}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Jokaisen sivun tulisi päättyä Category-luokkalauseeseen.  Näiden on oltava standardisoituja luokkia.  Luokkien nykyinen luettelo löydetään miltä tahansa kotoistajan sivulta linkitettynä [[Translation_Help_Needed|tämä kielisivu]]&lt;br /&gt;
&lt;br /&gt;
* Varmista, että missään kappaleessa ei ole parittomia sulkeita. Jos löydät parittomia sulkeita, lisää puuttuvat sulkeet &amp;amp;mdash; mahdollisesti kommenteissa kuten tämä: {{Input|1=&amp;lt;nowiki&amp;gt;&amp;lt;!--(--&amp;gt; a)&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
* Luetteloissa pitäisi olla etumerkkirivien välissä tyhjä rivi. Katso kappeleita luetteloissa  [[Special:myLanguage/Toolbox#Bulleted Lists|Etumerkilliset luettelot]].&lt;br /&gt;
&lt;br /&gt;
* Taulukot pitäisi jakaa samalla tavalla niin että jokaisen rivin välissä on tyhjä rivi. Ensimmäisellä ja viimeisellä rivillä on oltava parilliset aaltosulkeet.&lt;br /&gt;
&lt;br /&gt;
== Vaihe 2 - Opas uuteen markup-merkintään ==&lt;br /&gt;
&lt;br /&gt;
=== Merkitään linkit kotoistamiseen ===&lt;br /&gt;
&lt;br /&gt;
* Yksittäisen linkin, sellaisen kuin sovelluksen nimi kohteessa Applications/Internet, pitäisi käyttää muotoa &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Ark|&amp;amp;lt;translate&amp;gt;Ark&amp;amp;lt;/translate&amp;gt;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* Siellä missä linkki on lauseen sisällä, koko linkki pitäisi pitää kotoistettavan viestin sisällä.&lt;br /&gt;
&lt;br /&gt;
=== Erityistunnisteet ===&lt;br /&gt;
&lt;br /&gt;
* Tunnista kaikki näppäimistön näppäinnimet, ja tagitunnisteet, esim.: &amp;lt;nowiki&amp;gt;&amp;lt;keycap&amp;gt;Enter&amp;lt;/keycap&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* Sisällytä samanaikaisen näppäinten painallukset &amp;lt;nowiki&amp;gt;&amp;lt;keycap&amp;gt;&amp;lt;/nowiki&amp;gt; -tagitunniste, esim.: &amp;lt;keycap&amp;gt;Ctrl + Alt + F1&amp;lt;/keycap&amp;gt;. Huomaa, että erotin on (välilyönti)+(välilyönti)&lt;br /&gt;
* Kohtele valikkosarjoja samalla tavalla käyttäen &amp;lt;nowiki&amp;gt;&amp;lt;menuchoice&amp;gt;&amp;lt;/nowiki&amp;gt; -tagitunnistetta, esim.: &amp;lt;menuchoice&amp;gt;System Settings -&amp;gt; Account Details -&amp;gt; Social Desktop&amp;lt;/menuchoice&amp;gt;.  Huomaa, että erotin on (välilyönti)-&amp;gt;(välilyönti)&lt;br /&gt;
&lt;br /&gt;
{{Warning|2=Varoitus|1=&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;ÄLÄ KOSKAAN&amp;lt;/span&amp;gt; lisää translate-lohkotagitunnisteita (niitä, jotka näyttävät seuraavilta &amp;lt;nowiki&amp;gt;&amp;lt; !--T:18-- &amp;gt;&amp;lt;/nowiki&amp;gt;).  Ohjelmisto tekee kaikkien vaadittujen tagitunnisteiden käsittelyn, ja manuaaliset muutokset rikkovat järjestelmän.}}&lt;br /&gt;
&lt;br /&gt;
=== Lihavoidut ===&lt;br /&gt;
&lt;br /&gt;
* Tunnista ohjelmanimet ja merkitse ne lihavoituna, esim.: '''Klipper'''&lt;br /&gt;
* Tunnista nimiöt ja nimet, joita käyttäjä ei voi muuttaa, ja merkitse ne lihavoiduiksi.&lt;br /&gt;
* Poista kaikki aikaisemmat lihavoinnit, jotka on kirjoitettu aiemmin, mutta jotka eivät täsmää tähän ohjeeseen.   (Katso alle sanan tai fraasin painottamisesta.)&lt;br /&gt;
* Ikkunan otsikkotekstit ja kuvakkeiden nimiöt merkitään myös lihavoiduiksi.&lt;br /&gt;
&lt;br /&gt;
=== Kursiivit ===&lt;br /&gt;
&lt;br /&gt;
* Kursivointia käytetään painottamiseen kuten tehdään ei-teknisessä kirjoittamisessa&lt;br /&gt;
* Käytä kursiivia epätavallisen sanan tai fraasin ensimmäisessä esiintymisessä, ja jos mahdollista, linkitä se kohteeseen #Glossary tai sanakirjasanaan.&lt;br /&gt;
* Kun viitataan muihin (ulkoisiin) teoksiin, otsikot kursivoidaan.&lt;br /&gt;
&lt;br /&gt;
=== Yhdistetty lihavointi ja kursivointi ===&lt;br /&gt;
&lt;br /&gt;
* Tätä pitäisi käyttää ainoastaan asiayhteydessä, jossa käyttäjä on korvannut tekstiä, esim.: &amp;quot;Uudet osoitekirjatietueesi ovat kohteessa &amp;lt;tt&amp;gt;/home/&amp;lt;/tt&amp;gt;'''''user'''''&amp;lt;tt&amp;gt;/share/contacts&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
{{Tip|2=Vihje|Yksinkertaistettuja määrittelyjä - käyttäjät käynnistävät ''Ohjelmia'', ohjelmat käyttävät ''komponentteja''}}&lt;br /&gt;
&lt;br /&gt;
== Kohteet, jotka aiheuttavat kotoistamispulmia ==&lt;br /&gt;
&lt;br /&gt;
Useat kohteet on tunnistettu ja niistä on keskusteltu, ja ehdotetut ratkaisut ovat seuraavassa kappaleessa:&lt;br /&gt;
&lt;br /&gt;
* [[Typographical_Guidelines#Lists|Luetteloiden jakaminen luettavuuden vuoksi]]&lt;br /&gt;
* [[Typographical_Guidelines#Keeping_things_together|Muut &amp;quot;luettavuus&amp;quot; katkokset]]&lt;br /&gt;
* [[Typographical_Guidelines#Unbalanced_brackets|Sulkeet jakavat lohkoja]]&lt;br /&gt;
&lt;br /&gt;
Nämä havaitaan tavallisesti ensimmäisen markup-merkinnän jälkeen ja saattaa olla välttämätöntä järjestää uudelleen välit ja/tai rakenne pulmien välttämiseksi.&lt;br /&gt;
&lt;br /&gt;
== Lähes valmis ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* Kirjoita lopussa olevaan yhteenvetokenttään, mitä olet tehnyt markup-muokkauksessa.&lt;br /&gt;
* Käytä &amp;lt;menuchoice&amp;gt;Esikatselu&amp;lt;/menuchoice&amp;gt; ja lue koko työsi lävitse.  Jos olet tyytyväinen, tallenna sivu.&lt;br /&gt;
* Käytä sivupalkin linkkiä julkaisun pyytämiseen - se ottaa sivusi, kun lisäät muokkaamasi sivun verkko-osoitteen.  Linkkisi liittäminen sinne kertoo meille, että uskot sivun olevan valmis kotoistajien työskentelyä varten.  Tutkimme sitä, ja jos olemme tyytyväisiä, otamme sen mukaan kotoistamiseen.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Translator_Help]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Edit_Markup/20/fi</id>
		<title>Translations:Edit Markup/20/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Edit_Markup/20/fi"/>
				<updated>2012-12-23T17:06:30Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Warning|2=Varoitus|1=&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;ÄLÄ KOSKAAN&amp;lt;/span&amp;gt; lisää translate-lohkotagitunnisteita (niitä, jotka näyttävät seuraavilta &amp;lt;nowiki&amp;gt;&amp;lt; !--T:18-- &amp;gt;&amp;lt;/nowiki&amp;gt;).  Ohjelmisto tekee kaikkien vaadittujen tagitunnisteiden käsittelyn, ja manuaaliset muutokset rikkovat järjestelmän.}}&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Edit_Markup/fi</id>
		<title>Edit Markup/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Edit_Markup/fi"/>
				<updated>2012-12-23T16:53:51Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
== Käytettävissä olevat työkalut ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* [[Special:MyLanguage/Typographical_Guidelines]] standardisoi kotoistamisessa käytettävät markup-merkinnät, joko virallisia käsikirjoja varten (DocBook) tai muille kielille. Viittaa tähän taajaan, koska markup-merkkejä määritellään uudelleen täsmäämään kotoistajien tarpeita.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Työnkulku vaihe 1 ==&lt;br /&gt;
&lt;br /&gt;
=== Vanhan markup-merkinnän korjaaminen ===&lt;br /&gt;
&lt;br /&gt;
* Tarkista, että jokaista lohkon tai alilohkon otsaketta seuraa tyhjä rivi.&lt;br /&gt;
&lt;br /&gt;
* Monille sivuille on asetettu useita sisennyksiä.  Tämä sisällytettiin aikaisempaan mediawiki-dokumentaatioon, mutta ei ole enää hyväksyttävää, koska se aiheuttaa pulmia muiden muotojen viennissä, joten järjestele uudelleen käyttäen vain yksittäisiä sisennyksiä.  Etumerkki-luettelot voivat edelleen olla sisäkkäisiä.&lt;br /&gt;
&lt;br /&gt;
* ASCII-hymiöt aiheuttavat pulmia ja ne on poistettava.  Ne voidaan korvata pienikokoisilla (11px?) oxygen-kuvakkeilla.  Monia muita on saatavilla Wikimedia Commons -sivustolta - lisätiedot lisätään tänne.&lt;br /&gt;
&lt;br /&gt;
* Muotoa &amp;lt;nowiki&amp;gt;[[Kotoistamistyökulku]]&amp;lt;/nowiki&amp;gt; olevat sisäiset linkit olisi muokattava täydelliseen muotoon, jotka näyttävät linkin, sitten näkyvän tekstin, kuten &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Translation_Workflow|Kotoistamistyökulku]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Syöttötekstin näyttämiseen on käytetty monia tyylejä, mukaan lukien &amp;lt;nowiki&amp;gt;&amp;lt;code&amp;gt;, &amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; ja taulukot ja laatikot. Käyttäjän syötteeksi tarkoitetun tekstin tulisi käyttää Input-mallinnetta, &amp;lt;nowiki&amp;gt;{{Input|1=syöteteksti (voi olla useita rivejä tai yksi rivi)}}&amp;lt;/nowiki&amp;gt;. Voit yhä käyttää &amp;lt;nowiki&amp;gt;&amp;lt;code&amp;gt;&amp;lt;/nowiki&amp;gt; hyvin lyhyelle syötteelle, jos et halua tekstin esiintyvän usealla rivillä. &lt;br /&gt;
&lt;br /&gt;
* Pääteikkunatulosteet ja virheilmoitusviestit on samalla tavalla merkitty vaihtelevasti.  Nämä tulisi korvata Output-mallinteella, &amp;lt;nowiki&amp;gt;{{Output|1=pääteikkunatuloste}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Jokaisen sivun tulisi päättyä Category-luokkalauseeseen.  Näiden on oltava standardisoituja luokkia.  Luokkien nykyinen luettelo löydetään miltä tahansa kotoistajan sivulta linkitettynä [[Translation_Help_Needed|tämä kielisivu]]&lt;br /&gt;
&lt;br /&gt;
* Varmista, että missään kappaleessa ei ole parittomia sulkeita. Jos löydät parittomia sulkeita, lisää puuttuvat sulkeet &amp;amp;mdash; mahdollisesti kommenteissa kuten tämä: {{Input|1=&amp;lt;nowiki&amp;gt;&amp;lt;!--(--&amp;gt; a)&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
* Luetteloissa pitäisi olla etumerkkirivien välissä tyhjä rivi. Katso kappeleita luetteloissa  [[Special:myLanguage/Toolbox#Bulleted Lists|Etumerkilliset luettelot]].&lt;br /&gt;
&lt;br /&gt;
* Taulukot pitäisi jakaa samalla tavalla niin että jokaisen rivin välissä on tyhjä rivi. Ensimmäisellä ja viimeisellä rivillä on oltava parilliset aaltosulkeet.&lt;br /&gt;
&lt;br /&gt;
== Vaihe 2 - Opas uuteen markup-merkintään ==&lt;br /&gt;
&lt;br /&gt;
=== Merkitään linkit kotoistamiseen ===&lt;br /&gt;
&lt;br /&gt;
* Yksittäisen linkin, sellaisen kuin sovelluksen nimi kohteessa Applications/Internet, pitäisi käyttää muotoa &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Ark|&amp;amp;lt;translate&amp;gt;Ark&amp;amp;lt;/translate&amp;gt;]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* Siellä missä linkki on lauseen sisällä, koko linkki pitäisi pitää kotoistettavan viestin sisällä.&lt;br /&gt;
&lt;br /&gt;
=== Erityistunnisteet ===&lt;br /&gt;
&lt;br /&gt;
* Tunnista kaikki näppäimistön näppäinnimet, ja tagitunnisteet, esim.: &amp;lt;nowiki&amp;gt;&amp;lt;keycap&amp;gt;Enter&amp;lt;/keycap&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* Sisällytä samanaikaisen näppäinten painallukset &amp;lt;nowiki&amp;gt;&amp;lt;keycap&amp;gt;&amp;lt;/nowiki&amp;gt; -tagitunniste, esim.: &amp;lt;keycap&amp;gt;Ctrl + Alt + F1&amp;lt;/keycap&amp;gt;. Huomaa, että erotin on (välilyönti)+(välilyönti)&lt;br /&gt;
* Kohtele valikkosarjoja samalla tavalla käyttäen &amp;lt;nowiki&amp;gt;&amp;lt;menuchoice&amp;gt;&amp;lt;/nowiki&amp;gt; -tagitunnistetta, esim.: &amp;lt;menuchoice&amp;gt;System Settings -&amp;gt; Account Details -&amp;gt; Social Desktop&amp;lt;/menuchoice&amp;gt;.  Huomaa, että erotin on (välilyönti)-&amp;gt;(välilyönti)&lt;br /&gt;
&lt;br /&gt;
{{Warning|2=Varoitus|&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;ÄLÄ KOSKAAN&amp;lt;/span&amp;gt; lisää translate-lohkotagitunnisteita (niitä, jotka näyttävät seuraavilta &amp;lt;nowiki&amp;gt;&amp;lt; !--T:18-- &amp;gt;&amp;lt;/nowiki&amp;gt;).  Ohjelmisto tekee kaikkien vaadittujen tagitunnisteiden käsittelyn, ja manuaaliset muutokset rikkovat järjestelmän.}}&lt;br /&gt;
&lt;br /&gt;
=== Lihavoidut ===&lt;br /&gt;
&lt;br /&gt;
* Tunnista ohjelmanimet ja merkitse ne lihavoituna, esim.: '''Klipper'''&lt;br /&gt;
* Tunnista nimiöt ja nimet, joita käyttäjä ei voi muuttaa, ja merkitse ne lihavoiduiksi.&lt;br /&gt;
* Poista kaikki aikaisemmat lihavoinnit, jotka on kirjoitettu aiemmin, mutta jotka eivät täsmää tähän ohjeeseen.   (Katso alle sanan tai fraasin painottamisesta.)&lt;br /&gt;
* Ikkunan otsikkotekstit ja kuvakkeiden nimiöt merkitään myös lihavoiduiksi.&lt;br /&gt;
&lt;br /&gt;
=== Kursiivit ===&lt;br /&gt;
&lt;br /&gt;
* Kursivointia käytetään painottamiseen kuten tehdään ei-teknisessä kirjoittamisessa&lt;br /&gt;
* Käytä kursiivia epätavallisen sanan tai fraasin ensimmäisessä esiintymisessä, ja jos mahdollista, linkitä se kohteeseen #Glossary tai sanakirjasanaan.&lt;br /&gt;
* Kun viitataan muihin (ulkoisiin) teoksiin, otsikot kursivoidaan.&lt;br /&gt;
&lt;br /&gt;
=== Yhdistetty lihavointi ja kursivointi ===&lt;br /&gt;
&lt;br /&gt;
* Tätä pitäisi käyttää ainoastaan asiayhteydessä, jossa käyttäjä on korvannut tekstiä, esim.: &amp;quot;Uudet osoitekirjatietueesi ovat kohteessa &amp;lt;tt&amp;gt;/home/&amp;lt;/tt&amp;gt;'''''user'''''&amp;lt;tt&amp;gt;/share/contacts&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
{{Tip|2=Vihje|Yksinkertaistettuja määrittelyjä - käyttäjät käynnistävät ''Ohjelmia'', ohjelmat käyttävät ''komponentteja''}}&lt;br /&gt;
&lt;br /&gt;
== Kohteet, jotka aiheuttavat kotoistamispulmia ==&lt;br /&gt;
&lt;br /&gt;
Useat kohteet on tunnistettu ja niistä on keskusteltu, ja ehdotetut ratkaisut ovat seuraavassa kappaleessa:&lt;br /&gt;
&lt;br /&gt;
* [[Typographical_Guidelines#Lists|Luetteloiden jakaminen luettavuuden vuoksi]]&lt;br /&gt;
* [[Typographical_Guidelines#Keeping_things_together|Muut &amp;quot;luettavuus&amp;quot; katkokset]]&lt;br /&gt;
* [[Typographical_Guidelines#Unbalanced_brackets|Sulkeet jakavat lohkoja]]&lt;br /&gt;
&lt;br /&gt;
Nämä havaitaan tavallisesti ensimmäisen markup-merkinnän jälkeen ja saattaa olla välttämätöntä järjestää uudelleen välit ja/tai rakenne pulmien välttämiseksi.&lt;br /&gt;
&lt;br /&gt;
== Lähes valmis ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* Kirjoita lopussa olevaan yhteenvetokenttään, mitä olet tehnyt markup-muokkauksessa.&lt;br /&gt;
* Käytä &amp;lt;menuchoice&amp;gt;Esikatselu&amp;lt;/menuchoice&amp;gt; ja lue koko työsi lävitse.  Jos olet tyytyväinen, tallenna sivu.&lt;br /&gt;
* Käytä sivupalkin linkkiä julkaisun pyytämiseen - se ottaa sivusi, kun lisäät muokkaamasi sivun verkko-osoitteen.  Linkkisi liittäminen sinne kertoo meille, että uskot sivun olevan valmis kotoistajien työskentelyä varten.  Tutkimme sitä, ja jos olemme tyytyväisiä, otamme sen mukaan kotoistamiseen.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Translator_Help]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Edit_Markup/8/fi</id>
		<title>Translations:Edit Markup/8/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Edit_Markup/8/fi"/>
				<updated>2012-12-23T16:53:51Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Muotoa &amp;lt;nowiki&amp;gt;[[Kotoistamistyökulku]]&amp;lt;/nowiki&amp;gt; olevat sisäiset linkit olisi muokattava täydelliseen muotoon, jotka näyttävät linkin, sitten näkyvän tekstin, kuten &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Translation_Workflow|Kotoistamistyökulku]]&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translate_a_Page/fi</id>
		<title>Translate a Page/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translate_a_Page/fi"/>
				<updated>2012-12-23T15:58:43Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Käytettävissä olevat työkalut == &lt;br /&gt;
&lt;br /&gt;
* [[Special:myLanguage/Translation Workflow|Kotoistamistyön kulku]] kuvaa työkulun siirryttäessä uuteen kotoistamisjärjestelmään&lt;br /&gt;
&lt;br /&gt;
== Työnkulku == &lt;br /&gt;
&lt;br /&gt;
* Pyyntö lisäämisestä kotoistamisryhmään:&lt;br /&gt;
** Napsauta kohdetta [[Special:myLanguage/Translator Account|Hae kotoistajatili]] sivupalkissa&lt;br /&gt;
** Napsauta &amp;lt;menuchoice&amp;gt;Muokkaa&amp;lt;/menuchoice&amp;gt;-kuvaketta [[Image:Userbase-edit.png|14px]] ja kirjoita käyttäjänimesi, kieli, jolle haluat kotoistaa ja aiotko kotoistaa tekstiä erillistiedostoissa&lt;br /&gt;
** Käytä &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; tietojen tallentamiseksi&lt;br /&gt;
&lt;br /&gt;
* Kun käyttäjätilisi on lisätty ryhmään (sinun pitäisi saada siitä ilmoitus), napsauta kohdetta [[Special:LanguageStats|Aloita kotoistaminen]] sivupalkissa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita se kieli, jolle haluat kotoistaa &amp;lt;menuchoice&amp;gt;Kielikoodi&amp;lt;/menuchoice&amp;gt;-valintaan ja napsauta kohdetta &amp;lt;menuchoice&amp;gt;Siirry&amp;lt;/menuchoice&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Note|2=Huomaa|Kielikoodin ''en'' (englanti) kirjoittaminen kielikoodivalintaan ei näytä yhtään kotoistusviestiä, koska kaikki alkuperäinen sisältö on kirjoitettu englanniksi.}}&lt;br /&gt;
&lt;br /&gt;
* Napsauta luettelossa sivua, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Aseta '''Kotoista sivu''' asetuksessa &amp;lt;menuchoice&amp;gt;Katso kaikki kotoistamattomat viestit&amp;lt;/menuchoice&amp;gt; ensimmäisessä pudotusvalikkoluettelossa&lt;br /&gt;
&lt;br /&gt;
* Tarkista, että näkyvissä on oikea kielikoodi&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;menuchoice&amp;gt;Navigointi&amp;lt;/menuchoice&amp;gt;-osassa napsauta linkkiä sen viestin vasemmalla puolella, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita kotoistamisteksti - Google-ehdotus tarjotaan viitteenä, mutta oma kotoistamisteksti on tavallisesti parempi.&lt;br /&gt;
&lt;br /&gt;
* Napsauta kohdetta &amp;lt;menuchoice&amp;gt;Tallenna ja avaa seuraava&amp;lt;/menuchoice&amp;gt;, jos haluat jatkaa seuraavaan viestiin tai &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; kotoistamistekstin tallentamiseksi, jos haluat lopettaa työskentelyn.&lt;br /&gt;
&lt;br /&gt;
{{Warning|2=Varoitus|Älä luo kotoistettua sivuavarianttia manuaalisesti (kirjoittamalla sivunimen/kielikoodin ja yrittämällä kotoistaa alkuperäistekstin). Tämä sotkee kotoistamisjärjestelmän ja yhtään suomennosta ei näytetä.}}&lt;br /&gt;
&lt;br /&gt;
== Vihjeitä == &lt;br /&gt;
&lt;br /&gt;
=== Kuvan näyttämisohjeita === &lt;br /&gt;
&lt;br /&gt;
Tyypillinen esimerkki on &amp;lt;nowiki&amp;gt;[[Image:Plasma-kickoff.jpg|right|160px]]&amp;lt;/nowiki&amp;gt;.  Tämä on koko järjestelmäkäsky kuvan näyttämiseksi. Mitään siitä ei kotoisteta.&lt;br /&gt;
&lt;br /&gt;
=== Luokkaohjeet ===&lt;br /&gt;
&lt;br /&gt;
Ajattele tässä asiayhteydessä sanaa &amp;quot;Category&amp;quot; järjestelmäsanana, jota ei siksi pitäisi kotoistaa.  Esimerkiksi, &amp;lt;nowiki&amp;gt;[[Category:Administration]]&amp;lt;/nowiki&amp;gt; tulisi &amp;lt;nowiki&amp;gt;[[Category:Administrasi/id]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Johdonmukaisuuden vuoksi UserBase:ssa on hyväksyttyjen kotoistamisien luettelot.  Kotoistamisryhmät saattavat havaita samanlaiset luettelot hyödyllisiksi.  Sellaisia taulukkoja voidaan nähdä osoitteessa [{{UB}}Translation_Help_Needed Kotoistamisapua tarvitaan].  Pyydä apua, jos tarvitset sitä.&lt;br /&gt;
&lt;br /&gt;
=== Linkit muille sivuille TechBase-sivustolla === &lt;br /&gt;
&lt;br /&gt;
Nämä ovat muodoltaan &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Other page|linkkiteksti]]&amp;lt;/nowiki&amp;gt; Linkki pitäisi jättää kotoistamatta, kun taas linkin teksti on aina kotoistettava. Ellei linkin teksti on läsnä, lisätään sopiva (kotoistettu) linkin teksti.&lt;br /&gt;
&lt;br /&gt;
{{Note|2=Huomaa:|&amp;quot;myLanguage&amp;quot; yrittää ladata linkin kotoistetun version kielellä, jonka olet asettanut omiin asetuksiisi. Jos lataaminen epäonnistuu, se lataa vain englanninkielisen alkuperäistekstin, joten on turvallista käyttää sitä kaikissa sisäisissä linkeissä.}}&lt;br /&gt;
&lt;br /&gt;
=== Linkit ulkopuolisille sivustoille === &lt;br /&gt;
&lt;br /&gt;
Nämä saavat muodon  &amp;lt;nowiki&amp;gt;[http://example.com linkkiteksti]&amp;lt;/nowiki&amp;gt;.  Kuten sisäisissä linkeissä, säilytä varsinainen linkki ja kotoista linkkiteksti.&lt;br /&gt;
&lt;br /&gt;
=== Linkit sivupalkissa ===&lt;br /&gt;
&lt;br /&gt;
Ohjeita sivupalkkilinkkien kotoistamiseen löytyy osoitteesta [[Modifying_the_Sidebar#Translating_Sidebar_Items]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Tietolaatikot === &lt;br /&gt;
&lt;br /&gt;
Nämä yleensä koostuvat otsakesanasta &amp;quot;Information&amp;quot; ja muokattavasta tietotekstistä.  Jos sana &amp;quot;Information&amp;quot; ei ole tunnistettavissa kielelläsi, saatat tarvita kotoistetun version mallinteesta.  Kysy, jos tarvitset apua tämän kanssa.&lt;br /&gt;
&lt;br /&gt;
=== Kotoistetut yksiköt on merkitty sumeana === &lt;br /&gt;
&lt;br /&gt;
Joskus saattaa tapahtua, että sinun on kotoistettava sivu, mutta kotoistaminen on merkitty vaillinaiseksi. Tietyt virheet alkuperäissivun merkkauskielen merkeissä voivat aiheuttaa tämän. Yleisin virhetyyppi on parittomat sulkumerkit tai lainausmerkit. Kotoistamisjärjestelmä vaatii, että kaikilla avaavilla sulkumerkeillä ('[', '{' tai '(' ) on täsmäävä sulkeva sulkumerkki (']', '}' tai ')' ) samassa kotoistamisyksikössä, muutoin kotoistamista pidetään vaillinaisena.&lt;br /&gt;
&lt;br /&gt;
Sama sääntö ei ole pakollinen wiki-ohjelmistossa, joten kirjoittajat helposti sortuvat noihin virheisiin. Jos sulkumerkki yksinkertaisesti puuttuu, niin lisää se. Joskus sulkumerkkien sisään suljettu sisältö ulottuu useampaan kuin yhteen kotoistamisyksikköön, joten täsmäävä sulkeva lainausmerkki on myöhemmässä yksikössä. Tässä tapauksessa tarvitset parilliset lainausmerkit molemmissa yksiköissä, mutta et voi yksinkertaisesti lisätä sulkumerkkejä muuttamatta muotoilun merkitystä, joten sinun on kommentoitava piiloon lisätyt sulkumerkit, kuten tämä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt;&amp;lt;!--}}--&amp;gt;{{Info|1=Pitkän tietolaatikon alku... &amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
ja myöhemmässä yksikössä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt; ...pitkän tietolaatikon loppu}}&amp;lt;!--{{--&amp;gt;&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Jos rikkova sulkumerkki on osa hymiötä, korvaa se emoticon-kuvakkeella. Vakiohymiötä varten &amp;lt;!--(--&amp;gt;:-) voit käyttää mallinetta &amp;lt;nowiki&amp;gt;{{Smiley}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Korjaa myös alkuperäissivu, jotta muilla kotoistajilla ei ole sama pulma, tai jätä viesti keskustelusivulle.&lt;br /&gt;
&lt;br /&gt;
=== Kielitilastojen epäjohdonmukaisuuksia === &lt;br /&gt;
&lt;br /&gt;
Saatat havaita lievää epäjohdonmukaisuutta LanguageStats-sivulla osoitetuissa prosenttiluvuissa ja kielipalkin prosenttiluvuissa. Tämä on normaalia. LanguageStats vertaa vain niiden viestien lukumäärää, jotka ovat kotoistamattomia tai vanhentuneita. Kielipalkkitilasto yrittää olla älykkäämpi. Esimerkiksi yhdellä sivulla (100 viestiä) 8:ssa viestissä oli pieni (uudelleen-lajittelun-aiheuttama) muutos. Jokaisessa tapauksessa kyse oli yksittäisestä sanasta. Kahdessa tilastossa on 8% ero, koska se oli viestien oleellinen osa, mutta pieni osa koko kokoistamisesta.&lt;br /&gt;
&lt;br /&gt;
=== Jos käytät Chromium- tai Chrome-selainta... === &lt;br /&gt;
&lt;br /&gt;
Ole tietoinen, että Chromium-selaimessa on jonkinlainen välimuistipulma. Olen huomannut, että jopa pakotetuilla virkistyksillä jotkut tilastot eivät näy kuten niiden pitäisi näkyä (olen nähnyt vaikutuksia myös muissa asioissa), vaikka sama sivu Firefox-selaimessa avattuna näyttää tilastot oikein.&lt;br /&gt;
&lt;br /&gt;
== Katso myös == &lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* [http://translatewiki.net/wiki/Translating:Page_translation_feature#Translators]&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Translator_Help]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Translate_a_Page/23/fi</id>
		<title>Translations:Translate a Page/23/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Translate_a_Page/23/fi"/>
				<updated>2012-12-23T15:58:43Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|2=Huomaa:|&amp;quot;myLanguage&amp;quot; yrittää ladata linkin kotoistetun version kielellä, jonka olet asettanut omiin asetuksiisi. Jos lataaminen epäonnistuu, se lataa vain englanninkielisen alkuperäistekstin, joten on turvallista käyttää sitä kaikissa sisäisissä linkeissä.}}&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Translate_a_Page/23/fi</id>
		<title>Translations:Translate a Page/23/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Translate_a_Page/23/fi"/>
				<updated>2012-12-23T15:57:38Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{2=Huomaa:|&amp;quot;myLanguage&amp;quot; yrittää ladata linkin kotoistetun version kielellä, jonka olet asettanut omiin asetuksiisi. Jos lataaminen epäonnistuu, se lataa vain englanninkielisen alkuperäistekstin, joten on turvallista käyttää sitä kaikissa sisäisissä linkeissä.}}&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translate_a_Page/fi</id>
		<title>Translate a Page/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translate_a_Page/fi"/>
				<updated>2012-12-23T15:57:38Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Käytettävissä olevat työkalut == &lt;br /&gt;
&lt;br /&gt;
* [[Special:myLanguage/Translation Workflow|Kotoistamistyön kulku]] kuvaa työkulun siirryttäessä uuteen kotoistamisjärjestelmään&lt;br /&gt;
&lt;br /&gt;
== Työnkulku == &lt;br /&gt;
&lt;br /&gt;
* Pyyntö lisäämisestä kotoistamisryhmään:&lt;br /&gt;
** Napsauta kohdetta [[Special:myLanguage/Translator Account|Hae kotoistajatili]] sivupalkissa&lt;br /&gt;
** Napsauta &amp;lt;menuchoice&amp;gt;Muokkaa&amp;lt;/menuchoice&amp;gt;-kuvaketta [[Image:Userbase-edit.png|14px]] ja kirjoita käyttäjänimesi, kieli, jolle haluat kotoistaa ja aiotko kotoistaa tekstiä erillistiedostoissa&lt;br /&gt;
** Käytä &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; tietojen tallentamiseksi&lt;br /&gt;
&lt;br /&gt;
* Kun käyttäjätilisi on lisätty ryhmään (sinun pitäisi saada siitä ilmoitus), napsauta kohdetta [[Special:LanguageStats|Aloita kotoistaminen]] sivupalkissa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita se kieli, jolle haluat kotoistaa &amp;lt;menuchoice&amp;gt;Kielikoodi&amp;lt;/menuchoice&amp;gt;-valintaan ja napsauta kohdetta &amp;lt;menuchoice&amp;gt;Siirry&amp;lt;/menuchoice&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Note|2=Huomaa|Kielikoodin ''en'' (englanti) kirjoittaminen kielikoodivalintaan ei näytä yhtään kotoistusviestiä, koska kaikki alkuperäinen sisältö on kirjoitettu englanniksi.}}&lt;br /&gt;
&lt;br /&gt;
* Napsauta luettelossa sivua, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Aseta '''Kotoista sivu''' asetuksessa &amp;lt;menuchoice&amp;gt;Katso kaikki kotoistamattomat viestit&amp;lt;/menuchoice&amp;gt; ensimmäisessä pudotusvalikkoluettelossa&lt;br /&gt;
&lt;br /&gt;
* Tarkista, että näkyvissä on oikea kielikoodi&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;menuchoice&amp;gt;Navigointi&amp;lt;/menuchoice&amp;gt;-osassa napsauta linkkiä sen viestin vasemmalla puolella, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita kotoistamisteksti - Google-ehdotus tarjotaan viitteenä, mutta oma kotoistamisteksti on tavallisesti parempi.&lt;br /&gt;
&lt;br /&gt;
* Napsauta kohdetta &amp;lt;menuchoice&amp;gt;Tallenna ja avaa seuraava&amp;lt;/menuchoice&amp;gt;, jos haluat jatkaa seuraavaan viestiin tai &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; kotoistamistekstin tallentamiseksi, jos haluat lopettaa työskentelyn.&lt;br /&gt;
&lt;br /&gt;
{{Warning|2=Varoitus|Älä luo kotoistettua sivuavarianttia manuaalisesti (kirjoittamalla sivunimen/kielikoodin ja yrittämällä kotoistaa alkuperäistekstin). Tämä sotkee kotoistamisjärjestelmän ja yhtään suomennosta ei näytetä.}}&lt;br /&gt;
&lt;br /&gt;
== Vihjeitä == &lt;br /&gt;
&lt;br /&gt;
=== Kuvan näyttämisohjeita === &lt;br /&gt;
&lt;br /&gt;
Tyypillinen esimerkki on &amp;lt;nowiki&amp;gt;[[Image:Plasma-kickoff.jpg|right|160px]]&amp;lt;/nowiki&amp;gt;.  Tämä on koko järjestelmäkäsky kuvan näyttämiseksi. Mitään siitä ei kotoisteta.&lt;br /&gt;
&lt;br /&gt;
=== Luokkaohjeet ===&lt;br /&gt;
&lt;br /&gt;
Ajattele tässä asiayhteydessä sanaa &amp;quot;Category&amp;quot; järjestelmäsanana, jota ei siksi pitäisi kotoistaa.  Esimerkiksi, &amp;lt;nowiki&amp;gt;[[Category:Administration]]&amp;lt;/nowiki&amp;gt; tulisi &amp;lt;nowiki&amp;gt;[[Category:Administrasi/id]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Johdonmukaisuuden vuoksi UserBase:ssa on hyväksyttyjen kotoistamisien luettelot.  Kotoistamisryhmät saattavat havaita samanlaiset luettelot hyödyllisiksi.  Sellaisia taulukkoja voidaan nähdä osoitteessa [{{UB}}Translation_Help_Needed Kotoistamisapua tarvitaan].  Pyydä apua, jos tarvitset sitä.&lt;br /&gt;
&lt;br /&gt;
=== Linkit muille sivuille TechBase-sivustolla === &lt;br /&gt;
&lt;br /&gt;
Nämä ovat muodoltaan &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Other page|linkkiteksti]]&amp;lt;/nowiki&amp;gt; Linkki pitäisi jättää kotoistamatta, kun taas linkin teksti on aina kotoistettava. Ellei linkin teksti on läsnä, lisätään sopiva (kotoistettu) linkin teksti.&lt;br /&gt;
&lt;br /&gt;
{{2=Huomaa:|&amp;quot;myLanguage&amp;quot; yrittää ladata linkin kotoistetun version kielellä, jonka olet asettanut omiin asetuksiisi. Jos lataaminen epäonnistuu, se lataa vain englanninkielisen alkuperäistekstin, joten on turvallista käyttää sitä kaikissa sisäisissä linkeissä.}}&lt;br /&gt;
&lt;br /&gt;
=== Linkit ulkopuolisille sivustoille === &lt;br /&gt;
&lt;br /&gt;
Nämä saavat muodon  &amp;lt;nowiki&amp;gt;[http://example.com linkkiteksti]&amp;lt;/nowiki&amp;gt;.  Kuten sisäisissä linkeissä, säilytä varsinainen linkki ja kotoista linkkiteksti.&lt;br /&gt;
&lt;br /&gt;
=== Linkit sivupalkissa ===&lt;br /&gt;
&lt;br /&gt;
Ohjeita sivupalkkilinkkien kotoistamiseen löytyy osoitteesta [[Modifying_the_Sidebar#Translating_Sidebar_Items]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Tietolaatikot === &lt;br /&gt;
&lt;br /&gt;
Nämä yleensä koostuvat otsakesanasta &amp;quot;Information&amp;quot; ja muokattavasta tietotekstistä.  Jos sana &amp;quot;Information&amp;quot; ei ole tunnistettavissa kielelläsi, saatat tarvita kotoistetun version mallinteesta.  Kysy, jos tarvitset apua tämän kanssa.&lt;br /&gt;
&lt;br /&gt;
=== Kotoistetut yksiköt on merkitty sumeana === &lt;br /&gt;
&lt;br /&gt;
Joskus saattaa tapahtua, että sinun on kotoistettava sivu, mutta kotoistaminen on merkitty vaillinaiseksi. Tietyt virheet alkuperäissivun merkkauskielen merkeissä voivat aiheuttaa tämän. Yleisin virhetyyppi on parittomat sulkumerkit tai lainausmerkit. Kotoistamisjärjestelmä vaatii, että kaikilla avaavilla sulkumerkeillä ('[', '{' tai '(' ) on täsmäävä sulkeva sulkumerkki (']', '}' tai ')' ) samassa kotoistamisyksikössä, muutoin kotoistamista pidetään vaillinaisena.&lt;br /&gt;
&lt;br /&gt;
Sama sääntö ei ole pakollinen wiki-ohjelmistossa, joten kirjoittajat helposti sortuvat noihin virheisiin. Jos sulkumerkki yksinkertaisesti puuttuu, niin lisää se. Joskus sulkumerkkien sisään suljettu sisältö ulottuu useampaan kuin yhteen kotoistamisyksikköön, joten täsmäävä sulkeva lainausmerkki on myöhemmässä yksikössä. Tässä tapauksessa tarvitset parilliset lainausmerkit molemmissa yksiköissä, mutta et voi yksinkertaisesti lisätä sulkumerkkejä muuttamatta muotoilun merkitystä, joten sinun on kommentoitava piiloon lisätyt sulkumerkit, kuten tämä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt;&amp;lt;!--}}--&amp;gt;{{Info|1=Pitkän tietolaatikon alku... &amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
ja myöhemmässä yksikössä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt; ...pitkän tietolaatikon loppu}}&amp;lt;!--{{--&amp;gt;&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Jos rikkova sulkumerkki on osa hymiötä, korvaa se emoticon-kuvakkeella. Vakiohymiötä varten &amp;lt;!--(--&amp;gt;:-) voit käyttää mallinetta &amp;lt;nowiki&amp;gt;{{Smiley}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Korjaa myös alkuperäissivu, jotta muilla kotoistajilla ei ole sama pulma, tai jätä viesti keskustelusivulle.&lt;br /&gt;
&lt;br /&gt;
=== Kielitilastojen epäjohdonmukaisuuksia === &lt;br /&gt;
&lt;br /&gt;
Saatat havaita lievää epäjohdonmukaisuutta LanguageStats-sivulla osoitetuissa prosenttiluvuissa ja kielipalkin prosenttiluvuissa. Tämä on normaalia. LanguageStats vertaa vain niiden viestien lukumäärää, jotka ovat kotoistamattomia tai vanhentuneita. Kielipalkkitilasto yrittää olla älykkäämpi. Esimerkiksi yhdellä sivulla (100 viestiä) 8:ssa viestissä oli pieni (uudelleen-lajittelun-aiheuttama) muutos. Jokaisessa tapauksessa kyse oli yksittäisestä sanasta. Kahdessa tilastossa on 8% ero, koska se oli viestien oleellinen osa, mutta pieni osa koko kokoistamisesta.&lt;br /&gt;
&lt;br /&gt;
=== Jos käytät Chromium- tai Chrome-selainta... === &lt;br /&gt;
&lt;br /&gt;
Ole tietoinen, että Chromium-selaimessa on jonkinlainen välimuistipulma. Olen huomannut, että jopa pakotetuilla virkistyksillä jotkut tilastot eivät näy kuten niiden pitäisi näkyä (olen nähnyt vaikutuksia myös muissa asioissa), vaikka sama sivu Firefox-selaimessa avattuna näyttää tilastot oikein.&lt;br /&gt;
&lt;br /&gt;
== Katso myös == &lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* [http://translatewiki.net/wiki/Translating:Page_translation_feature#Translators]&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Translator_Help]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translate_a_Page/fi</id>
		<title>Translate a Page/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translate_a_Page/fi"/>
				<updated>2012-12-23T15:55:15Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Käytettävissä olevat työkalut == &lt;br /&gt;
&lt;br /&gt;
* [[Special:myLanguage/Translation Workflow|Kotoistamistyön kulku]] kuvaa työkulun siirryttäessä uuteen kotoistamisjärjestelmään&lt;br /&gt;
&lt;br /&gt;
== Työnkulku == &lt;br /&gt;
&lt;br /&gt;
* Pyyntö lisäämisestä kotoistamisryhmään:&lt;br /&gt;
** Napsauta kohdetta [[Special:myLanguage/Translator Account|Hae kotoistajatili]] sivupalkissa&lt;br /&gt;
** Napsauta &amp;lt;menuchoice&amp;gt;Muokkaa&amp;lt;/menuchoice&amp;gt;-kuvaketta [[Image:Userbase-edit.png|14px]] ja kirjoita käyttäjänimesi, kieli, jolle haluat kotoistaa ja aiotko kotoistaa tekstiä erillistiedostoissa&lt;br /&gt;
** Käytä &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; tietojen tallentamiseksi&lt;br /&gt;
&lt;br /&gt;
* Kun käyttäjätilisi on lisätty ryhmään (sinun pitäisi saada siitä ilmoitus), napsauta kohdetta [[Special:LanguageStats|Aloita kotoistaminen]] sivupalkissa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita se kieli, jolle haluat kotoistaa &amp;lt;menuchoice&amp;gt;Kielikoodi&amp;lt;/menuchoice&amp;gt;-valintaan ja napsauta kohdetta &amp;lt;menuchoice&amp;gt;Siirry&amp;lt;/menuchoice&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Note|2=Huomaa|Kielikoodin ''en'' (englanti) kirjoittaminen kielikoodivalintaan ei näytä yhtään kotoistusviestiä, koska kaikki alkuperäinen sisältö on kirjoitettu englanniksi.}}&lt;br /&gt;
&lt;br /&gt;
* Napsauta luettelossa sivua, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Aseta '''Kotoista sivu''' asetuksessa &amp;lt;menuchoice&amp;gt;Katso kaikki kotoistamattomat viestit&amp;lt;/menuchoice&amp;gt; ensimmäisessä pudotusvalikkoluettelossa&lt;br /&gt;
&lt;br /&gt;
* Tarkista, että näkyvissä on oikea kielikoodi&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;menuchoice&amp;gt;Navigointi&amp;lt;/menuchoice&amp;gt;-osassa napsauta linkkiä sen viestin vasemmalla puolella, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita kotoistamisteksti - Google-ehdotus tarjotaan viitteenä, mutta oma kotoistamisteksti on tavallisesti parempi.&lt;br /&gt;
&lt;br /&gt;
* Napsauta kohdetta &amp;lt;menuchoice&amp;gt;Tallenna ja avaa seuraava&amp;lt;/menuchoice&amp;gt;, jos haluat jatkaa seuraavaan viestiin tai &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; kotoistamistekstin tallentamiseksi, jos haluat lopettaa työskentelyn.&lt;br /&gt;
&lt;br /&gt;
{{Warning|2=Varoitus|Älä luo kotoistettua sivuavarianttia manuaalisesti (kirjoittamalla sivunimen/kielikoodin ja yrittämällä kotoistaa alkuperäistekstin). Tämä sotkee kotoistamisjärjestelmän ja yhtään suomennosta ei näytetä.}}&lt;br /&gt;
&lt;br /&gt;
== Vihjeitä == &lt;br /&gt;
&lt;br /&gt;
=== Kuvan näyttämisohjeita === &lt;br /&gt;
&lt;br /&gt;
Tyypillinen esimerkki on &amp;lt;nowiki&amp;gt;[[Image:Plasma-kickoff.jpg|right|160px]]&amp;lt;/nowiki&amp;gt;.  Tämä on koko järjestelmäkäsky kuvan näyttämiseksi. Mitään siitä ei kotoisteta.&lt;br /&gt;
&lt;br /&gt;
=== Luokkaohjeet ===&lt;br /&gt;
&lt;br /&gt;
Ajattele tässä asiayhteydessä sanaa &amp;quot;Category&amp;quot; järjestelmäsanana, jota ei siksi pitäisi kotoistaa.  Esimerkiksi, &amp;lt;nowiki&amp;gt;[[Category:Administration]]&amp;lt;/nowiki&amp;gt; tulisi &amp;lt;nowiki&amp;gt;[[Category:Administrasi/id]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Johdonmukaisuuden vuoksi UserBase:ssa on hyväksyttyjen kotoistamisien luettelot.  Kotoistamisryhmät saattavat havaita samanlaiset luettelot hyödyllisiksi.  Sellaisia taulukkoja voidaan nähdä osoitteessa [{{UB}}Translation_Help_Needed Kotoistamisapua tarvitaan].  Pyydä apua, jos tarvitset sitä.&lt;br /&gt;
&lt;br /&gt;
=== Linkit muille sivuille TechBase-sivustolla === &lt;br /&gt;
&lt;br /&gt;
Nämä ovat muodoltaan &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Other page|linkkiteksti]]&amp;lt;/nowiki&amp;gt; Linkki pitäisi jättää kotoistamatta, kun taas linkin teksti on aina kotoistettava. Ellei linkin teksti on läsnä, lisätään sopiva (kotoistettu) linkin teksti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
Huomaa: &amp;quot;myLanguage&amp;quot; yrittää ladata linkin kotoistetun version kielellä, jonka olet asettanut omiin asetuksiisi. Jos lataaminen epäonnistuu, se lataa vain englanninkielisen alkuperäistekstin, joten on turvallista käyttää sitä kaikissa sisäisissä linkeissä.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Linkit ulkopuolisille sivustoille === &lt;br /&gt;
&lt;br /&gt;
Nämä saavat muodon  &amp;lt;nowiki&amp;gt;[http://example.com linkkiteksti]&amp;lt;/nowiki&amp;gt;.  Kuten sisäisissä linkeissä, säilytä varsinainen linkki ja kotoista linkkiteksti.&lt;br /&gt;
&lt;br /&gt;
=== Linkit sivupalkissa ===&lt;br /&gt;
&lt;br /&gt;
Ohjeita sivupalkkilinkkien kotoistamiseen löytyy osoitteesta [[Modifying_the_Sidebar#Translating_Sidebar_Items]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Tietolaatikot === &lt;br /&gt;
&lt;br /&gt;
Nämä yleensä koostuvat otsakesanasta &amp;quot;Information&amp;quot; ja muokattavasta tietotekstistä.  Jos sana &amp;quot;Information&amp;quot; ei ole tunnistettavissa kielelläsi, saatat tarvita kotoistetun version mallinteesta.  Kysy, jos tarvitset apua tämän kanssa.&lt;br /&gt;
&lt;br /&gt;
=== Kotoistetut yksiköt on merkitty sumeana === &lt;br /&gt;
&lt;br /&gt;
Joskus saattaa tapahtua, että sinun on kotoistettava sivu, mutta kotoistaminen on merkitty vaillinaiseksi. Tietyt virheet alkuperäissivun merkkauskielen merkeissä voivat aiheuttaa tämän. Yleisin virhetyyppi on parittomat sulkumerkit tai lainausmerkit. Kotoistamisjärjestelmä vaatii, että kaikilla avaavilla sulkumerkeillä ('[', '{' tai '(' ) on täsmäävä sulkeva sulkumerkki (']', '}' tai ')' ) samassa kotoistamisyksikössä, muutoin kotoistamista pidetään vaillinaisena.&lt;br /&gt;
&lt;br /&gt;
Sama sääntö ei ole pakollinen wiki-ohjelmistossa, joten kirjoittajat helposti sortuvat noihin virheisiin. Jos sulkumerkki yksinkertaisesti puuttuu, niin lisää se. Joskus sulkumerkkien sisään suljettu sisältö ulottuu useampaan kuin yhteen kotoistamisyksikköön, joten täsmäävä sulkeva lainausmerkki on myöhemmässä yksikössä. Tässä tapauksessa tarvitset parilliset lainausmerkit molemmissa yksiköissä, mutta et voi yksinkertaisesti lisätä sulkumerkkejä muuttamatta muotoilun merkitystä, joten sinun on kommentoitava piiloon lisätyt sulkumerkit, kuten tämä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt;&amp;lt;!--}}--&amp;gt;{{Info|1=Pitkän tietolaatikon alku... &amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
ja myöhemmässä yksikössä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt; ...pitkän tietolaatikon loppu}}&amp;lt;!--{{--&amp;gt;&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Jos rikkova sulkumerkki on osa hymiötä, korvaa se emoticon-kuvakkeella. Vakiohymiötä varten &amp;lt;!--(--&amp;gt;:-) voit käyttää mallinetta &amp;lt;nowiki&amp;gt;{{Smiley}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Korjaa myös alkuperäissivu, jotta muilla kotoistajilla ei ole sama pulma, tai jätä viesti keskustelusivulle.&lt;br /&gt;
&lt;br /&gt;
=== Kielitilastojen epäjohdonmukaisuuksia === &lt;br /&gt;
&lt;br /&gt;
Saatat havaita lievää epäjohdonmukaisuutta LanguageStats-sivulla osoitetuissa prosenttiluvuissa ja kielipalkin prosenttiluvuissa. Tämä on normaalia. LanguageStats vertaa vain niiden viestien lukumäärää, jotka ovat kotoistamattomia tai vanhentuneita. Kielipalkkitilasto yrittää olla älykkäämpi. Esimerkiksi yhdellä sivulla (100 viestiä) 8:ssa viestissä oli pieni (uudelleen-lajittelun-aiheuttama) muutos. Jokaisessa tapauksessa kyse oli yksittäisestä sanasta. Kahdessa tilastossa on 8% ero, koska se oli viestien oleellinen osa, mutta pieni osa koko kokoistamisesta.&lt;br /&gt;
&lt;br /&gt;
=== Jos käytät Chromium- tai Chrome-selainta... === &lt;br /&gt;
&lt;br /&gt;
Ole tietoinen, että Chromium-selaimessa on jonkinlainen välimuistipulma. Olen huomannut, että jopa pakotetuilla virkistyksillä jotkut tilastot eivät näy kuten niiden pitäisi näkyä (olen nähnyt vaikutuksia myös muissa asioissa), vaikka sama sivu Firefox-selaimessa avattuna näyttää tilastot oikein.&lt;br /&gt;
&lt;br /&gt;
== Katso myös == &lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* [http://translatewiki.net/wiki/Translating:Page_translation_feature#Translators]&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Translator_Help]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translate_a_Page/fi</id>
		<title>Translate a Page/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translate_a_Page/fi"/>
				<updated>2012-12-23T15:49:08Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Käytettävissä olevat työkalut == &lt;br /&gt;
&lt;br /&gt;
* [[Special:myLanguage/Translation Workflow|Kotoistamistyön kulku]] kuvaa työkulun siirryttäessä uuteen kotoistamisjärjestelmään&lt;br /&gt;
&lt;br /&gt;
== Työnkulku == &lt;br /&gt;
&lt;br /&gt;
* Pyyntö lisäämisestä kotoistamisryhmään:&lt;br /&gt;
** Napsauta kohdetta [[Special:myLanguage/Translator Account|Hae kotoistajatili]] sivupalkissa&lt;br /&gt;
** Napsauta &amp;lt;menuchoice&amp;gt;Muokkaa&amp;lt;/menuchoice&amp;gt;-kuvaketta [[Image:Userbase-edit.png|14px]] ja kirjoita käyttäjänimesi, kieli, jolle haluat kotoistaa ja aiotko kotoistaa tekstiä erillistiedostoissa&lt;br /&gt;
** Käytä &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; tietojen tallentamiseksi&lt;br /&gt;
&lt;br /&gt;
* Kun käyttäjätilisi on lisätty ryhmään (sinun pitäisi saada siitä ilmoitus), napsauta kohdetta [[Special:LanguageStats|Aloita kotoistaminen]] sivupalkissa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita se kieli, jolle haluat kotoistaa &amp;lt;menuchoice&amp;gt;Kielikoodi&amp;lt;/menuchoice&amp;gt;-valintaan ja napsauta kohdetta &amp;lt;menuchoice&amp;gt;Siirry&amp;lt;/menuchoice&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Note|2=Huomaa|Kielikoodin ''en'' (englanti) kirjoittaminen kielikoodivalintaan ei näytä yhtään kotoistusviestiä, koska kaikki alkuperäinen sisältö on kirjoitettu englanniksi.}}&lt;br /&gt;
&lt;br /&gt;
* Napsauta luettelossa sivua, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Aseta '''Kotoista sivu''' asetuksessa &amp;lt;menuchoice&amp;gt;Katso kaikki kotoistamattomat viestit&amp;lt;/menuchoice&amp;gt; ensimmäisessä pudotusvalikkoluettelossa&lt;br /&gt;
&lt;br /&gt;
* Tarkista, että näkyvissä on oikea kielikoodi&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;menuchoice&amp;gt;Navigointi&amp;lt;/menuchoice&amp;gt;-osassa napsauta linkkiä sen viestin vasemmalla puolella, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita kotoistamisteksti - Google-ehdotus tarjotaan viitteenä, mutta oma kotoistamisteksti on tavallisesti parempi.&lt;br /&gt;
&lt;br /&gt;
* Napsauta kohdetta &amp;lt;menuchoice&amp;gt;Tallenna ja avaa seuraava&amp;lt;/menuchoice&amp;gt;, jos haluat jatkaa seuraavaan viestiin tai &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; kotoistamistekstin tallentamiseksi, jos haluat lopettaa työskentelyn.&lt;br /&gt;
&lt;br /&gt;
{{Warning|2=Varoitus|Älä luo kotoistettua sivuavarianttia manuaalisesti (kirjoittamalla sivunimen/kielikoodin ja yrittämällä kotoistaa alkuperäistekstin). Tämä sotkee kotoistamisjärjestelmän ja yhtään suomennosta ei näytetä.}}&lt;br /&gt;
&lt;br /&gt;
== Vihjeitä == &lt;br /&gt;
&lt;br /&gt;
=== Kuvan näyttämisohjeita === &lt;br /&gt;
&lt;br /&gt;
Tyypillinen esimerkki on &amp;lt;nowiki&amp;gt;[[Image:Plasma-kickoff.jpg|right|160px]]&amp;lt;/nowiki&amp;gt;.  Tämä on koko järjestelmäkäsky kuvan näyttämiseksi. Mitään siitä ei kotoisteta.&lt;br /&gt;
&lt;br /&gt;
=== Luokkaohjeet ===&lt;br /&gt;
&lt;br /&gt;
Ajattele tässä asiayhteydessä sanaa &amp;quot;Category&amp;quot; järjestelmäsanana, jota ei siksi pitäisi kotoistaa.  Esimerkiksi, &amp;lt;nowiki&amp;gt;[[Category:Administration]]&amp;lt;/nowiki&amp;gt; tulisi &amp;lt;nowiki&amp;gt;[[Category:Administrasi/id]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
Johdonmukaisuuden vuoksi UserBase:ssa on hyväksyttyjen kotoistamisien luettelot.  Kotoistamisryhmät saattavat havaita samanlaiset luettelot hyödyllisiksi.  Sellaisia taulukkoja voidaan nähdä osoitteessa [{{UB}}Translation_Help_Needed Kotoistamisapua tarvitaan].  Pyydä apua, jos tarvitset sitä.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Linkit muille sivuille TechBase-sivustolla === &lt;br /&gt;
&lt;br /&gt;
Nämä ovat muodoltaan &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Other page|linkkiteksti]]&amp;lt;/nowiki&amp;gt; Linkki pitäisi jättää kotoistamatta, kun taas linkin teksti on aina kotoistettava. Ellei linkin teksti on läsnä, lisätään sopiva (kotoistettu) linkin teksti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
Huomaa: &amp;quot;myLanguage&amp;quot; yrittää ladata linkin kotoistetun version kielellä, jonka olet asettanut omiin asetuksiisi. Jos lataaminen epäonnistuu, se lataa vain englanninkielisen alkuperäistekstin, joten on turvallista käyttää sitä kaikissa sisäisissä linkeissä.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Linkit ulkopuolisille sivustoille === &lt;br /&gt;
&lt;br /&gt;
Nämä saavat muodon  &amp;lt;nowiki&amp;gt;[http://example.com linkkiteksti]&amp;lt;/nowiki&amp;gt;.  Kuten sisäisissä linkeissä, säilytä varsinainen linkki ja kotoista linkkiteksti.&lt;br /&gt;
&lt;br /&gt;
=== Linkit sivupalkissa ===&lt;br /&gt;
&lt;br /&gt;
Ohjeita sivupalkkilinkkien kotoistamiseen löytyy osoitteesta [[Modifying_the_Sidebar#Translating_Sidebar_Items]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Tietolaatikot === &lt;br /&gt;
&lt;br /&gt;
Nämä yleensä koostuvat otsakesanasta &amp;quot;Information&amp;quot; ja muokattavasta tietotekstistä.  Jos sana &amp;quot;Information&amp;quot; ei ole tunnistettavissa kielelläsi, saatat tarvita kotoistetun version mallinteesta.  Kysy, jos tarvitset apua tämän kanssa.&lt;br /&gt;
&lt;br /&gt;
=== Kotoistetut yksiköt on merkitty sumeana === &lt;br /&gt;
&lt;br /&gt;
Joskus saattaa tapahtua, että sinun on kotoistettava sivu, mutta kotoistaminen on merkitty vaillinaiseksi. Tietyt virheet alkuperäissivun merkkauskielen merkeissä voivat aiheuttaa tämän. Yleisin virhetyyppi on parittomat sulkumerkit tai lainausmerkit. Kotoistamisjärjestelmä vaatii, että kaikilla avaavilla sulkumerkeillä ('[', '{' tai '(' ) on täsmäävä sulkeva sulkumerkki (']', '}' tai ')' ) samassa kotoistamisyksikössä, muutoin kotoistamista pidetään vaillinaisena.&lt;br /&gt;
&lt;br /&gt;
Sama sääntö ei ole pakollinen wiki-ohjelmistossa, joten kirjoittajat helposti sortuvat noihin virheisiin. Jos sulkumerkki yksinkertaisesti puuttuu, niin lisää se. Joskus sulkumerkkien sisään suljettu sisältö ulottuu useampaan kuin yhteen kotoistamisyksikköön, joten täsmäävä sulkeva lainausmerkki on myöhemmässä yksikössä. Tässä tapauksessa tarvitset parilliset lainausmerkit molemmissa yksiköissä, mutta et voi yksinkertaisesti lisätä sulkumerkkejä muuttamatta muotoilun merkitystä, joten sinun on kommentoitava piiloon lisätyt sulkumerkit, kuten tämä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt;&amp;lt;!--}}--&amp;gt;{{Info|1=Pitkän tietolaatikon alku... &amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
ja myöhemmässä yksikössä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt; ...pitkän tietolaatikon loppu}}&amp;lt;!--{{--&amp;gt;&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Jos rikkova sulkumerkki on osa hymiötä, korvaa se emoticon-kuvakkeella. Vakiohymiötä varten &amp;lt;!--(--&amp;gt;:-) voit käyttää mallinetta &amp;lt;nowiki&amp;gt;{{Smiley}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Korjaa myös alkuperäissivu, jotta muilla kotoistajilla ei ole sama pulma, tai jätä viesti keskustelusivulle.&lt;br /&gt;
&lt;br /&gt;
=== Kielitilastojen epäjohdonmukaisuuksia === &lt;br /&gt;
&lt;br /&gt;
Saatat havaita lievää epäjohdonmukaisuutta LanguageStats-sivulla osoitetuissa prosenttiluvuissa ja kielipalkin prosenttiluvuissa. Tämä on normaalia. LanguageStats vertaa vain niiden viestien lukumäärää, jotka ovat kotoistamattomia tai vanhentuneita. Kielipalkkitilasto yrittää olla älykkäämpi. Esimerkiksi yhdellä sivulla (100 viestiä) 8:ssa viestissä oli pieni (uudelleen-lajittelun-aiheuttama) muutos. Jokaisessa tapauksessa kyse oli yksittäisestä sanasta. Kahdessa tilastossa on 8% ero, koska se oli viestien oleellinen osa, mutta pieni osa koko kokoistamisesta.&lt;br /&gt;
&lt;br /&gt;
=== Jos käytät Chromium- tai Chrome-selainta... === &lt;br /&gt;
&lt;br /&gt;
Ole tietoinen, että Chromium-selaimessa on jonkinlainen välimuistipulma. Olen huomannut, että jopa pakotetuilla virkistyksillä jotkut tilastot eivät näy kuten niiden pitäisi näkyä (olen nähnyt vaikutuksia myös muissa asioissa), vaikka sama sivu Firefox-selaimessa avattuna näyttää tilastot oikein.&lt;br /&gt;
&lt;br /&gt;
== Katso myös == &lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* [http://translatewiki.net/wiki/Translating:Page_translation_feature#Translators]&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Translator_Help]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Translate_a_Page/9/fi</id>
		<title>Translations:Translate a Page/9/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Translate_a_Page/9/fi"/>
				<updated>2012-12-23T15:49:07Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Aseta '''Kotoista sivu''' asetuksessa &amp;lt;menuchoice&amp;gt;Katso kaikki kotoistamattomat viestit&amp;lt;/menuchoice&amp;gt; ensimmäisessä pudotusvalikkoluettelossa&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translate_a_Page/fi</id>
		<title>Translate a Page/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translate_a_Page/fi"/>
				<updated>2012-12-23T15:48:03Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Käytettävissä olevat työkalut == &lt;br /&gt;
&lt;br /&gt;
* [[Special:myLanguage/Translation Workflow|Kotoistamistyön kulku]] kuvaa työkulun siirryttäessä uuteen kotoistamisjärjestelmään&lt;br /&gt;
&lt;br /&gt;
== Työnkulku == &lt;br /&gt;
&lt;br /&gt;
* Pyyntö lisäämisestä kotoistamisryhmään:&lt;br /&gt;
** Napsauta kohdetta [[Special:myLanguage/Translator Account|Hae kotoistajatili]] sivupalkissa&lt;br /&gt;
** Napsauta &amp;lt;menuchoice&amp;gt;Muokkaa&amp;lt;/menuchoice&amp;gt;-kuvaketta [[Image:Userbase-edit.png|14px]] ja kirjoita käyttäjänimesi, kieli, jolle haluat kotoistaa ja aiotko kotoistaa tekstiä erillistiedostoissa&lt;br /&gt;
** Käytä &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; tietojen tallentamiseksi&lt;br /&gt;
&lt;br /&gt;
* Kun käyttäjätilisi on lisätty ryhmään (sinun pitäisi saada siitä ilmoitus), napsauta kohdetta [[Special:LanguageStats|Aloita kotoistaminen]] sivupalkissa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita se kieli, jolle haluat kotoistaa &amp;lt;menuchoice&amp;gt;Kielikoodi&amp;lt;/menuchoice&amp;gt;-valintaan ja napsauta kohdetta &amp;lt;menuchoice&amp;gt;Siirry&amp;lt;/menuchoice&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Note|2=Huomaa|Kielikoodin ''en'' (englanti) kirjoittaminen kielikoodivalintaan ei näytä yhtään kotoistusviestiä, koska kaikki alkuperäinen sisältö on kirjoitettu englanniksi.}}&lt;br /&gt;
&lt;br /&gt;
* Napsauta luettelossa sivua, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Aseta '''Kotoista sivu''' asetuksessa &amp;lt;menuchoice&amp;gt;Katso kaikki kotoistamattomat viestit&amp;lt;/menuchoice&amp;gt; ensimmäisessä vetovalikkoluettelossa&lt;br /&gt;
&lt;br /&gt;
* Tarkista, että näkyvissä on oikea kielikoodi&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;menuchoice&amp;gt;Navigointi&amp;lt;/menuchoice&amp;gt;-osassa napsauta linkkiä sen viestin vasemmalla puolella, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita kotoistamisteksti - Google-ehdotus tarjotaan viitteenä, mutta oma kotoistamisteksti on tavallisesti parempi.&lt;br /&gt;
&lt;br /&gt;
* Napsauta kohdetta &amp;lt;menuchoice&amp;gt;Tallenna ja avaa seuraava&amp;lt;/menuchoice&amp;gt;, jos haluat jatkaa seuraavaan viestiin tai &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; kotoistamistekstin tallentamiseksi, jos haluat lopettaa työskentelyn.&lt;br /&gt;
&lt;br /&gt;
{{Warning|2=Varoitus|Älä luo kotoistettua sivuavarianttia manuaalisesti (kirjoittamalla sivunimen/kielikoodin ja yrittämällä kotoistaa alkuperäistekstin). Tämä sotkee kotoistamisjärjestelmän ja yhtään suomennosta ei näytetä.}}&lt;br /&gt;
&lt;br /&gt;
== Vihjeitä == &lt;br /&gt;
&lt;br /&gt;
=== Kuvan näyttämisohjeita === &lt;br /&gt;
&lt;br /&gt;
Tyypillinen esimerkki on &amp;lt;nowiki&amp;gt;[[Image:Plasma-kickoff.jpg|right|160px]]&amp;lt;/nowiki&amp;gt;.  Tämä on koko järjestelmäkäsky kuvan näyttämiseksi. Mitään siitä ei kotoisteta.&lt;br /&gt;
&lt;br /&gt;
=== Luokkaohjeet ===&lt;br /&gt;
&lt;br /&gt;
Ajattele tässä asiayhteydessä sanaa &amp;quot;Category&amp;quot; järjestelmäsanana, jota ei siksi pitäisi kotoistaa.  Esimerkiksi, &amp;lt;nowiki&amp;gt;[[Category:Administration]]&amp;lt;/nowiki&amp;gt; tulisi &amp;lt;nowiki&amp;gt;[[Category:Administrasi/id]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
Johdonmukaisuuden vuoksi UserBase:ssa on hyväksyttyjen kotoistamisien luettelot.  Kotoistamisryhmät saattavat havaita samanlaiset luettelot hyödyllisiksi.  Sellaisia taulukkoja voidaan nähdä osoitteessa [{{UB}}Translation_Help_Needed Kotoistamisapua tarvitaan].  Pyydä apua, jos tarvitset sitä.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Linkit muille sivuille TechBase-sivustolla === &lt;br /&gt;
&lt;br /&gt;
Nämä ovat muodoltaan &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Other page|linkkiteksti]]&amp;lt;/nowiki&amp;gt; Linkki pitäisi jättää kotoistamatta, kun taas linkin teksti on aina kotoistettava. Ellei linkin teksti on läsnä, lisätään sopiva (kotoistettu) linkin teksti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
Huomaa: &amp;quot;myLanguage&amp;quot; yrittää ladata linkin kotoistetun version kielellä, jonka olet asettanut omiin asetuksiisi. Jos lataaminen epäonnistuu, se lataa vain englanninkielisen alkuperäistekstin, joten on turvallista käyttää sitä kaikissa sisäisissä linkeissä.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Linkit ulkopuolisille sivustoille === &lt;br /&gt;
&lt;br /&gt;
Nämä saavat muodon  &amp;lt;nowiki&amp;gt;[http://example.com linkkiteksti]&amp;lt;/nowiki&amp;gt;.  Kuten sisäisissä linkeissä, säilytä varsinainen linkki ja kotoista linkkiteksti.&lt;br /&gt;
&lt;br /&gt;
=== Linkit sivupalkissa ===&lt;br /&gt;
&lt;br /&gt;
Ohjeita sivupalkkilinkkien kotoistamiseen löytyy osoitteesta [[Modifying_the_Sidebar#Translating_Sidebar_Items]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Tietolaatikot === &lt;br /&gt;
&lt;br /&gt;
Nämä yleensä koostuvat otsakesanasta &amp;quot;Information&amp;quot; ja muokattavasta tietotekstistä.  Jos sana &amp;quot;Information&amp;quot; ei ole tunnistettavissa kielelläsi, saatat tarvita kotoistetun version mallinteesta.  Kysy, jos tarvitset apua tämän kanssa.&lt;br /&gt;
&lt;br /&gt;
=== Kotoistetut yksiköt on merkitty sumeana === &lt;br /&gt;
&lt;br /&gt;
Joskus saattaa tapahtua, että sinun on kotoistettava sivu, mutta kotoistaminen on merkitty vaillinaiseksi. Tietyt virheet alkuperäissivun merkkauskielen merkeissä voivat aiheuttaa tämän. Yleisin virhetyyppi on parittomat sulkumerkit tai lainausmerkit. Kotoistamisjärjestelmä vaatii, että kaikilla avaavilla sulkumerkeillä ('[', '{' tai '(' ) on täsmäävä sulkeva sulkumerkki (']', '}' tai ')' ) samassa kotoistamisyksikössä, muutoin kotoistamista pidetään vaillinaisena.&lt;br /&gt;
&lt;br /&gt;
Sama sääntö ei ole pakollinen wiki-ohjelmistossa, joten kirjoittajat helposti sortuvat noihin virheisiin. Jos sulkumerkki yksinkertaisesti puuttuu, niin lisää se. Joskus sulkumerkkien sisään suljettu sisältö ulottuu useampaan kuin yhteen kotoistamisyksikköön, joten täsmäävä sulkeva lainausmerkki on myöhemmässä yksikössä. Tässä tapauksessa tarvitset parilliset lainausmerkit molemmissa yksiköissä, mutta et voi yksinkertaisesti lisätä sulkumerkkejä muuttamatta muotoilun merkitystä, joten sinun on kommentoitava piiloon lisätyt sulkumerkit, kuten tämä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt;&amp;lt;!--}}--&amp;gt;{{Info|1=Pitkän tietolaatikon alku... &amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
ja myöhemmässä yksikössä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt; ...pitkän tietolaatikon loppu}}&amp;lt;!--{{--&amp;gt;&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Jos rikkova sulkumerkki on osa hymiötä, korvaa se emoticon-kuvakkeella. Vakiohymiötä varten &amp;lt;!--(--&amp;gt;:-) voit käyttää mallinetta &amp;lt;nowiki&amp;gt;{{Smiley}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Korjaa myös alkuperäissivu, jotta muilla kotoistajilla ei ole sama pulma, tai jätä viesti keskustelusivulle.&lt;br /&gt;
&lt;br /&gt;
=== Kielitilastojen epäjohdonmukaisuuksia === &lt;br /&gt;
&lt;br /&gt;
Saatat havaita lievää epäjohdonmukaisuutta LanguageStats-sivulla osoitetuissa prosenttiluvuissa ja kielipalkin prosenttiluvuissa. Tämä on normaalia. LanguageStats vertaa vain niiden viestien lukumäärää, jotka ovat kotoistamattomia tai vanhentuneita. Kielipalkkitilasto yrittää olla älykkäämpi. Esimerkiksi yhdellä sivulla (100 viestiä) 8:ssa viestissä oli pieni (uudelleen-lajittelun-aiheuttama) muutos. Jokaisessa tapauksessa kyse oli yksittäisestä sanasta. Kahdessa tilastossa on 8% ero, koska se oli viestien oleellinen osa, mutta pieni osa koko kokoistamisesta.&lt;br /&gt;
&lt;br /&gt;
=== Jos käytät Chromium- tai Chrome-selainta... === &lt;br /&gt;
&lt;br /&gt;
Ole tietoinen, että Chromium-selaimessa on jonkinlainen välimuistipulma. Olen huomannut, että jopa pakotetuilla virkistyksillä jotkut tilastot eivät näy kuten niiden pitäisi näkyä (olen nähnyt vaikutuksia myös muissa asioissa), vaikka sama sivu Firefox-selaimessa avattuna näyttää tilastot oikein.&lt;br /&gt;
&lt;br /&gt;
== Katso myös == &lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* [http://translatewiki.net/wiki/Translating:Page_translation_feature#Translators]&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Translator_Help]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Translate_a_Page/7/fi</id>
		<title>Translations:Translate a Page/7/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Translate_a_Page/7/fi"/>
				<updated>2012-12-23T15:48:03Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|2=Huomaa|Kielikoodin ''en'' (englanti) kirjoittaminen kielikoodivalintaan ei näytä yhtään kotoistusviestiä, koska kaikki alkuperäinen sisältö on kirjoitettu englanniksi.}}&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translate_a_Page/fi</id>
		<title>Translate a Page/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translate_a_Page/fi"/>
				<updated>2012-12-23T15:46:42Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Käytettävissä olevat työkalut == &lt;br /&gt;
&lt;br /&gt;
* [[Special:myLanguage/Translation Workflow|Kotoistamistyön kulku]] kuvaa työkulun siirryttäessä uuteen kotoistamisjärjestelmään&lt;br /&gt;
&lt;br /&gt;
== Työnkulku == &lt;br /&gt;
&lt;br /&gt;
* Pyyntö lisäämisestä kotoistamisryhmään:&lt;br /&gt;
** Napsauta kohdetta [[Special:myLanguage/Translator Account|Hae kotoistajatili]] sivupalkissa&lt;br /&gt;
** Napsauta &amp;lt;menuchoice&amp;gt;Muokkaa&amp;lt;/menuchoice&amp;gt;-kuvaketta [[Image:Userbase-edit.png|14px]] ja kirjoita käyttäjänimesi, kieli, jolle haluat kotoistaa ja aiotko kotoistaa tekstiä erillistiedostoissa&lt;br /&gt;
** Käytä &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; tietojen tallentamiseksi&lt;br /&gt;
&lt;br /&gt;
* Kun käyttäjätilisi on lisätty ryhmään (sinun pitäisi saada siitä ilmoitus), napsauta kohdetta [[Special:LanguageStats|Aloita kotoistaminen]] sivupalkissa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita se kieli, jolle haluat kotoistaa &amp;lt;menuchoice&amp;gt;Kielikoodi&amp;lt;/menuchoice&amp;gt;-valintaan ja napsauta kohdetta &amp;lt;menuchoice&amp;gt;Siirry&amp;lt;/menuchoice&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Note|Huomaa|Kielikoodin ''en'' (englanti) kirjoittaminen kielikoodivalintaan ei näytä yhtään kotoistusviestiä, koska kaikki alkuperäinen sisältö on kirjoitettu englanniksi.}}&lt;br /&gt;
&lt;br /&gt;
* Napsauta luettelossa sivua, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Aseta '''Kotoista sivu''' asetuksessa &amp;lt;menuchoice&amp;gt;Katso kaikki kotoistamattomat viestit&amp;lt;/menuchoice&amp;gt; ensimmäisessä vetovalikkoluettelossa&lt;br /&gt;
&lt;br /&gt;
* Tarkista, että näkyvissä on oikea kielikoodi&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;menuchoice&amp;gt;Navigointi&amp;lt;/menuchoice&amp;gt;-osassa napsauta linkkiä sen viestin vasemmalla puolella, jonka haluat kotoistaa&lt;br /&gt;
&lt;br /&gt;
* Kirjoita kotoistamisteksti - Google-ehdotus tarjotaan viitteenä, mutta oma kotoistamisteksti on tavallisesti parempi.&lt;br /&gt;
&lt;br /&gt;
* Napsauta kohdetta &amp;lt;menuchoice&amp;gt;Tallenna ja avaa seuraava&amp;lt;/menuchoice&amp;gt;, jos haluat jatkaa seuraavaan viestiin tai &amp;lt;menuchoice&amp;gt;Tallenna sivu&amp;lt;/menuchoice&amp;gt; kotoistamistekstin tallentamiseksi, jos haluat lopettaa työskentelyn.&lt;br /&gt;
&lt;br /&gt;
{{Warning|2=Varoitus|Älä luo kotoistettua sivuavarianttia manuaalisesti (kirjoittamalla sivunimen/kielikoodin ja yrittämällä kotoistaa alkuperäistekstin). Tämä sotkee kotoistamisjärjestelmän ja yhtään suomennosta ei näytetä.}}&lt;br /&gt;
&lt;br /&gt;
== Vihjeitä == &lt;br /&gt;
&lt;br /&gt;
=== Kuvan näyttämisohjeita === &lt;br /&gt;
&lt;br /&gt;
Tyypillinen esimerkki on &amp;lt;nowiki&amp;gt;[[Image:Plasma-kickoff.jpg|right|160px]]&amp;lt;/nowiki&amp;gt;.  Tämä on koko järjestelmäkäsky kuvan näyttämiseksi. Mitään siitä ei kotoisteta.&lt;br /&gt;
&lt;br /&gt;
=== Luokkaohjeet ===&lt;br /&gt;
&lt;br /&gt;
Ajattele tässä asiayhteydessä sanaa &amp;quot;Category&amp;quot; järjestelmäsanana, jota ei siksi pitäisi kotoistaa.  Esimerkiksi, &amp;lt;nowiki&amp;gt;[[Category:Administration]]&amp;lt;/nowiki&amp;gt; tulisi &amp;lt;nowiki&amp;gt;[[Category:Administrasi/id]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
Johdonmukaisuuden vuoksi UserBase:ssa on hyväksyttyjen kotoistamisien luettelot.  Kotoistamisryhmät saattavat havaita samanlaiset luettelot hyödyllisiksi.  Sellaisia taulukkoja voidaan nähdä osoitteessa [{{UB}}Translation_Help_Needed Kotoistamisapua tarvitaan].  Pyydä apua, jos tarvitset sitä.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Linkit muille sivuille TechBase-sivustolla === &lt;br /&gt;
&lt;br /&gt;
Nämä ovat muodoltaan &amp;lt;nowiki&amp;gt;[[Special:myLanguage/Other page|linkkiteksti]]&amp;lt;/nowiki&amp;gt; Linkki pitäisi jättää kotoistamatta, kun taas linkin teksti on aina kotoistettava. Ellei linkin teksti on läsnä, lisätään sopiva (kotoistettu) linkin teksti.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
Huomaa: &amp;quot;myLanguage&amp;quot; yrittää ladata linkin kotoistetun version kielellä, jonka olet asettanut omiin asetuksiisi. Jos lataaminen epäonnistuu, se lataa vain englanninkielisen alkuperäistekstin, joten on turvallista käyttää sitä kaikissa sisäisissä linkeissä.&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Linkit ulkopuolisille sivustoille === &lt;br /&gt;
&lt;br /&gt;
Nämä saavat muodon  &amp;lt;nowiki&amp;gt;[http://example.com linkkiteksti]&amp;lt;/nowiki&amp;gt;.  Kuten sisäisissä linkeissä, säilytä varsinainen linkki ja kotoista linkkiteksti.&lt;br /&gt;
&lt;br /&gt;
=== Linkit sivupalkissa ===&lt;br /&gt;
&lt;br /&gt;
Ohjeita sivupalkkilinkkien kotoistamiseen löytyy osoitteesta [[Modifying_the_Sidebar#Translating_Sidebar_Items]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Tietolaatikot === &lt;br /&gt;
&lt;br /&gt;
Nämä yleensä koostuvat otsakesanasta &amp;quot;Information&amp;quot; ja muokattavasta tietotekstistä.  Jos sana &amp;quot;Information&amp;quot; ei ole tunnistettavissa kielelläsi, saatat tarvita kotoistetun version mallinteesta.  Kysy, jos tarvitset apua tämän kanssa.&lt;br /&gt;
&lt;br /&gt;
=== Kotoistetut yksiköt on merkitty sumeana === &lt;br /&gt;
&lt;br /&gt;
Joskus saattaa tapahtua, että sinun on kotoistettava sivu, mutta kotoistaminen on merkitty vaillinaiseksi. Tietyt virheet alkuperäissivun merkkauskielen merkeissä voivat aiheuttaa tämän. Yleisin virhetyyppi on parittomat sulkumerkit tai lainausmerkit. Kotoistamisjärjestelmä vaatii, että kaikilla avaavilla sulkumerkeillä ('[', '{' tai '(' ) on täsmäävä sulkeva sulkumerkki (']', '}' tai ')' ) samassa kotoistamisyksikössä, muutoin kotoistamista pidetään vaillinaisena.&lt;br /&gt;
&lt;br /&gt;
Sama sääntö ei ole pakollinen wiki-ohjelmistossa, joten kirjoittajat helposti sortuvat noihin virheisiin. Jos sulkumerkki yksinkertaisesti puuttuu, niin lisää se. Joskus sulkumerkkien sisään suljettu sisältö ulottuu useampaan kuin yhteen kotoistamisyksikköön, joten täsmäävä sulkeva lainausmerkki on myöhemmässä yksikössä. Tässä tapauksessa tarvitset parilliset lainausmerkit molemmissa yksiköissä, mutta et voi yksinkertaisesti lisätä sulkumerkkejä muuttamatta muotoilun merkitystä, joten sinun on kommentoitava piiloon lisätyt sulkumerkit, kuten tämä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt;&amp;lt;!--}}--&amp;gt;{{Info|1=Pitkän tietolaatikon alku... &amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
ja myöhemmässä yksikössä&lt;br /&gt;
&lt;br /&gt;
{{Input|1=&amp;lt;nowiki&amp;gt; ...pitkän tietolaatikon loppu}}&amp;lt;!--{{--&amp;gt;&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Jos rikkova sulkumerkki on osa hymiötä, korvaa se emoticon-kuvakkeella. Vakiohymiötä varten &amp;lt;!--(--&amp;gt;:-) voit käyttää mallinetta &amp;lt;nowiki&amp;gt;{{Smiley}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Korjaa myös alkuperäissivu, jotta muilla kotoistajilla ei ole sama pulma, tai jätä viesti keskustelusivulle.&lt;br /&gt;
&lt;br /&gt;
=== Kielitilastojen epäjohdonmukaisuuksia === &lt;br /&gt;
&lt;br /&gt;
Saatat havaita lievää epäjohdonmukaisuutta LanguageStats-sivulla osoitetuissa prosenttiluvuissa ja kielipalkin prosenttiluvuissa. Tämä on normaalia. LanguageStats vertaa vain niiden viestien lukumäärää, jotka ovat kotoistamattomia tai vanhentuneita. Kielipalkkitilasto yrittää olla älykkäämpi. Esimerkiksi yhdellä sivulla (100 viestiä) 8:ssa viestissä oli pieni (uudelleen-lajittelun-aiheuttama) muutos. Jokaisessa tapauksessa kyse oli yksittäisestä sanasta. Kahdessa tilastossa on 8% ero, koska se oli viestien oleellinen osa, mutta pieni osa koko kokoistamisesta.&lt;br /&gt;
&lt;br /&gt;
=== Jos käytät Chromium- tai Chrome-selainta... === &lt;br /&gt;
&lt;br /&gt;
Ole tietoinen, että Chromium-selaimessa on jonkinlainen välimuistipulma. Olen huomannut, että jopa pakotetuilla virkistyksillä jotkut tilastot eivät näy kuten niiden pitäisi näkyä (olen nähnyt vaikutuksia myös muissa asioissa), vaikka sama sivu Firefox-selaimessa avattuna näyttää tilastot oikein.&lt;br /&gt;
&lt;br /&gt;
== Katso myös == &lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;mw-translate-fuzzy&amp;quot;&amp;gt;&lt;br /&gt;
* [http://translatewiki.net/wiki/Translating:Page_translation_feature#Translators]&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Translator_Help]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Translate_a_Page/7/fi</id>
		<title>Translations:Translate a Page/7/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Translate_a_Page/7/fi"/>
				<updated>2012-12-23T15:46:41Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Huomaa|Kielikoodin ''en'' (englanti) kirjoittaminen kielikoodivalintaan ei näytä yhtään kotoistusviestiä, koska kaikki alkuperäinen sisältö on kirjoitettu englanniksi.}}&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/44/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/44/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/44/fi"/>
				<updated>2011-11-01T17:34:19Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Category:Ruby&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi"/>
				<updated>2011-11-01T17:34:13Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Facing the Wall|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Tutorial 13 - Game Over]]&lt;br /&gt;
}}&lt;br /&gt;
== Facing the Wall ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_14.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/t14.rb t14.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
This is the final example: a complete game.&lt;br /&gt;
&lt;br /&gt;
We add keyboard accelerators and introduce mouse events to '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' and add a barrier (wall) to make the game more challenging. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' can now receive mouse events to make the user aim the barrel by clicking on it and dragging. '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' also has a barrier wall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@barrelPressed = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. Initially, the mouse is not pressed on the barrel.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height() ||&lt;br /&gt;
    shotR.intersects(barrierRect())&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have a barrier, there are three ways to miss. We test for the third, too. (In '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;'''.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mousePressEvent(event)&lt;br /&gt;
  unless event.button() == Qt::LeftButton&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if barrelHit(event.pos())&lt;br /&gt;
    @barrelPressed = true&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a Qt event handler. It is called when the user presses a mouse button when the mouse cursor is over the widget.&lt;br /&gt;
&lt;br /&gt;
If the event was not generated by the left mouse button, we return immediately. Otherwise, we check if the position of the mouse cursor is within the cannon's barrel. If it is, we set '''&amp;lt;tt&amp;gt;barrelPressed&amp;lt;/tt&amp;gt;''' to true.&lt;br /&gt;
&lt;br /&gt;
Notice that the [http://doc.qt.nokia.com/latest/qmouseevent.html#pos Qt::MouseEvent::pos()] function returns a point in the widget's coordinate system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseMoveEvent(event)&lt;br /&gt;
  unless @barrelPressed&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  pos = event.pos();&lt;br /&gt;
&lt;br /&gt;
  if pos.x() &amp;lt;= 0&lt;br /&gt;
    pos.setX(1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if pos.y() &amp;gt;= height()&lt;br /&gt;
    pos.setY(height() - 1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  rad = atan2((rect().bottom() - pos.y()), pos.x())&lt;br /&gt;
  setAngle((rad * 180 / 3.14159265).round())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is another Qt event handler. It is called when the user already has pressed the mouse button inside this widget and then moves/drags the mouse. (You can make Qt send mouse move events even when no buttons are pressed. See [http://doc.qt.nokia.com/latest/qwidget.html#mouseTracking-prop Qt::Widget::setMouseTracking()].)&lt;br /&gt;
&lt;br /&gt;
This handler repositions the cannon's barrel according to the position of the mouse cursor.&lt;br /&gt;
&lt;br /&gt;
First, if the barrel is not pressed, we return. Next, we fetch the mouse cursor's position. If the mouse cursor is to the left or below the widget, we adjust the point to be inside the widget.&lt;br /&gt;
&lt;br /&gt;
Then we calculate the angle between the bottom edge of the widget and the imaginary line between the bottom-left corner of the widget and the cursor position. Finally we set the cannon's angle to the new value converted to degrees.&lt;br /&gt;
&lt;br /&gt;
Remember that '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;''' redraws the cannon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseReleaseEvent(event)&lt;br /&gt;
  if event.button() == Qt::LeftButton&lt;br /&gt;
    @barrelPressed = false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Qt event handler is called whenever the user releases a mouse button and it was pressed inside this widget.&lt;br /&gt;
&lt;br /&gt;
If the left button is released, we can be sure that the barrel is no longer pressed.&lt;br /&gt;
&lt;br /&gt;
The paint event has one extra line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
paintBarrier(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;paintBarrier()&amp;lt;/tt&amp;gt;''' does the same sort of thing as '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''', '''&amp;lt;tt&amp;gt;paintTarget()&amp;lt;/tt&amp;gt;''', and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintBarrier( painter )&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::yellow))&lt;br /&gt;
  painter.setPen(Qt::Color.new(Qt::black))&lt;br /&gt;
  painter.drawRect(barrierRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the barrier as a rectangle filled with yellow and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrierRect()&lt;br /&gt;
  return Qt::Rect.new(145, height() - 100, 15, 99)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns the rectangle of the barrier. We fix the bottom edge of the barrier to the bottom edge of the widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrelHit(pos)&lt;br /&gt;
  matrix = Qt::Matrix.new()&lt;br /&gt;
  matrix.translate(0, height())&lt;br /&gt;
  matrix.rotate(-@currentAngle)&lt;br /&gt;
  matrix = matrix.inverted()&lt;br /&gt;
  return @barrelRect.contains(matrix.map(pos))&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if the point is in the barrel; otherwise it returns '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Here we use the class [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix]. [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix] defines a coordinate system mapping. It can perform the same transformations as the [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter].&lt;br /&gt;
&lt;br /&gt;
Here we perform the same transformation steps as we do when drawing the barrel in the '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' function. First we translate the coordinate system and then we rotate it.&lt;br /&gt;
&lt;br /&gt;
Now we need to check whether the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' (in widget coordinates) lies inside the barrel. To do this, we invert the transformation matrix. The inverted matrix performs the inverse transformation that we used when drawing the barrel. We map the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' using the inverted matrix and return '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if it is inside the original barrel rectangle.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
cannonBox = Qt::Frame.new()&lt;br /&gt;
cannonBox.setFrameStyle(Qt::Frame::WinPanel | Qt::Frame::Sunken)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create and set up a [http://doc.qt.nokia.com/latest/qframe.html Qt::Frame], and set its frame style. This results in a 3D frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Enter.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Return.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::CTRL.to_i + Qt::Key_Q.to_i),&lt;br /&gt;
                 self, SLOT('close()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we create and set up three [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] objects. These objects intercept keyboard events to a widget and call slots if certain keys are pressed. Note that a [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] object is a child of a widget and will be destroyed when that widget is destroyed. [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] itself is not a widget and has no visible effect on its parent.&lt;br /&gt;
&lt;br /&gt;
We define three shortcut keys. We want the '''&amp;lt;tt&amp;gt;fire()&amp;lt;/tt&amp;gt;''' slot to be called when the user presses Enter or Return. We also want the application to quit when key Ctrl+Q is pressed. Instead of connecting to [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit Qt::CoreApplication::quit()], we connect to [http://doc.qt.nokia.com/latest/qwidget.html#close Qt::Widget::close()] this time. Since the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' is the application's main widget, this has the same effect as [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit QCoreApplication::quit()].&lt;br /&gt;
&lt;br /&gt;
Qt::CTRL, Qt::Key_Enter, Qt::Key_Return, and Qt::Key_Q are all constants declared in the Qt namespace. Unfortunately, in the current version of qtruby, they need to be converted to integers before we can use them in our shortcuts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(topLayout, 0, 1)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(@cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
setLayout(gridLayout)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''' its own [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout], and we add '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to that layout. This implicitly makes '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' a child of '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;'''. Because nothing else is in the box, the effect is that the [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] will put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''', not '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', in the grid layout.&lt;br /&gt;
&lt;br /&gt;
=== Sovellusen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The cannon now shoots when you press Enter. You can also position the cannon's angle using the mouse. The barrier makes it a little more challenging to play the game. We also have a nice looking frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
&lt;br /&gt;
Write a space invaders game.&lt;br /&gt;
&lt;br /&gt;
The new exercise is: Write a Breakout game.&lt;br /&gt;
&lt;br /&gt;
Final exhortation: Go forth now and create masterpieces of the programming art!&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/40/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/40/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/40/fi"/>
				<updated>2011-11-01T17:34:12Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Harjoitukset ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi"/>
				<updated>2011-11-01T17:34:00Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Sovellusen suorittaminen ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Facing the Wall|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Tutorial 13 - Game Over]]&lt;br /&gt;
}}&lt;br /&gt;
== Facing the Wall ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_14.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/t14.rb t14.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
This is the final example: a complete game.&lt;br /&gt;
&lt;br /&gt;
We add keyboard accelerators and introduce mouse events to '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' and add a barrier (wall) to make the game more challenging. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' can now receive mouse events to make the user aim the barrel by clicking on it and dragging. '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' also has a barrier wall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@barrelPressed = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. Initially, the mouse is not pressed on the barrel.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height() ||&lt;br /&gt;
    shotR.intersects(barrierRect())&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have a barrier, there are three ways to miss. We test for the third, too. (In '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;'''.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mousePressEvent(event)&lt;br /&gt;
  unless event.button() == Qt::LeftButton&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if barrelHit(event.pos())&lt;br /&gt;
    @barrelPressed = true&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a Qt event handler. It is called when the user presses a mouse button when the mouse cursor is over the widget.&lt;br /&gt;
&lt;br /&gt;
If the event was not generated by the left mouse button, we return immediately. Otherwise, we check if the position of the mouse cursor is within the cannon's barrel. If it is, we set '''&amp;lt;tt&amp;gt;barrelPressed&amp;lt;/tt&amp;gt;''' to true.&lt;br /&gt;
&lt;br /&gt;
Notice that the [http://doc.qt.nokia.com/latest/qmouseevent.html#pos Qt::MouseEvent::pos()] function returns a point in the widget's coordinate system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseMoveEvent(event)&lt;br /&gt;
  unless @barrelPressed&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  pos = event.pos();&lt;br /&gt;
&lt;br /&gt;
  if pos.x() &amp;lt;= 0&lt;br /&gt;
    pos.setX(1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if pos.y() &amp;gt;= height()&lt;br /&gt;
    pos.setY(height() - 1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  rad = atan2((rect().bottom() - pos.y()), pos.x())&lt;br /&gt;
  setAngle((rad * 180 / 3.14159265).round())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is another Qt event handler. It is called when the user already has pressed the mouse button inside this widget and then moves/drags the mouse. (You can make Qt send mouse move events even when no buttons are pressed. See [http://doc.qt.nokia.com/latest/qwidget.html#mouseTracking-prop Qt::Widget::setMouseTracking()].)&lt;br /&gt;
&lt;br /&gt;
This handler repositions the cannon's barrel according to the position of the mouse cursor.&lt;br /&gt;
&lt;br /&gt;
First, if the barrel is not pressed, we return. Next, we fetch the mouse cursor's position. If the mouse cursor is to the left or below the widget, we adjust the point to be inside the widget.&lt;br /&gt;
&lt;br /&gt;
Then we calculate the angle between the bottom edge of the widget and the imaginary line between the bottom-left corner of the widget and the cursor position. Finally we set the cannon's angle to the new value converted to degrees.&lt;br /&gt;
&lt;br /&gt;
Remember that '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;''' redraws the cannon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseReleaseEvent(event)&lt;br /&gt;
  if event.button() == Qt::LeftButton&lt;br /&gt;
    @barrelPressed = false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Qt event handler is called whenever the user releases a mouse button and it was pressed inside this widget.&lt;br /&gt;
&lt;br /&gt;
If the left button is released, we can be sure that the barrel is no longer pressed.&lt;br /&gt;
&lt;br /&gt;
The paint event has one extra line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
paintBarrier(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;paintBarrier()&amp;lt;/tt&amp;gt;''' does the same sort of thing as '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''', '''&amp;lt;tt&amp;gt;paintTarget()&amp;lt;/tt&amp;gt;''', and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintBarrier( painter )&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::yellow))&lt;br /&gt;
  painter.setPen(Qt::Color.new(Qt::black))&lt;br /&gt;
  painter.drawRect(barrierRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the barrier as a rectangle filled with yellow and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrierRect()&lt;br /&gt;
  return Qt::Rect.new(145, height() - 100, 15, 99)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns the rectangle of the barrier. We fix the bottom edge of the barrier to the bottom edge of the widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrelHit(pos)&lt;br /&gt;
  matrix = Qt::Matrix.new()&lt;br /&gt;
  matrix.translate(0, height())&lt;br /&gt;
  matrix.rotate(-@currentAngle)&lt;br /&gt;
  matrix = matrix.inverted()&lt;br /&gt;
  return @barrelRect.contains(matrix.map(pos))&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if the point is in the barrel; otherwise it returns '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Here we use the class [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix]. [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix] defines a coordinate system mapping. It can perform the same transformations as the [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter].&lt;br /&gt;
&lt;br /&gt;
Here we perform the same transformation steps as we do when drawing the barrel in the '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' function. First we translate the coordinate system and then we rotate it.&lt;br /&gt;
&lt;br /&gt;
Now we need to check whether the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' (in widget coordinates) lies inside the barrel. To do this, we invert the transformation matrix. The inverted matrix performs the inverse transformation that we used when drawing the barrel. We map the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' using the inverted matrix and return '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if it is inside the original barrel rectangle.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
cannonBox = Qt::Frame.new()&lt;br /&gt;
cannonBox.setFrameStyle(Qt::Frame::WinPanel | Qt::Frame::Sunken)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create and set up a [http://doc.qt.nokia.com/latest/qframe.html Qt::Frame], and set its frame style. This results in a 3D frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Enter.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Return.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::CTRL.to_i + Qt::Key_Q.to_i),&lt;br /&gt;
                 self, SLOT('close()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we create and set up three [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] objects. These objects intercept keyboard events to a widget and call slots if certain keys are pressed. Note that a [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] object is a child of a widget and will be destroyed when that widget is destroyed. [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] itself is not a widget and has no visible effect on its parent.&lt;br /&gt;
&lt;br /&gt;
We define three shortcut keys. We want the '''&amp;lt;tt&amp;gt;fire()&amp;lt;/tt&amp;gt;''' slot to be called when the user presses Enter or Return. We also want the application to quit when key Ctrl+Q is pressed. Instead of connecting to [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit Qt::CoreApplication::quit()], we connect to [http://doc.qt.nokia.com/latest/qwidget.html#close Qt::Widget::close()] this time. Since the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' is the application's main widget, this has the same effect as [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit QCoreApplication::quit()].&lt;br /&gt;
&lt;br /&gt;
Qt::CTRL, Qt::Key_Enter, Qt::Key_Return, and Qt::Key_Q are all constants declared in the Qt namespace. Unfortunately, in the current version of qtruby, they need to be converted to integers before we can use them in our shortcuts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(topLayout, 0, 1)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(@cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
setLayout(gridLayout)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''' its own [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout], and we add '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to that layout. This implicitly makes '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' a child of '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;'''. Because nothing else is in the box, the effect is that the [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] will put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''', not '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', in the grid layout.&lt;br /&gt;
&lt;br /&gt;
=== Sovellusen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The cannon now shoots when you press Enter. You can also position the cannon's angle using the mouse. The barrier makes it a little more challenging to play the game. We also have a nice looking frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Write a space invaders game.&lt;br /&gt;
&lt;br /&gt;
The new exercise is: Write a Breakout game.&lt;br /&gt;
&lt;br /&gt;
Final exhortation: Go forth now and create masterpieces of the programming art!&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/38/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/38/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/38/fi"/>
				<updated>2011-11-01T17:34:00Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Sovellusen suorittaminen ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Sovellusen suorittaminen ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi"/>
				<updated>2011-11-01T17:33:35Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Läpikäynti rivi riviltä ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Facing the Wall|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Tutorial 13 - Game Over]]&lt;br /&gt;
}}&lt;br /&gt;
== Facing the Wall ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_14.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/t14.rb t14.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
This is the final example: a complete game.&lt;br /&gt;
&lt;br /&gt;
We add keyboard accelerators and introduce mouse events to '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' and add a barrier (wall) to make the game more challenging. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' can now receive mouse events to make the user aim the barrel by clicking on it and dragging. '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' also has a barrier wall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@barrelPressed = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. Initially, the mouse is not pressed on the barrel.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height() ||&lt;br /&gt;
    shotR.intersects(barrierRect())&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have a barrier, there are three ways to miss. We test for the third, too. (In '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;'''.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mousePressEvent(event)&lt;br /&gt;
  unless event.button() == Qt::LeftButton&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if barrelHit(event.pos())&lt;br /&gt;
    @barrelPressed = true&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a Qt event handler. It is called when the user presses a mouse button when the mouse cursor is over the widget.&lt;br /&gt;
&lt;br /&gt;
If the event was not generated by the left mouse button, we return immediately. Otherwise, we check if the position of the mouse cursor is within the cannon's barrel. If it is, we set '''&amp;lt;tt&amp;gt;barrelPressed&amp;lt;/tt&amp;gt;''' to true.&lt;br /&gt;
&lt;br /&gt;
Notice that the [http://doc.qt.nokia.com/latest/qmouseevent.html#pos Qt::MouseEvent::pos()] function returns a point in the widget's coordinate system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseMoveEvent(event)&lt;br /&gt;
  unless @barrelPressed&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  pos = event.pos();&lt;br /&gt;
&lt;br /&gt;
  if pos.x() &amp;lt;= 0&lt;br /&gt;
    pos.setX(1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if pos.y() &amp;gt;= height()&lt;br /&gt;
    pos.setY(height() - 1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  rad = atan2((rect().bottom() - pos.y()), pos.x())&lt;br /&gt;
  setAngle((rad * 180 / 3.14159265).round())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is another Qt event handler. It is called when the user already has pressed the mouse button inside this widget and then moves/drags the mouse. (You can make Qt send mouse move events even when no buttons are pressed. See [http://doc.qt.nokia.com/latest/qwidget.html#mouseTracking-prop Qt::Widget::setMouseTracking()].)&lt;br /&gt;
&lt;br /&gt;
This handler repositions the cannon's barrel according to the position of the mouse cursor.&lt;br /&gt;
&lt;br /&gt;
First, if the barrel is not pressed, we return. Next, we fetch the mouse cursor's position. If the mouse cursor is to the left or below the widget, we adjust the point to be inside the widget.&lt;br /&gt;
&lt;br /&gt;
Then we calculate the angle between the bottom edge of the widget and the imaginary line between the bottom-left corner of the widget and the cursor position. Finally we set the cannon's angle to the new value converted to degrees.&lt;br /&gt;
&lt;br /&gt;
Remember that '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;''' redraws the cannon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseReleaseEvent(event)&lt;br /&gt;
  if event.button() == Qt::LeftButton&lt;br /&gt;
    @barrelPressed = false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Qt event handler is called whenever the user releases a mouse button and it was pressed inside this widget.&lt;br /&gt;
&lt;br /&gt;
If the left button is released, we can be sure that the barrel is no longer pressed.&lt;br /&gt;
&lt;br /&gt;
The paint event has one extra line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
paintBarrier(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;paintBarrier()&amp;lt;/tt&amp;gt;''' does the same sort of thing as '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''', '''&amp;lt;tt&amp;gt;paintTarget()&amp;lt;/tt&amp;gt;''', and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintBarrier( painter )&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::yellow))&lt;br /&gt;
  painter.setPen(Qt::Color.new(Qt::black))&lt;br /&gt;
  painter.drawRect(barrierRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the barrier as a rectangle filled with yellow and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrierRect()&lt;br /&gt;
  return Qt::Rect.new(145, height() - 100, 15, 99)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns the rectangle of the barrier. We fix the bottom edge of the barrier to the bottom edge of the widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrelHit(pos)&lt;br /&gt;
  matrix = Qt::Matrix.new()&lt;br /&gt;
  matrix.translate(0, height())&lt;br /&gt;
  matrix.rotate(-@currentAngle)&lt;br /&gt;
  matrix = matrix.inverted()&lt;br /&gt;
  return @barrelRect.contains(matrix.map(pos))&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if the point is in the barrel; otherwise it returns '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Here we use the class [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix]. [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix] defines a coordinate system mapping. It can perform the same transformations as the [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter].&lt;br /&gt;
&lt;br /&gt;
Here we perform the same transformation steps as we do when drawing the barrel in the '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' function. First we translate the coordinate system and then we rotate it.&lt;br /&gt;
&lt;br /&gt;
Now we need to check whether the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' (in widget coordinates) lies inside the barrel. To do this, we invert the transformation matrix. The inverted matrix performs the inverse transformation that we used when drawing the barrel. We map the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' using the inverted matrix and return '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if it is inside the original barrel rectangle.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
cannonBox = Qt::Frame.new()&lt;br /&gt;
cannonBox.setFrameStyle(Qt::Frame::WinPanel | Qt::Frame::Sunken)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create and set up a [http://doc.qt.nokia.com/latest/qframe.html Qt::Frame], and set its frame style. This results in a 3D frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Enter.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Return.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::CTRL.to_i + Qt::Key_Q.to_i),&lt;br /&gt;
                 self, SLOT('close()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we create and set up three [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] objects. These objects intercept keyboard events to a widget and call slots if certain keys are pressed. Note that a [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] object is a child of a widget and will be destroyed when that widget is destroyed. [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] itself is not a widget and has no visible effect on its parent.&lt;br /&gt;
&lt;br /&gt;
We define three shortcut keys. We want the '''&amp;lt;tt&amp;gt;fire()&amp;lt;/tt&amp;gt;''' slot to be called when the user presses Enter or Return. We also want the application to quit when key Ctrl+Q is pressed. Instead of connecting to [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit Qt::CoreApplication::quit()], we connect to [http://doc.qt.nokia.com/latest/qwidget.html#close Qt::Widget::close()] this time. Since the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' is the application's main widget, this has the same effect as [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit QCoreApplication::quit()].&lt;br /&gt;
&lt;br /&gt;
Qt::CTRL, Qt::Key_Enter, Qt::Key_Return, and Qt::Key_Q are all constants declared in the Qt namespace. Unfortunately, in the current version of qtruby, they need to be converted to integers before we can use them in our shortcuts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(topLayout, 0, 1)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(@cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
setLayout(gridLayout)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''' its own [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout], and we add '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to that layout. This implicitly makes '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' a child of '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;'''. Because nothing else is in the box, the effect is that the [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] will put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''', not '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', in the grid layout.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon now shoots when you press Enter. You can also position the cannon's angle using the mouse. The barrier makes it a little more challenging to play the game. We also have a nice looking frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Write a space invaders game.&lt;br /&gt;
&lt;br /&gt;
The new exercise is: Write a Breakout game.&lt;br /&gt;
&lt;br /&gt;
Final exhortation: Go forth now and create masterpieces of the programming art!&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/11/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/11/fi"/>
				<updated>2011-11-01T17:33:34Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Läpikäynti rivi riviltä ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Läpikäynti rivi riviltä ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi"/>
				<updated>2011-11-01T17:33:20Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Yleiskuva ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Facing the Wall|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Tutorial 13 - Game Over]]&lt;br /&gt;
}}&lt;br /&gt;
== Facing the Wall ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_14.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/t14.rb t14.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
This is the final example: a complete game.&lt;br /&gt;
&lt;br /&gt;
We add keyboard accelerators and introduce mouse events to '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' and add a barrier (wall) to make the game more challenging. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' can now receive mouse events to make the user aim the barrel by clicking on it and dragging. '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' also has a barrier wall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@barrelPressed = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. Initially, the mouse is not pressed on the barrel.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height() ||&lt;br /&gt;
    shotR.intersects(barrierRect())&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have a barrier, there are three ways to miss. We test for the third, too. (In '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;'''.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mousePressEvent(event)&lt;br /&gt;
  unless event.button() == Qt::LeftButton&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if barrelHit(event.pos())&lt;br /&gt;
    @barrelPressed = true&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a Qt event handler. It is called when the user presses a mouse button when the mouse cursor is over the widget.&lt;br /&gt;
&lt;br /&gt;
If the event was not generated by the left mouse button, we return immediately. Otherwise, we check if the position of the mouse cursor is within the cannon's barrel. If it is, we set '''&amp;lt;tt&amp;gt;barrelPressed&amp;lt;/tt&amp;gt;''' to true.&lt;br /&gt;
&lt;br /&gt;
Notice that the [http://doc.qt.nokia.com/latest/qmouseevent.html#pos Qt::MouseEvent::pos()] function returns a point in the widget's coordinate system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseMoveEvent(event)&lt;br /&gt;
  unless @barrelPressed&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  pos = event.pos();&lt;br /&gt;
&lt;br /&gt;
  if pos.x() &amp;lt;= 0&lt;br /&gt;
    pos.setX(1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if pos.y() &amp;gt;= height()&lt;br /&gt;
    pos.setY(height() - 1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  rad = atan2((rect().bottom() - pos.y()), pos.x())&lt;br /&gt;
  setAngle((rad * 180 / 3.14159265).round())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is another Qt event handler. It is called when the user already has pressed the mouse button inside this widget and then moves/drags the mouse. (You can make Qt send mouse move events even when no buttons are pressed. See [http://doc.qt.nokia.com/latest/qwidget.html#mouseTracking-prop Qt::Widget::setMouseTracking()].)&lt;br /&gt;
&lt;br /&gt;
This handler repositions the cannon's barrel according to the position of the mouse cursor.&lt;br /&gt;
&lt;br /&gt;
First, if the barrel is not pressed, we return. Next, we fetch the mouse cursor's position. If the mouse cursor is to the left or below the widget, we adjust the point to be inside the widget.&lt;br /&gt;
&lt;br /&gt;
Then we calculate the angle between the bottom edge of the widget and the imaginary line between the bottom-left corner of the widget and the cursor position. Finally we set the cannon's angle to the new value converted to degrees.&lt;br /&gt;
&lt;br /&gt;
Remember that '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;''' redraws the cannon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseReleaseEvent(event)&lt;br /&gt;
  if event.button() == Qt::LeftButton&lt;br /&gt;
    @barrelPressed = false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Qt event handler is called whenever the user releases a mouse button and it was pressed inside this widget.&lt;br /&gt;
&lt;br /&gt;
If the left button is released, we can be sure that the barrel is no longer pressed.&lt;br /&gt;
&lt;br /&gt;
The paint event has one extra line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
paintBarrier(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;paintBarrier()&amp;lt;/tt&amp;gt;''' does the same sort of thing as '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''', '''&amp;lt;tt&amp;gt;paintTarget()&amp;lt;/tt&amp;gt;''', and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintBarrier( painter )&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::yellow))&lt;br /&gt;
  painter.setPen(Qt::Color.new(Qt::black))&lt;br /&gt;
  painter.drawRect(barrierRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the barrier as a rectangle filled with yellow and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrierRect()&lt;br /&gt;
  return Qt::Rect.new(145, height() - 100, 15, 99)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns the rectangle of the barrier. We fix the bottom edge of the barrier to the bottom edge of the widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrelHit(pos)&lt;br /&gt;
  matrix = Qt::Matrix.new()&lt;br /&gt;
  matrix.translate(0, height())&lt;br /&gt;
  matrix.rotate(-@currentAngle)&lt;br /&gt;
  matrix = matrix.inverted()&lt;br /&gt;
  return @barrelRect.contains(matrix.map(pos))&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if the point is in the barrel; otherwise it returns '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Here we use the class [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix]. [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix] defines a coordinate system mapping. It can perform the same transformations as the [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter].&lt;br /&gt;
&lt;br /&gt;
Here we perform the same transformation steps as we do when drawing the barrel in the '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' function. First we translate the coordinate system and then we rotate it.&lt;br /&gt;
&lt;br /&gt;
Now we need to check whether the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' (in widget coordinates) lies inside the barrel. To do this, we invert the transformation matrix. The inverted matrix performs the inverse transformation that we used when drawing the barrel. We map the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' using the inverted matrix and return '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if it is inside the original barrel rectangle.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
cannonBox = Qt::Frame.new()&lt;br /&gt;
cannonBox.setFrameStyle(Qt::Frame::WinPanel | Qt::Frame::Sunken)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create and set up a [http://doc.qt.nokia.com/latest/qframe.html Qt::Frame], and set its frame style. This results in a 3D frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Enter.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Return.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::CTRL.to_i + Qt::Key_Q.to_i),&lt;br /&gt;
                 self, SLOT('close()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we create and set up three [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] objects. These objects intercept keyboard events to a widget and call slots if certain keys are pressed. Note that a [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] object is a child of a widget and will be destroyed when that widget is destroyed. [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] itself is not a widget and has no visible effect on its parent.&lt;br /&gt;
&lt;br /&gt;
We define three shortcut keys. We want the '''&amp;lt;tt&amp;gt;fire()&amp;lt;/tt&amp;gt;''' slot to be called when the user presses Enter or Return. We also want the application to quit when key Ctrl+Q is pressed. Instead of connecting to [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit Qt::CoreApplication::quit()], we connect to [http://doc.qt.nokia.com/latest/qwidget.html#close Qt::Widget::close()] this time. Since the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' is the application's main widget, this has the same effect as [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit QCoreApplication::quit()].&lt;br /&gt;
&lt;br /&gt;
Qt::CTRL, Qt::Key_Enter, Qt::Key_Return, and Qt::Key_Q are all constants declared in the Qt namespace. Unfortunately, in the current version of qtruby, they need to be converted to integers before we can use them in our shortcuts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(topLayout, 0, 1)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(@cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
setLayout(gridLayout)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''' its own [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout], and we add '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to that layout. This implicitly makes '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' a child of '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;'''. Because nothing else is in the box, the effect is that the [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] will put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''', not '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', in the grid layout.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon now shoots when you press Enter. You can also position the cannon's angle using the mouse. The barrier makes it a little more challenging to play the game. We also have a nice looking frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Write a space invaders game.&lt;br /&gt;
&lt;br /&gt;
The new exercise is: Write a Breakout game.&lt;br /&gt;
&lt;br /&gt;
Final exhortation: Go forth now and create masterpieces of the programming art!&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/8/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/8/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/8/fi"/>
				<updated>2011-11-01T17:33:20Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Yleiskuva ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Yleiskuva ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/6/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/6/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/6/fi"/>
				<updated>2011-11-01T17:33:09Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;center&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:Qt4_Ruby_Tutorial_Screenshot_14.png|center]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi"/>
				<updated>2011-11-01T17:33:01Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Qt4 Ruby -oppikurssi&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Facing the Wall|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Tutorial 13 - Game Over]]&lt;br /&gt;
}}&lt;br /&gt;
== Facing the Wall ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_14.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/t14.rb t14.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
This is the final example: a complete game.&lt;br /&gt;
&lt;br /&gt;
We add keyboard accelerators and introduce mouse events to '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' and add a barrier (wall) to make the game more challenging. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' can now receive mouse events to make the user aim the barrel by clicking on it and dragging. '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' also has a barrier wall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@barrelPressed = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. Initially, the mouse is not pressed on the barrel.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height() ||&lt;br /&gt;
    shotR.intersects(barrierRect())&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have a barrier, there are three ways to miss. We test for the third, too. (In '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;'''.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mousePressEvent(event)&lt;br /&gt;
  unless event.button() == Qt::LeftButton&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if barrelHit(event.pos())&lt;br /&gt;
    @barrelPressed = true&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a Qt event handler. It is called when the user presses a mouse button when the mouse cursor is over the widget.&lt;br /&gt;
&lt;br /&gt;
If the event was not generated by the left mouse button, we return immediately. Otherwise, we check if the position of the mouse cursor is within the cannon's barrel. If it is, we set '''&amp;lt;tt&amp;gt;barrelPressed&amp;lt;/tt&amp;gt;''' to true.&lt;br /&gt;
&lt;br /&gt;
Notice that the [http://doc.qt.nokia.com/latest/qmouseevent.html#pos Qt::MouseEvent::pos()] function returns a point in the widget's coordinate system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseMoveEvent(event)&lt;br /&gt;
  unless @barrelPressed&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  pos = event.pos();&lt;br /&gt;
&lt;br /&gt;
  if pos.x() &amp;lt;= 0&lt;br /&gt;
    pos.setX(1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if pos.y() &amp;gt;= height()&lt;br /&gt;
    pos.setY(height() - 1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  rad = atan2((rect().bottom() - pos.y()), pos.x())&lt;br /&gt;
  setAngle((rad * 180 / 3.14159265).round())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is another Qt event handler. It is called when the user already has pressed the mouse button inside this widget and then moves/drags the mouse. (You can make Qt send mouse move events even when no buttons are pressed. See [http://doc.qt.nokia.com/latest/qwidget.html#mouseTracking-prop Qt::Widget::setMouseTracking()].)&lt;br /&gt;
&lt;br /&gt;
This handler repositions the cannon's barrel according to the position of the mouse cursor.&lt;br /&gt;
&lt;br /&gt;
First, if the barrel is not pressed, we return. Next, we fetch the mouse cursor's position. If the mouse cursor is to the left or below the widget, we adjust the point to be inside the widget.&lt;br /&gt;
&lt;br /&gt;
Then we calculate the angle between the bottom edge of the widget and the imaginary line between the bottom-left corner of the widget and the cursor position. Finally we set the cannon's angle to the new value converted to degrees.&lt;br /&gt;
&lt;br /&gt;
Remember that '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;''' redraws the cannon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseReleaseEvent(event)&lt;br /&gt;
  if event.button() == Qt::LeftButton&lt;br /&gt;
    @barrelPressed = false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Qt event handler is called whenever the user releases a mouse button and it was pressed inside this widget.&lt;br /&gt;
&lt;br /&gt;
If the left button is released, we can be sure that the barrel is no longer pressed.&lt;br /&gt;
&lt;br /&gt;
The paint event has one extra line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
paintBarrier(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;paintBarrier()&amp;lt;/tt&amp;gt;''' does the same sort of thing as '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''', '''&amp;lt;tt&amp;gt;paintTarget()&amp;lt;/tt&amp;gt;''', and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintBarrier( painter )&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::yellow))&lt;br /&gt;
  painter.setPen(Qt::Color.new(Qt::black))&lt;br /&gt;
  painter.drawRect(barrierRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the barrier as a rectangle filled with yellow and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrierRect()&lt;br /&gt;
  return Qt::Rect.new(145, height() - 100, 15, 99)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns the rectangle of the barrier. We fix the bottom edge of the barrier to the bottom edge of the widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrelHit(pos)&lt;br /&gt;
  matrix = Qt::Matrix.new()&lt;br /&gt;
  matrix.translate(0, height())&lt;br /&gt;
  matrix.rotate(-@currentAngle)&lt;br /&gt;
  matrix = matrix.inverted()&lt;br /&gt;
  return @barrelRect.contains(matrix.map(pos))&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if the point is in the barrel; otherwise it returns '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Here we use the class [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix]. [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix] defines a coordinate system mapping. It can perform the same transformations as the [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter].&lt;br /&gt;
&lt;br /&gt;
Here we perform the same transformation steps as we do when drawing the barrel in the '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' function. First we translate the coordinate system and then we rotate it.&lt;br /&gt;
&lt;br /&gt;
Now we need to check whether the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' (in widget coordinates) lies inside the barrel. To do this, we invert the transformation matrix. The inverted matrix performs the inverse transformation that we used when drawing the barrel. We map the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' using the inverted matrix and return '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if it is inside the original barrel rectangle.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
cannonBox = Qt::Frame.new()&lt;br /&gt;
cannonBox.setFrameStyle(Qt::Frame::WinPanel | Qt::Frame::Sunken)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create and set up a [http://doc.qt.nokia.com/latest/qframe.html Qt::Frame], and set its frame style. This results in a 3D frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Enter.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Return.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::CTRL.to_i + Qt::Key_Q.to_i),&lt;br /&gt;
                 self, SLOT('close()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we create and set up three [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] objects. These objects intercept keyboard events to a widget and call slots if certain keys are pressed. Note that a [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] object is a child of a widget and will be destroyed when that widget is destroyed. [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] itself is not a widget and has no visible effect on its parent.&lt;br /&gt;
&lt;br /&gt;
We define three shortcut keys. We want the '''&amp;lt;tt&amp;gt;fire()&amp;lt;/tt&amp;gt;''' slot to be called when the user presses Enter or Return. We also want the application to quit when key Ctrl+Q is pressed. Instead of connecting to [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit Qt::CoreApplication::quit()], we connect to [http://doc.qt.nokia.com/latest/qwidget.html#close Qt::Widget::close()] this time. Since the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' is the application's main widget, this has the same effect as [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit QCoreApplication::quit()].&lt;br /&gt;
&lt;br /&gt;
Qt::CTRL, Qt::Key_Enter, Qt::Key_Return, and Qt::Key_Q are all constants declared in the Qt namespace. Unfortunately, in the current version of qtruby, they need to be converted to integers before we can use them in our shortcuts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(topLayout, 0, 1)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(@cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
setLayout(gridLayout)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''' its own [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout], and we add '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to that layout. This implicitly makes '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' a child of '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;'''. Because nothing else is in the box, the effect is that the [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] will put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''', not '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', in the grid layout.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon now shoots when you press Enter. You can also position the cannon's angle using the mouse. The barrier makes it a little more challenging to play the game. We also have a nice looking frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Write a space invaders game.&lt;br /&gt;
&lt;br /&gt;
The new exercise is: Write a Breakout game.&lt;br /&gt;
&lt;br /&gt;
Final exhortation: Go forth now and create masterpieces of the programming art!&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/2/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/2/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/2/fi"/>
				<updated>2011-11-01T17:33:00Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Qt4 Ruby -oppikurssi&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Qt4 Ruby -oppikurssi&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/1/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/1/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/1/fi"/>
				<updated>2011-11-01T17:32:45Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;TutorialBrowser&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TutorialBrowser&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14/fi"/>
				<updated>2011-11-01T17:32:45Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;TutorialBrowser&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 14}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby Tutorial]]|&lt;br /&gt;
name=Facing the Wall|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Tutorial 13 - Game Over]]&lt;br /&gt;
}}&lt;br /&gt;
== Facing the Wall ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_14.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/t14.rb t14.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
This is the final example: a complete game.&lt;br /&gt;
&lt;br /&gt;
We add keyboard accelerators and introduce mouse events to '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' and add a barrier (wall) to make the game more challenging. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' can now receive mouse events to make the user aim the barrel by clicking on it and dragging. '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' also has a barrier wall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@barrelPressed = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. Initially, the mouse is not pressed on the barrel.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height() ||&lt;br /&gt;
    shotR.intersects(barrierRect())&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have a barrier, there are three ways to miss. We test for the third, too. (In '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;'''.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mousePressEvent(event)&lt;br /&gt;
  unless event.button() == Qt::LeftButton&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if barrelHit(event.pos())&lt;br /&gt;
    @barrelPressed = true&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a Qt event handler. It is called when the user presses a mouse button when the mouse cursor is over the widget.&lt;br /&gt;
&lt;br /&gt;
If the event was not generated by the left mouse button, we return immediately. Otherwise, we check if the position of the mouse cursor is within the cannon's barrel. If it is, we set '''&amp;lt;tt&amp;gt;barrelPressed&amp;lt;/tt&amp;gt;''' to true.&lt;br /&gt;
&lt;br /&gt;
Notice that the [http://doc.qt.nokia.com/latest/qmouseevent.html#pos Qt::MouseEvent::pos()] function returns a point in the widget's coordinate system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseMoveEvent(event)&lt;br /&gt;
  unless @barrelPressed&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  pos = event.pos();&lt;br /&gt;
&lt;br /&gt;
  if pos.x() &amp;lt;= 0&lt;br /&gt;
    pos.setX(1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if pos.y() &amp;gt;= height()&lt;br /&gt;
    pos.setY(height() - 1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  rad = atan2((rect().bottom() - pos.y()), pos.x())&lt;br /&gt;
  setAngle((rad * 180 / 3.14159265).round())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is another Qt event handler. It is called when the user already has pressed the mouse button inside this widget and then moves/drags the mouse. (You can make Qt send mouse move events even when no buttons are pressed. See [http://doc.qt.nokia.com/latest/qwidget.html#mouseTracking-prop Qt::Widget::setMouseTracking()].)&lt;br /&gt;
&lt;br /&gt;
This handler repositions the cannon's barrel according to the position of the mouse cursor.&lt;br /&gt;
&lt;br /&gt;
First, if the barrel is not pressed, we return. Next, we fetch the mouse cursor's position. If the mouse cursor is to the left or below the widget, we adjust the point to be inside the widget.&lt;br /&gt;
&lt;br /&gt;
Then we calculate the angle between the bottom edge of the widget and the imaginary line between the bottom-left corner of the widget and the cursor position. Finally we set the cannon's angle to the new value converted to degrees.&lt;br /&gt;
&lt;br /&gt;
Remember that '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;''' redraws the cannon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def mouseReleaseEvent(event)&lt;br /&gt;
  if event.button() == Qt::LeftButton&lt;br /&gt;
    @barrelPressed = false&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Qt event handler is called whenever the user releases a mouse button and it was pressed inside this widget.&lt;br /&gt;
&lt;br /&gt;
If the left button is released, we can be sure that the barrel is no longer pressed.&lt;br /&gt;
&lt;br /&gt;
The paint event has one extra line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
paintBarrier(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;paintBarrier()&amp;lt;/tt&amp;gt;''' does the same sort of thing as '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''', '''&amp;lt;tt&amp;gt;paintTarget()&amp;lt;/tt&amp;gt;''', and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintBarrier( painter )&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::yellow))&lt;br /&gt;
  painter.setPen(Qt::Color.new(Qt::black))&lt;br /&gt;
  painter.drawRect(barrierRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the barrier as a rectangle filled with yellow and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrierRect()&lt;br /&gt;
  return Qt::Rect.new(145, height() - 100, 15, 99)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns the rectangle of the barrier. We fix the bottom edge of the barrier to the bottom edge of the widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def barrelHit(pos)&lt;br /&gt;
  matrix = Qt::Matrix.new()&lt;br /&gt;
  matrix.translate(0, height())&lt;br /&gt;
  matrix.rotate(-@currentAngle)&lt;br /&gt;
  matrix = matrix.inverted()&lt;br /&gt;
  return @barrelRect.contains(matrix.map(pos))&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function returns '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if the point is in the barrel; otherwise it returns '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Here we use the class [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix]. [http://doc.qt.nokia.com/latest/qmatrix.html Qt::Matrix] defines a coordinate system mapping. It can perform the same transformations as the [http://doc.qt.nokia.com/latest/qpainter.html Qt::Painter].&lt;br /&gt;
&lt;br /&gt;
Here we perform the same transformation steps as we do when drawing the barrel in the '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' function. First we translate the coordinate system and then we rotate it.&lt;br /&gt;
&lt;br /&gt;
Now we need to check whether the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' (in widget coordinates) lies inside the barrel. To do this, we invert the transformation matrix. The inverted matrix performs the inverse transformation that we used when drawing the barrel. We map the point '''&amp;lt;tt&amp;gt;pos&amp;lt;/tt&amp;gt;''' using the inverted matrix and return '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' if it is inside the original barrel rectangle.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t14/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
cannonBox = Qt::Frame.new()&lt;br /&gt;
cannonBox.setFrameStyle(Qt::Frame::WinPanel | Qt::Frame::Sunken)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create and set up a [http://doc.qt.nokia.com/latest/qframe.html Qt::Frame], and set its frame style. This results in a 3D frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Enter.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::Key_Return.to_i),&lt;br /&gt;
                 self, SLOT('fire()'))&lt;br /&gt;
Qt::Shortcut.new(Qt::KeySequence.new(Qt::CTRL.to_i + Qt::Key_Q.to_i),&lt;br /&gt;
                 self, SLOT('close()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we create and set up three [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] objects. These objects intercept keyboard events to a widget and call slots if certain keys are pressed. Note that a [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] object is a child of a widget and will be destroyed when that widget is destroyed. [http://doc.qt.nokia.com/latest/qshortcut.html Qt::Shortcut] itself is not a widget and has no visible effect on its parent.&lt;br /&gt;
&lt;br /&gt;
We define three shortcut keys. We want the '''&amp;lt;tt&amp;gt;fire()&amp;lt;/tt&amp;gt;''' slot to be called when the user presses Enter or Return. We also want the application to quit when key Ctrl+Q is pressed. Instead of connecting to [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit Qt::CoreApplication::quit()], we connect to [http://doc.qt.nokia.com/latest/qwidget.html#close Qt::Widget::close()] this time. Since the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' is the application's main widget, this has the same effect as [http://doc.qt.nokia.com/latest/qcoreapplication.html#quit QCoreApplication::quit()].&lt;br /&gt;
&lt;br /&gt;
Qt::CTRL, Qt::Key_Enter, Qt::Key_Return, and Qt::Key_Q are all constants declared in the Qt namespace. Unfortunately, in the current version of qtruby, they need to be converted to integers before we can use them in our shortcuts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(topLayout, 0, 1)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(@cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
setLayout(gridLayout)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''' its own [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout], and we add '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to that layout. This implicitly makes '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' a child of '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;'''. Because nothing else is in the box, the effect is that the [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] will put a frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''. We put '''&amp;lt;tt&amp;gt;cannonBox&amp;lt;/tt&amp;gt;''', not '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', in the grid layout.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon now shoots when you press Enter. You can also position the cannon's angle using the mouse. The barrier makes it a little more challenging to play the game. We also have a nice looking frame around the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Write a space invaders game.&lt;br /&gt;
&lt;br /&gt;
The new exercise is: Write a Breakout game.&lt;br /&gt;
&lt;br /&gt;
Final exhortation: Go forth now and create masterpieces of the programming art!&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/52/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/52/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/52/fi"/>
				<updated>2011-11-01T17:32:19Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Category:Ruby&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi"/>
				<updated>2011-11-01T17:32:11Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Peli loppui|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14|Tutorial 14 - Facing the Wall]]&lt;br /&gt;
}}&lt;br /&gt;
== Peli loppui ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_13.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we start to approach a real playable game with a score.&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' a new name ('''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;'''), add some slots, and move it to '''&amp;lt;tt&amp;gt;gamebrd.rb&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state.&lt;br /&gt;
&lt;br /&gt;
The layout problems in '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' are fixed. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @label.setSizePolicy(Qt::SizePolicy::Preferred, Qt::SizePolicy::Fixed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the size policy of the [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] to ([http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Preferred], [http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Fixed]). The vertical component ensures that the label won't stretch or shrink vertically; it will stay at its optimal size (its [http://doc.qt.nokia.com/latest/qwidget.html#sizeHint-prop QWidget::sizeHint()]). This solves the layout problems observed in Chapter 12.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state and a few new functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'canShoot(bool)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new signal indicates that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is in a state where the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot makes sense. We'll use it below to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @gameEnded = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This variable contains the game state; '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' means that the game is over, and '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;''' means that a game is going on. Initially, the game is not over (luckily for the player :-).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
  emit canShoot(false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We added a new '''&amp;lt;tt&amp;gt;isShooting()&amp;lt;/tt&amp;gt;''' function, so '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' uses it instead of testing directly. Also, shoot tells the world that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' cannot shoot now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setGameOver()&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = true&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot ends the game. It must be called from outside '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', because this widget does not know when to end the game. This is an important design principle in component programming. We choose to make the component as flexible as possible to make it usable with different rules (for example, a multi-player version of this in which the first player to hit ten times wins could use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' unchanged).&lt;br /&gt;
&lt;br /&gt;
If the game has already been ended we return immediately. If a game is going on we stop the shot, set the game over flag, and repaint the entire widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def restartGame()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = false&lt;br /&gt;
&lt;br /&gt;
  update()&lt;br /&gt;
  emit canShoot(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot starts a new game. If a shot is in the air, we stop shooting. We then reset the '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' variable and repaint the widget.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' too emits the new '''&amp;lt;tt&amp;gt;canShoot(true)&amp;lt;/tt&amp;gt;''' signal at the same time as either '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' or '''&amp;lt;tt&amp;gt;miss()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Modifications in CannonField::paintEvent():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    painter.setPen(Qt::black)&lt;br /&gt;
    painter.setFont(Qt::Font.new( &amp;quot;Courier&amp;quot;, 48, Qt::Font::Bold))&lt;br /&gt;
    painter.drawText(rect(), Qt::AlignCenter, tr(&amp;quot;Game Over&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event has been enhanced to display the text &amp;quot;Game Over&amp;quot; if the game is over, i.e., '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' is '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;'''. We don't bother to check the update rectangle here because speed is not critical when the game is over.&lt;br /&gt;
&lt;br /&gt;
To draw the text we first set a black pen; the pen color is used when drawing text. Next we choose a 48 point bold font from the Courier family. Finally we draw the text centered in the widget's rectangle. Unfortunately, on some systems (especially X servers with Unicode fonts) it can take a while to load such a large font. Because Qt caches fonts, you will notice this only the first time the font is used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end        &lt;br /&gt;
&lt;br /&gt;
  unless @gameEnded&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We draw the shot only when shooting and the target only when playing (that is, when the game is not ended).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file is new. It contains the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' class, which was last seen as '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  slots 'fire()', 'hit()', 'missed()', 'newGame()'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We have now added four slots.&lt;br /&gt;
&lt;br /&gt;
We have also made some changes in the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' constructor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @cannonField = CannonField.new()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;@cannonField&amp;lt;/tt&amp;gt;''' is now a member variable, so we carefully change the constructor to use it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('hit()'),&lt;br /&gt;
        self, SLOT('hit()'))&lt;br /&gt;
connect(@cannonField, SIGNAL('missed()'),&lt;br /&gt;
        self, SLOT('missed()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time we want to do something when the shot has hit or missed the target. Thus we connect the '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signals of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to two protected slots with the same names in this class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    connect(shoot, SIGNAL('clicked()'), self, SLOT('fire()') )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Previously we connected the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button's '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal directly to the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot. This time we want to keep track of the number of shots fired, so we connect it to a slot in this class instead.&lt;br /&gt;
&lt;br /&gt;
Notice how easy it is to change the behavior of a program when you are working with self-contained components.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('canShoot(bool)'),&lt;br /&gt;
        shoot, SLOT('setEnabled(bool)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;canShoot()&amp;lt;/tt&amp;gt;''' signal to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button appropriately.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
restart = Qt::PushButton.new(tr('&amp;amp;New Game'))&lt;br /&gt;
restart.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&lt;br /&gt;
connect(restart, SIGNAL('clicked()'), self, SLOT('newGame()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create, set up, and connect the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button as we have done with the other buttons. Clicking this button will activate the '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' slot in this widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@hits = Qt::LCDNumber.new(2)&lt;br /&gt;
@shotsLeft = Qt::LCDNumber.new(2)&lt;br /&gt;
hitsLabel = Qt::Label.new(tr('HITS'))&lt;br /&gt;
shotsLeftLabel = Qt::Label.new(tr('SHOTS LEFT'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create four new widgets, to display the number of hits and shots left.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
topLayout = Qt::HBoxLayout.new()&lt;br /&gt;
topLayout.addWidget(shoot)&lt;br /&gt;
topLayout.addWidget(@hits)&lt;br /&gt;
topLayout.addWidget(hitsLabel)&lt;br /&gt;
topLayout.addWidget(@shotsLeft)&lt;br /&gt;
topLayout.addWidget(shotsLeftLabel)&lt;br /&gt;
topLayout.addStretch(1)&lt;br /&gt;
topLayout.addWidget(restart)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The top-right cell of the [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] is starting to get crowded. We put a stretch just to the left of the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button to ensure that this button will always appear on the right side of the window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newGame()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We're all done constructing the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''', so we start it all using '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;'''. Although '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' is a slot, it can also be used as an ordinary function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def fire()&lt;br /&gt;
  if @cannonField.gameOver() || @cannonField.isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @shotsLeft.display(@shotsLeft.intValue() - 1)&lt;br /&gt;
  @cannonField.shoot()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function fires a shot. If the game is over or if there is a shot in the air, we return immediately. We decrement the number of shots left and tell the cannon to shoot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def hit()&lt;br /&gt;
  @hits.display(@hits.intValue() + 1)&lt;br /&gt;
&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  else&lt;br /&gt;
    @cannonField.newTarget()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has hit the target. We increment the number of hits. If there are no shots left, the game is over. Otherwise, we make the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' generate a new target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def missed()&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has missed the target. If there are no shots left, the game is over.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def newGame()&lt;br /&gt;
  @shotsLeft.display(15)&lt;br /&gt;
  @hits.display(0)&lt;br /&gt;
  @cannonField.restartGame()&lt;br /&gt;
  @cannonField.newTarget()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when the user clicks the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button. It is also called from the constructor. First it sets the number of shots to 15. Note that this is the only place in the program where we set the number of shots. Change it to whatever you like to change the game rules. Next we reset the number of hits, restart the game, and generate a new target.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file has just been on a diet. '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' is gone, and the only thing left is the '''&amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;''' function, unchanged except for the name change.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot at a target; a new target is automatically created when one has been hit.&lt;br /&gt;
&lt;br /&gt;
Hits and shots left are displayed and the program keeps track of them. The game can end, and there's a button to start a new game.&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
&lt;br /&gt;
Add a random wind factor and show it to the user.&lt;br /&gt;
&lt;br /&gt;
Make some splatter effects when the shot hits the target.&lt;br /&gt;
&lt;br /&gt;
Implement multiple targets.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/48/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/48/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/48/fi"/>
				<updated>2011-11-01T17:32:11Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Harjoitukset ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi"/>
				<updated>2011-11-01T17:32:00Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Sovelluksen suorittaminen ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Peli loppui|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14|Tutorial 14 - Facing the Wall]]&lt;br /&gt;
}}&lt;br /&gt;
== Peli loppui ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_13.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we start to approach a real playable game with a score.&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' a new name ('''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;'''), add some slots, and move it to '''&amp;lt;tt&amp;gt;gamebrd.rb&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state.&lt;br /&gt;
&lt;br /&gt;
The layout problems in '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' are fixed. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @label.setSizePolicy(Qt::SizePolicy::Preferred, Qt::SizePolicy::Fixed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the size policy of the [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] to ([http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Preferred], [http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Fixed]). The vertical component ensures that the label won't stretch or shrink vertically; it will stay at its optimal size (its [http://doc.qt.nokia.com/latest/qwidget.html#sizeHint-prop QWidget::sizeHint()]). This solves the layout problems observed in Chapter 12.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state and a few new functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'canShoot(bool)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new signal indicates that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is in a state where the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot makes sense. We'll use it below to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @gameEnded = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This variable contains the game state; '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' means that the game is over, and '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;''' means that a game is going on. Initially, the game is not over (luckily for the player :-).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
  emit canShoot(false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We added a new '''&amp;lt;tt&amp;gt;isShooting()&amp;lt;/tt&amp;gt;''' function, so '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' uses it instead of testing directly. Also, shoot tells the world that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' cannot shoot now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setGameOver()&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = true&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot ends the game. It must be called from outside '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', because this widget does not know when to end the game. This is an important design principle in component programming. We choose to make the component as flexible as possible to make it usable with different rules (for example, a multi-player version of this in which the first player to hit ten times wins could use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' unchanged).&lt;br /&gt;
&lt;br /&gt;
If the game has already been ended we return immediately. If a game is going on we stop the shot, set the game over flag, and repaint the entire widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def restartGame()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = false&lt;br /&gt;
&lt;br /&gt;
  update()&lt;br /&gt;
  emit canShoot(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot starts a new game. If a shot is in the air, we stop shooting. We then reset the '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' variable and repaint the widget.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' too emits the new '''&amp;lt;tt&amp;gt;canShoot(true)&amp;lt;/tt&amp;gt;''' signal at the same time as either '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' or '''&amp;lt;tt&amp;gt;miss()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Modifications in CannonField::paintEvent():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    painter.setPen(Qt::black)&lt;br /&gt;
    painter.setFont(Qt::Font.new( &amp;quot;Courier&amp;quot;, 48, Qt::Font::Bold))&lt;br /&gt;
    painter.drawText(rect(), Qt::AlignCenter, tr(&amp;quot;Game Over&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event has been enhanced to display the text &amp;quot;Game Over&amp;quot; if the game is over, i.e., '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' is '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;'''. We don't bother to check the update rectangle here because speed is not critical when the game is over.&lt;br /&gt;
&lt;br /&gt;
To draw the text we first set a black pen; the pen color is used when drawing text. Next we choose a 48 point bold font from the Courier family. Finally we draw the text centered in the widget's rectangle. Unfortunately, on some systems (especially X servers with Unicode fonts) it can take a while to load such a large font. Because Qt caches fonts, you will notice this only the first time the font is used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end        &lt;br /&gt;
&lt;br /&gt;
  unless @gameEnded&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We draw the shot only when shooting and the target only when playing (that is, when the game is not ended).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file is new. It contains the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' class, which was last seen as '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  slots 'fire()', 'hit()', 'missed()', 'newGame()'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We have now added four slots.&lt;br /&gt;
&lt;br /&gt;
We have also made some changes in the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' constructor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @cannonField = CannonField.new()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;@cannonField&amp;lt;/tt&amp;gt;''' is now a member variable, so we carefully change the constructor to use it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('hit()'),&lt;br /&gt;
        self, SLOT('hit()'))&lt;br /&gt;
connect(@cannonField, SIGNAL('missed()'),&lt;br /&gt;
        self, SLOT('missed()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time we want to do something when the shot has hit or missed the target. Thus we connect the '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signals of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to two protected slots with the same names in this class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    connect(shoot, SIGNAL('clicked()'), self, SLOT('fire()') )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Previously we connected the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button's '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal directly to the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot. This time we want to keep track of the number of shots fired, so we connect it to a slot in this class instead.&lt;br /&gt;
&lt;br /&gt;
Notice how easy it is to change the behavior of a program when you are working with self-contained components.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('canShoot(bool)'),&lt;br /&gt;
        shoot, SLOT('setEnabled(bool)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;canShoot()&amp;lt;/tt&amp;gt;''' signal to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button appropriately.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
restart = Qt::PushButton.new(tr('&amp;amp;New Game'))&lt;br /&gt;
restart.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&lt;br /&gt;
connect(restart, SIGNAL('clicked()'), self, SLOT('newGame()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create, set up, and connect the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button as we have done with the other buttons. Clicking this button will activate the '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' slot in this widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@hits = Qt::LCDNumber.new(2)&lt;br /&gt;
@shotsLeft = Qt::LCDNumber.new(2)&lt;br /&gt;
hitsLabel = Qt::Label.new(tr('HITS'))&lt;br /&gt;
shotsLeftLabel = Qt::Label.new(tr('SHOTS LEFT'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create four new widgets, to display the number of hits and shots left.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
topLayout = Qt::HBoxLayout.new()&lt;br /&gt;
topLayout.addWidget(shoot)&lt;br /&gt;
topLayout.addWidget(@hits)&lt;br /&gt;
topLayout.addWidget(hitsLabel)&lt;br /&gt;
topLayout.addWidget(@shotsLeft)&lt;br /&gt;
topLayout.addWidget(shotsLeftLabel)&lt;br /&gt;
topLayout.addStretch(1)&lt;br /&gt;
topLayout.addWidget(restart)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The top-right cell of the [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] is starting to get crowded. We put a stretch just to the left of the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button to ensure that this button will always appear on the right side of the window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newGame()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We're all done constructing the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''', so we start it all using '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;'''. Although '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' is a slot, it can also be used as an ordinary function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def fire()&lt;br /&gt;
  if @cannonField.gameOver() || @cannonField.isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @shotsLeft.display(@shotsLeft.intValue() - 1)&lt;br /&gt;
  @cannonField.shoot()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function fires a shot. If the game is over or if there is a shot in the air, we return immediately. We decrement the number of shots left and tell the cannon to shoot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def hit()&lt;br /&gt;
  @hits.display(@hits.intValue() + 1)&lt;br /&gt;
&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  else&lt;br /&gt;
    @cannonField.newTarget()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has hit the target. We increment the number of hits. If there are no shots left, the game is over. Otherwise, we make the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' generate a new target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def missed()&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has missed the target. If there are no shots left, the game is over.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def newGame()&lt;br /&gt;
  @shotsLeft.display(15)&lt;br /&gt;
  @hits.display(0)&lt;br /&gt;
  @cannonField.restartGame()&lt;br /&gt;
  @cannonField.newTarget()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when the user clicks the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button. It is also called from the constructor. First it sets the number of shots to 15. Note that this is the only place in the program where we set the number of shots. Change it to whatever you like to change the game rules. Next we reset the number of hits, restart the game, and generate a new target.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file has just been on a diet. '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' is gone, and the only thing left is the '''&amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;''' function, unchanged except for the name change.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot at a target; a new target is automatically created when one has been hit.&lt;br /&gt;
&lt;br /&gt;
Hits and shots left are displayed and the program keeps track of them. The game can end, and there's a button to start a new game.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Add a random wind factor and show it to the user.&lt;br /&gt;
&lt;br /&gt;
Make some splatter effects when the shot hits the target.&lt;br /&gt;
&lt;br /&gt;
Implement multiple targets.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/45/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/45/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/45/fi"/>
				<updated>2011-11-01T17:31:59Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Sovelluksen suorittaminen ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Sovelluksen suorittaminen ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi"/>
				<updated>2011-11-01T17:31:37Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Läpikäynti rivi riviltä ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Peli loppui|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14|Tutorial 14 - Facing the Wall]]&lt;br /&gt;
}}&lt;br /&gt;
== Peli loppui ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_13.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we start to approach a real playable game with a score.&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' a new name ('''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;'''), add some slots, and move it to '''&amp;lt;tt&amp;gt;gamebrd.rb&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state.&lt;br /&gt;
&lt;br /&gt;
The layout problems in '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' are fixed. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @label.setSizePolicy(Qt::SizePolicy::Preferred, Qt::SizePolicy::Fixed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the size policy of the [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] to ([http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Preferred], [http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Fixed]). The vertical component ensures that the label won't stretch or shrink vertically; it will stay at its optimal size (its [http://doc.qt.nokia.com/latest/qwidget.html#sizeHint-prop QWidget::sizeHint()]). This solves the layout problems observed in Chapter 12.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state and a few new functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'canShoot(bool)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new signal indicates that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is in a state where the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot makes sense. We'll use it below to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @gameEnded = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This variable contains the game state; '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' means that the game is over, and '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;''' means that a game is going on. Initially, the game is not over (luckily for the player :-).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
  emit canShoot(false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We added a new '''&amp;lt;tt&amp;gt;isShooting()&amp;lt;/tt&amp;gt;''' function, so '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' uses it instead of testing directly. Also, shoot tells the world that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' cannot shoot now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setGameOver()&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = true&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot ends the game. It must be called from outside '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', because this widget does not know when to end the game. This is an important design principle in component programming. We choose to make the component as flexible as possible to make it usable with different rules (for example, a multi-player version of this in which the first player to hit ten times wins could use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' unchanged).&lt;br /&gt;
&lt;br /&gt;
If the game has already been ended we return immediately. If a game is going on we stop the shot, set the game over flag, and repaint the entire widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def restartGame()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = false&lt;br /&gt;
&lt;br /&gt;
  update()&lt;br /&gt;
  emit canShoot(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot starts a new game. If a shot is in the air, we stop shooting. We then reset the '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' variable and repaint the widget.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' too emits the new '''&amp;lt;tt&amp;gt;canShoot(true)&amp;lt;/tt&amp;gt;''' signal at the same time as either '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' or '''&amp;lt;tt&amp;gt;miss()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Modifications in CannonField::paintEvent():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    painter.setPen(Qt::black)&lt;br /&gt;
    painter.setFont(Qt::Font.new( &amp;quot;Courier&amp;quot;, 48, Qt::Font::Bold))&lt;br /&gt;
    painter.drawText(rect(), Qt::AlignCenter, tr(&amp;quot;Game Over&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event has been enhanced to display the text &amp;quot;Game Over&amp;quot; if the game is over, i.e., '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' is '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;'''. We don't bother to check the update rectangle here because speed is not critical when the game is over.&lt;br /&gt;
&lt;br /&gt;
To draw the text we first set a black pen; the pen color is used when drawing text. Next we choose a 48 point bold font from the Courier family. Finally we draw the text centered in the widget's rectangle. Unfortunately, on some systems (especially X servers with Unicode fonts) it can take a while to load such a large font. Because Qt caches fonts, you will notice this only the first time the font is used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end        &lt;br /&gt;
&lt;br /&gt;
  unless @gameEnded&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We draw the shot only when shooting and the target only when playing (that is, when the game is not ended).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file is new. It contains the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' class, which was last seen as '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  slots 'fire()', 'hit()', 'missed()', 'newGame()'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We have now added four slots.&lt;br /&gt;
&lt;br /&gt;
We have also made some changes in the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' constructor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @cannonField = CannonField.new()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;@cannonField&amp;lt;/tt&amp;gt;''' is now a member variable, so we carefully change the constructor to use it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('hit()'),&lt;br /&gt;
        self, SLOT('hit()'))&lt;br /&gt;
connect(@cannonField, SIGNAL('missed()'),&lt;br /&gt;
        self, SLOT('missed()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time we want to do something when the shot has hit or missed the target. Thus we connect the '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signals of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to two protected slots with the same names in this class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    connect(shoot, SIGNAL('clicked()'), self, SLOT('fire()') )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Previously we connected the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button's '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal directly to the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot. This time we want to keep track of the number of shots fired, so we connect it to a slot in this class instead.&lt;br /&gt;
&lt;br /&gt;
Notice how easy it is to change the behavior of a program when you are working with self-contained components.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('canShoot(bool)'),&lt;br /&gt;
        shoot, SLOT('setEnabled(bool)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;canShoot()&amp;lt;/tt&amp;gt;''' signal to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button appropriately.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
restart = Qt::PushButton.new(tr('&amp;amp;New Game'))&lt;br /&gt;
restart.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&lt;br /&gt;
connect(restart, SIGNAL('clicked()'), self, SLOT('newGame()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create, set up, and connect the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button as we have done with the other buttons. Clicking this button will activate the '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' slot in this widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@hits = Qt::LCDNumber.new(2)&lt;br /&gt;
@shotsLeft = Qt::LCDNumber.new(2)&lt;br /&gt;
hitsLabel = Qt::Label.new(tr('HITS'))&lt;br /&gt;
shotsLeftLabel = Qt::Label.new(tr('SHOTS LEFT'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create four new widgets, to display the number of hits and shots left.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
topLayout = Qt::HBoxLayout.new()&lt;br /&gt;
topLayout.addWidget(shoot)&lt;br /&gt;
topLayout.addWidget(@hits)&lt;br /&gt;
topLayout.addWidget(hitsLabel)&lt;br /&gt;
topLayout.addWidget(@shotsLeft)&lt;br /&gt;
topLayout.addWidget(shotsLeftLabel)&lt;br /&gt;
topLayout.addStretch(1)&lt;br /&gt;
topLayout.addWidget(restart)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The top-right cell of the [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] is starting to get crowded. We put a stretch just to the left of the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button to ensure that this button will always appear on the right side of the window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newGame()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We're all done constructing the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''', so we start it all using '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;'''. Although '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' is a slot, it can also be used as an ordinary function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def fire()&lt;br /&gt;
  if @cannonField.gameOver() || @cannonField.isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @shotsLeft.display(@shotsLeft.intValue() - 1)&lt;br /&gt;
  @cannonField.shoot()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function fires a shot. If the game is over or if there is a shot in the air, we return immediately. We decrement the number of shots left and tell the cannon to shoot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def hit()&lt;br /&gt;
  @hits.display(@hits.intValue() + 1)&lt;br /&gt;
&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  else&lt;br /&gt;
    @cannonField.newTarget()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has hit the target. We increment the number of hits. If there are no shots left, the game is over. Otherwise, we make the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' generate a new target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def missed()&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has missed the target. If there are no shots left, the game is over.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def newGame()&lt;br /&gt;
  @shotsLeft.display(15)&lt;br /&gt;
  @hits.display(0)&lt;br /&gt;
  @cannonField.restartGame()&lt;br /&gt;
  @cannonField.newTarget()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when the user clicks the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button. It is also called from the constructor. First it sets the number of shots to 15. Note that this is the only place in the program where we set the number of shots. Change it to whatever you like to change the game rules. Next we reset the number of hits, restart the game, and generate a new target.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file has just been on a diet. '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' is gone, and the only thing left is the '''&amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;''' function, unchanged except for the name change.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot at a target; a new target is automatically created when one has been hit.&lt;br /&gt;
&lt;br /&gt;
Hits and shots left are displayed and the program keeps track of them. The game can end, and there's a button to start a new game.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Add a random wind factor and show it to the user.&lt;br /&gt;
&lt;br /&gt;
Make some splatter effects when the shot hits the target.&lt;br /&gt;
&lt;br /&gt;
Implement multiple targets.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/14/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/14/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/14/fi"/>
				<updated>2011-11-01T17:31:37Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Läpikäynti rivi riviltä ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Läpikäynti rivi riviltä ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi"/>
				<updated>2011-11-01T17:31:13Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Yleiskuva ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Peli loppui|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14|Tutorial 14 - Facing the Wall]]&lt;br /&gt;
}}&lt;br /&gt;
== Peli loppui ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_13.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we start to approach a real playable game with a score.&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' a new name ('''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;'''), add some slots, and move it to '''&amp;lt;tt&amp;gt;gamebrd.rb&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state.&lt;br /&gt;
&lt;br /&gt;
The layout problems in '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' are fixed. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @label.setSizePolicy(Qt::SizePolicy::Preferred, Qt::SizePolicy::Fixed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the size policy of the [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] to ([http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Preferred], [http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Fixed]). The vertical component ensures that the label won't stretch or shrink vertically; it will stay at its optimal size (its [http://doc.qt.nokia.com/latest/qwidget.html#sizeHint-prop QWidget::sizeHint()]). This solves the layout problems observed in Chapter 12.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state and a few new functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'canShoot(bool)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new signal indicates that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is in a state where the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot makes sense. We'll use it below to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @gameEnded = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This variable contains the game state; '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' means that the game is over, and '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;''' means that a game is going on. Initially, the game is not over (luckily for the player :-).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
  emit canShoot(false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We added a new '''&amp;lt;tt&amp;gt;isShooting()&amp;lt;/tt&amp;gt;''' function, so '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' uses it instead of testing directly. Also, shoot tells the world that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' cannot shoot now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setGameOver()&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = true&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot ends the game. It must be called from outside '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', because this widget does not know when to end the game. This is an important design principle in component programming. We choose to make the component as flexible as possible to make it usable with different rules (for example, a multi-player version of this in which the first player to hit ten times wins could use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' unchanged).&lt;br /&gt;
&lt;br /&gt;
If the game has already been ended we return immediately. If a game is going on we stop the shot, set the game over flag, and repaint the entire widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def restartGame()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = false&lt;br /&gt;
&lt;br /&gt;
  update()&lt;br /&gt;
  emit canShoot(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot starts a new game. If a shot is in the air, we stop shooting. We then reset the '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' variable and repaint the widget.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' too emits the new '''&amp;lt;tt&amp;gt;canShoot(true)&amp;lt;/tt&amp;gt;''' signal at the same time as either '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' or '''&amp;lt;tt&amp;gt;miss()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Modifications in CannonField::paintEvent():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    painter.setPen(Qt::black)&lt;br /&gt;
    painter.setFont(Qt::Font.new( &amp;quot;Courier&amp;quot;, 48, Qt::Font::Bold))&lt;br /&gt;
    painter.drawText(rect(), Qt::AlignCenter, tr(&amp;quot;Game Over&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event has been enhanced to display the text &amp;quot;Game Over&amp;quot; if the game is over, i.e., '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' is '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;'''. We don't bother to check the update rectangle here because speed is not critical when the game is over.&lt;br /&gt;
&lt;br /&gt;
To draw the text we first set a black pen; the pen color is used when drawing text. Next we choose a 48 point bold font from the Courier family. Finally we draw the text centered in the widget's rectangle. Unfortunately, on some systems (especially X servers with Unicode fonts) it can take a while to load such a large font. Because Qt caches fonts, you will notice this only the first time the font is used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end        &lt;br /&gt;
&lt;br /&gt;
  unless @gameEnded&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We draw the shot only when shooting and the target only when playing (that is, when the game is not ended).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file is new. It contains the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' class, which was last seen as '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  slots 'fire()', 'hit()', 'missed()', 'newGame()'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We have now added four slots.&lt;br /&gt;
&lt;br /&gt;
We have also made some changes in the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' constructor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @cannonField = CannonField.new()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;@cannonField&amp;lt;/tt&amp;gt;''' is now a member variable, so we carefully change the constructor to use it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('hit()'),&lt;br /&gt;
        self, SLOT('hit()'))&lt;br /&gt;
connect(@cannonField, SIGNAL('missed()'),&lt;br /&gt;
        self, SLOT('missed()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time we want to do something when the shot has hit or missed the target. Thus we connect the '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signals of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to two protected slots with the same names in this class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    connect(shoot, SIGNAL('clicked()'), self, SLOT('fire()') )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Previously we connected the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button's '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal directly to the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot. This time we want to keep track of the number of shots fired, so we connect it to a slot in this class instead.&lt;br /&gt;
&lt;br /&gt;
Notice how easy it is to change the behavior of a program when you are working with self-contained components.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('canShoot(bool)'),&lt;br /&gt;
        shoot, SLOT('setEnabled(bool)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;canShoot()&amp;lt;/tt&amp;gt;''' signal to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button appropriately.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
restart = Qt::PushButton.new(tr('&amp;amp;New Game'))&lt;br /&gt;
restart.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&lt;br /&gt;
connect(restart, SIGNAL('clicked()'), self, SLOT('newGame()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create, set up, and connect the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button as we have done with the other buttons. Clicking this button will activate the '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' slot in this widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@hits = Qt::LCDNumber.new(2)&lt;br /&gt;
@shotsLeft = Qt::LCDNumber.new(2)&lt;br /&gt;
hitsLabel = Qt::Label.new(tr('HITS'))&lt;br /&gt;
shotsLeftLabel = Qt::Label.new(tr('SHOTS LEFT'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create four new widgets, to display the number of hits and shots left.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
topLayout = Qt::HBoxLayout.new()&lt;br /&gt;
topLayout.addWidget(shoot)&lt;br /&gt;
topLayout.addWidget(@hits)&lt;br /&gt;
topLayout.addWidget(hitsLabel)&lt;br /&gt;
topLayout.addWidget(@shotsLeft)&lt;br /&gt;
topLayout.addWidget(shotsLeftLabel)&lt;br /&gt;
topLayout.addStretch(1)&lt;br /&gt;
topLayout.addWidget(restart)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The top-right cell of the [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] is starting to get crowded. We put a stretch just to the left of the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button to ensure that this button will always appear on the right side of the window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newGame()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We're all done constructing the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''', so we start it all using '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;'''. Although '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' is a slot, it can also be used as an ordinary function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def fire()&lt;br /&gt;
  if @cannonField.gameOver() || @cannonField.isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @shotsLeft.display(@shotsLeft.intValue() - 1)&lt;br /&gt;
  @cannonField.shoot()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function fires a shot. If the game is over or if there is a shot in the air, we return immediately. We decrement the number of shots left and tell the cannon to shoot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def hit()&lt;br /&gt;
  @hits.display(@hits.intValue() + 1)&lt;br /&gt;
&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  else&lt;br /&gt;
    @cannonField.newTarget()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has hit the target. We increment the number of hits. If there are no shots left, the game is over. Otherwise, we make the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' generate a new target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def missed()&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has missed the target. If there are no shots left, the game is over.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def newGame()&lt;br /&gt;
  @shotsLeft.display(15)&lt;br /&gt;
  @hits.display(0)&lt;br /&gt;
  @cannonField.restartGame()&lt;br /&gt;
  @cannonField.newTarget()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when the user clicks the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button. It is also called from the constructor. First it sets the number of shots to 15. Note that this is the only place in the program where we set the number of shots. Change it to whatever you like to change the game rules. Next we reset the number of hits, restart the game, and generate a new target.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file has just been on a diet. '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' is gone, and the only thing left is the '''&amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;''' function, unchanged except for the name change.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot at a target; a new target is automatically created when one has been hit.&lt;br /&gt;
&lt;br /&gt;
Hits and shots left are displayed and the program keeps track of them. The game can end, and there's a button to start a new game.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Add a random wind factor and show it to the user.&lt;br /&gt;
&lt;br /&gt;
Make some splatter effects when the shot hits the target.&lt;br /&gt;
&lt;br /&gt;
Implement multiple targets.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/9/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/9/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/9/fi"/>
				<updated>2011-11-01T17:31:13Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Yleiskuva ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Yleiskuva ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/7/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/7/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/7/fi"/>
				<updated>2011-11-01T17:31:02Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;center&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:Qt4_Ruby_Tutorial_Screenshot_13.png|center]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi"/>
				<updated>2011-11-01T17:30:53Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;== Peli loppui ==&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Peli loppui|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14|Tutorial 14 - Facing the Wall]]&lt;br /&gt;
}}&lt;br /&gt;
== Peli loppui ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_13.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example we start to approach a real playable game with a score.&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' a new name ('''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;'''), add some slots, and move it to '''&amp;lt;tt&amp;gt;gamebrd.rb&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state.&lt;br /&gt;
&lt;br /&gt;
The layout problems in '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' are fixed. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @label.setSizePolicy(Qt::SizePolicy::Preferred, Qt::SizePolicy::Fixed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the size policy of the [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] to ([http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Preferred], [http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Fixed]). The vertical component ensures that the label won't stretch or shrink vertically; it will stay at its optimal size (its [http://doc.qt.nokia.com/latest/qwidget.html#sizeHint-prop QWidget::sizeHint()]). This solves the layout problems observed in Chapter 12.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state and a few new functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'canShoot(bool)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new signal indicates that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is in a state where the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot makes sense. We'll use it below to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @gameEnded = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This variable contains the game state; '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' means that the game is over, and '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;''' means that a game is going on. Initially, the game is not over (luckily for the player :-).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
  emit canShoot(false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We added a new '''&amp;lt;tt&amp;gt;isShooting()&amp;lt;/tt&amp;gt;''' function, so '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' uses it instead of testing directly. Also, shoot tells the world that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' cannot shoot now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setGameOver()&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = true&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot ends the game. It must be called from outside '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', because this widget does not know when to end the game. This is an important design principle in component programming. We choose to make the component as flexible as possible to make it usable with different rules (for example, a multi-player version of this in which the first player to hit ten times wins could use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' unchanged).&lt;br /&gt;
&lt;br /&gt;
If the game has already been ended we return immediately. If a game is going on we stop the shot, set the game over flag, and repaint the entire widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def restartGame()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = false&lt;br /&gt;
&lt;br /&gt;
  update()&lt;br /&gt;
  emit canShoot(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot starts a new game. If a shot is in the air, we stop shooting. We then reset the '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' variable and repaint the widget.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' too emits the new '''&amp;lt;tt&amp;gt;canShoot(true)&amp;lt;/tt&amp;gt;''' signal at the same time as either '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' or '''&amp;lt;tt&amp;gt;miss()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Modifications in CannonField::paintEvent():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    painter.setPen(Qt::black)&lt;br /&gt;
    painter.setFont(Qt::Font.new( &amp;quot;Courier&amp;quot;, 48, Qt::Font::Bold))&lt;br /&gt;
    painter.drawText(rect(), Qt::AlignCenter, tr(&amp;quot;Game Over&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event has been enhanced to display the text &amp;quot;Game Over&amp;quot; if the game is over, i.e., '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' is '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;'''. We don't bother to check the update rectangle here because speed is not critical when the game is over.&lt;br /&gt;
&lt;br /&gt;
To draw the text we first set a black pen; the pen color is used when drawing text. Next we choose a 48 point bold font from the Courier family. Finally we draw the text centered in the widget's rectangle. Unfortunately, on some systems (especially X servers with Unicode fonts) it can take a while to load such a large font. Because Qt caches fonts, you will notice this only the first time the font is used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end        &lt;br /&gt;
&lt;br /&gt;
  unless @gameEnded&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We draw the shot only when shooting and the target only when playing (that is, when the game is not ended).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file is new. It contains the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' class, which was last seen as '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  slots 'fire()', 'hit()', 'missed()', 'newGame()'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We have now added four slots.&lt;br /&gt;
&lt;br /&gt;
We have also made some changes in the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' constructor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @cannonField = CannonField.new()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;@cannonField&amp;lt;/tt&amp;gt;''' is now a member variable, so we carefully change the constructor to use it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('hit()'),&lt;br /&gt;
        self, SLOT('hit()'))&lt;br /&gt;
connect(@cannonField, SIGNAL('missed()'),&lt;br /&gt;
        self, SLOT('missed()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time we want to do something when the shot has hit or missed the target. Thus we connect the '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signals of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to two protected slots with the same names in this class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    connect(shoot, SIGNAL('clicked()'), self, SLOT('fire()') )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Previously we connected the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button's '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal directly to the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot. This time we want to keep track of the number of shots fired, so we connect it to a slot in this class instead.&lt;br /&gt;
&lt;br /&gt;
Notice how easy it is to change the behavior of a program when you are working with self-contained components.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('canShoot(bool)'),&lt;br /&gt;
        shoot, SLOT('setEnabled(bool)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;canShoot()&amp;lt;/tt&amp;gt;''' signal to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button appropriately.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
restart = Qt::PushButton.new(tr('&amp;amp;New Game'))&lt;br /&gt;
restart.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&lt;br /&gt;
connect(restart, SIGNAL('clicked()'), self, SLOT('newGame()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create, set up, and connect the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button as we have done with the other buttons. Clicking this button will activate the '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' slot in this widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@hits = Qt::LCDNumber.new(2)&lt;br /&gt;
@shotsLeft = Qt::LCDNumber.new(2)&lt;br /&gt;
hitsLabel = Qt::Label.new(tr('HITS'))&lt;br /&gt;
shotsLeftLabel = Qt::Label.new(tr('SHOTS LEFT'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create four new widgets, to display the number of hits and shots left.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
topLayout = Qt::HBoxLayout.new()&lt;br /&gt;
topLayout.addWidget(shoot)&lt;br /&gt;
topLayout.addWidget(@hits)&lt;br /&gt;
topLayout.addWidget(hitsLabel)&lt;br /&gt;
topLayout.addWidget(@shotsLeft)&lt;br /&gt;
topLayout.addWidget(shotsLeftLabel)&lt;br /&gt;
topLayout.addStretch(1)&lt;br /&gt;
topLayout.addWidget(restart)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The top-right cell of the [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] is starting to get crowded. We put a stretch just to the left of the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button to ensure that this button will always appear on the right side of the window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newGame()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We're all done constructing the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''', so we start it all using '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;'''. Although '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' is a slot, it can also be used as an ordinary function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def fire()&lt;br /&gt;
  if @cannonField.gameOver() || @cannonField.isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @shotsLeft.display(@shotsLeft.intValue() - 1)&lt;br /&gt;
  @cannonField.shoot()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function fires a shot. If the game is over or if there is a shot in the air, we return immediately. We decrement the number of shots left and tell the cannon to shoot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def hit()&lt;br /&gt;
  @hits.display(@hits.intValue() + 1)&lt;br /&gt;
&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  else&lt;br /&gt;
    @cannonField.newTarget()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has hit the target. We increment the number of hits. If there are no shots left, the game is over. Otherwise, we make the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' generate a new target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def missed()&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has missed the target. If there are no shots left, the game is over.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def newGame()&lt;br /&gt;
  @shotsLeft.display(15)&lt;br /&gt;
  @hits.display(0)&lt;br /&gt;
  @cannonField.restartGame()&lt;br /&gt;
  @cannonField.newTarget()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when the user clicks the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button. It is also called from the constructor. First it sets the number of shots to 15. Note that this is the only place in the program where we set the number of shots. Change it to whatever you like to change the game rules. Next we reset the number of hits, restart the game, and generate a new target.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file has just been on a diet. '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' is gone, and the only thing left is the '''&amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;''' function, unchanged except for the name change.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot at a target; a new target is automatically created when one has been hit.&lt;br /&gt;
&lt;br /&gt;
Hits and shots left are displayed and the program keeps track of them. The game can end, and there's a button to start a new game.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Add a random wind factor and show it to the user.&lt;br /&gt;
&lt;br /&gt;
Make some splatter effects when the shot hits the target.&lt;br /&gt;
&lt;br /&gt;
Implement multiple targets.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/6/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/6/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/6/fi"/>
				<updated>2011-11-01T17:30:53Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;== Peli loppui ==&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Peli loppui ==&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi"/>
				<updated>2011-11-01T17:30:34Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Peli loppui&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Peli loppui|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14|Tutorial 14 - Facing the Wall]]&lt;br /&gt;
}}&lt;br /&gt;
== Game Over ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_13.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example we start to approach a real playable game with a score.&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' a new name ('''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;'''), add some slots, and move it to '''&amp;lt;tt&amp;gt;gamebrd.rb&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state.&lt;br /&gt;
&lt;br /&gt;
The layout problems in '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' are fixed. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @label.setSizePolicy(Qt::SizePolicy::Preferred, Qt::SizePolicy::Fixed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the size policy of the [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] to ([http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Preferred], [http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Fixed]). The vertical component ensures that the label won't stretch or shrink vertically; it will stay at its optimal size (its [http://doc.qt.nokia.com/latest/qwidget.html#sizeHint-prop QWidget::sizeHint()]). This solves the layout problems observed in Chapter 12.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state and a few new functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'canShoot(bool)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new signal indicates that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is in a state where the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot makes sense. We'll use it below to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @gameEnded = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This variable contains the game state; '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' means that the game is over, and '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;''' means that a game is going on. Initially, the game is not over (luckily for the player :-).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
  emit canShoot(false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We added a new '''&amp;lt;tt&amp;gt;isShooting()&amp;lt;/tt&amp;gt;''' function, so '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' uses it instead of testing directly. Also, shoot tells the world that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' cannot shoot now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setGameOver()&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = true&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot ends the game. It must be called from outside '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', because this widget does not know when to end the game. This is an important design principle in component programming. We choose to make the component as flexible as possible to make it usable with different rules (for example, a multi-player version of this in which the first player to hit ten times wins could use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' unchanged).&lt;br /&gt;
&lt;br /&gt;
If the game has already been ended we return immediately. If a game is going on we stop the shot, set the game over flag, and repaint the entire widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def restartGame()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = false&lt;br /&gt;
&lt;br /&gt;
  update()&lt;br /&gt;
  emit canShoot(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot starts a new game. If a shot is in the air, we stop shooting. We then reset the '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' variable and repaint the widget.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' too emits the new '''&amp;lt;tt&amp;gt;canShoot(true)&amp;lt;/tt&amp;gt;''' signal at the same time as either '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' or '''&amp;lt;tt&amp;gt;miss()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Modifications in CannonField::paintEvent():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    painter.setPen(Qt::black)&lt;br /&gt;
    painter.setFont(Qt::Font.new( &amp;quot;Courier&amp;quot;, 48, Qt::Font::Bold))&lt;br /&gt;
    painter.drawText(rect(), Qt::AlignCenter, tr(&amp;quot;Game Over&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event has been enhanced to display the text &amp;quot;Game Over&amp;quot; if the game is over, i.e., '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' is '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;'''. We don't bother to check the update rectangle here because speed is not critical when the game is over.&lt;br /&gt;
&lt;br /&gt;
To draw the text we first set a black pen; the pen color is used when drawing text. Next we choose a 48 point bold font from the Courier family. Finally we draw the text centered in the widget's rectangle. Unfortunately, on some systems (especially X servers with Unicode fonts) it can take a while to load such a large font. Because Qt caches fonts, you will notice this only the first time the font is used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end        &lt;br /&gt;
&lt;br /&gt;
  unless @gameEnded&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We draw the shot only when shooting and the target only when playing (that is, when the game is not ended).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file is new. It contains the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' class, which was last seen as '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  slots 'fire()', 'hit()', 'missed()', 'newGame()'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We have now added four slots.&lt;br /&gt;
&lt;br /&gt;
We have also made some changes in the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' constructor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @cannonField = CannonField.new()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;@cannonField&amp;lt;/tt&amp;gt;''' is now a member variable, so we carefully change the constructor to use it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('hit()'),&lt;br /&gt;
        self, SLOT('hit()'))&lt;br /&gt;
connect(@cannonField, SIGNAL('missed()'),&lt;br /&gt;
        self, SLOT('missed()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time we want to do something when the shot has hit or missed the target. Thus we connect the '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signals of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to two protected slots with the same names in this class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    connect(shoot, SIGNAL('clicked()'), self, SLOT('fire()') )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Previously we connected the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button's '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal directly to the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot. This time we want to keep track of the number of shots fired, so we connect it to a slot in this class instead.&lt;br /&gt;
&lt;br /&gt;
Notice how easy it is to change the behavior of a program when you are working with self-contained components.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('canShoot(bool)'),&lt;br /&gt;
        shoot, SLOT('setEnabled(bool)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;canShoot()&amp;lt;/tt&amp;gt;''' signal to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button appropriately.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
restart = Qt::PushButton.new(tr('&amp;amp;New Game'))&lt;br /&gt;
restart.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&lt;br /&gt;
connect(restart, SIGNAL('clicked()'), self, SLOT('newGame()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create, set up, and connect the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button as we have done with the other buttons. Clicking this button will activate the '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' slot in this widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@hits = Qt::LCDNumber.new(2)&lt;br /&gt;
@shotsLeft = Qt::LCDNumber.new(2)&lt;br /&gt;
hitsLabel = Qt::Label.new(tr('HITS'))&lt;br /&gt;
shotsLeftLabel = Qt::Label.new(tr('SHOTS LEFT'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create four new widgets, to display the number of hits and shots left.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
topLayout = Qt::HBoxLayout.new()&lt;br /&gt;
topLayout.addWidget(shoot)&lt;br /&gt;
topLayout.addWidget(@hits)&lt;br /&gt;
topLayout.addWidget(hitsLabel)&lt;br /&gt;
topLayout.addWidget(@shotsLeft)&lt;br /&gt;
topLayout.addWidget(shotsLeftLabel)&lt;br /&gt;
topLayout.addStretch(1)&lt;br /&gt;
topLayout.addWidget(restart)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The top-right cell of the [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] is starting to get crowded. We put a stretch just to the left of the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button to ensure that this button will always appear on the right side of the window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newGame()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We're all done constructing the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''', so we start it all using '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;'''. Although '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' is a slot, it can also be used as an ordinary function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def fire()&lt;br /&gt;
  if @cannonField.gameOver() || @cannonField.isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @shotsLeft.display(@shotsLeft.intValue() - 1)&lt;br /&gt;
  @cannonField.shoot()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function fires a shot. If the game is over or if there is a shot in the air, we return immediately. We decrement the number of shots left and tell the cannon to shoot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def hit()&lt;br /&gt;
  @hits.display(@hits.intValue() + 1)&lt;br /&gt;
&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  else&lt;br /&gt;
    @cannonField.newTarget()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has hit the target. We increment the number of hits. If there are no shots left, the game is over. Otherwise, we make the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' generate a new target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def missed()&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has missed the target. If there are no shots left, the game is over.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def newGame()&lt;br /&gt;
  @shotsLeft.display(15)&lt;br /&gt;
  @hits.display(0)&lt;br /&gt;
  @cannonField.restartGame()&lt;br /&gt;
  @cannonField.newTarget()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when the user clicks the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button. It is also called from the constructor. First it sets the number of shots to 15. Note that this is the only place in the program where we set the number of shots. Change it to whatever you like to change the game rules. Next we reset the number of hits, restart the game, and generate a new target.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file has just been on a diet. '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' is gone, and the only thing left is the '''&amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;''' function, unchanged except for the name change.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot at a target; a new target is automatically created when one has been hit.&lt;br /&gt;
&lt;br /&gt;
Hits and shots left are displayed and the program keeps track of them. The game can end, and there's a button to start a new game.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Add a random wind factor and show it to the user.&lt;br /&gt;
&lt;br /&gt;
Make some splatter effects when the shot hits the target.&lt;br /&gt;
&lt;br /&gt;
Implement multiple targets.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/3/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/3/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/3/fi"/>
				<updated>2011-11-01T17:30:34Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Peli loppui&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Peli loppui&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi"/>
				<updated>2011-11-01T17:30:23Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Qt4 Ruby -oppikurssi&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Game Over|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14|Tutorial 14 - Facing the Wall]]&lt;br /&gt;
}}&lt;br /&gt;
== Game Over ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_13.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example we start to approach a real playable game with a score.&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' a new name ('''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;'''), add some slots, and move it to '''&amp;lt;tt&amp;gt;gamebrd.rb&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state.&lt;br /&gt;
&lt;br /&gt;
The layout problems in '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' are fixed. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @label.setSizePolicy(Qt::SizePolicy::Preferred, Qt::SizePolicy::Fixed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the size policy of the [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] to ([http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Preferred], [http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Fixed]). The vertical component ensures that the label won't stretch or shrink vertically; it will stay at its optimal size (its [http://doc.qt.nokia.com/latest/qwidget.html#sizeHint-prop QWidget::sizeHint()]). This solves the layout problems observed in Chapter 12.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state and a few new functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'canShoot(bool)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new signal indicates that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is in a state where the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot makes sense. We'll use it below to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @gameEnded = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This variable contains the game state; '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' means that the game is over, and '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;''' means that a game is going on. Initially, the game is not over (luckily for the player :-).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
  emit canShoot(false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We added a new '''&amp;lt;tt&amp;gt;isShooting()&amp;lt;/tt&amp;gt;''' function, so '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' uses it instead of testing directly. Also, shoot tells the world that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' cannot shoot now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setGameOver()&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = true&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot ends the game. It must be called from outside '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', because this widget does not know when to end the game. This is an important design principle in component programming. We choose to make the component as flexible as possible to make it usable with different rules (for example, a multi-player version of this in which the first player to hit ten times wins could use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' unchanged).&lt;br /&gt;
&lt;br /&gt;
If the game has already been ended we return immediately. If a game is going on we stop the shot, set the game over flag, and repaint the entire widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def restartGame()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = false&lt;br /&gt;
&lt;br /&gt;
  update()&lt;br /&gt;
  emit canShoot(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot starts a new game. If a shot is in the air, we stop shooting. We then reset the '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' variable and repaint the widget.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' too emits the new '''&amp;lt;tt&amp;gt;canShoot(true)&amp;lt;/tt&amp;gt;''' signal at the same time as either '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' or '''&amp;lt;tt&amp;gt;miss()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Modifications in CannonField::paintEvent():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    painter.setPen(Qt::black)&lt;br /&gt;
    painter.setFont(Qt::Font.new( &amp;quot;Courier&amp;quot;, 48, Qt::Font::Bold))&lt;br /&gt;
    painter.drawText(rect(), Qt::AlignCenter, tr(&amp;quot;Game Over&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event has been enhanced to display the text &amp;quot;Game Over&amp;quot; if the game is over, i.e., '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' is '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;'''. We don't bother to check the update rectangle here because speed is not critical when the game is over.&lt;br /&gt;
&lt;br /&gt;
To draw the text we first set a black pen; the pen color is used when drawing text. Next we choose a 48 point bold font from the Courier family. Finally we draw the text centered in the widget's rectangle. Unfortunately, on some systems (especially X servers with Unicode fonts) it can take a while to load such a large font. Because Qt caches fonts, you will notice this only the first time the font is used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end        &lt;br /&gt;
&lt;br /&gt;
  unless @gameEnded&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We draw the shot only when shooting and the target only when playing (that is, when the game is not ended).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file is new. It contains the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' class, which was last seen as '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  slots 'fire()', 'hit()', 'missed()', 'newGame()'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We have now added four slots.&lt;br /&gt;
&lt;br /&gt;
We have also made some changes in the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' constructor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @cannonField = CannonField.new()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;@cannonField&amp;lt;/tt&amp;gt;''' is now a member variable, so we carefully change the constructor to use it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('hit()'),&lt;br /&gt;
        self, SLOT('hit()'))&lt;br /&gt;
connect(@cannonField, SIGNAL('missed()'),&lt;br /&gt;
        self, SLOT('missed()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time we want to do something when the shot has hit or missed the target. Thus we connect the '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signals of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to two protected slots with the same names in this class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    connect(shoot, SIGNAL('clicked()'), self, SLOT('fire()') )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Previously we connected the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button's '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal directly to the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot. This time we want to keep track of the number of shots fired, so we connect it to a slot in this class instead.&lt;br /&gt;
&lt;br /&gt;
Notice how easy it is to change the behavior of a program when you are working with self-contained components.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('canShoot(bool)'),&lt;br /&gt;
        shoot, SLOT('setEnabled(bool)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;canShoot()&amp;lt;/tt&amp;gt;''' signal to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button appropriately.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
restart = Qt::PushButton.new(tr('&amp;amp;New Game'))&lt;br /&gt;
restart.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&lt;br /&gt;
connect(restart, SIGNAL('clicked()'), self, SLOT('newGame()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create, set up, and connect the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button as we have done with the other buttons. Clicking this button will activate the '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' slot in this widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@hits = Qt::LCDNumber.new(2)&lt;br /&gt;
@shotsLeft = Qt::LCDNumber.new(2)&lt;br /&gt;
hitsLabel = Qt::Label.new(tr('HITS'))&lt;br /&gt;
shotsLeftLabel = Qt::Label.new(tr('SHOTS LEFT'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create four new widgets, to display the number of hits and shots left.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
topLayout = Qt::HBoxLayout.new()&lt;br /&gt;
topLayout.addWidget(shoot)&lt;br /&gt;
topLayout.addWidget(@hits)&lt;br /&gt;
topLayout.addWidget(hitsLabel)&lt;br /&gt;
topLayout.addWidget(@shotsLeft)&lt;br /&gt;
topLayout.addWidget(shotsLeftLabel)&lt;br /&gt;
topLayout.addStretch(1)&lt;br /&gt;
topLayout.addWidget(restart)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The top-right cell of the [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] is starting to get crowded. We put a stretch just to the left of the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button to ensure that this button will always appear on the right side of the window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newGame()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We're all done constructing the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''', so we start it all using '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;'''. Although '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' is a slot, it can also be used as an ordinary function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def fire()&lt;br /&gt;
  if @cannonField.gameOver() || @cannonField.isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @shotsLeft.display(@shotsLeft.intValue() - 1)&lt;br /&gt;
  @cannonField.shoot()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function fires a shot. If the game is over or if there is a shot in the air, we return immediately. We decrement the number of shots left and tell the cannon to shoot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def hit()&lt;br /&gt;
  @hits.display(@hits.intValue() + 1)&lt;br /&gt;
&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  else&lt;br /&gt;
    @cannonField.newTarget()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has hit the target. We increment the number of hits. If there are no shots left, the game is over. Otherwise, we make the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' generate a new target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def missed()&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has missed the target. If there are no shots left, the game is over.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def newGame()&lt;br /&gt;
  @shotsLeft.display(15)&lt;br /&gt;
  @hits.display(0)&lt;br /&gt;
  @cannonField.restartGame()&lt;br /&gt;
  @cannonField.newTarget()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when the user clicks the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button. It is also called from the constructor. First it sets the number of shots to 15. Note that this is the only place in the program where we set the number of shots. Change it to whatever you like to change the game rules. Next we reset the number of hits, restart the game, and generate a new target.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file has just been on a diet. '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' is gone, and the only thing left is the '''&amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;''' function, unchanged except for the name change.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot at a target; a new target is automatically created when one has been hit.&lt;br /&gt;
&lt;br /&gt;
Hits and shots left are displayed and the program keeps track of them. The game can end, and there's a button to start a new game.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Add a random wind factor and show it to the user.&lt;br /&gt;
&lt;br /&gt;
Make some splatter effects when the shot hits the target.&lt;br /&gt;
&lt;br /&gt;
Implement multiple targets.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/2/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/2/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/2/fi"/>
				<updated>2011-11-01T17:30:23Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Qt4 Ruby -oppikurssi&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Qt4 Ruby -oppikurssi&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/1/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/1/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/1/fi"/>
				<updated>2011-11-01T17:30:10Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;TutorialBrowser&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TutorialBrowser&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13/fi"/>
				<updated>2011-11-01T17:30:10Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;TutorialBrowser&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 13}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby Tutorial]]|&lt;br /&gt;
name=Game Over|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_14|Tutorial 14 - Facing the Wall]]&lt;br /&gt;
}}&lt;br /&gt;
== Game Over ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_13.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example we start to approach a real playable game with a score.&lt;br /&gt;
&lt;br /&gt;
We give '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' a new name ('''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;'''), add some slots, and move it to '''&amp;lt;tt&amp;gt;gamebrd.rb&amp;lt;/tt&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state.&lt;br /&gt;
&lt;br /&gt;
The layout problems in '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' are fixed. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @label.setSizePolicy(Qt::SizePolicy::Preferred, Qt::SizePolicy::Fixed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the size policy of the [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] to ([http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Preferred], [http://doc.qt.nokia.com/latest/qsizepolicy.html#Policy-enum Qt::SizePolicy::Fixed]). The vertical component ensures that the label won't stretch or shrink vertically; it will stay at its optimal size (its [http://doc.qt.nokia.com/latest/qwidget.html#sizeHint-prop QWidget::sizeHint()]). This solves the layout problems observed in Chapter 12.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has a game over state and a few new functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'canShoot(bool)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This new signal indicates that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is in a state where the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot makes sense. We'll use it below to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @gameEnded = false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This variable contains the game state; '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;''' means that the game is over, and '''&amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt;''' means that a game is going on. Initially, the game is not over (luckily for the player :-).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
  emit canShoot(false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We added a new '''&amp;lt;tt&amp;gt;isShooting()&amp;lt;/tt&amp;gt;''' function, so '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' uses it instead of testing directly. Also, shoot tells the world that the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' cannot shoot now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setGameOver()&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = true&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot ends the game. It must be called from outside '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''', because this widget does not know when to end the game. This is an important design principle in component programming. We choose to make the component as flexible as possible to make it usable with different rules (for example, a multi-player version of this in which the first player to hit ten times wins could use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' unchanged).&lt;br /&gt;
&lt;br /&gt;
If the game has already been ended we return immediately. If a game is going on we stop the shot, set the game over flag, and repaint the entire widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def restartGame()&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @gameEnded = false&lt;br /&gt;
&lt;br /&gt;
  update()&lt;br /&gt;
  emit canShoot(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot starts a new game. If a shot is in the air, we stop shooting. We then reset the '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' variable and repaint the widget.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' too emits the new '''&amp;lt;tt&amp;gt;canShoot(true)&amp;lt;/tt&amp;gt;''' signal at the same time as either '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' or '''&amp;lt;tt&amp;gt;miss()&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Modifications in CannonField::paintEvent():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  if @gameEnded&lt;br /&gt;
    painter.setPen(Qt::black)&lt;br /&gt;
    painter.setFont(Qt::Font.new( &amp;quot;Courier&amp;quot;, 48, Qt::Font::Bold))&lt;br /&gt;
    painter.drawText(rect(), Qt::AlignCenter, tr(&amp;quot;Game Over&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event has been enhanced to display the text &amp;quot;Game Over&amp;quot; if the game is over, i.e., '''&amp;lt;tt&amp;gt;gameEnded&amp;lt;/tt&amp;gt;''' is '''&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;'''. We don't bother to check the update rectangle here because speed is not critical when the game is over.&lt;br /&gt;
&lt;br /&gt;
To draw the text we first set a black pen; the pen color is used when drawing text. Next we choose a 48 point bold font from the Courier family. Finally we draw the text centered in the widget's rectangle. Unfortunately, on some systems (especially X servers with Unicode fonts) it can take a while to load such a large font. Because Qt caches fonts, you will notice this only the first time the font is used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
&lt;br /&gt;
  if isShooting()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end        &lt;br /&gt;
&lt;br /&gt;
  unless @gameEnded&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We draw the shot only when shooting and the target only when playing (that is, when the game is not ended).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/gamebrd.rb gamebrd.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file is new. It contains the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' class, which was last seen as '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  slots 'fire()', 'hit()', 'missed()', 'newGame()'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We have now added four slots.&lt;br /&gt;
&lt;br /&gt;
We have also made some changes in the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''' constructor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    @cannonField = CannonField.new()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;@cannonField&amp;lt;/tt&amp;gt;''' is now a member variable, so we carefully change the constructor to use it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('hit()'),&lt;br /&gt;
        self, SLOT('hit()'))&lt;br /&gt;
connect(@cannonField, SIGNAL('missed()'),&lt;br /&gt;
        self, SLOT('missed()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time we want to do something when the shot has hit or missed the target. Thus we connect the '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signals of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' to two protected slots with the same names in this class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    connect(shoot, SIGNAL('clicked()'), self, SLOT('fire()') )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Previously we connected the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button's '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal directly to the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot. This time we want to keep track of the number of shots fired, so we connect it to a slot in this class instead.&lt;br /&gt;
&lt;br /&gt;
Notice how easy it is to change the behavior of a program when you are working with self-contained components.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(@cannonField, SIGNAL('canShoot(bool)'),&lt;br /&gt;
        shoot, SLOT('setEnabled(bool)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also use the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''''s '''&amp;lt;tt&amp;gt;canShoot()&amp;lt;/tt&amp;gt;''' signal to enable or disable the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button appropriately.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
restart = Qt::PushButton.new(tr('&amp;amp;New Game'))&lt;br /&gt;
restart.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&lt;br /&gt;
connect(restart, SIGNAL('clicked()'), self, SLOT('newGame()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create, set up, and connect the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button as we have done with the other buttons. Clicking this button will activate the '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' slot in this widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@hits = Qt::LCDNumber.new(2)&lt;br /&gt;
@shotsLeft = Qt::LCDNumber.new(2)&lt;br /&gt;
hitsLabel = Qt::Label.new(tr('HITS'))&lt;br /&gt;
shotsLeftLabel = Qt::Label.new(tr('SHOTS LEFT'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We create four new widgets, to display the number of hits and shots left.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
topLayout = Qt::HBoxLayout.new()&lt;br /&gt;
topLayout.addWidget(shoot)&lt;br /&gt;
topLayout.addWidget(@hits)&lt;br /&gt;
topLayout.addWidget(hitsLabel)&lt;br /&gt;
topLayout.addWidget(@shotsLeft)&lt;br /&gt;
topLayout.addWidget(shotsLeftLabel)&lt;br /&gt;
topLayout.addStretch(1)&lt;br /&gt;
topLayout.addWidget(restart)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The top-right cell of the [http://doc.qt.nokia.com/latest/qgridlayout.html Qt::GridLayout] is starting to get crowded. We put a stretch just to the left of the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button to ensure that this button will always appear on the right side of the window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newGame()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We're all done constructing the '''&amp;lt;tt&amp;gt;GameBoard&amp;lt;/tt&amp;gt;''', so we start it all using '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;'''. Although '''&amp;lt;tt&amp;gt;newGame()&amp;lt;/tt&amp;gt;''' is a slot, it can also be used as an ordinary function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def fire()&lt;br /&gt;
  if @cannonField.gameOver() || @cannonField.isShooting()&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @shotsLeft.display(@shotsLeft.intValue() - 1)&lt;br /&gt;
  @cannonField.shoot()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function fires a shot. If the game is over or if there is a shot in the air, we return immediately. We decrement the number of shots left and tell the cannon to shoot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def hit()&lt;br /&gt;
  @hits.display(@hits.intValue() + 1)&lt;br /&gt;
&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  else&lt;br /&gt;
    @cannonField.newTarget()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has hit the target. We increment the number of hits. If there are no shots left, the game is over. Otherwise, we make the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' generate a new target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def missed()&lt;br /&gt;
  if @shotsLeft.intValue() == 0&lt;br /&gt;
    @cannonField.setGameOver()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when a shot has missed the target. If there are no shots left, the game is over.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def newGame()&lt;br /&gt;
  @shotsLeft.display(15)&lt;br /&gt;
  @hits.display(0)&lt;br /&gt;
  @cannonField.restartGame()&lt;br /&gt;
  @cannonField.newTarget()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This slot is activated when the user clicks the &amp;lt;strong&amp;gt;New Game&amp;lt;/strong&amp;gt; button. It is also called from the constructor. First it sets the number of shots to 15. Note that this is the only place in the program where we set the number of shots. Change it to whatever you like to change the game rules. Next we reset the number of hits, restart the game, and generate a new target.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t13/t13.rb t13.rb]'''&lt;br /&gt;
&lt;br /&gt;
This file has just been on a diet. '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' is gone, and the only thing left is the '''&amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt;''' function, unchanged except for the name change.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot at a target; a new target is automatically created when one has been hit.&lt;br /&gt;
&lt;br /&gt;
Hits and shots left are displayed and the program keeps track of them. The game can end, and there's a button to start a new game.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Add a random wind factor and show it to the user.&lt;br /&gt;
&lt;br /&gt;
Make some splatter effects when the shot hits the target.&lt;br /&gt;
&lt;br /&gt;
Implement multiple targets.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi"/>
				<updated>2011-11-01T17:29:37Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Yleiskuva ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Hanging in the Air the Way Bricks Don't|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Ammutaan tykillä]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Oppikurssi 13 - Peli loppui]]&lt;br /&gt;
}}&lt;br /&gt;
== Hanging in the Air the Way Bricks Don't ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;br /&gt;
Tiedostot:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example, we extend our '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' class to include a text label. We also provide something to shoot at.  &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(s, parent = nil)&lt;br /&gt;
  super(parent)&lt;br /&gt;
  init()&lt;br /&gt;
  setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This constructor first calls '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' and then sets the label text. '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' is a separate function performing initialization mosty because of function overloading matters in the original C++ version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def init()&lt;br /&gt;
  lcd = Qt::LCDNumber.new(2)&lt;br /&gt;
  lcd.setSegmentStyle(Qt::LCDNumber::Filled)&lt;br /&gt;
&lt;br /&gt;
  @slider = Qt::Slider.new(Qt::Horizontal)&lt;br /&gt;
  @slider.setRange(0, 99)&lt;br /&gt;
  @slider.setValue(0)&lt;br /&gt;
&lt;br /&gt;
  @label = Qt::Label.new()&lt;br /&gt;
  @label.setAlignment(Qt::AlignHCenter.to_i | Qt::AlignTop.to_i)&lt;br /&gt;
&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  lcd, SLOT('display(int)'))&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  self, SIGNAL('valueChanged(int)'))&lt;br /&gt;
&lt;br /&gt;
  layout = Qt::VBoxLayout.new()&lt;br /&gt;
  layout.addWidget(lcd)&lt;br /&gt;
  layout.addWidget(@slider)&lt;br /&gt;
  layout.addWidget(@label)&lt;br /&gt;
  setLayout(layout)&lt;br /&gt;
&lt;br /&gt;
  setFocusProxy(@slider)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup of '''&amp;lt;tt&amp;gt;lcd&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;slider&amp;lt;/tt&amp;gt;''' is the same as in the previous chapter. Next we create a [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] and tell it to align the contents centered horizontally and to the top vertically. The [http://doc.qt.nokia.com/latest/qobject.html#connect Qt::Object::connect()] calls have also been taken from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setText(s)&lt;br /&gt;
  @label.setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function sets the label text.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has two new signals: '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;'''. In addition, it contains a target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'hit()', 'missed()' #...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal is emitted when a shot hits the target. The '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' 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).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newTarget()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. It creates a &amp;quot;random&amp;quot; position for the target. In fact, the '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' function will try to paint the target. Because we are in a constructor, the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' widget is invisible. Qt guarantees that no harm is done when calling [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] on a hidden widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@@first_time = true&lt;br /&gt;
&lt;br /&gt;
def newTarget()&lt;br /&gt;
  if @@first_time&lt;br /&gt;
    @@first_time = false&lt;br /&gt;
    midnight = Qt::Time.new(0, 0, 0)&lt;br /&gt;
    srand(midnight.secsTo(Qt::Time.currentTime()))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @target = Qt::Point.new(200 + rand(190), 10 + rand(255))&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function creates a target center point at a new random position.&lt;br /&gt;
&lt;br /&gt;
We create the [http://doc.qt.nokia.com/latest/qtime.html Qt::Time] object '''&amp;lt;tt&amp;gt;midnight&amp;lt;/tt&amp;gt;''', 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 [http://doc.qt.nokia.com/latest/qdate.html Qt::Date], [http://doc.qt.nokia.com/latest/qtime.html Qt::Time], and [http://doc.qt.nokia.com/latest/qdatetime.html Qt::DateTime] for more information.&lt;br /&gt;
&lt;br /&gt;
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 200 to 389 and 35 to 289, respectively) 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.&lt;br /&gt;
&lt;br /&gt;
By experimentation we have found this to always be in reach of the shot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the timer event has not changed from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
if shotR.intersects(targetRect()) &lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit hit()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This '''&amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;''' 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 '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal to tell the outside world that a target was destroyed, and return. Note that we could have created a new target on the spot, but because the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is a component we leave such decisions to the user of the component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit missed()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as in the previous chapter, except that it now emits the '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signal to tell the outside world about the failure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the rest of the function is as before.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;CannonField::paintEvent()&amp;lt;/tt&amp;gt;''' is as before, except that this has been added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line makes sure that the target is also painted when necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintTarget(painter)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::red))&lt;br /&gt;
  painter.setPen(Qt::Pen.new(Qt::Color.new(Qt::black)))&lt;br /&gt;
  painter.drawRect(targetRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the target; a rectangle filled with red and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def targetRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 20, 10)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(@target.x(), height() - 1 - @target.y()))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function returns the enclosing rectangle of the target. Remember from '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' that the '''&amp;lt;tt&amp;gt;target&amp;lt;/tt&amp;gt;''' point uses y coordinate 0 at the bottom of the widget. We calculate the point in widget coordinates before we call [http://doc.qt.nokia.com/latest/qrect.html#moveCenter Qt::Rect::moveCenter()].&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]'''&lt;br /&gt;
&lt;br /&gt;
There are no new members in the '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' class, but we have slightly changed the constructor to set the new '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' text labels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    angle = LCDRange.new(tr('ANGLE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the angle text label to &amp;quot;ANGLE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    force  = LCDRange.new(tr('FORCE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the force text label to &amp;quot;FORCE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets look a bit strange: When resizing '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''', the built-in layout management in [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] gives the labels too much space and the rest not enough; making the space between the two '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets change size. We'll fix that in the next chapter&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
&lt;br /&gt;
Make a cheat button that, when pressed, makes the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' display the shot trajectory for five seconds.&lt;br /&gt;
&lt;br /&gt;
If you did the &amp;quot;round shot&amp;quot; exercise from the previous chapter, try changing the '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to a '''&amp;lt;tt&amp;gt;shotRegion()&amp;lt;/tt&amp;gt;''' that returns a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] so you can have really accurate collision detection.&lt;br /&gt;
&lt;br /&gt;
Make a moving target.&lt;br /&gt;
&lt;br /&gt;
Make sure that the target is always created entirely on-screen.&lt;br /&gt;
&lt;br /&gt;
Make sure that the widget cannot be resized so that the target isn't visible. [Hint: [http://doc.qt.nokia.com/latest/qwidget.html#minimumSize-prop Qt::Widget::setMinimumSize()] is your friend.]&lt;br /&gt;
&lt;br /&gt;
Not easy; make it possible to have several shots in the air at the same time. [Hint: Make a '''&amp;lt;tt&amp;gt;Shot&amp;lt;/tt&amp;gt;''' class.]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/9/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/9/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/9/fi"/>
				<updated>2011-11-01T17:29:36Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Yleiskuva ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Yleiskuva ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi"/>
				<updated>2011-11-01T17:29:25Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Tiedostot:&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Hanging in the Air the Way Bricks Don't|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Ammutaan tykillä]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Oppikurssi 13 - Peli loppui]]&lt;br /&gt;
}}&lt;br /&gt;
== Hanging in the Air the Way Bricks Don't ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;br /&gt;
Tiedostot:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example, we extend our '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' class to include a text label. We also provide something to shoot at.  &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(s, parent = nil)&lt;br /&gt;
  super(parent)&lt;br /&gt;
  init()&lt;br /&gt;
  setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This constructor first calls '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' and then sets the label text. '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' is a separate function performing initialization mosty because of function overloading matters in the original C++ version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def init()&lt;br /&gt;
  lcd = Qt::LCDNumber.new(2)&lt;br /&gt;
  lcd.setSegmentStyle(Qt::LCDNumber::Filled)&lt;br /&gt;
&lt;br /&gt;
  @slider = Qt::Slider.new(Qt::Horizontal)&lt;br /&gt;
  @slider.setRange(0, 99)&lt;br /&gt;
  @slider.setValue(0)&lt;br /&gt;
&lt;br /&gt;
  @label = Qt::Label.new()&lt;br /&gt;
  @label.setAlignment(Qt::AlignHCenter.to_i | Qt::AlignTop.to_i)&lt;br /&gt;
&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  lcd, SLOT('display(int)'))&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  self, SIGNAL('valueChanged(int)'))&lt;br /&gt;
&lt;br /&gt;
  layout = Qt::VBoxLayout.new()&lt;br /&gt;
  layout.addWidget(lcd)&lt;br /&gt;
  layout.addWidget(@slider)&lt;br /&gt;
  layout.addWidget(@label)&lt;br /&gt;
  setLayout(layout)&lt;br /&gt;
&lt;br /&gt;
  setFocusProxy(@slider)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup of '''&amp;lt;tt&amp;gt;lcd&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;slider&amp;lt;/tt&amp;gt;''' is the same as in the previous chapter. Next we create a [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] and tell it to align the contents centered horizontally and to the top vertically. The [http://doc.qt.nokia.com/latest/qobject.html#connect Qt::Object::connect()] calls have also been taken from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setText(s)&lt;br /&gt;
  @label.setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function sets the label text.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has two new signals: '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;'''. In addition, it contains a target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'hit()', 'missed()' #...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal is emitted when a shot hits the target. The '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' 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).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newTarget()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. It creates a &amp;quot;random&amp;quot; position for the target. In fact, the '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' function will try to paint the target. Because we are in a constructor, the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' widget is invisible. Qt guarantees that no harm is done when calling [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] on a hidden widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@@first_time = true&lt;br /&gt;
&lt;br /&gt;
def newTarget()&lt;br /&gt;
  if @@first_time&lt;br /&gt;
    @@first_time = false&lt;br /&gt;
    midnight = Qt::Time.new(0, 0, 0)&lt;br /&gt;
    srand(midnight.secsTo(Qt::Time.currentTime()))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @target = Qt::Point.new(200 + rand(190), 10 + rand(255))&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function creates a target center point at a new random position.&lt;br /&gt;
&lt;br /&gt;
We create the [http://doc.qt.nokia.com/latest/qtime.html Qt::Time] object '''&amp;lt;tt&amp;gt;midnight&amp;lt;/tt&amp;gt;''', 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 [http://doc.qt.nokia.com/latest/qdate.html Qt::Date], [http://doc.qt.nokia.com/latest/qtime.html Qt::Time], and [http://doc.qt.nokia.com/latest/qdatetime.html Qt::DateTime] for more information.&lt;br /&gt;
&lt;br /&gt;
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 200 to 389 and 35 to 289, respectively) 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.&lt;br /&gt;
&lt;br /&gt;
By experimentation we have found this to always be in reach of the shot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the timer event has not changed from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
if shotR.intersects(targetRect()) &lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit hit()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This '''&amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;''' 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 '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal to tell the outside world that a target was destroyed, and return. Note that we could have created a new target on the spot, but because the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is a component we leave such decisions to the user of the component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit missed()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as in the previous chapter, except that it now emits the '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signal to tell the outside world about the failure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the rest of the function is as before.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;CannonField::paintEvent()&amp;lt;/tt&amp;gt;''' is as before, except that this has been added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line makes sure that the target is also painted when necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintTarget(painter)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::red))&lt;br /&gt;
  painter.setPen(Qt::Pen.new(Qt::Color.new(Qt::black)))&lt;br /&gt;
  painter.drawRect(targetRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the target; a rectangle filled with red and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def targetRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 20, 10)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(@target.x(), height() - 1 - @target.y()))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function returns the enclosing rectangle of the target. Remember from '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' that the '''&amp;lt;tt&amp;gt;target&amp;lt;/tt&amp;gt;''' point uses y coordinate 0 at the bottom of the widget. We calculate the point in widget coordinates before we call [http://doc.qt.nokia.com/latest/qrect.html#moveCenter Qt::Rect::moveCenter()].&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]'''&lt;br /&gt;
&lt;br /&gt;
There are no new members in the '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' class, but we have slightly changed the constructor to set the new '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' text labels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    angle = LCDRange.new(tr('ANGLE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the angle text label to &amp;quot;ANGLE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    force  = LCDRange.new(tr('FORCE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the force text label to &amp;quot;FORCE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets look a bit strange: When resizing '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''', the built-in layout management in [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] gives the labels too much space and the rest not enough; making the space between the two '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets change size. We'll fix that in the next chapter&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
&lt;br /&gt;
Make a cheat button that, when pressed, makes the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' display the shot trajectory for five seconds.&lt;br /&gt;
&lt;br /&gt;
If you did the &amp;quot;round shot&amp;quot; exercise from the previous chapter, try changing the '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to a '''&amp;lt;tt&amp;gt;shotRegion()&amp;lt;/tt&amp;gt;''' that returns a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] so you can have really accurate collision detection.&lt;br /&gt;
&lt;br /&gt;
Make a moving target.&lt;br /&gt;
&lt;br /&gt;
Make sure that the target is always created entirely on-screen.&lt;br /&gt;
&lt;br /&gt;
Make sure that the widget cannot be resized so that the target isn't visible. [Hint: [http://doc.qt.nokia.com/latest/qwidget.html#minimumSize-prop Qt::Widget::setMinimumSize()] is your friend.]&lt;br /&gt;
&lt;br /&gt;
Not easy; make it possible to have several shots in the air at the same time. [Hint: Make a '''&amp;lt;tt&amp;gt;Shot&amp;lt;/tt&amp;gt;''' class.]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/8/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/8/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/8/fi"/>
				<updated>2011-11-01T17:29:24Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Tiedostot:&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Tiedostot:&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi"/>
				<updated>2011-11-01T17:29:06Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Hanging in the Air the Way Bricks Don't|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Ammutaan tykillä]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Oppikurssi 13 - Peli loppui]]&lt;br /&gt;
}}&lt;br /&gt;
== Hanging in the Air the Way Bricks Don't ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example, we extend our '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' class to include a text label. We also provide something to shoot at.  &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(s, parent = nil)&lt;br /&gt;
  super(parent)&lt;br /&gt;
  init()&lt;br /&gt;
  setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This constructor first calls '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' and then sets the label text. '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' is a separate function performing initialization mosty because of function overloading matters in the original C++ version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def init()&lt;br /&gt;
  lcd = Qt::LCDNumber.new(2)&lt;br /&gt;
  lcd.setSegmentStyle(Qt::LCDNumber::Filled)&lt;br /&gt;
&lt;br /&gt;
  @slider = Qt::Slider.new(Qt::Horizontal)&lt;br /&gt;
  @slider.setRange(0, 99)&lt;br /&gt;
  @slider.setValue(0)&lt;br /&gt;
&lt;br /&gt;
  @label = Qt::Label.new()&lt;br /&gt;
  @label.setAlignment(Qt::AlignHCenter.to_i | Qt::AlignTop.to_i)&lt;br /&gt;
&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  lcd, SLOT('display(int)'))&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  self, SIGNAL('valueChanged(int)'))&lt;br /&gt;
&lt;br /&gt;
  layout = Qt::VBoxLayout.new()&lt;br /&gt;
  layout.addWidget(lcd)&lt;br /&gt;
  layout.addWidget(@slider)&lt;br /&gt;
  layout.addWidget(@label)&lt;br /&gt;
  setLayout(layout)&lt;br /&gt;
&lt;br /&gt;
  setFocusProxy(@slider)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup of '''&amp;lt;tt&amp;gt;lcd&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;slider&amp;lt;/tt&amp;gt;''' is the same as in the previous chapter. Next we create a [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] and tell it to align the contents centered horizontally and to the top vertically. The [http://doc.qt.nokia.com/latest/qobject.html#connect Qt::Object::connect()] calls have also been taken from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setText(s)&lt;br /&gt;
  @label.setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function sets the label text.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has two new signals: '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;'''. In addition, it contains a target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'hit()', 'missed()' #...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal is emitted when a shot hits the target. The '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' 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).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newTarget()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. It creates a &amp;quot;random&amp;quot; position for the target. In fact, the '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' function will try to paint the target. Because we are in a constructor, the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' widget is invisible. Qt guarantees that no harm is done when calling [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] on a hidden widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@@first_time = true&lt;br /&gt;
&lt;br /&gt;
def newTarget()&lt;br /&gt;
  if @@first_time&lt;br /&gt;
    @@first_time = false&lt;br /&gt;
    midnight = Qt::Time.new(0, 0, 0)&lt;br /&gt;
    srand(midnight.secsTo(Qt::Time.currentTime()))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @target = Qt::Point.new(200 + rand(190), 10 + rand(255))&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function creates a target center point at a new random position.&lt;br /&gt;
&lt;br /&gt;
We create the [http://doc.qt.nokia.com/latest/qtime.html Qt::Time] object '''&amp;lt;tt&amp;gt;midnight&amp;lt;/tt&amp;gt;''', 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 [http://doc.qt.nokia.com/latest/qdate.html Qt::Date], [http://doc.qt.nokia.com/latest/qtime.html Qt::Time], and [http://doc.qt.nokia.com/latest/qdatetime.html Qt::DateTime] for more information.&lt;br /&gt;
&lt;br /&gt;
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 200 to 389 and 35 to 289, respectively) 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.&lt;br /&gt;
&lt;br /&gt;
By experimentation we have found this to always be in reach of the shot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the timer event has not changed from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
if shotR.intersects(targetRect()) &lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit hit()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This '''&amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;''' 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 '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal to tell the outside world that a target was destroyed, and return. Note that we could have created a new target on the spot, but because the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is a component we leave such decisions to the user of the component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit missed()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as in the previous chapter, except that it now emits the '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signal to tell the outside world about the failure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the rest of the function is as before.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;CannonField::paintEvent()&amp;lt;/tt&amp;gt;''' is as before, except that this has been added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line makes sure that the target is also painted when necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintTarget(painter)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::red))&lt;br /&gt;
  painter.setPen(Qt::Pen.new(Qt::Color.new(Qt::black)))&lt;br /&gt;
  painter.drawRect(targetRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the target; a rectangle filled with red and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def targetRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 20, 10)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(@target.x(), height() - 1 - @target.y()))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function returns the enclosing rectangle of the target. Remember from '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' that the '''&amp;lt;tt&amp;gt;target&amp;lt;/tt&amp;gt;''' point uses y coordinate 0 at the bottom of the widget. We calculate the point in widget coordinates before we call [http://doc.qt.nokia.com/latest/qrect.html#moveCenter Qt::Rect::moveCenter()].&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]'''&lt;br /&gt;
&lt;br /&gt;
There are no new members in the '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' class, but we have slightly changed the constructor to set the new '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' text labels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    angle = LCDRange.new(tr('ANGLE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the angle text label to &amp;quot;ANGLE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    force  = LCDRange.new(tr('FORCE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the force text label to &amp;quot;FORCE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets look a bit strange: When resizing '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''', the built-in layout management in [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] gives the labels too much space and the rest not enough; making the space between the two '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets change size. We'll fix that in the next chapter&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
&lt;br /&gt;
Make a cheat button that, when pressed, makes the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' display the shot trajectory for five seconds.&lt;br /&gt;
&lt;br /&gt;
If you did the &amp;quot;round shot&amp;quot; exercise from the previous chapter, try changing the '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to a '''&amp;lt;tt&amp;gt;shotRegion()&amp;lt;/tt&amp;gt;''' that returns a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] so you can have really accurate collision detection.&lt;br /&gt;
&lt;br /&gt;
Make a moving target.&lt;br /&gt;
&lt;br /&gt;
Make sure that the target is always created entirely on-screen.&lt;br /&gt;
&lt;br /&gt;
Make sure that the widget cannot be resized so that the target isn't visible. [Hint: [http://doc.qt.nokia.com/latest/qwidget.html#minimumSize-prop Qt::Widget::setMinimumSize()] is your friend.]&lt;br /&gt;
&lt;br /&gt;
Not easy; make it possible to have several shots in the air at the same time. [Hint: Make a '''&amp;lt;tt&amp;gt;Shot&amp;lt;/tt&amp;gt;''' class.]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/36/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/36/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/36/fi"/>
				<updated>2011-11-01T17:29:05Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Harjoitukset ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/43/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/43/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/43/fi"/>
				<updated>2011-11-01T17:28:52Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Category:Ruby&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi"/>
				<updated>2011-11-01T17:28:46Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Sovelluksen suorittaminen ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Hanging in the Air the Way Bricks Don't|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Ammutaan tykillä]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Oppikurssi 13 - Peli loppui]]&lt;br /&gt;
}}&lt;br /&gt;
== Hanging in the Air the Way Bricks Don't ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example, we extend our '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' class to include a text label. We also provide something to shoot at.  &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(s, parent = nil)&lt;br /&gt;
  super(parent)&lt;br /&gt;
  init()&lt;br /&gt;
  setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This constructor first calls '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' and then sets the label text. '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' is a separate function performing initialization mosty because of function overloading matters in the original C++ version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def init()&lt;br /&gt;
  lcd = Qt::LCDNumber.new(2)&lt;br /&gt;
  lcd.setSegmentStyle(Qt::LCDNumber::Filled)&lt;br /&gt;
&lt;br /&gt;
  @slider = Qt::Slider.new(Qt::Horizontal)&lt;br /&gt;
  @slider.setRange(0, 99)&lt;br /&gt;
  @slider.setValue(0)&lt;br /&gt;
&lt;br /&gt;
  @label = Qt::Label.new()&lt;br /&gt;
  @label.setAlignment(Qt::AlignHCenter.to_i | Qt::AlignTop.to_i)&lt;br /&gt;
&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  lcd, SLOT('display(int)'))&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  self, SIGNAL('valueChanged(int)'))&lt;br /&gt;
&lt;br /&gt;
  layout = Qt::VBoxLayout.new()&lt;br /&gt;
  layout.addWidget(lcd)&lt;br /&gt;
  layout.addWidget(@slider)&lt;br /&gt;
  layout.addWidget(@label)&lt;br /&gt;
  setLayout(layout)&lt;br /&gt;
&lt;br /&gt;
  setFocusProxy(@slider)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup of '''&amp;lt;tt&amp;gt;lcd&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;slider&amp;lt;/tt&amp;gt;''' is the same as in the previous chapter. Next we create a [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] and tell it to align the contents centered horizontally and to the top vertically. The [http://doc.qt.nokia.com/latest/qobject.html#connect Qt::Object::connect()] calls have also been taken from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setText(s)&lt;br /&gt;
  @label.setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function sets the label text.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has two new signals: '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;'''. In addition, it contains a target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'hit()', 'missed()' #...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal is emitted when a shot hits the target. The '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' 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).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newTarget()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. It creates a &amp;quot;random&amp;quot; position for the target. In fact, the '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' function will try to paint the target. Because we are in a constructor, the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' widget is invisible. Qt guarantees that no harm is done when calling [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] on a hidden widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@@first_time = true&lt;br /&gt;
&lt;br /&gt;
def newTarget()&lt;br /&gt;
  if @@first_time&lt;br /&gt;
    @@first_time = false&lt;br /&gt;
    midnight = Qt::Time.new(0, 0, 0)&lt;br /&gt;
    srand(midnight.secsTo(Qt::Time.currentTime()))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @target = Qt::Point.new(200 + rand(190), 10 + rand(255))&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function creates a target center point at a new random position.&lt;br /&gt;
&lt;br /&gt;
We create the [http://doc.qt.nokia.com/latest/qtime.html Qt::Time] object '''&amp;lt;tt&amp;gt;midnight&amp;lt;/tt&amp;gt;''', 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 [http://doc.qt.nokia.com/latest/qdate.html Qt::Date], [http://doc.qt.nokia.com/latest/qtime.html Qt::Time], and [http://doc.qt.nokia.com/latest/qdatetime.html Qt::DateTime] for more information.&lt;br /&gt;
&lt;br /&gt;
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 200 to 389 and 35 to 289, respectively) 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.&lt;br /&gt;
&lt;br /&gt;
By experimentation we have found this to always be in reach of the shot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the timer event has not changed from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
if shotR.intersects(targetRect()) &lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit hit()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This '''&amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;''' 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 '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal to tell the outside world that a target was destroyed, and return. Note that we could have created a new target on the spot, but because the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is a component we leave such decisions to the user of the component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit missed()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as in the previous chapter, except that it now emits the '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signal to tell the outside world about the failure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the rest of the function is as before.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;CannonField::paintEvent()&amp;lt;/tt&amp;gt;''' is as before, except that this has been added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line makes sure that the target is also painted when necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintTarget(painter)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::red))&lt;br /&gt;
  painter.setPen(Qt::Pen.new(Qt::Color.new(Qt::black)))&lt;br /&gt;
  painter.drawRect(targetRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the target; a rectangle filled with red and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def targetRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 20, 10)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(@target.x(), height() - 1 - @target.y()))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function returns the enclosing rectangle of the target. Remember from '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' that the '''&amp;lt;tt&amp;gt;target&amp;lt;/tt&amp;gt;''' point uses y coordinate 0 at the bottom of the widget. We calculate the point in widget coordinates before we call [http://doc.qt.nokia.com/latest/qrect.html#moveCenter Qt::Rect::moveCenter()].&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]'''&lt;br /&gt;
&lt;br /&gt;
There are no new members in the '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' class, but we have slightly changed the constructor to set the new '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' text labels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    angle = LCDRange.new(tr('ANGLE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the angle text label to &amp;quot;ANGLE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    force  = LCDRange.new(tr('FORCE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the force text label to &amp;quot;FORCE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets look a bit strange: When resizing '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''', the built-in layout management in [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] gives the labels too much space and the rest not enough; making the space between the two '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets change size. We'll fix that in the next chapter&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make a cheat button that, when pressed, makes the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' display the shot trajectory for five seconds.&lt;br /&gt;
&lt;br /&gt;
If you did the &amp;quot;round shot&amp;quot; exercise from the previous chapter, try changing the '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to a '''&amp;lt;tt&amp;gt;shotRegion()&amp;lt;/tt&amp;gt;''' that returns a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] so you can have really accurate collision detection.&lt;br /&gt;
&lt;br /&gt;
Make a moving target.&lt;br /&gt;
&lt;br /&gt;
Make sure that the target is always created entirely on-screen.&lt;br /&gt;
&lt;br /&gt;
Make sure that the widget cannot be resized so that the target isn't visible. [Hint: [http://doc.qt.nokia.com/latest/qwidget.html#minimumSize-prop Qt::Widget::setMinimumSize()] is your friend.]&lt;br /&gt;
&lt;br /&gt;
Not easy; make it possible to have several shots in the air at the same time. [Hint: Make a '''&amp;lt;tt&amp;gt;Shot&amp;lt;/tt&amp;gt;''' class.]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/34/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/34/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/34/fi"/>
				<updated>2011-11-01T17:28:45Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Sovelluksen suorittaminen ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Sovelluksen suorittaminen ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi"/>
				<updated>2011-11-01T17:28:25Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Läpikäynti rivi riviltä ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Hanging in the Air the Way Bricks Don't|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Ammutaan tykillä]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Oppikurssi 13 - Peli loppui]]&lt;br /&gt;
}}&lt;br /&gt;
== Hanging in the Air the Way Bricks Don't ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example, we extend our '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' class to include a text label. We also provide something to shoot at.  &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(s, parent = nil)&lt;br /&gt;
  super(parent)&lt;br /&gt;
  init()&lt;br /&gt;
  setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This constructor first calls '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' and then sets the label text. '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' is a separate function performing initialization mosty because of function overloading matters in the original C++ version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def init()&lt;br /&gt;
  lcd = Qt::LCDNumber.new(2)&lt;br /&gt;
  lcd.setSegmentStyle(Qt::LCDNumber::Filled)&lt;br /&gt;
&lt;br /&gt;
  @slider = Qt::Slider.new(Qt::Horizontal)&lt;br /&gt;
  @slider.setRange(0, 99)&lt;br /&gt;
  @slider.setValue(0)&lt;br /&gt;
&lt;br /&gt;
  @label = Qt::Label.new()&lt;br /&gt;
  @label.setAlignment(Qt::AlignHCenter.to_i | Qt::AlignTop.to_i)&lt;br /&gt;
&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  lcd, SLOT('display(int)'))&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  self, SIGNAL('valueChanged(int)'))&lt;br /&gt;
&lt;br /&gt;
  layout = Qt::VBoxLayout.new()&lt;br /&gt;
  layout.addWidget(lcd)&lt;br /&gt;
  layout.addWidget(@slider)&lt;br /&gt;
  layout.addWidget(@label)&lt;br /&gt;
  setLayout(layout)&lt;br /&gt;
&lt;br /&gt;
  setFocusProxy(@slider)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup of '''&amp;lt;tt&amp;gt;lcd&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;slider&amp;lt;/tt&amp;gt;''' is the same as in the previous chapter. Next we create a [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] and tell it to align the contents centered horizontally and to the top vertically. The [http://doc.qt.nokia.com/latest/qobject.html#connect Qt::Object::connect()] calls have also been taken from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setText(s)&lt;br /&gt;
  @label.setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function sets the label text.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has two new signals: '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;'''. In addition, it contains a target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'hit()', 'missed()' #...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal is emitted when a shot hits the target. The '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' 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).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newTarget()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. It creates a &amp;quot;random&amp;quot; position for the target. In fact, the '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' function will try to paint the target. Because we are in a constructor, the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' widget is invisible. Qt guarantees that no harm is done when calling [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] on a hidden widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@@first_time = true&lt;br /&gt;
&lt;br /&gt;
def newTarget()&lt;br /&gt;
  if @@first_time&lt;br /&gt;
    @@first_time = false&lt;br /&gt;
    midnight = Qt::Time.new(0, 0, 0)&lt;br /&gt;
    srand(midnight.secsTo(Qt::Time.currentTime()))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @target = Qt::Point.new(200 + rand(190), 10 + rand(255))&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function creates a target center point at a new random position.&lt;br /&gt;
&lt;br /&gt;
We create the [http://doc.qt.nokia.com/latest/qtime.html Qt::Time] object '''&amp;lt;tt&amp;gt;midnight&amp;lt;/tt&amp;gt;''', 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 [http://doc.qt.nokia.com/latest/qdate.html Qt::Date], [http://doc.qt.nokia.com/latest/qtime.html Qt::Time], and [http://doc.qt.nokia.com/latest/qdatetime.html Qt::DateTime] for more information.&lt;br /&gt;
&lt;br /&gt;
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 200 to 389 and 35 to 289, respectively) 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.&lt;br /&gt;
&lt;br /&gt;
By experimentation we have found this to always be in reach of the shot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the timer event has not changed from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
if shotR.intersects(targetRect()) &lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit hit()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This '''&amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;''' 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 '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal to tell the outside world that a target was destroyed, and return. Note that we could have created a new target on the spot, but because the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is a component we leave such decisions to the user of the component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit missed()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as in the previous chapter, except that it now emits the '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signal to tell the outside world about the failure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the rest of the function is as before.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;CannonField::paintEvent()&amp;lt;/tt&amp;gt;''' is as before, except that this has been added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line makes sure that the target is also painted when necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintTarget(painter)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::red))&lt;br /&gt;
  painter.setPen(Qt::Pen.new(Qt::Color.new(Qt::black)))&lt;br /&gt;
  painter.drawRect(targetRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the target; a rectangle filled with red and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def targetRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 20, 10)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(@target.x(), height() - 1 - @target.y()))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function returns the enclosing rectangle of the target. Remember from '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' that the '''&amp;lt;tt&amp;gt;target&amp;lt;/tt&amp;gt;''' point uses y coordinate 0 at the bottom of the widget. We calculate the point in widget coordinates before we call [http://doc.qt.nokia.com/latest/qrect.html#moveCenter Qt::Rect::moveCenter()].&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]'''&lt;br /&gt;
&lt;br /&gt;
There are no new members in the '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' class, but we have slightly changed the constructor to set the new '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' text labels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    angle = LCDRange.new(tr('ANGLE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the angle text label to &amp;quot;ANGLE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    force  = LCDRange.new(tr('FORCE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the force text label to &amp;quot;FORCE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets look a bit strange: When resizing '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''', the built-in layout management in [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] gives the labels too much space and the rest not enough; making the space between the two '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets change size. We'll fix that in the next chapter&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make a cheat button that, when pressed, makes the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' display the shot trajectory for five seconds.&lt;br /&gt;
&lt;br /&gt;
If you did the &amp;quot;round shot&amp;quot; exercise from the previous chapter, try changing the '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to a '''&amp;lt;tt&amp;gt;shotRegion()&amp;lt;/tt&amp;gt;''' that returns a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] so you can have really accurate collision detection.&lt;br /&gt;
&lt;br /&gt;
Make a moving target.&lt;br /&gt;
&lt;br /&gt;
Make sure that the target is always created entirely on-screen.&lt;br /&gt;
&lt;br /&gt;
Make sure that the widget cannot be resized so that the target isn't visible. [Hint: [http://doc.qt.nokia.com/latest/qwidget.html#minimumSize-prop Qt::Widget::setMinimumSize()] is your friend.]&lt;br /&gt;
&lt;br /&gt;
Not easy; make it possible to have several shots in the air at the same time. [Hint: Make a '''&amp;lt;tt&amp;gt;Shot&amp;lt;/tt&amp;gt;''' class.]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/11/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/11/fi"/>
				<updated>2011-11-01T17:28:25Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Läpikäynti rivi riviltä ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Läpikäynti rivi riviltä ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/7/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/7/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/7/fi"/>
				<updated>2011-11-01T17:28:09Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;center&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi"/>
				<updated>2011-11-01T17:27:59Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Oppikurssi 11 - Ammutaan tykillä&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Hanging in the Air the Way Bricks Don't|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Ammutaan tykillä]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Oppikurssi 13 - Peli loppui]]&lt;br /&gt;
}}&lt;br /&gt;
== Hanging in the Air the Way Bricks Don't ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example, we extend our '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' class to include a text label. We also provide something to shoot at.  &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(s, parent = nil)&lt;br /&gt;
  super(parent)&lt;br /&gt;
  init()&lt;br /&gt;
  setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This constructor first calls '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' and then sets the label text. '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' is a separate function performing initialization mosty because of function overloading matters in the original C++ version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def init()&lt;br /&gt;
  lcd = Qt::LCDNumber.new(2)&lt;br /&gt;
  lcd.setSegmentStyle(Qt::LCDNumber::Filled)&lt;br /&gt;
&lt;br /&gt;
  @slider = Qt::Slider.new(Qt::Horizontal)&lt;br /&gt;
  @slider.setRange(0, 99)&lt;br /&gt;
  @slider.setValue(0)&lt;br /&gt;
&lt;br /&gt;
  @label = Qt::Label.new()&lt;br /&gt;
  @label.setAlignment(Qt::AlignHCenter.to_i | Qt::AlignTop.to_i)&lt;br /&gt;
&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  lcd, SLOT('display(int)'))&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  self, SIGNAL('valueChanged(int)'))&lt;br /&gt;
&lt;br /&gt;
  layout = Qt::VBoxLayout.new()&lt;br /&gt;
  layout.addWidget(lcd)&lt;br /&gt;
  layout.addWidget(@slider)&lt;br /&gt;
  layout.addWidget(@label)&lt;br /&gt;
  setLayout(layout)&lt;br /&gt;
&lt;br /&gt;
  setFocusProxy(@slider)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup of '''&amp;lt;tt&amp;gt;lcd&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;slider&amp;lt;/tt&amp;gt;''' is the same as in the previous chapter. Next we create a [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] and tell it to align the contents centered horizontally and to the top vertically. The [http://doc.qt.nokia.com/latest/qobject.html#connect Qt::Object::connect()] calls have also been taken from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setText(s)&lt;br /&gt;
  @label.setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function sets the label text.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has two new signals: '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;'''. In addition, it contains a target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'hit()', 'missed()' #...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal is emitted when a shot hits the target. The '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' 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).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newTarget()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. It creates a &amp;quot;random&amp;quot; position for the target. In fact, the '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' function will try to paint the target. Because we are in a constructor, the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' widget is invisible. Qt guarantees that no harm is done when calling [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] on a hidden widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@@first_time = true&lt;br /&gt;
&lt;br /&gt;
def newTarget()&lt;br /&gt;
  if @@first_time&lt;br /&gt;
    @@first_time = false&lt;br /&gt;
    midnight = Qt::Time.new(0, 0, 0)&lt;br /&gt;
    srand(midnight.secsTo(Qt::Time.currentTime()))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @target = Qt::Point.new(200 + rand(190), 10 + rand(255))&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function creates a target center point at a new random position.&lt;br /&gt;
&lt;br /&gt;
We create the [http://doc.qt.nokia.com/latest/qtime.html Qt::Time] object '''&amp;lt;tt&amp;gt;midnight&amp;lt;/tt&amp;gt;''', 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 [http://doc.qt.nokia.com/latest/qdate.html Qt::Date], [http://doc.qt.nokia.com/latest/qtime.html Qt::Time], and [http://doc.qt.nokia.com/latest/qdatetime.html Qt::DateTime] for more information.&lt;br /&gt;
&lt;br /&gt;
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 200 to 389 and 35 to 289, respectively) 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.&lt;br /&gt;
&lt;br /&gt;
By experimentation we have found this to always be in reach of the shot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the timer event has not changed from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
if shotR.intersects(targetRect()) &lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit hit()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This '''&amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;''' 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 '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal to tell the outside world that a target was destroyed, and return. Note that we could have created a new target on the spot, but because the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is a component we leave such decisions to the user of the component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit missed()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as in the previous chapter, except that it now emits the '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signal to tell the outside world about the failure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the rest of the function is as before.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;CannonField::paintEvent()&amp;lt;/tt&amp;gt;''' is as before, except that this has been added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line makes sure that the target is also painted when necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintTarget(painter)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::red))&lt;br /&gt;
  painter.setPen(Qt::Pen.new(Qt::Color.new(Qt::black)))&lt;br /&gt;
  painter.drawRect(targetRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the target; a rectangle filled with red and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def targetRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 20, 10)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(@target.x(), height() - 1 - @target.y()))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function returns the enclosing rectangle of the target. Remember from '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' that the '''&amp;lt;tt&amp;gt;target&amp;lt;/tt&amp;gt;''' point uses y coordinate 0 at the bottom of the widget. We calculate the point in widget coordinates before we call [http://doc.qt.nokia.com/latest/qrect.html#moveCenter Qt::Rect::moveCenter()].&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]'''&lt;br /&gt;
&lt;br /&gt;
There are no new members in the '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' class, but we have slightly changed the constructor to set the new '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' text labels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    angle = LCDRange.new(tr('ANGLE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the angle text label to &amp;quot;ANGLE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    force  = LCDRange.new(tr('FORCE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the force text label to &amp;quot;FORCE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets look a bit strange: When resizing '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''', the built-in layout management in [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] gives the labels too much space and the rest not enough; making the space between the two '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets change size. We'll fix that in the next chapter&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make a cheat button that, when pressed, makes the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' display the shot trajectory for five seconds.&lt;br /&gt;
&lt;br /&gt;
If you did the &amp;quot;round shot&amp;quot; exercise from the previous chapter, try changing the '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to a '''&amp;lt;tt&amp;gt;shotRegion()&amp;lt;/tt&amp;gt;''' that returns a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] so you can have really accurate collision detection.&lt;br /&gt;
&lt;br /&gt;
Make a moving target.&lt;br /&gt;
&lt;br /&gt;
Make sure that the target is always created entirely on-screen.&lt;br /&gt;
&lt;br /&gt;
Make sure that the widget cannot be resized so that the target isn't visible. [Hint: [http://doc.qt.nokia.com/latest/qwidget.html#minimumSize-prop Qt::Widget::setMinimumSize()] is your friend.]&lt;br /&gt;
&lt;br /&gt;
Not easy; make it possible to have several shots in the air at the same time. [Hint: Make a '''&amp;lt;tt&amp;gt;Shot&amp;lt;/tt&amp;gt;''' class.]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/4/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/4/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/4/fi"/>
				<updated>2011-11-01T17:27:59Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Oppikurssi 11 - Ammutaan tykillä&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Oppikurssi 11 - Ammutaan tykillä&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi"/>
				<updated>2011-11-01T17:27:35Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Oppikurssi 13 - Peli loppui&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Hanging in the Air the Way Bricks Don't|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Tutorial 11 - Giving It a Shot]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Oppikurssi 13 - Peli loppui]]&lt;br /&gt;
}}&lt;br /&gt;
== Hanging in the Air the Way Bricks Don't ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example, we extend our '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' class to include a text label. We also provide something to shoot at.  &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(s, parent = nil)&lt;br /&gt;
  super(parent)&lt;br /&gt;
  init()&lt;br /&gt;
  setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This constructor first calls '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' and then sets the label text. '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' is a separate function performing initialization mosty because of function overloading matters in the original C++ version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def init()&lt;br /&gt;
  lcd = Qt::LCDNumber.new(2)&lt;br /&gt;
  lcd.setSegmentStyle(Qt::LCDNumber::Filled)&lt;br /&gt;
&lt;br /&gt;
  @slider = Qt::Slider.new(Qt::Horizontal)&lt;br /&gt;
  @slider.setRange(0, 99)&lt;br /&gt;
  @slider.setValue(0)&lt;br /&gt;
&lt;br /&gt;
  @label = Qt::Label.new()&lt;br /&gt;
  @label.setAlignment(Qt::AlignHCenter.to_i | Qt::AlignTop.to_i)&lt;br /&gt;
&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  lcd, SLOT('display(int)'))&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  self, SIGNAL('valueChanged(int)'))&lt;br /&gt;
&lt;br /&gt;
  layout = Qt::VBoxLayout.new()&lt;br /&gt;
  layout.addWidget(lcd)&lt;br /&gt;
  layout.addWidget(@slider)&lt;br /&gt;
  layout.addWidget(@label)&lt;br /&gt;
  setLayout(layout)&lt;br /&gt;
&lt;br /&gt;
  setFocusProxy(@slider)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup of '''&amp;lt;tt&amp;gt;lcd&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;slider&amp;lt;/tt&amp;gt;''' is the same as in the previous chapter. Next we create a [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] and tell it to align the contents centered horizontally and to the top vertically. The [http://doc.qt.nokia.com/latest/qobject.html#connect Qt::Object::connect()] calls have also been taken from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setText(s)&lt;br /&gt;
  @label.setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function sets the label text.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has two new signals: '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;'''. In addition, it contains a target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'hit()', 'missed()' #...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal is emitted when a shot hits the target. The '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' 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).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newTarget()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. It creates a &amp;quot;random&amp;quot; position for the target. In fact, the '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' function will try to paint the target. Because we are in a constructor, the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' widget is invisible. Qt guarantees that no harm is done when calling [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] on a hidden widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@@first_time = true&lt;br /&gt;
&lt;br /&gt;
def newTarget()&lt;br /&gt;
  if @@first_time&lt;br /&gt;
    @@first_time = false&lt;br /&gt;
    midnight = Qt::Time.new(0, 0, 0)&lt;br /&gt;
    srand(midnight.secsTo(Qt::Time.currentTime()))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @target = Qt::Point.new(200 + rand(190), 10 + rand(255))&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function creates a target center point at a new random position.&lt;br /&gt;
&lt;br /&gt;
We create the [http://doc.qt.nokia.com/latest/qtime.html Qt::Time] object '''&amp;lt;tt&amp;gt;midnight&amp;lt;/tt&amp;gt;''', 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 [http://doc.qt.nokia.com/latest/qdate.html Qt::Date], [http://doc.qt.nokia.com/latest/qtime.html Qt::Time], and [http://doc.qt.nokia.com/latest/qdatetime.html Qt::DateTime] for more information.&lt;br /&gt;
&lt;br /&gt;
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 200 to 389 and 35 to 289, respectively) 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.&lt;br /&gt;
&lt;br /&gt;
By experimentation we have found this to always be in reach of the shot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the timer event has not changed from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
if shotR.intersects(targetRect()) &lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit hit()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This '''&amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;''' 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 '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal to tell the outside world that a target was destroyed, and return. Note that we could have created a new target on the spot, but because the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is a component we leave such decisions to the user of the component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit missed()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as in the previous chapter, except that it now emits the '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signal to tell the outside world about the failure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the rest of the function is as before.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;CannonField::paintEvent()&amp;lt;/tt&amp;gt;''' is as before, except that this has been added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line makes sure that the target is also painted when necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintTarget(painter)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::red))&lt;br /&gt;
  painter.setPen(Qt::Pen.new(Qt::Color.new(Qt::black)))&lt;br /&gt;
  painter.drawRect(targetRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the target; a rectangle filled with red and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def targetRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 20, 10)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(@target.x(), height() - 1 - @target.y()))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function returns the enclosing rectangle of the target. Remember from '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' that the '''&amp;lt;tt&amp;gt;target&amp;lt;/tt&amp;gt;''' point uses y coordinate 0 at the bottom of the widget. We calculate the point in widget coordinates before we call [http://doc.qt.nokia.com/latest/qrect.html#moveCenter Qt::Rect::moveCenter()].&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]'''&lt;br /&gt;
&lt;br /&gt;
There are no new members in the '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' class, but we have slightly changed the constructor to set the new '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' text labels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    angle = LCDRange.new(tr('ANGLE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the angle text label to &amp;quot;ANGLE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    force  = LCDRange.new(tr('FORCE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the force text label to &amp;quot;FORCE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets look a bit strange: When resizing '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''', the built-in layout management in [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] gives the labels too much space and the rest not enough; making the space between the two '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets change size. We'll fix that in the next chapter&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make a cheat button that, when pressed, makes the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' display the shot trajectory for five seconds.&lt;br /&gt;
&lt;br /&gt;
If you did the &amp;quot;round shot&amp;quot; exercise from the previous chapter, try changing the '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to a '''&amp;lt;tt&amp;gt;shotRegion()&amp;lt;/tt&amp;gt;''' that returns a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] so you can have really accurate collision detection.&lt;br /&gt;
&lt;br /&gt;
Make a moving target.&lt;br /&gt;
&lt;br /&gt;
Make sure that the target is always created entirely on-screen.&lt;br /&gt;
&lt;br /&gt;
Make sure that the widget cannot be resized so that the target isn't visible. [Hint: [http://doc.qt.nokia.com/latest/qwidget.html#minimumSize-prop Qt::Widget::setMinimumSize()] is your friend.]&lt;br /&gt;
&lt;br /&gt;
Not easy; make it possible to have several shots in the air at the same time. [Hint: Make a '''&amp;lt;tt&amp;gt;Shot&amp;lt;/tt&amp;gt;''' class.]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/5/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/5/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/5/fi"/>
				<updated>2011-11-01T17:27:35Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Oppikurssi 13 - Peli loppui&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Oppikurssi 13 - Peli loppui&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi"/>
				<updated>2011-11-01T17:27:10Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Qt4 Ruby -oppikurssi&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Hanging in the Air the Way Bricks Don't|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Tutorial 11 - Giving It a Shot]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Tutorial 13 - Game Over]]&lt;br /&gt;
}}&lt;br /&gt;
== Hanging in the Air the Way Bricks Don't ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example, we extend our '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' class to include a text label. We also provide something to shoot at.  &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(s, parent = nil)&lt;br /&gt;
  super(parent)&lt;br /&gt;
  init()&lt;br /&gt;
  setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This constructor first calls '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' and then sets the label text. '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' is a separate function performing initialization mosty because of function overloading matters in the original C++ version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def init()&lt;br /&gt;
  lcd = Qt::LCDNumber.new(2)&lt;br /&gt;
  lcd.setSegmentStyle(Qt::LCDNumber::Filled)&lt;br /&gt;
&lt;br /&gt;
  @slider = Qt::Slider.new(Qt::Horizontal)&lt;br /&gt;
  @slider.setRange(0, 99)&lt;br /&gt;
  @slider.setValue(0)&lt;br /&gt;
&lt;br /&gt;
  @label = Qt::Label.new()&lt;br /&gt;
  @label.setAlignment(Qt::AlignHCenter.to_i | Qt::AlignTop.to_i)&lt;br /&gt;
&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  lcd, SLOT('display(int)'))&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  self, SIGNAL('valueChanged(int)'))&lt;br /&gt;
&lt;br /&gt;
  layout = Qt::VBoxLayout.new()&lt;br /&gt;
  layout.addWidget(lcd)&lt;br /&gt;
  layout.addWidget(@slider)&lt;br /&gt;
  layout.addWidget(@label)&lt;br /&gt;
  setLayout(layout)&lt;br /&gt;
&lt;br /&gt;
  setFocusProxy(@slider)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup of '''&amp;lt;tt&amp;gt;lcd&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;slider&amp;lt;/tt&amp;gt;''' is the same as in the previous chapter. Next we create a [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] and tell it to align the contents centered horizontally and to the top vertically. The [http://doc.qt.nokia.com/latest/qobject.html#connect Qt::Object::connect()] calls have also been taken from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setText(s)&lt;br /&gt;
  @label.setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function sets the label text.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has two new signals: '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;'''. In addition, it contains a target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'hit()', 'missed()' #...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal is emitted when a shot hits the target. The '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' 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).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newTarget()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. It creates a &amp;quot;random&amp;quot; position for the target. In fact, the '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' function will try to paint the target. Because we are in a constructor, the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' widget is invisible. Qt guarantees that no harm is done when calling [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] on a hidden widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@@first_time = true&lt;br /&gt;
&lt;br /&gt;
def newTarget()&lt;br /&gt;
  if @@first_time&lt;br /&gt;
    @@first_time = false&lt;br /&gt;
    midnight = Qt::Time.new(0, 0, 0)&lt;br /&gt;
    srand(midnight.secsTo(Qt::Time.currentTime()))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @target = Qt::Point.new(200 + rand(190), 10 + rand(255))&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function creates a target center point at a new random position.&lt;br /&gt;
&lt;br /&gt;
We create the [http://doc.qt.nokia.com/latest/qtime.html Qt::Time] object '''&amp;lt;tt&amp;gt;midnight&amp;lt;/tt&amp;gt;''', 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 [http://doc.qt.nokia.com/latest/qdate.html Qt::Date], [http://doc.qt.nokia.com/latest/qtime.html Qt::Time], and [http://doc.qt.nokia.com/latest/qdatetime.html Qt::DateTime] for more information.&lt;br /&gt;
&lt;br /&gt;
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 200 to 389 and 35 to 289, respectively) 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.&lt;br /&gt;
&lt;br /&gt;
By experimentation we have found this to always be in reach of the shot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the timer event has not changed from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
if shotR.intersects(targetRect()) &lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit hit()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This '''&amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;''' 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 '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal to tell the outside world that a target was destroyed, and return. Note that we could have created a new target on the spot, but because the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is a component we leave such decisions to the user of the component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit missed()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as in the previous chapter, except that it now emits the '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signal to tell the outside world about the failure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the rest of the function is as before.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;CannonField::paintEvent()&amp;lt;/tt&amp;gt;''' is as before, except that this has been added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line makes sure that the target is also painted when necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintTarget(painter)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::red))&lt;br /&gt;
  painter.setPen(Qt::Pen.new(Qt::Color.new(Qt::black)))&lt;br /&gt;
  painter.drawRect(targetRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the target; a rectangle filled with red and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def targetRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 20, 10)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(@target.x(), height() - 1 - @target.y()))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function returns the enclosing rectangle of the target. Remember from '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' that the '''&amp;lt;tt&amp;gt;target&amp;lt;/tt&amp;gt;''' point uses y coordinate 0 at the bottom of the widget. We calculate the point in widget coordinates before we call [http://doc.qt.nokia.com/latest/qrect.html#moveCenter Qt::Rect::moveCenter()].&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]'''&lt;br /&gt;
&lt;br /&gt;
There are no new members in the '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' class, but we have slightly changed the constructor to set the new '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' text labels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    angle = LCDRange.new(tr('ANGLE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the angle text label to &amp;quot;ANGLE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    force  = LCDRange.new(tr('FORCE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the force text label to &amp;quot;FORCE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets look a bit strange: When resizing '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''', the built-in layout management in [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] gives the labels too much space and the rest not enough; making the space between the two '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets change size. We'll fix that in the next chapter&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make a cheat button that, when pressed, makes the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' display the shot trajectory for five seconds.&lt;br /&gt;
&lt;br /&gt;
If you did the &amp;quot;round shot&amp;quot; exercise from the previous chapter, try changing the '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to a '''&amp;lt;tt&amp;gt;shotRegion()&amp;lt;/tt&amp;gt;''' that returns a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] so you can have really accurate collision detection.&lt;br /&gt;
&lt;br /&gt;
Make a moving target.&lt;br /&gt;
&lt;br /&gt;
Make sure that the target is always created entirely on-screen.&lt;br /&gt;
&lt;br /&gt;
Make sure that the widget cannot be resized so that the target isn't visible. [Hint: [http://doc.qt.nokia.com/latest/qwidget.html#minimumSize-prop Qt::Widget::setMinimumSize()] is your friend.]&lt;br /&gt;
&lt;br /&gt;
Not easy; make it possible to have several shots in the air at the same time. [Hint: Make a '''&amp;lt;tt&amp;gt;Shot&amp;lt;/tt&amp;gt;''' class.]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/2/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/2/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/2/fi"/>
				<updated>2011-11-01T17:27:10Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Qt4 Ruby -oppikurssi&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Qt4 Ruby -oppikurssi&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/1/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/1/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/1/fi"/>
				<updated>2011-11-01T17:26:57Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;TutorialBrowser&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TutorialBrowser&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12/fi"/>
				<updated>2011-11-01T17:26:57Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;TutorialBrowser&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 12}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby Tutorial]]|&lt;br /&gt;
name=Hanging in the Air the Way Bricks Don't|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Tutorial 11 - Giving It a Shot]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_13|Tutorial 13 - Game Over]]&lt;br /&gt;
}}&lt;br /&gt;
== Hanging in the Air the Way Bricks Don't ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_12.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example, we extend our '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' class to include a text label. We also provide something to shoot at.  &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/lcdrange.rb lcdrange.rb]'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(s, parent = nil)&lt;br /&gt;
  super(parent)&lt;br /&gt;
  init()&lt;br /&gt;
  setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This constructor first calls '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' and then sets the label text. '''&amp;lt;tt&amp;gt;init()&amp;lt;/tt&amp;gt;''' is a separate function performing initialization mosty because of function overloading matters in the original C++ version.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def init()&lt;br /&gt;
  lcd = Qt::LCDNumber.new(2)&lt;br /&gt;
  lcd.setSegmentStyle(Qt::LCDNumber::Filled)&lt;br /&gt;
&lt;br /&gt;
  @slider = Qt::Slider.new(Qt::Horizontal)&lt;br /&gt;
  @slider.setRange(0, 99)&lt;br /&gt;
  @slider.setValue(0)&lt;br /&gt;
&lt;br /&gt;
  @label = Qt::Label.new()&lt;br /&gt;
  @label.setAlignment(Qt::AlignHCenter.to_i | Qt::AlignTop.to_i)&lt;br /&gt;
&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  lcd, SLOT('display(int)'))&lt;br /&gt;
  connect(@slider, SIGNAL('valueChanged(int)'),&lt;br /&gt;
  self, SIGNAL('valueChanged(int)'))&lt;br /&gt;
&lt;br /&gt;
  layout = Qt::VBoxLayout.new()&lt;br /&gt;
  layout.addWidget(lcd)&lt;br /&gt;
  layout.addWidget(@slider)&lt;br /&gt;
  layout.addWidget(@label)&lt;br /&gt;
  setLayout(layout)&lt;br /&gt;
&lt;br /&gt;
  setFocusProxy(@slider)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup of '''&amp;lt;tt&amp;gt;lcd&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;slider&amp;lt;/tt&amp;gt;''' is the same as in the previous chapter. Next we create a [http://doc.qt.nokia.com/latest/qlabel.html Qt::Label] and tell it to align the contents centered horizontally and to the top vertically. The [http://doc.qt.nokia.com/latest/qobject.html#connect Qt::Object::connect()] calls have also been taken from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setText(s)&lt;br /&gt;
  @label.setText(s)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function sets the label text.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has two new signals: '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;'''. In addition, it contains a target.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  signals 'hit()', 'missed()' #...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal is emitted when a shot hits the target. The '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' 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).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    newTarget()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line has been added to the constructor. It creates a &amp;quot;random&amp;quot; position for the target. In fact, the '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' function will try to paint the target. Because we are in a constructor, the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' widget is invisible. Qt guarantees that no harm is done when calling [http://doc.qt.nokia.com/latest/qwidget.html#update Qt::Widget::update()] on a hidden widget.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@@first_time = true&lt;br /&gt;
&lt;br /&gt;
def newTarget()&lt;br /&gt;
  if @@first_time&lt;br /&gt;
    @@first_time = false&lt;br /&gt;
    midnight = Qt::Time.new(0, 0, 0)&lt;br /&gt;
    srand(midnight.secsTo(Qt::Time.currentTime()))&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @target = Qt::Point.new(200 + rand(190), 10 + rand(255))&lt;br /&gt;
  update()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function creates a target center point at a new random position.&lt;br /&gt;
&lt;br /&gt;
We create the [http://doc.qt.nokia.com/latest/qtime.html Qt::Time] object '''&amp;lt;tt&amp;gt;midnight&amp;lt;/tt&amp;gt;''', 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 [http://doc.qt.nokia.com/latest/qdate.html Qt::Date], [http://doc.qt.nokia.com/latest/qtime.html Qt::Time], and [http://doc.qt.nokia.com/latest/qdatetime.html Qt::DateTime] for more information.&lt;br /&gt;
&lt;br /&gt;
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 200 to 389 and 35 to 289, respectively) 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.&lt;br /&gt;
&lt;br /&gt;
By experimentation we have found this to always be in reach of the shot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This part of the timer event has not changed from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
if shotR.intersects(targetRect()) &lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit hit()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This '''&amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt;''' 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 '''&amp;lt;tt&amp;gt;hit()&amp;lt;/tt&amp;gt;''' signal to tell the outside world that a target was destroyed, and return. Note that we could have created a new target on the spot, but because the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' is a component we leave such decisions to the user of the component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
elsif shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
  @autoShootTimer.stop()&lt;br /&gt;
  emit missed()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the same as in the previous chapter, except that it now emits the '''&amp;lt;tt&amp;gt;missed()&amp;lt;/tt&amp;gt;''' signal to tell the outside world about the failure.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the rest of the function is as before.&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;CannonField::paintEvent()&amp;lt;/tt&amp;gt;''' is as before, except that this has been added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    paintTarget(painter)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line makes sure that the target is also painted when necessary.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintTarget(painter)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::red))&lt;br /&gt;
  painter.setPen(Qt::Pen.new(Qt::Color.new(Qt::black)))&lt;br /&gt;
  painter.drawRect(targetRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function paints the target; a rectangle filled with red and with a black outline.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def targetRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 20, 10)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(@target.x(), height() - 1 - @target.y()))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function returns the enclosing rectangle of the target. Remember from '''&amp;lt;tt&amp;gt;newTarget()&amp;lt;/tt&amp;gt;''' that the '''&amp;lt;tt&amp;gt;target&amp;lt;/tt&amp;gt;''' point uses y coordinate 0 at the bottom of the widget. We calculate the point in widget coordinates before we call [http://doc.qt.nokia.com/latest/qrect.html#moveCenter Qt::Rect::moveCenter()].&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t12/t12.rb t12.rb]'''&lt;br /&gt;
&lt;br /&gt;
There are no new members in the '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''' class, but we have slightly changed the constructor to set the new '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' text labels.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    angle = LCDRange.new(tr('ANGLE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the angle text label to &amp;quot;ANGLE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
    force  = LCDRange.new(tr('FORCE'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We set the force text label to &amp;quot;FORCE&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets look a bit strange: When resizing '''&amp;lt;tt&amp;gt;MyWidget&amp;lt;/tt&amp;gt;''', the built-in layout management in [http://doc.qt.nokia.com/latest/qvboxlayout.html Qt::VBoxLayout] gives the labels too much space and the rest not enough; making the space between the two '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;''' widgets change size. We'll fix that in the next chapter&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make a cheat button that, when pressed, makes the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' display the shot trajectory for five seconds.&lt;br /&gt;
&lt;br /&gt;
If you did the &amp;quot;round shot&amp;quot; exercise from the previous chapter, try changing the '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to a '''&amp;lt;tt&amp;gt;shotRegion()&amp;lt;/tt&amp;gt;''' that returns a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] so you can have really accurate collision detection.&lt;br /&gt;
&lt;br /&gt;
Make a moving target.&lt;br /&gt;
&lt;br /&gt;
Make sure that the target is always created entirely on-screen.&lt;br /&gt;
&lt;br /&gt;
Make sure that the widget cannot be resized so that the target isn't visible. [Hint: [http://doc.qt.nokia.com/latest/qwidget.html#minimumSize-prop Qt::Widget::setMinimumSize()] is your friend.]&lt;br /&gt;
&lt;br /&gt;
Not easy; make it possible to have several shots in the air at the same time. [Hint: Make a '''&amp;lt;tt&amp;gt;Shot&amp;lt;/tt&amp;gt;''' class.]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:46:34Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Kanuuna voi laukaista, mutta ei ole mitään mitä ampua.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Oppikurssi 10 - Sileää kuin silkki]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
Kanuuna voi laukaista, mutta ei ole mitään mitä ampua.&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
&lt;br /&gt;
Tee laukauksesta täytetty ympyrä. [Vihje: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] saattaa auttaa.]&lt;br /&gt;
&lt;br /&gt;
Vaihda kanuunan väriä kun laukaus on ilmassa.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/34/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/34/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/34/fi"/>
				<updated>2011-10-29T12:46:34Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Kanuuna voi laukaista, mutta ei ole mitään mitä ampua.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Kanuuna voi laukaista, mutta ei ole mitään mitä ampua.&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:45:36Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Tee laukauksesta täytetty ympyrä. [Vihje: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] saattaa auttaa.]&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Oppikurssi 10 - Sileää kuin silkki]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot, but there's nothing to shoot at.&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
&lt;br /&gt;
Tee laukauksesta täytetty ympyrä. [Vihje: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] saattaa auttaa.]&lt;br /&gt;
&lt;br /&gt;
Vaihda kanuunan väriä kun laukaus on ilmassa.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/36/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/36/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/36/fi"/>
				<updated>2011-10-29T12:45:36Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Tee laukauksesta täytetty ympyrä. [Vihje: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] saattaa auttaa.]&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Tee laukauksesta täytetty ympyrä. [Vihje: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] saattaa auttaa.]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:44:56Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Vaihda kanuunan väriä kun laukaus on ilmassa.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Oppikurssi 10 - Sileää kuin silkki]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot, but there's nothing to shoot at.&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
&lt;br /&gt;
Make the shot a filled circle. [Hint: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] may help.]&lt;br /&gt;
&lt;br /&gt;
Vaihda kanuunan väriä kun laukaus on ilmassa.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/37/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/37/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/37/fi"/>
				<updated>2011-10-29T12:44:56Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Vaihda kanuunan väriä kun laukaus on ilmassa.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vaihda kanuunan väriä kun laukaus on ilmassa.&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/38/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/38/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/38/fi"/>
				<updated>2011-10-29T12:44:25Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Category:Ruby&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:44:17Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Oppikurssi 10 - Sileää kuin silkki]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot, but there's nothing to shoot at.&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
&lt;br /&gt;
Make the shot a filled circle. [Hint: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] may help.]&lt;br /&gt;
&lt;br /&gt;
Change the color of the cannon when a shot is in the air.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/35/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/35/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/35/fi"/>
				<updated>2011-10-29T12:44:17Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Harjoitukset ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:43:49Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Sovelluksen suorittaminen ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Oppikurssi 10 - Sileää kuin silkki]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot, but there's nothing to shoot at.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make the shot a filled circle. [Hint: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] may help.]&lt;br /&gt;
&lt;br /&gt;
Change the color of the cannon when a shot is in the air.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/33/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/33/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/33/fi"/>
				<updated>2011-10-29T12:43:48Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Sovelluksen suorittaminen ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Sovelluksen suorittaminen ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:43:23Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Läpikäynti rivi riviltä ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Oppikurssi 10 - Sileää kuin silkki]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot, but there's nothing to shoot at.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make the shot a filled circle. [Hint: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] may help.]&lt;br /&gt;
&lt;br /&gt;
Change the color of the cannon when a shot is in the air.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/11/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/11/fi"/>
				<updated>2011-10-29T12:43:23Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Läpikäynti rivi riviltä ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Läpikäynti rivi riviltä ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:43:02Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Yleiskuva ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Oppikurssi 10 - Sileää kuin silkki]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot, but there's nothing to shoot at.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make the shot a filled circle. [Hint: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] may help.]&lt;br /&gt;
&lt;br /&gt;
Change the color of the cannon when a shot is in the air.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/9/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/9/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/9/fi"/>
				<updated>2011-10-29T12:43:01Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Yleiskuva ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Yleiskuva ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/7/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/7/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/7/fi"/>
				<updated>2011-10-29T12:42:22Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;center&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:42:15Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Oppikurssi 10 - Sileää kuin silkki&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Oppikurssi 10 - Sileää kuin silkki]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot, but there's nothing to shoot at.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make the shot a filled circle. [Hint: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] may help.]&lt;br /&gt;
&lt;br /&gt;
Change the color of the cannon when a shot is in the air.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/4/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/4/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/4/fi"/>
				<updated>2011-10-29T12:42:15Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Oppikurssi 10 - Sileää kuin silkki&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Oppikurssi 10 - Sileää kuin silkki&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:41:47Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Qt4 Ruby -oppikurssi&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Tutorial 10 - Smooth as Silk]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot, but there's nothing to shoot at.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make the shot a filled circle. [Hint: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] may help.]&lt;br /&gt;
&lt;br /&gt;
Change the color of the cannon when a shot is in the air.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/2/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/2/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/2/fi"/>
				<updated>2011-10-29T12:41:47Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Qt4 Ruby -oppikurssi&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Qt4 Ruby -oppikurssi&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/1/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/1/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/1/fi"/>
				<updated>2011-10-29T12:41:30Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;TutorialBrowser&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TutorialBrowser&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11/fi"/>
				<updated>2011-10-29T12:41:30Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;TutorialBrowser&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 11}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby Tutorial]]|&lt;br /&gt;
name=Giving It a Shot|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10|Tutorial 10 - Smooth as Silk]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_12|Tutorial 12 - Hanging in the Air the Way Bricks Don't]]&lt;br /&gt;
}}&lt;br /&gt;
== Giving It a Shot ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_11.png|center]]&lt;br /&gt;
Files:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
In this example we introduce a timer to implement animated shooting. &lt;br /&gt;
&lt;br /&gt;
=== Line by Line Walkthrough ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' now has shooting capabilities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
include Math&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We include '''&amp;lt;tt&amp;gt;Math&amp;lt;/tt&amp;gt;''' because we need the '''&amp;lt;tt&amp;gt;sin()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;cos()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
@timerCount = 0&lt;br /&gt;
&lt;br /&gt;
@autoShootTimer = Qt::Timer.new(self)&lt;br /&gt;
connect(@autoShootTimer, SIGNAL('timeout()'),&lt;br /&gt;
         self, SLOT('moveShot()'))&lt;br /&gt;
&lt;br /&gt;
@shootAngle = 0&lt;br /&gt;
@shootForce = 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We initialize our new private variables and connect the [http://doc.qt.nokia.com/latest/qtimer.html#timeout Qt::Timer::timeout()] signal to our '''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' slot. We'll move the shot every time the timer times out.&lt;br /&gt;
&lt;br /&gt;
The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' keeps track of the time passed since the shot was fired. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' is the cannon angle and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' is the cannon force when the shot was fired.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shoot()&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    return&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  @timerCount = 0&lt;br /&gt;
  @shootAngle = @currentAngle&lt;br /&gt;
  @shootForce = @currentForce&lt;br /&gt;
  @autoShootTimer.start(5)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function shoots a shot unless a shot is in the air. The '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''' is reset to zero. The '''&amp;lt;tt&amp;gt;shootAngle&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;shootForce&amp;lt;/tt&amp;gt;''' variables are set to the current cannon angle and force. Finally, we start the timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def moveShot()&lt;br /&gt;
  region = Qt::Region.new(shotRect())&lt;br /&gt;
  @timerCount += 1&lt;br /&gt;
&lt;br /&gt;
  shotR = shotRect()&lt;br /&gt;
&lt;br /&gt;
  if shotR.x() &amp;gt; width() || shotR.y() &amp;gt; height()&lt;br /&gt;
    @autoShootTimer.stop()&lt;br /&gt;
  else&lt;br /&gt;
    region = region.unite(Qt::Region.new(shotR))&lt;br /&gt;
  end&lt;br /&gt;
  update(region)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;moveShot()&amp;lt;/tt&amp;gt;''' is the slot that moves the shot, called every 5 milliseconds when the [http://doc.qt.nokia.com/latest/qtimer.html Qt::Timer] fires.&lt;br /&gt;
&lt;br /&gt;
Its tasks are to compute the new position, update the screen with the shot in the new position, and if necessary, stop the timer.&lt;br /&gt;
&lt;br /&gt;
First we make a [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] that holds the old '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;'''. A [http://doc.qt.nokia.com/latest/qregion.html Qt::Region] is capable of holding any sort of region, and we'll use it here to simplify the painting. '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' returns the rectangle where the shot is now. It is explained in detail later.&lt;br /&gt;
&lt;br /&gt;
Then we increment the '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which has the effect of moving the shot one step along its trajectory.&lt;br /&gt;
&lt;br /&gt;
Next we fetch the new shot rectangle.&lt;br /&gt;
&lt;br /&gt;
If the shot has moved beyond the right or bottom edge of the widget we stop the timer, or we add the new '''&amp;lt;tt&amp;gt;shotRect()&amp;lt;/tt&amp;gt;''' to the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region].&lt;br /&gt;
&lt;br /&gt;
Finally, we repaint the [http://doc.qt.nokia.com/latest/qregion.html Qt::Region]. This will send a single paint event for just the one or two rectangles that need updating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  paintCannon(painter)&lt;br /&gt;
  if @autoShootTimer.isActive()&lt;br /&gt;
    paintShot(painter)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paint event function has been simplified since the previous chapter. Most of the logic has been moved to the new '''&amp;lt;tt&amp;gt;paintShot()&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;''' functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintShot(painter)&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::black))&lt;br /&gt;
  painter.drawRect(shotRect())&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function paints the shot by drawing a black filled rectangle.&lt;br /&gt;
&lt;br /&gt;
We leave out the implementation of '''&amp;lt;tt&amp;gt;paintCannon()&amp;lt;/tt&amp;gt;'''; it is the same as the [http://doc.qt.nokia.com/latest/qwidget.html#paintEvent Qt::Widget::paintEvent()] reimplementation from the previous chapter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def shotRect()&lt;br /&gt;
  gravity = 4.0&lt;br /&gt;
&lt;br /&gt;
  time = @timerCount / 20.0&lt;br /&gt;
  velocity = @shootForce&lt;br /&gt;
  radians = @shootAngle * 3.14159265 / 180.0&lt;br /&gt;
&lt;br /&gt;
  velx = velocity * cos(radians)&lt;br /&gt;
  vely = velocity * sin(radians)&lt;br /&gt;
  x0 = (@barrelRect.right() + 5.0) * cos(radians)&lt;br /&gt;
  y0 = (@barrelRect.right() + 5.0) * sin(radians)&lt;br /&gt;
  x = x0 + velx * time&lt;br /&gt;
  y = y0 + vely * time - 0.5 * gravity * time * time&lt;br /&gt;
&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 6, 6)&lt;br /&gt;
  result.moveCenter(Qt::Point.new(x.round, height() - 1 - y.round))&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This private function calculates the center point of the shot and returns the enclosing rectangle of the shot. It uses the initial cannon force and angle in addition to '''&amp;lt;tt&amp;gt;timerCount&amp;lt;/tt&amp;gt;''', which increases as time passes.&lt;br /&gt;
&lt;br /&gt;
The formula used is the standard Newtonian formula for frictionless movement in a gravity field. For simplicity, we've chosen to disregard any Einsteinian effects.&lt;br /&gt;
&lt;br /&gt;
We calculate the center point in a coordinate system where y coordinates increase upward. After we have calculated the center point, we construct a [http://doc.qt.nokia.com/latest/qrect.html Qt::Rect] with size 6 x 6 and move its center point to the point calculated above. In the same operation we convert the point into the widget's coordinate system (see [http://doc.qt.nokia.com/latest/coordsys.html The Coordinate System]).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t11/t11.rb t11.rb]'''&lt;br /&gt;
&lt;br /&gt;
The only addition is the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
shoot = Qt::PushButton.new(tr('&amp;amp;Shoot'))&lt;br /&gt;
shoot.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the constructor we create and set up the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button exactly like we did with the &amp;lt;strong&amp;gt;Quit&amp;lt;/strong&amp;gt; button.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connects the '''&amp;lt;tt&amp;gt;clicked()&amp;lt;/tt&amp;gt;''' signal of the &amp;lt;strong&amp;gt;Shoot&amp;lt;/strong&amp;gt; button to the '''&amp;lt;tt&amp;gt;shoot()&amp;lt;/tt&amp;gt;''' slot of the '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
=== Running the Application ===&lt;br /&gt;
&lt;br /&gt;
The cannon can shoot, but there's nothing to shoot at.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
&lt;br /&gt;
Make the shot a filled circle. [Hint: [http://doc.qt.nokia.com/latest/qpainter.html#drawEllipse Qt::Painter::drawEllipse()] may help.]&lt;br /&gt;
&lt;br /&gt;
Change the color of the cannon when a shot is in the air.&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/30/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/30/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/30/fi"/>
				<updated>2011-10-29T12:35:25Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Category:Ruby&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/fi"/>
				<updated>2011-10-29T12:35:17Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Yritä lisätä parempi näppäimistörajapinta. Esimerkiksi, tee + ja - kasvattamaan ja pienennättämään voimaa ja laukaisemaan kanuunan. Jos olet vaivautunut tavasta, jolla ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Sileää kuin silkki|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_09|Oppikurssi 9 - Kanuunalla onnistuu]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Annetaan sille laukaus]]&lt;br /&gt;
}}&lt;br /&gt;
== Sileää kuin silkki ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_10.png|center]]&lt;br /&gt;
Tiedostot:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/t10.rb t10.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
Tässä esimerkissä lisäämme voimaa ohjaimeen. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
Kentällä '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' on nyt voima-arvo kulman lisäksi.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
signals 'angleChanged(int)', 'forceChanged(int)'&lt;br /&gt;
slots 'setAngle(int)', 'setForce(int)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voiman rajapinta noudattaa samaa käytäntöä kuin kulma.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(parent = nil)&lt;br /&gt;
  super()&lt;br /&gt;
&lt;br /&gt;
  @currentAngle = 45&lt;br /&gt;
  @currentForce = 0&lt;br /&gt;
&lt;br /&gt;
  setPalette(Qt::Palette.new(Qt::Color.new(250, 250, 200)))&lt;br /&gt;
  setAutoFillBackground(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voima '''&amp;lt;tt&amp;gt;@currentForce&amp;lt;/tt&amp;gt;''' on alustettu nollaksi.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setAngle(angle)&lt;br /&gt;
  if angle &amp;lt; 5&lt;br /&gt;
    angle = 5&lt;br /&gt;
  elsif angle &amp;gt; 70&lt;br /&gt;
    angle = 70&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if @currentAngle == angle&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @currentAngle = angle&lt;br /&gt;
  update(cannonRect())&lt;br /&gt;
  emit angleChanged(@currentAngle)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Teimme pienen muutoksen '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;'''-funktioon. Se piirtää uudelleen käyttöliittymän osan, joka sisältää kanuunan.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setForce(force)&lt;br /&gt;
  if force &amp;lt; 0&lt;br /&gt;
    force = 0&lt;br /&gt;
  end&lt;br /&gt;
  if @currentForce == force&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @currentForce = force&lt;br /&gt;
  emit forceChanged(@currentForce)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;setForce()&amp;lt;/tt&amp;gt;'''-toteutus on aika samanlainen kuin '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;'''. Ainoa erilaisuus on, että koska emme näytä voima-arvoa, käyttöliittymäkomponenttia ei tarvitse piirtää uudelleen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::blue))&lt;br /&gt;
&lt;br /&gt;
  painter.translate(0, height())&lt;br /&gt;
  painter.drawPie(Qt::Rect.new(-35, -35, 70, 70), 0, 90 * 16)&lt;br /&gt;
  painter.rotate(-@currentAngle)&lt;br /&gt;
  painter.drawRect(Qt::Rect.new(30, -5, 20, 10))&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Piirrämme kuin kappaleessa 9.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def cannonRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 50, 50)&lt;br /&gt;
  result.moveBottomLeft(rect().bottomLeft())&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktio '''&amp;lt;tt&amp;gt;cannonRect()&amp;lt;/tt&amp;gt;''' palauttaa nelikulmion, joka sisältää kanuunan sisältävän käyttöliittymäkomponentin. Luomme aluksi nelikulmion, jonka koko on 50 x 50 ja siirrämme sen niin, että sen vasen alakulma on sama kuin käyttöliittymäkomponentin vasen alakulma.&lt;br /&gt;
&lt;br /&gt;
Funktio [http://doc.qt.nokia.com/latest/qwidget.html#rect-prop Qt::Widget::rect()] palauttaa käyttöliittymän sisältämän nelikulmion käyttöliittymän omina koordinaatteina. Nelikulmion vasen yläkulma on aina (0, 0).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/t10.rb t10.rb]'''&lt;br /&gt;
&lt;br /&gt;
Konstruktori on enimmäkseen sama, mutta joitakin uusia bittejä on lisätty.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
force = LCDRange.new()&lt;br /&gt;
force.setRange(10, 50)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lisäämme toisen '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;'''-komponentin, jota käytetään voiman asettamiseen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(force, SIGNAL('valueChanged(int)'),&lt;br /&gt;
         cannonField, SLOT('setForce(int)'))&lt;br /&gt;
connect(cannonField, SIGNAL('forceChanged(int)'),&lt;br /&gt;
         force, SLOT('setValue(int)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Yhdistämme käyttöliittymäkomponentin '''&amp;lt;tt&amp;gt;force&amp;lt;/tt&amp;gt;''' ja käyttöliittymäkomponentin '''&amp;lt;tt&amp;gt;cannonField&amp;lt;/tt&amp;gt;''', aivan kuin teimme käyttöliittymäkomponentille '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kappaleessa 9 sijoitamme '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;'''-komponentin asettelun vasemman alakulman soluun. Nyt haluamme siihen soluun kaksi käyttöliittymäkomponenttial, joten teemme pystysuoran ruudun, laitamme pystysuoran ruudun rasterinsoluunl, ja laitamme sekä '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;''' että '''&amp;lt;tt&amp;gt;range&amp;lt;/tt&amp;gt;''' pystysuoraan ruutuun.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
force.setValue(25)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alustamme voima-arvoksi 25.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
Meillä on nyt voimaohjaus.&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
Tee kanuuna piipun koko riippuvaiseksi voimasta.&lt;br /&gt;
&lt;br /&gt;
Laita kanuuna oikeaan alakulmaan.&lt;br /&gt;
&lt;br /&gt;
Yritä lisätä parempi näppäimistörajapinta. Esimerkiksi, tee + ja - kasvattamaan ja pienennättämään voimaa ja laukaisemaan kanuunan. Jos olet vaivautunut tavasta, jolla näppäimet '''&amp;lt;tt&amp;gt;Left&amp;lt;/tt&amp;gt;''' ja '''&amp;lt;tt&amp;gt;Right&amp;lt;/tt&amp;gt;''' toimivat, muuta sitä myös. [Vihje: Toteuta uudelleen [http://doc.qt.nokia.com/latest/qwidget.html#keyPressEvent Qt::Widget::keyPressEvent()].]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/29/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/29/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/29/fi"/>
				<updated>2011-10-29T12:35:17Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Yritä lisätä parempi näppäimistörajapinta. Esimerkiksi, tee + ja - kasvattamaan ja pienennättämään voimaa ja laukaisemaan kanuunan. Jos olet vaivautunut tavasta, jolla ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Yritä lisätä parempi näppäimistörajapinta. Esimerkiksi, tee + ja - kasvattamaan ja pienennättämään voimaa ja laukaisemaan kanuunan. Jos olet vaivautunut tavasta, jolla näppäimet '''&amp;lt;tt&amp;gt;Left&amp;lt;/tt&amp;gt;''' ja '''&amp;lt;tt&amp;gt;Right&amp;lt;/tt&amp;gt;''' toimivat, muuta sitä myös. [Vihje: Toteuta uudelleen [http://doc.qt.nokia.com/latest/qwidget.html#keyPressEvent Qt::Widget::keyPressEvent()].]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/fi"/>
				<updated>2011-10-29T12:32:01Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Laita kanuuna oikeaan alakulmaan.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Sileää kuin silkki|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_09|Oppikurssi 9 - Kanuunalla onnistuu]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Annetaan sille laukaus]]&lt;br /&gt;
}}&lt;br /&gt;
== Sileää kuin silkki ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_10.png|center]]&lt;br /&gt;
Tiedostot:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/t10.rb t10.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
Tässä esimerkissä lisäämme voimaa ohjaimeen. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
Kentällä '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' on nyt voima-arvo kulman lisäksi.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
signals 'angleChanged(int)', 'forceChanged(int)'&lt;br /&gt;
slots 'setAngle(int)', 'setForce(int)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voiman rajapinta noudattaa samaa käytäntöä kuin kulma.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(parent = nil)&lt;br /&gt;
  super()&lt;br /&gt;
&lt;br /&gt;
  @currentAngle = 45&lt;br /&gt;
  @currentForce = 0&lt;br /&gt;
&lt;br /&gt;
  setPalette(Qt::Palette.new(Qt::Color.new(250, 250, 200)))&lt;br /&gt;
  setAutoFillBackground(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voima '''&amp;lt;tt&amp;gt;@currentForce&amp;lt;/tt&amp;gt;''' on alustettu nollaksi.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setAngle(angle)&lt;br /&gt;
  if angle &amp;lt; 5&lt;br /&gt;
    angle = 5&lt;br /&gt;
  elsif angle &amp;gt; 70&lt;br /&gt;
    angle = 70&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if @currentAngle == angle&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @currentAngle = angle&lt;br /&gt;
  update(cannonRect())&lt;br /&gt;
  emit angleChanged(@currentAngle)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Teimme pienen muutoksen '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;'''-funktioon. Se piirtää uudelleen käyttöliittymän osan, joka sisältää kanuunan.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setForce(force)&lt;br /&gt;
  if force &amp;lt; 0&lt;br /&gt;
    force = 0&lt;br /&gt;
  end&lt;br /&gt;
  if @currentForce == force&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @currentForce = force&lt;br /&gt;
  emit forceChanged(@currentForce)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;setForce()&amp;lt;/tt&amp;gt;'''-toteutus on aika samanlainen kuin '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;'''. Ainoa erilaisuus on, että koska emme näytä voima-arvoa, käyttöliittymäkomponenttia ei tarvitse piirtää uudelleen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::blue))&lt;br /&gt;
&lt;br /&gt;
  painter.translate(0, height())&lt;br /&gt;
  painter.drawPie(Qt::Rect.new(-35, -35, 70, 70), 0, 90 * 16)&lt;br /&gt;
  painter.rotate(-@currentAngle)&lt;br /&gt;
  painter.drawRect(Qt::Rect.new(30, -5, 20, 10))&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Piirrämme kuin kappaleessa 9.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def cannonRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 50, 50)&lt;br /&gt;
  result.moveBottomLeft(rect().bottomLeft())&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktio '''&amp;lt;tt&amp;gt;cannonRect()&amp;lt;/tt&amp;gt;''' palauttaa nelikulmion, joka sisältää kanuunan sisältävän käyttöliittymäkomponentin. Luomme aluksi nelikulmion, jonka koko on 50 x 50 ja siirrämme sen niin, että sen vasen alakulma on sama kuin käyttöliittymäkomponentin vasen alakulma.&lt;br /&gt;
&lt;br /&gt;
Funktio [http://doc.qt.nokia.com/latest/qwidget.html#rect-prop Qt::Widget::rect()] palauttaa käyttöliittymän sisältämän nelikulmion käyttöliittymän omina koordinaatteina. Nelikulmion vasen yläkulma on aina (0, 0).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/t10.rb t10.rb]'''&lt;br /&gt;
&lt;br /&gt;
Konstruktori on enimmäkseen sama, mutta joitakin uusia bittejä on lisätty.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
force = LCDRange.new()&lt;br /&gt;
force.setRange(10, 50)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lisäämme toisen '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;'''-komponentin, jota käytetään voiman asettamiseen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(force, SIGNAL('valueChanged(int)'),&lt;br /&gt;
         cannonField, SLOT('setForce(int)'))&lt;br /&gt;
connect(cannonField, SIGNAL('forceChanged(int)'),&lt;br /&gt;
         force, SLOT('setValue(int)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Yhdistämme käyttöliittymäkomponentin '''&amp;lt;tt&amp;gt;force&amp;lt;/tt&amp;gt;''' ja käyttöliittymäkomponentin '''&amp;lt;tt&amp;gt;cannonField&amp;lt;/tt&amp;gt;''', aivan kuin teimme käyttöliittymäkomponentille '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kappaleessa 9 sijoitamme '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;'''-komponentin asettelun vasemman alakulman soluun. Nyt haluamme siihen soluun kaksi käyttöliittymäkomponenttial, joten teemme pystysuoran ruudun, laitamme pystysuoran ruudun rasterinsoluunl, ja laitamme sekä '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;''' että '''&amp;lt;tt&amp;gt;range&amp;lt;/tt&amp;gt;''' pystysuoraan ruutuun.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
force.setValue(25)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alustamme voima-arvoksi 25.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
Meillä on nyt voimaohjaus.&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
Tee kanuuna piipun koko riippuvaiseksi voimasta.&lt;br /&gt;
&lt;br /&gt;
Laita kanuuna oikeaan alakulmaan.&lt;br /&gt;
&lt;br /&gt;
Try adding a better keyboard interface. For example, make + and - increase and decrease the force and enter shoot. If you're bothered by the way the '''&amp;lt;tt&amp;gt;Left&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;Right&amp;lt;/tt&amp;gt;''' keys work, change that too. [Hint: Reimplement [http://doc.qt.nokia.com/latest/qwidget.html#keyPressEvent Qt::Widget::keyPressEvent()].]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/28/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/28/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/28/fi"/>
				<updated>2011-10-29T12:32:01Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Laita kanuuna oikeaan alakulmaan.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Laita kanuuna oikeaan alakulmaan.&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/fi"/>
				<updated>2011-10-29T12:31:17Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset === Tee kanuuna piipun koko riippuvaiseksi voimasta.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Sileää kuin silkki|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_09|Oppikurssi 9 - Kanuunalla onnistuu]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Annetaan sille laukaus]]&lt;br /&gt;
}}&lt;br /&gt;
== Sileää kuin silkki ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_10.png|center]]&lt;br /&gt;
Tiedostot:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/t10.rb t10.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
Tässä esimerkissä lisäämme voimaa ohjaimeen. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
Kentällä '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' on nyt voima-arvo kulman lisäksi.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
signals 'angleChanged(int)', 'forceChanged(int)'&lt;br /&gt;
slots 'setAngle(int)', 'setForce(int)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voiman rajapinta noudattaa samaa käytäntöä kuin kulma.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(parent = nil)&lt;br /&gt;
  super()&lt;br /&gt;
&lt;br /&gt;
  @currentAngle = 45&lt;br /&gt;
  @currentForce = 0&lt;br /&gt;
&lt;br /&gt;
  setPalette(Qt::Palette.new(Qt::Color.new(250, 250, 200)))&lt;br /&gt;
  setAutoFillBackground(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voima '''&amp;lt;tt&amp;gt;@currentForce&amp;lt;/tt&amp;gt;''' on alustettu nollaksi.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setAngle(angle)&lt;br /&gt;
  if angle &amp;lt; 5&lt;br /&gt;
    angle = 5&lt;br /&gt;
  elsif angle &amp;gt; 70&lt;br /&gt;
    angle = 70&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if @currentAngle == angle&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @currentAngle = angle&lt;br /&gt;
  update(cannonRect())&lt;br /&gt;
  emit angleChanged(@currentAngle)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Teimme pienen muutoksen '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;'''-funktioon. Se piirtää uudelleen käyttöliittymän osan, joka sisältää kanuunan.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setForce(force)&lt;br /&gt;
  if force &amp;lt; 0&lt;br /&gt;
    force = 0&lt;br /&gt;
  end&lt;br /&gt;
  if @currentForce == force&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @currentForce = force&lt;br /&gt;
  emit forceChanged(@currentForce)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;setForce()&amp;lt;/tt&amp;gt;'''-toteutus on aika samanlainen kuin '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;'''. Ainoa erilaisuus on, että koska emme näytä voima-arvoa, käyttöliittymäkomponenttia ei tarvitse piirtää uudelleen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::blue))&lt;br /&gt;
&lt;br /&gt;
  painter.translate(0, height())&lt;br /&gt;
  painter.drawPie(Qt::Rect.new(-35, -35, 70, 70), 0, 90 * 16)&lt;br /&gt;
  painter.rotate(-@currentAngle)&lt;br /&gt;
  painter.drawRect(Qt::Rect.new(30, -5, 20, 10))&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Piirrämme kuin kappaleessa 9.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def cannonRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 50, 50)&lt;br /&gt;
  result.moveBottomLeft(rect().bottomLeft())&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktio '''&amp;lt;tt&amp;gt;cannonRect()&amp;lt;/tt&amp;gt;''' palauttaa nelikulmion, joka sisältää kanuunan sisältävän käyttöliittymäkomponentin. Luomme aluksi nelikulmion, jonka koko on 50 x 50 ja siirrämme sen niin, että sen vasen alakulma on sama kuin käyttöliittymäkomponentin vasen alakulma.&lt;br /&gt;
&lt;br /&gt;
Funktio [http://doc.qt.nokia.com/latest/qwidget.html#rect-prop Qt::Widget::rect()] palauttaa käyttöliittymän sisältämän nelikulmion käyttöliittymän omina koordinaatteina. Nelikulmion vasen yläkulma on aina (0, 0).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/t10.rb t10.rb]'''&lt;br /&gt;
&lt;br /&gt;
Konstruktori on enimmäkseen sama, mutta joitakin uusia bittejä on lisätty.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
force = LCDRange.new()&lt;br /&gt;
force.setRange(10, 50)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lisäämme toisen '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;'''-komponentin, jota käytetään voiman asettamiseen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(force, SIGNAL('valueChanged(int)'),&lt;br /&gt;
         cannonField, SLOT('setForce(int)'))&lt;br /&gt;
connect(cannonField, SIGNAL('forceChanged(int)'),&lt;br /&gt;
         force, SLOT('setValue(int)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Yhdistämme käyttöliittymäkomponentin '''&amp;lt;tt&amp;gt;force&amp;lt;/tt&amp;gt;''' ja käyttöliittymäkomponentin '''&amp;lt;tt&amp;gt;cannonField&amp;lt;/tt&amp;gt;''', aivan kuin teimme käyttöliittymäkomponentille '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kappaleessa 9 sijoitamme '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;'''-komponentin asettelun vasemman alakulman soluun. Nyt haluamme siihen soluun kaksi käyttöliittymäkomponenttial, joten teemme pystysuoran ruudun, laitamme pystysuoran ruudun rasterinsoluunl, ja laitamme sekä '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;''' että '''&amp;lt;tt&amp;gt;range&amp;lt;/tt&amp;gt;''' pystysuoraan ruutuun.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
force.setValue(25)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alustamme voima-arvoksi 25.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
Meillä on nyt voimaohjaus.&lt;br /&gt;
&lt;br /&gt;
=== Harjoitukset ===&lt;br /&gt;
Tee kanuuna piipun koko riippuvaiseksi voimasta.&lt;br /&gt;
&lt;br /&gt;
Put the cannon in the bottom-right corner.&lt;br /&gt;
&lt;br /&gt;
Try adding a better keyboard interface. For example, make + and - increase and decrease the force and enter shoot. If you're bothered by the way the '''&amp;lt;tt&amp;gt;Left&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;Right&amp;lt;/tt&amp;gt;''' keys work, change that too. [Hint: Reimplement [http://doc.qt.nokia.com/latest/qwidget.html#keyPressEvent Qt::Widget::keyPressEvent()].]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/27/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/27/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/27/fi"/>
				<updated>2011-10-29T12:31:16Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Harjoitukset === Tee kanuuna piipun koko riippuvaiseksi voimasta.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Harjoitukset ===&lt;br /&gt;
Tee kanuuna piipun koko riippuvaiseksi voimasta.&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/26/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/26/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/26/fi"/>
				<updated>2011-10-29T12:29:52Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Meillä on nyt voimaohjaus.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Meillä on nyt voimaohjaus.&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/fi</id>
		<title>Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/fi"/>
				<updated>2011-10-29T12:29:52Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;Meillä on nyt voimaohjaus.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;languages /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10}}&lt;br /&gt;
&lt;br /&gt;
{{TutorialBrowser|&lt;br /&gt;
series=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby -oppikurssi]]|&lt;br /&gt;
name=Sileää kuin silkki|&lt;br /&gt;
pre=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_09|Oppikurssi 9 - Kanuunalla onnistuu]]|&lt;br /&gt;
next=[[Special:myLanguage/Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_11|Oppikurssi 11 - Annetaan sille laukaus]]&lt;br /&gt;
}}&lt;br /&gt;
== Sileää kuin silkki ==&lt;br /&gt;
[[Image:Qt4_Ruby_Tutorial_Screenshot_10.png|center]]&lt;br /&gt;
Tiedostot:&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/lcdrange.rb lcdrange.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/t10.rb t10.rb]&lt;br /&gt;
* [http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/cannon.rb cannon.rb]&lt;br /&gt;
&lt;br /&gt;
=== Yleiskuva ===&lt;br /&gt;
&lt;br /&gt;
Tässä esimerkissä lisäämme voimaa ohjaimeen. &lt;br /&gt;
&lt;br /&gt;
=== Läpikäynti rivi riviltä ===&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/cannon.rb cannon.rb]'''&lt;br /&gt;
&lt;br /&gt;
Kentällä '''&amp;lt;tt&amp;gt;CannonField&amp;lt;/tt&amp;gt;''' on nyt voima-arvo kulman lisäksi.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
signals 'angleChanged(int)', 'forceChanged(int)'&lt;br /&gt;
slots 'setAngle(int)', 'setForce(int)'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voiman rajapinta noudattaa samaa käytäntöä kuin kulma.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def initialize(parent = nil)&lt;br /&gt;
  super()&lt;br /&gt;
&lt;br /&gt;
  @currentAngle = 45&lt;br /&gt;
  @currentForce = 0&lt;br /&gt;
&lt;br /&gt;
  setPalette(Qt::Palette.new(Qt::Color.new(250, 250, 200)))&lt;br /&gt;
  setAutoFillBackground(true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voima '''&amp;lt;tt&amp;gt;@currentForce&amp;lt;/tt&amp;gt;''' on alustettu nollaksi.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setAngle(angle)&lt;br /&gt;
  if angle &amp;lt; 5&lt;br /&gt;
    angle = 5&lt;br /&gt;
  elsif angle &amp;gt; 70&lt;br /&gt;
    angle = 70&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  if @currentAngle == angle&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @currentAngle = angle&lt;br /&gt;
  update(cannonRect())&lt;br /&gt;
  emit angleChanged(@currentAngle)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Teimme pienen muutoksen '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;'''-funktioon. Se piirtää uudelleen käyttöliittymän osan, joka sisältää kanuunan.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def setForce(force)&lt;br /&gt;
  if force &amp;lt; 0&lt;br /&gt;
    force = 0&lt;br /&gt;
  end&lt;br /&gt;
  if @currentForce == force&lt;br /&gt;
    return&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  @currentForce = force&lt;br /&gt;
  emit forceChanged(@currentForce)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''&amp;lt;tt&amp;gt;setForce()&amp;lt;/tt&amp;gt;'''-toteutus on aika samanlainen kuin '''&amp;lt;tt&amp;gt;setAngle()&amp;lt;/tt&amp;gt;'''. Ainoa erilaisuus on, että koska emme näytä voima-arvoa, käyttöliittymäkomponenttia ei tarvitse piirtää uudelleen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def paintEvent(event)&lt;br /&gt;
  painter = Qt::Painter.new(self)&lt;br /&gt;
&lt;br /&gt;
  painter.setPen(Qt::NoPen)&lt;br /&gt;
  painter.setBrush(Qt::Brush.new(Qt::blue))&lt;br /&gt;
&lt;br /&gt;
  painter.translate(0, height())&lt;br /&gt;
  painter.drawPie(Qt::Rect.new(-35, -35, 70, 70), 0, 90 * 16)&lt;br /&gt;
  painter.rotate(-@currentAngle)&lt;br /&gt;
  painter.drawRect(Qt::Rect.new(30, -5, 20, 10))&lt;br /&gt;
  painter.end()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Piirrämme kuin kappaleessa 9.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
def cannonRect()&lt;br /&gt;
  result = Qt::Rect.new(0, 0, 50, 50)&lt;br /&gt;
  result.moveBottomLeft(rect().bottomLeft())&lt;br /&gt;
  return result&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktio '''&amp;lt;tt&amp;gt;cannonRect()&amp;lt;/tt&amp;gt;''' palauttaa nelikulmion, joka sisältää kanuunan sisältävän käyttöliittymäkomponentin. Luomme aluksi nelikulmion, jonka koko on 50 x 50 ja siirrämme sen niin, että sen vasen alakulma on sama kuin käyttöliittymäkomponentin vasen alakulma.&lt;br /&gt;
&lt;br /&gt;
Funktio [http://doc.qt.nokia.com/latest/qwidget.html#rect-prop Qt::Widget::rect()] palauttaa käyttöliittymän sisältämän nelikulmion käyttöliittymän omina koordinaatteina. Nelikulmion vasen yläkulma on aina (0, 0).&lt;br /&gt;
&lt;br /&gt;
'''[http://www.darshancomputing.com/qt4-qtruby-tutorial/tutorial/t10/t10.rb t10.rb]'''&lt;br /&gt;
&lt;br /&gt;
Konstruktori on enimmäkseen sama, mutta joitakin uusia bittejä on lisätty.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
force = LCDRange.new()&lt;br /&gt;
force.setRange(10, 50)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lisäämme toisen '''&amp;lt;tt&amp;gt;LCDRange&amp;lt;/tt&amp;gt;'''-komponentin, jota käytetään voiman asettamiseen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
connect(force, SIGNAL('valueChanged(int)'),&lt;br /&gt;
         cannonField, SLOT('setForce(int)'))&lt;br /&gt;
connect(cannonField, SIGNAL('forceChanged(int)'),&lt;br /&gt;
         force, SLOT('setValue(int)'))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Yhdistämme käyttöliittymäkomponentin '''&amp;lt;tt&amp;gt;force&amp;lt;/tt&amp;gt;''' ja käyttöliittymäkomponentin '''&amp;lt;tt&amp;gt;cannonField&amp;lt;/tt&amp;gt;''', aivan kuin teimme käyttöliittymäkomponentille '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
leftLayout = Qt::VBoxLayout.new()&lt;br /&gt;
leftLayout.addWidget(angle)&lt;br /&gt;
leftLayout.addWidget(force)&lt;br /&gt;
&lt;br /&gt;
gridLayout = Qt::GridLayout.new()&lt;br /&gt;
gridLayout.addWidget(quit, 0, 0)&lt;br /&gt;
gridLayout.addLayout(leftLayout, 1, 0)&lt;br /&gt;
gridLayout.addWidget(cannonField, 1, 1, 2, 1)&lt;br /&gt;
gridLayout.setColumnStretch(1, 10)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kappaleessa 9 sijoitamme '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;'''-komponentin asettelun vasemman alakulman soluun. Nyt haluamme siihen soluun kaksi käyttöliittymäkomponenttial, joten teemme pystysuoran ruudun, laitamme pystysuoran ruudun rasterinsoluunl, ja laitamme sekä '''&amp;lt;tt&amp;gt;angle&amp;lt;/tt&amp;gt;''' että '''&amp;lt;tt&amp;gt;range&amp;lt;/tt&amp;gt;''' pystysuoraan ruutuun.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ruby&amp;quot;&amp;gt;&lt;br /&gt;
force.setValue(25)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alustamme voima-arvoksi 25.&lt;br /&gt;
&lt;br /&gt;
=== Sovelluksen suorittaminen ===&lt;br /&gt;
&lt;br /&gt;
Meillä on nyt voimaohjaus.&lt;br /&gt;
&lt;br /&gt;
=== Exercises ===&lt;br /&gt;
Make the size of the cannon barrel be dependent on the force.&lt;br /&gt;
&lt;br /&gt;
Put the cannon in the bottom-right corner.&lt;br /&gt;
&lt;br /&gt;
Try adding a better keyboard interface. For example, make + and - increase and decrease the force and enter shoot. If you're bothered by the way the '''&amp;lt;tt&amp;gt;Left&amp;lt;/tt&amp;gt;''' and '''&amp;lt;tt&amp;gt;Right&amp;lt;/tt&amp;gt;''' keys work, change that too. [Hint: Reimplement [http://doc.qt.nokia.com/latest/qwidget.html#keyPressEvent Qt::Widget::keyPressEvent()].]&lt;br /&gt;
&lt;br /&gt;
[[Category:Ruby]]&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	<entry>
		<id>http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/25/fi</id>
		<title>Translations:Development/Tutorials/Qt4 Ruby Tutorial/Chapter 10/25/fi</title>
		<link rel="alternate" type="text/html" href="http://techbase.kde.org/Translations:Development/Tutorials/Qt4_Ruby_Tutorial/Chapter_10/25/fi"/>
				<updated>2011-10-29T12:23:58Z</updated>
		
		<summary type="html">&lt;p&gt;Centerlink: Created page with &amp;quot;=== Sovelluksen suorittaminen ===&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Sovelluksen suorittaminen ===&lt;/div&gt;</summary>
		<author><name>Centerlink</name></author>	</entry>

	</feed>