Sign in Join
Wiki copytemporary

Peg Solitaire tutorial/fi: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11Tämä opetusohjelma on toinen Lazarus opetusohjelma, jonka tavoitteena on ottaa käyttöön Lazaruksen sovelluskehityksen perusteet. On parasta aloittaa tämän opetusohjelman ensimmäisellä osalla: ([[Howdy World (Hello World on steroids)/fi]]). Tämä opetusohjelma selittää vähän sitä, miten työskennellä grafiikan parissa ja miten tehdään modulaarinen ohjelma. Tämän opetusohjelman lopputuotteena on yksinkertainen, mutta toimiva versio Peg Solitaire pelistä ([1](http://en.wikipedia.org/wiki/Peg_solitaire)). Jos kaikki menee hyvin niin lopulta se näyttää tältä:
22
3-<figure>
4-<img src="tutpeg_solitaire.png" title="tutpeg_solitaire.png" />
5-<figcaption>tutpeg_solitaire.png</figcaption>
6-</figure>
3+![](/wiki-images/5/5f/Tutpeg_solitaire.png)
74
85## Projektin aloitus
96
107Kuten edellisessä opetusohjelmassakin niin on parasta aloittaa puhtaalta pöydältä. Tee erillinen hakemisto(tai kansio) kutakin projektia kohti. Nopea kertaus:
118
129- Luo uusi hakemisto tähän peliin.
1310- Aloita uusi projekti (Projekti / Uusi projekti ... ja valitse Sovellus).
1411- Tallenna projekti nimellä *PegSolitaire*.
1512- Tallenna aloitusikkuna/lomake nimellä *ufrmMain*.
1613- Komponenttimuokkaimessa muuta lomakkeen nimeksi *frmMain*.
1714- Muuta Caption arvoon *Lazarus Peg Solitaire*.
1815- Valitse valikosta: Projekti / Projektikohtaiset asetukset ...
1916- Valitse Kääntäjän asetukset / Hakupolut (klikkaa solmun puunäkymää)
2017- Kirjoita teksti bin\\ ennen kohdetiedostonimeä (tai bin/ esim. unix/linux ympäristössä)
2118
2219Ja lisänä tässä projektissa:
2320
24-- Avaa projekti valintaikkunan (<span class="kbd">Shift</span>+<span class="kbd">Ctrl</span>+<span class="kbd">F11</span>).
21+- Avaa projekti valintaikkunan (`Shift`+`Ctrl`+`F11`).
2522- Valitse kääntäjän asetukset / Virheenjäljitys.
2623- Ota käyttöön ylivuoto- ja aluevirhe tarkistus (katso kuva alla).
2724
28-<figure>
29-<img src="tutpeg_compiler_options.png" title="tutpeg_compiler_options.png" />
30-<figcaption>tutpeg_compiler_options.png</figcaption>
31-</figure>
25+![](/wiki-images/1/10/Tutpeg_compiler_options.png)
3226
3327## Ensiaskeleet
3428
3529On aina hyvä idea erottaa käyttöliittymään liittyvä koodi muusta esim. tietorakennetta määritelevästä koodista. Joten ensimmäinen askel on tehdä erillinen käännösyksikkö Solitaire tietorakenteita varten.
3630
3731- Valitse valikosta *Tiedosto / Uusi käännösyksikkö*.
3832- Tallenna käännösyksikkö nimellä *PegDatastructures.pas*
3933
4034Peruselementit PegSolitaire laudalla ovat marmorit, levyn rakenne ja tyhjät paikat. Simuloidaan yksinkertaisella matriisilla, jossa paikat ovat pelin solujen tyyppisiä (tyhjä, pelinappula ja ei pääse). Ja tämä kaikki kiteytetään luokkaan, joka käsittelee kaikkea tietojen manipulointia.
4135
4236- Lisää seuraava koodi PegDatastructures käännösyksikköön ( *[[Uses/fi|uses]]*-lausekkeen jälkeen juuri ennen *[[Implementation/fi|implementation]]* osiota):
4337
4438``` pascal
4539const
4640 C_MAX = 7; // Max board size: 7x7
4741
4842type
4943 TCellNums = 1..C_MAX;
5044 TCellType = (ctNoAccess, ctEmpty, ctPeg);
5145 TPegCells = array[TCellNums, TCellNums] of TCellType;
5246
5347 TPegSolitaire = class
5448 private
5549 Size: TCellNums;
5650 PegCells: TPegCells;
5751
5852 public
5953 constructor Create(const pSize: TCellNums);
6054 end;
6155```
6256
6357On kohtuullista olettaa, että muu koodi, joka aikoo käyttää tätä luokkaa tarvitsee pääsyn solujen sisältöön (eli PegCells). Tapa käsitellä tätä on joko määrittelemällä joukko funktioita jotka hakee ja vie soluihin tai määritellä ns taulukko-ominaisuus. Valitaan jälkimmäinen lähestymistapa ja lisätään seuraava rivi TPegSolitaire luokan public osioon:
6458
6559``` pascal
6660property Cell[const pRow, pCol: TCellNums]: TCellType;
6761```
6862
6963- Sijoita tekstikursori rakentajan eli constructor:n riville.
70-- Paina <span class="kbd">Ctrl</span>+<span class="kbd">Shift</span>+<span class="kbd">C</span>: ohjelman kehitysympäristö luo rakentajan rungon (kuten aiemmissa esimerkeissä), mutta se myös luo tyhjän rungon kahdelle metodille, jotka antavat pääsyn *Cell*-ominaisuuden kautta *PegCells* taulukkoon.
64+- Paina `Ctrl`+`Shift`+`C`: ohjelman kehitysympäristö luo rakentajan rungon (kuten aiemmissa esimerkeissä), mutta se myös luo tyhjän rungon kahdelle metodille, jotka antavat pääsyn *Cell*-ominaisuuden kautta *PegCells* taulukkoon.
7165- Funktio GetCell noutaa tiedot PegCells taulukosta. Lisää seuraava koodi tähän funktioon:
7266
7367``` pascal
7468 result := PegCells[pRow,pCol];
7569```
7670
7771- Aliohjelma SetCell sijoittaa dataa PegCells taulukkoon. Lisää seuraava koodi tähän aliohjelmaan:
7872
7973``` pascal
8074 PegCells[pRow,pCol] := AValue;
8175```
8276
8377- Ja viimeistellä rakentaja Create. Lisää tämä koodi sen runkoon:
8478
8579``` pascal
8680var iRow,iCol: integer;
8781begin
8882 // Store the size of the board locally
8983 Size := pSize;
9084
9185 // Initialize all cells to 'not accessible'
9286 for iRow := 1 to C_MAX do
9387 for iCol := 1 to C_MAX do
9488 Cell[iRow,iCol] := ctNoAccess;
9589```
9690
9791Nyt kun rakenteen perustiedot ovat paikallaan, on aika tarkastella mitä grafiikka tarvitsee. On monia tapoja näyttää solitaire pöytä. Tähän voidaan käyttää [[TPaintbox]]- komponenttia. Se antaa täydellisen määräysvallan graafisiin ominaisuuksiin.
9892
9993Ohjelman ikkunalomake aikoo käyttää datarakennetta joka on määritelty PegDatastructure käännösyksikköön.
10094
10195- Siirry lähdekoodieditorissa ufrmmain-käännösyksikköön.
10296- Lisää PegDatastructures sen uses luetteloon joka on tiedoston yläosassa:
10397
10498``` pascal
10599uses
106100 PegDatastructures,
107101 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs;
108102```
109103
110-- Paina <span class="kbd">F12</span> (tämä tuo esiin lomakkeen).
104+- Paina `F12` (tämä tuo esiin lomakkeen).
111105- Komponenttipaletin [[Standard tab/fi|Standard]]-välilehdeltä valitaan [[TButton/fi|TButton]] ja pudota se lomakkeelle vasempaan yläkulmaan.
112106- Vaihda sen Caption ominaisuuten teksti *Test paint*.
113107- Komponenttipaletin [[Additional tab/fi|Additional]]-välilehdeltä valitaan TPaintbox-komponentti ja tuodaan se lomakkeelle.
114108- Muuta sen Align arvoon *alRight*.
115109- Muuta BordSpacing.Around arvoon *4*.
116110- Muuta Anchors.akLeft arvoon *true*.
117111- Kirjoita Name-ominaisuuteen teksti: *pbPeg*.
118112- Muuta lomakkeen kokoa, jotta se näyttää suunnilleen tältä:
119113
120-<figure>
121-<img src="tutpeg_empty.png" title="tutpeg_empty.png" />
122-<figcaption>tutpeg_empty.png</figcaption>
123-</figure>
114+![](/wiki-images/0/0d/Tutpeg_empty.png)
124115
125116Seuraava vaihe on kiinnittää solujen matriisi tähän TPaintbox-komponenttiin jakamalla se riveihin ja sarakkeisiin, jotka sisältävät levyn jokaisen solun. Jotta se olisi skaalautuva niin lasketaan leveys ja korkeus itsenäisesti. Tarvitaan pari muuttujaa pitämään tulosta. Ensin solujen leveys ja korkeus, jotta kaikki solut (7) sopivat täsmälleen lomakkeelle. Kehitetään piirtokoodi interaktiivisesti. Tähän käyttää painiketta, joka tuotiin lomakkeelle.
126117
127118- Tuplaklikkaa *Test paint*-painiketta (tämä luo tapahtumakäsittelijän).
128119- Lisää kaksi muuttujaa:
129120
130121``` pascal
131122var
132123 CellWidth : integer;
133124 CellHeight: integer;
134125```
135126
136127Tarvitaan ylimääräisiä muuttujia pitämään välituloksia:
137128
138129- Lisää kolme paikallista muuttujaa:
139130
140131``` pascal
141132 iRow, iCol: TCellNums;
142133 CellArea : TRect;
143134```
144135
145136CellArea käytetään rajoittamaan suorakulmaista aluetta näytöllä, johon solu piirretään.
146137
147138Jotta käsittellään kaikki rivit ja sarakkeet niin tehdään se kahdella suoraviivaisella [[For/fi|for]]-silmukalla.
148139
149140- Lisää seuraava koodi tapahtumankäsittelijään:
150141
151142``` pascal
152143
153144// Calculate the width/height of each cell to accomodate for all cells in the paintbox
154145 CellWidth := pbPeg.Width div 7;
155146 CellHeight := pbPeg.Height div 7;
156147
157148 // Draw boxes for all cells
158149 for iRow := 1 to 7 do
159150 for iCol := 1 to 7 do
160151 begin
161152 // Calculate the position of the cell in the paintbox
162153 CellArea.Top := (iRow-1) * CellHeight;
163154 CellArea.Left := (iCol-1) * CellWidth;
164155 CellArea.Right := CellArea.Left + CellWidth;
165156 CellArea.Bottom := CellArea.Top + CellHeight;
166157 // And now draw the cell
167158 pbPeg.Canvas.Rectangle(CellArea);
168159 end;
169160```
170161
171162Canvas on nimensä mukaisesti on ohjaus, joka auttaa meitä piirtämään asioita, kuten viivoja, suorakaiteita, ympyröitä jne. TPaintbox-komponentti sisältää Canvas:n. Siksi rivillä pbPeg.Canvas.Rectangle (CellArea) ohjelma piirtää suorakulmion paintbox, rajattu alue on määritelty CellArea. Ja koska paintbox sijoitetaan lomakkeelle, voimme nähdä tuloksen siellä.
172163
173-- Kääntää ja ajaa ohjelma (paina <span class="kbd">F9</span>).
164+- Kääntää ja ajaa ohjelma (paina `F9`).
174165- Paina *Test paint*-painiketta.
175166- Suurenna lomaketta (solut häviävät mutta älä huoli se korjatuu).
176167- Paina *Test paint*-painiketta uudelleen
177168
178169Tämä todistaa, että laskelmat olivat paikallaan ja että on nyt keino tehdä kaikki tarpeellisen oikealla paikalla. Yksi asia on tehtävä kuitenkin ennen lisäämällä piirustus toiminnallisuutta. Piirustus solujen ei mitenkään tärkein muodossa tai toisessa (tai minkäänlaista että asia). Ainoa asia, meidän piirtämiseen asiat on Canvas ja joitakin mittauksia soluille. Joten aiomme luoda tukea luokan siivota tärkeimmäksi.
179170
180171- Luo uusi käännösyksikkö (Tiedosto / Uusi käännösyksikkö).
181172- Tallenna se nimellä PegSolPainter.pas (Tiedosto / Tallenna nimellä ...).
182173- Lisää uusi luokka tähän käännösyksikköön, se tekee kaiken piirtämisen (luokka tulee uses-lauseen jälkeen, ennen
183174
184175implementation osiota).
185176
186177``` pascal
187178type
188179 TPegSolPainter = class
189180 private
190181 PegSol : TPegSolitaire;
191182 Canvas : TCanvas;
192183 public
193184 constructor Create(pPegSol: TPegSolitaire; pCanvas: TCanvas);
194185 end;
195186```
196187
197188Huomaa, että TPegSolitaire muuttuja lisätään myös, koska käyttää tätä luokkaa käytetään noutamaan solujen tila.
198189
199-- Sijoita tekstikursorin rakentajan eli constructor:n riville ja paina <span class="kbd">Ctrl</span>+<span class="kbd">Shift</span>+<span class="kbd">C</span>.
190+- Sijoita tekstikursorin rakentajan eli constructor:n riville ja paina `Ctrl`+`Shift`+`C`.
200191- Rakentajan kaksi alustus parametriä on sijoitettava luokan private muuttujiin (Täydennä luokan rakentajaa siten että se näyttää tältä) :
201192
202193``` pascal
203194constructor TPegSolPainter.Create(pPegSol: TPegSolitaire; pCanvas: TCanvas);
204195begin
205196 PegSol := pPegSol;
206197 Canvas := pCanvas;
207198end;
208199```
209200
210201Yritettäessä kääntää koodia niin tulee virheilmoitus koska ei olla lisätty PegDatastrucures käännösyksikköä uses-lauseseen. Ja koska käytetään myös TCanvas-luokkaa niin täytyy lisätä Graphics käännösyksikkö samoin.
211202
212203- Lisää *PegDatastructures* ja *Graphics* *uses* lauseen luetteloon.
213204
214205``` pascal
215206uses
216207 PegDatastructures,
217208 Graphics,
218209 Classes, SysUtils;
219210```
220211
221212Syy tämän luokan rakentamiseen oli poistaa kaikki piirtäminen koodilla lomakkeella. Joten on luotava menetelmä, joka tekee piirtämisen. Ennen lisäystä että menetelmä on jotain, johon on puututtava: laskea leveys solun, jaamme paintbox leveyttä useissa solujen. Teoriassa voisimme käyttää ominaisuutta Canvas.Width tähän. Kuitenkin tämä ominaisuus ei aina anna oikeata leveyttä oikeaan aikaan. Joten piirrettäesä soluja täytyy tarjota piirtää menetelmälle oikeat Canvas arvot leveydelle ja korkeudelle.
222213
223214Nyt tiedetään tämä, voidaan lisätä piirustusmetodi luokkaan.
224215
225216- Lisää aliohjelma Repaint luokkaan (jolloin luokka määrittely näyttää tältä).
226217
227218``` pascal
228219
229220TPegSolPainter = class
230221 private
231222 PegSol : TPegSolitaire;
232223 Canvas : TCanvas;
233224
234225 public
235226 constructor Create(pPegSol: TPegSolitaire; pCanvas: TCanvas);
236227 procedure Repaint(const pCanvasWidth, pCanvasHeight: integer);
237228 end;
238229</sourcet>
239-* Luo aliohjelman Repaint runko. Paina <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>C</kbd>.
230+* Luo aliohjelman Repaint runko. Paina <code>Ctrl</code>+<code>Shift</code>+<code>C</code>.
240231* Kopio koodi ''TfrmMain.Button1Click(Sender: TObject)''-aliohjelmasta tähän runkoon (Jolloin siitä tulee tälläinen)
241232<syntaxhighlight lang="pascal">
242233procedure TPegSolPainter.Repaint(const pCanvasWidth, pCanvasHeight: integer);
243234var
244235 CellWidth : integer;
245236 CellHeight : integer;
246237 iRow, iCol : TCellNums;
247238 CellArea : TRect;
248239begin
249240 // Calculate the width of each cell to accomodate for all cells
250241 CellWidth := pbPeg.Width div 7;
251242 CellHeight := pbPeg.Height div 7;
252243
253244 // Draw boxes for all cells
254245 for iRow := 1 to 7 do
255246 for iCol := 1 to 7 do
256247 begin
257248 // Calculate the position of the cell in the paintbox
258249 CellArea.Top := (iRow-1) * CellHeight;
259250 CellArea.Left := (iCol-1) * CellWidth;
260251 CellArea.Right := CellArea.Left + CellWidth;
261252 CellArea.Bottom := CellArea.Top + CellHeight;
262253 // And now draw the cell
263254 pbPeg.Canvas.Rectangle(CellArea);
264255 end;
265256end;
266257```
267258
268259Koska ei enää tarvita TPaintbox-komponenttia pbPeg. Niin on poistettava viittaukset siihen. Joten kolmessa kohdassa tarvitaan muutoksia:
269260
270261- Muutos CellWidth:n ja CellHeight:n laskennassa:
271262
272263``` pascal
273264 CellWidth := pCanvasWidth div 7;
274265 CellHeight := pCanvasHeight div 7;
275266```
276267
277268- Muutos suorakulmion piirtämisessä:
278269
279270``` pascal
280271 Canvas.Rectangle(CellArea);
281272```
282273
283274Nyt on luokka, jolla voidaan tehdä haluttu piirtäminen, on aika käyttää sitä. Tätä piirtoluokkaa käytetään yhdessä PegSolitare luokan kanssa solujen piirtämiseen.
284275
285276- Käännösyksikössä *ufrmmain.pas*, etsi Button1Click aliohjelma.
286277- Poista siitä kaikki lausekkeet ja muuttujat (Tyhjennä se).
287278- Lisätään kaksi uutta muuttujaa: peliluokan ja piirtämisluokan (Kaikkien näiden toimien tuloksena aliohjelma nyt näyttää tältä):
288279
289280``` pascal
290281procedure TfrmMain.Button1Click(Sender: TObject);
291282var
292283 pegsol : TPegSolitaire; // The game data
293284 pegpaint: TPegSolPainter; // The paint class for the game
294285begin
295286end;
296287```
297288
298289- Lisää *PegSolPainter* uses-lauseen luetteloon.
299290
300291Piirtoluokan käyttö on yksinkertaista: Luodaan uusi esiintymä ja kutsutaan piirto aliohjelmaa:
301292
302293- Lisää seuraava koodi Button1Click aliohjelmaan:
303294
304295``` pascal
305296
306297 // Create a new game object
307298 pegsol := TPegSolitaire.Create(7);
308299
309300 // Create a new painter object to paint this game
310301 pegpaint := TPegSolPainter.Create(pegsol, pbPeg.Canvas);
311302
312303 // And paint the board
313304 pegpaint.Repaint(pbPeg.Width, pbPeg.Height);
314305
315306 // Clean up
316307 pegpaint.Free;
317308 pegsol.Free
318309```
319310
320311Suorita ja testta ohjelma. Nähdään että se toimii samaan tapaan kuin ennen. Tulos näyttää tältä: ![](/wiki-images/2/2b/Tutpeg_empty_cells.png)
321312
322313## Kyse tapahtumista
323314
324315Mitä on saatu aikaan tähän mennessä? On tietorakenne, joka sisältää kaikki tiedot PegSolitaire peliä varten. On luokka, johon voi piirtää. Ja on melko yksinkertainen lomake, jossa on testipainike. Joten mitä seuraavaksi? Tapahtumat!
325316
326317Kuten edellisessä osassa on nähty, solun matriisi joka tehtiin hävisi jos lomakkeen kokoa muutettiin. Näin tapahtuu, koska lomake ei tiedä mitään "pikku pelistä". Heti kun lomakkeen mielestä on aika piirtää itse, se tekee niin ja ohittaa "pikku pelin". Mitä se tekee? Se vain lähettää viestin lapsi kontrolleille, että virkistäminen on välttämätön. Tämä viesti on käytettävissämme tapahtumana: OnPaint-tapahtuma.
327318
328-- Mene lomakkeelle (Valitse ufrmMain lähdekoodieditorissa ja paina <span class="kbd">F12</span>).
319+- Mene lomakkeelle (Valitse ufrmMain lähdekoodieditorissa ja paina `F12`).
329320- Valitse TPaintbox pbPeg.
330321- Siirry *tapahtumat*-välilehdelle komponenttimuokkaimessa.
331322- Yksi luetelluista tapahtumista on OnPaint.
332323
333-<figure>
334-<img src="tutpeg_onpaint.png" title="tutpeg_onpaint.png" />
335-<figcaption>tutpeg_onpaint.png</figcaption>
336-</figure>
324+![](/wiki-images/3/3a/Tutpeg_onpaint.png)
337325
338326Tätä tapahtumaa kutsutaan joka kerta kun TPaintbox tarvitsee uudelleenpiirtämistä. Se on paikka johon tehdään piirtäminen.
339327
340328- Valitse OnPaint tapahtuma komponenttimuokkaimessa ja klikkaa pientä (...) painiketta kolmella pisteellä . Tämä luo tapahtumakäsittelijän rungon.
341329- Kopioi / Liitä tarkka koodi *Button1Click* tapahtumakäsittelystä tähän uuteen aliohjelmaan.
342330
343331``` pascal
344332procedure TfrmMain.pbPegPaint(Sender: TObject);
345333var
346334 pegsol : TPegSolitaire; // The game data
347335 pegpaint: TPegSolPainter; // The paint class for the game
348336begin
349337 // Create a new game object
350338 pegsol := TPegSolitaire.Create(7);
351339
352340 // Create a new painter object to paint this game
353341 pegpaint := TPegSolPainter.Create(pegsol, pbPeg.Canvas);
354342
355343 // And paint the board
356344 pegpaint.Repaint(pbPeg.Width, pbPeg.Height);
357345
358346 // Clean up
359347 pegpaint.Free;
360348 pegsol.Free
361349end;
362350```
363351
364352- Poista kaikki koodi ja muuttujat aliohjelmasta Button1Click. Muista: Ohjelmankehitysympäristö automaattisesti poistaa tämän tyhjän aliohjelman.
365353- Poista *Test paint* -painike lomakkeelta.
366354- Suorita ohjelma, katso mitä tapahtuu.
367355
368356Nyt on selvää, että me luoda pelin objekti OnPaint menetelmässä, piirretään tyhjät solut ja sitten tuhota se. Mutta täytyy tallentaa peliolio kunnes peli on päättynyt. Sama koskee piirtämisoliota. Joten OnPaint tapahtuma ei ole loogisin paikka luoda näitä olioita. Lomakkeen luokan määrittely on parempi paikka tallentaa ne.
369357
370358- Siirry lomakkeen määrittelyyn.
371359- Lisää kaksi muuttujaa jotka luotiin OnPaint tapahtumaan:
372360
373361``` pascal
374362 TfrmMain = class(TForm)
375363 pbPeg: TPaintBox;
376364 procedure pbPegPaint(Sender: TObject);
377365 private
378366 { private declarations }
379367 pegsol : TPegSolitaire; // The game data
380368 pegpaint: TPegSolPainter; // The paint class for the game
381369 public
382370 { public declarations }
383371 end;
384372```
385373
386374Nämä muuttujat pitää alustaa heti, kun lomake avataan (tai kun halutaan aloittaa uusi peli). Joten luodaan aliohjelma, joka tekee sen meille ja lisätään se private-osioon lomakkeelle.
387375
388376- Lisää aliohjelma StartNewGame lomakkeelle.
389377
390378``` pascal
391379
392380 private
393381 { private declarations }
394382 pegsol : TPegSolitaire; // The game data
395383 pegpaint: TPegSolPainter; // The paint class for the game
396384
397385 procedure StartNewGame;
398386```
399387
400-- Luo aliohjelman runko. Paina <span class="kbd">Ctrl</span>+<span class="kbd">Shift</span>+<span class="kbd">C</span>.
388+- Luo aliohjelman runko. Paina `Ctrl`+`Shift`+`C`.
401389- Lisää alustus koodi:
402390
403391``` pascal
404392procedure TfrmMain.StartNewGame;
405393begin
406394 // Clean up the previous game
407395 pegpaint.Free;
408396 pegsol.Free;
409397
410398 // Start with a new game
411399 pegsol := TPegSolitaire.Create(7);
412400 pegpaint := TPegSolPainter.Create(pegsol, pbPeg.Canvas);
413401end;
414402```
415403
416404Nyt kun alustuksen koodi on luotu, se on suoritettava. Looginen aika tehdä tämä on, kun lomake on luodaan (eli sovellus käynnistetään). Tähän toiseen tapahtumaan pääse kiinni: FormCreate-tapahtumassa. Se voidaan luoda kahdella eri tavalla: Komponenttimuokkaimessa löytää OnFormCreate tapahtuma ja klikata "..." -painiketta. Toinen tapa tuottaa se on tuplaklikata lomaketta.
417405
418-- Mene lomakkeelle (Lähdekoodieditorissa paina <span class="kbd">F12</span>).
406+- Mene lomakkeelle (Lähdekoodieditorissa paina `F12`).
419407- Tuplaklikkaa jossain vapaata aluetta. Älä klikkaa TPaintbox:a.
420408
421-<figure>
422-<img src="tutpeg_form_create.png" title="tutpeg_form_create.png" />
423-<figcaption>tutpeg_form_create.png</figcaption>
424-</figure>
409+![](/wiki-images/4/4a/Tutpeg_form_create.png)
425410
426411- Lisää sen runkoon aliohjelman StartNewGame kutsu:
427412
428413``` pascal
429414procedure TfrmMain.FormCreate(Sender: TObject);
430415begin
431416 StartNewGame;
432417end;
433418```
434419
435420Nyt kun peli- ja piirto-oliot luodaan ohjelman alkaessa niitä ei enää tarvita OnPaint aliohjelmassa.
436421
437422- Paikallista aliohjelma procedure TfrmMain.pbPegPaint (Sender: TObject);
438423- Poista paikalliset muuttujat ja kaikki koodi paitsi rivin joka tekee piirtämisen. (jolloin se on näin yksinkertainen)
439424
440425``` pascal
441426procedure TfrmMain.pbPegPaint(Sender: TObject);
442427begin
443428 // Paint the board
444429 pegpaint.Repaint(pbPeg.Width, pbPeg.Height);
445430end;
446431```
447432
448433- Suorita ohjelma ja katso mitä tapahtuu.
449434
450435## Intermezzo
451436
452437Tähän mennessä ollaan keskittynyt rakentamaan ohjelmaa jolla pelata klassista pasianssi peliä 7x7 ruudukossa. Onko nyt mahdollista luoda pienempi tai suurempi ruudukko esim. muun tyyppiselle pelille? Testataan tätä.
453438
454439- Mene käännösyksikköön ufrmmain.pas ja siellä aliohjelmaan StartNewGame.
455440- Muuta rivi `pegsol: = TPegSolitaire.Create (7);` riviksi `pegsol: = TPegSolitaire.Create (5);`. Joten pienempi lauta 5x5 neliöitä on luotu.
456441- Suorita ohjelma ja katso mitä tapahtuu.
457442
458443Kuten ruudulla nähdään niin vielä on 7x7 ruudukko! Tämä on seurausta kun käyttää (taika) numeroita, jota olisi voitu välttää (ks <http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Unnamed_numerical_constants> ).
459444
460445Taikanumeroiden käyttäminen on suuri katastrofi: se on asia, kun, ei jos, ohjelma epäonnistuu.
461446
462447- Avaa käännösyksikkö PegSolPainter.
463448- Paikanna aliohjelma *TPegSolPainter.Repaint(const pCanvasWidth, pCanvasHeight: integer);*.
464449
465450Siellä nähdään numero 7 muutamia kertoja. Tämä on se maaginen numero, joka tekee temppuja. Laskettaessa solun leveys ja korkeus, tarvitsemme laudalle koon joka on tallennettu pegsol pelin Size muuttujaan. Ja sama pätee iRow ja iCol silmukoihin. Joten korjataan ne kerralla:
466451
467452``` pascal
468453
469454// Calculate the width of each cell to accomodate for all cells
470455 CellWidth := pCanvasWidth div pegsol.Size;
471456 CellHeight := pCanvasHeight div pegsol.Size;
472457
473458 // Draw boxes for all cells
474459 for iRow := 1 to pegsol.Size do
475460 for iCol := 1 to pegsol.Size do
476461 begin
477462 // Calculate the position of the cell in the paintbox
478463 CellArea.Top := (iRow-1) * CellHeight;
479464 CellArea.Left := (iCol-1) * CellWidth;
480465 CellArea.Right := CellArea.Left + CellWidth;
481466 CellArea.Bottom := CellArea.Top + CellHeight;
482467 // And now draw the cell
483468 Canvas.Rectangle(CellArea);
484469 end;
485470```
486471
487472Tässä varoitus: pegsol:ssa ei ole julkisesti saatavilla Size -muuttujaa. Ja näin se pitäisi olla: kaikki luokan muuttujat pitäisi olla yksityisiä. Tapa käyttää näitä yksityisiä arvoja on funktioiden tai ominaisuuksien (rajapinta luokan) kautta. Tähän yksinkertaiseen arvoon sovelletaan ominaisuutta.
488473
489474- Mene käännösyksikköön PegDatastructures.
490475- Uudelleen nimeä luokan TPegSolitaire yksityisen muuttujan Size uudeksi nimeksi *FSize*.
491476- Lisää julkinen vain luku ominaisuus luokkaan: property Size: TCellNums read FSize;
492477
493478Luokka nyt näyttää tältä:
494479
495480``` pascal
496481
497482TPegSolitaire = class
498483 private
499484 FSize: TCellNums;
500485 PegCells: TPegCells;
501486 function GetCell(const pRow, pCol: TCellNums): TCellType;
502487 procedure SetCell(const pRow, pCol: TCellNums; const pValue: TCellType);
503488
504489 public
505490 constructor Create(const pSize: TCellNums);
506491 property Cell[const pRow, pCol: TCellNums]: TCellType read GetCell write SetCell;
507492 property Size: TCellNums read FSize;
508493 end;
509494```
510495
511496On yleinen käytäntö käyttää muuttujien etuliitteenä kirjainta *F* joihin päästään käsiksi ominaisuuksilla. Julkinen pääsy ominaisuuteen Size on vain sen arvon lukeminen koska sitä ei pidä koskaan muuttaa kun peli käynnistetään. Ainoa paikka, jossa tämä yksityinen muuttuja pitäisi saada sen lopullinen arvon on Create rakentaja.
512497
513498- Paikallista rakentaja (constructor).
514499- Muuta rivi*Size := pSize;* riviksi *FSize := pSize;* (Jotta ei saada käännösvirhettä).
515500- Ja kun ollaan siellä niin alustusta tarvitsee vähäisen korjata. Ei tarvitse alustaa soluja joita ei aiota käyttää. Joten rakentaja tulisi näyttää tältä (*C_MAX* korvataan *Size*:lla):
516501
517502``` pascal
518503constructor TPegSolitaire.Create(const pSize: TCellNums);
519504var iRow,iCol: integer;
520505begin
521506 FSize := pSize;
522507 for iRow := 1 to Size do
523508 for iCol := 1 to Size do
524509 Cell[iRow,iCol] := ctNoAccess;
525510end;
526511```
527512
528513Olemme nyt valmis testaamaan ohjelman ja katso jos se piirtää nyt mukavan 5x5 matriisi.
529514
530515- Suorita ohjelma ja katso mitä tapahtuu (5x5 matriisi piirretään).
531516
532517Nyt kun pelin perusteet ovat paikoillaan, on aika täsmentää käyttöliittymää.
533518
534519## Ollaan taiteellisia
535520
536521Hienoa. Nyt on peli luokka, tukiluokka piirtämiseen ja ruudullinen pelilauta lomakkeella. Pasianssipelin solu voi olla kolmessa (3) tilassa: ei saatavilla, tyhjä tai käytössä. Kuhunkin solutyyppiin halutaan erilainen graafinen esitys. Tehdään nyt se.
537522
538523- Avaa lähdekoodieditorissa käännösyksikkö PegSolPainter (käännösyksikkö joka piirtää pelilaudan).
539524- Siirry Repaint aliohjelmaan.
540525- Etsi rivi, jossa solu on piirretään: *Canvas.Rectangle (CellArea);*.
541526
542527Täällä täytyy tehdä muutoksia. Se riippuu solun tilasta mitä tarvitaan piirtämiseen (ei käytettävissä oleva solu, tyhjä solu tai pelinappula solu). Tapaus ... toiminta tulee pelastus.
543528
544529- Muuta solujen piirtämistä:
545530
546531``` pascal
547532 // Draw boxes for all cells
548533 for iRow := 1 to pegsol.Size do
549534 for iCol := 1 to pegsol.Size do
550535 begin
551536 // Calculate the position of the cell in the paintbox
552537 CellArea.Top := (iRow-1) * CellHeight;
553538 CellArea.Left := (iCol-1) * CellWidth;
554539 CellArea.Right := CellArea.Left + CellWidth;
555540 CellArea.Bottom := CellArea.Top + CellHeight;
556541
557542 // And now draw the cell based on the cell's contents
558543 case pegsol.Cell[iRow,iCol] of
559544
560545 ctNoAccess: // Draw cells that are not accessible
561546 begin
562547 Canvas.Brush.Color := clGray;
563548 Canvas.Rectangle(CellArea);
564549 end;
565550
566551 ctEmpty: // Draw cells that are currently empty
567552 begin
568553 Canvas.Brush.Color := clBlue;
569554 Canvas.Rectangle(CellArea);
570555 end;
571556
572557 ctPeg: // Draw cells that are occupied
573558 begin
574559 Canvas.Brush.Color := clBlue;
575560 Canvas.Rectangle(CellArea); // Erase the background first
576561 Canvas.Brush.Color := clGreen;
577562 Canvas.Ellipse(CellArea); // Draw the pegs as green circles
578563 end;
579564 end;
580565 end;
581566```
582567
583568Ohjelmaa voitaisiin ajaa tässä vaiheessa (tai vain kokeilla sitä), mutta se on vain tylsä? (5x5) harmaa ruudukko. Tämä johtuu siitä ettei vielä ole määritelty mitään peliasetuksia. Korjataan sitä seuraavaksi.
584569
585570- Avaa ufrmmain käännösyksikkö.
586571- Paikallista StartNewGame aliohjelma.
587572- Luo 5x5 pelin sijasta 7x7 peli.
588573- Alusta muutamia soluja. Esimerkiksi:
589574
590575``` pascal
591576procedure TfrmMain.StartNewGame;
592577begin
593578 // Clean up the previous game
594579 pegpaint.Free;
595580 pegsol.Free;
596581
597582 // Start with a new 7x7 game
598583 pegsol := TPegSolitaire.Create(7);
599584 pegpaint := TPegSolPainter.Create(pegsol, pbPeg.Canvas);
600585
601586 // Initialize some cells
602587 pegsol.Cell[3,4] := ctEmpty;
603588 pegsol.Cell[4,2] := ctPeg;
604589 pegsol.Cell[4,3] := ctPeg;
605590 pegsol.Cell[4,4] := ctEmpty;
606591 pegsol.Cell[4,5] := ctPeg;
607592 pegsol.Cell[4,6] := ctPeg;
608593 pegsol.Cell[5,4] := ctEmpty;
609594end;
610595```
611596
612597- Suorita ohjelma (sen tulee näyttää jokseenkin samanlaiselta kuin kuva alla).
613598
614-<figure>
615-<img src="tutpeg_first_pegs.png" title="tutpeg_first_pegs.png" />
616-<figcaption>tutpeg_first_pegs.png</figcaption>
617-</figure>
599+![](/wiki-images/0/0b/Tutpeg_first_pegs.png)
618600
619601## Täytä pelilauta
620602
621603Kuten tiedetään niin klassinen solitaire pelilaudan pitäisi näyttää tältä:
622604
623-<figure>
624-<img src="tutpeg_classic.png" title="tutpeg_classic.png" />
625-<figcaption>tutpeg_classic.png</figcaption>
626-</figure>
605+![](/wiki-images/6/6c/Tutpeg_classic.png)
627606
628607Jos täytetään kaikki solut yksitellen, niin se johtaisi suureen koodimäärään. Mitä jos voitaisiin alustaa peli vain tekstillä, joka symbolisesti kuvaa pelilaudan? Jotain tällaista:
629608
630609``` pascal
631610
632611// Initialize the cells to the classic game
633612 pegsol.InitializeBoard( ' ooo ' + LineEnding +
634613 ' ooo ' + LineEnding +
635614 'ooooooo' + LineEnding +
636615 'ooo.ooo' + LineEnding +
637616 'ooooooo' + LineEnding +
638617 ' ooo ' + LineEnding +
639618 ' ooo ' );
640619```
641620
6426211. **o** on solu jossa on pelinappula.
6436222. **.** on tyhjä, mutta pelattavaa solu.
6446233. Välilyönnit osoittavat solut, jotka eivät ole käytettävissä.
645624
646625Oletetaan että tämä tulee toimimaan ja luodaan aliohjelma TPegSolitaire luokkaan joka voi hoitaa tämän.
647626
648627- Ollaan optimistinen (kutsutaan myös *Top down* suunnitteluksi) ja lisätään edellä ollut koodi TfrmMain.StartNewGame:
649628
650629``` pascal
651630procedure TfrmMain.StartNewGame;
652631begin
653632 // Clean up the previous game
654633 pegpaint.Free;
655634 pegsol.Free;
656635
657636 // Start with a new 7x7 game
658637 pegsol := TPegSolitaire.Create(7);
659638 pegpaint := TPegSolPainter.Create(pegsol, pbPeg.Canvas);
660639
661640 // Initialize the cells to the classic game
662641 pegsol.InitializeBoard( ' ooo ' + LineEnding +
663642 ' ooo ' + LineEnding +
664643 'ooooooo' + LineEnding +
665644 'ooo.ooo' + LineEnding +
666645 'ooooooo' + LineEnding +
667646 ' ooo ' + LineEnding +
668647 ' ooo ' );
669648end;
670649```
671650
672651- Avaa PegDatastructures lähdekooditiedosto.
673652- Lisää tämä aliohjelman esittely luokan public osioon: *InitializeBoard(const pBoard: ansistring);*
674653
675654``` pascal
676655
677656public
678657 constructor Create(const pSize: TCellNums);
679658 procedure InitializeBoard(const pBoard: ansistring);
680659
681660 property Cell[const pRow, pCol: TCellNums]: TCellType read GetCell write SetCell;
682661 property Size: TCellNums read FSize;
683662```
684663
685-- Luo aliohjelman InitializeBoard:n runko. Paina <span class="kbd">Ctrl</span>+<span class="kbd">Shift</span>+<span class="kbd">C</span>.
664+- Luo aliohjelman InitializeBoard:n runko. Paina `Ctrl`+`Shift`+`C`.
686665
687666Mitä tämä aliohjelman tarvitse tehdä? Se jakaa textstringin osiksi erillisiin riveihin ja sitten käsitellä nämä rivit, koska käytettiin LineEnding-vakiota erottamaan rivit niin voidaan käyttää *TStringList* luokkaa erottamaan ne.
688667
689668- Lisää *InitalizeBoard* koodi:
690669
691670``` pascal
692671procedure TPegSolitaire.InitializeBoard(const pBoard: ansistring);
693672var lst : TStringList;
694673 iRow,iCol: integer;
695674 s : string;
696675begin
697676 // Create a list with the board text in it. This will split all lines
698677 // into individual lines, because of the LineEnding 'splitter'.
699678 lst := TStringList.Create;
700679 lst.Text := pBoard;
701680
702681 // Process all lines one at a time
703682 for iRow := 0 to lst.Count-1 do
704683 if iRow < Size then // Make sure there is no overflow in the rows
705684 begin
706685 // Process a single line of text
707686 s := lst[iRow];
708687 for iCol := 1 to length(s) do
709688 if iCol <= Size then // Make sure there is no overflow in the columns
710689 case s[iCol] of
711690 ' ': Cell[iRow+1,iCol] := ctNoAccess;
712691 '.': Cell[iRow+1,iCol] := ctEmpty;
713692 'o': Cell[iRow+1,iCol] := ctPeg;
714693 end;
715694 end;
716695
717696 // Clean up the list
718697 lst.Free;
719698end;
720699```
721700
7227011. TStringList käytetään puskurina. Tämä toimii, koska *LineEnding*:a käytettiin rivien erottimena.
7237022. *Count* kertoo rivien määrän, mutta ne on numeroitu 0..Count-1. Ja solut on numeroitu aloittaen ykkösestä(1). Siksi on solua osoittaessa tehtävä *iRow + 1*.
724703
725704Edellä esitetty menettely sisältää paljon ylimääräisiä muuttujia ja ei pitäisi olla kovin vaikea ymmärtää. On mahdollista vähentää aliohjelma minimiin kuten näin:
726705
727706``` pascal
728707procedure TPegSolitaire.InitializeBoard(const pBoard: ansistring);
729708var iRow,iCol: integer;
730709begin
731710 with TStringList.Create do
732711 begin
733712 Text := pBoard;
734713 for iRow := 0 to Min(Count-1, Size-1) do
735714 for iCol := 1 to Min(length(Strings[iRow]),Size) do
736715 case Strings[iRow][iCol] of
737716 ' ': Cell[iRow+1,iCol] := ctNoAccess;
738717 '.': Cell[iRow+1,iCol] := ctEmpty;
739718 'o': Cell[iRow+1,iCol] := ctPeg;
740719 end;
741720 Free;
742721 end;
743722end;
744723```
745724
746725Tämä menettely tekee täsmälleen saman. Se käyttää kätevää ominaisuutta, sitä että voidaan käyttää With-lausetta kun luodaan dynaamisesti oliota. Toimiakseen tämä aliohjelma vaatii että lisätään *Math* käännösyksikkö uses lauseen luetteloon.
747726
748727- Suorita ohjelma. Kaikki soluissa on pelinappula kuten klassisessa Peg Solitaire pelissä.
749728
750729## Tapahtumien uudelleenkäynti
751730
752731Se ei kovin vaikuttava vielä, mutta tehty on jo paljon. Tärkein joka puuttuu tällä hetkellä on kyky hypätä solujen poistaa ne pelilaudalta. Ja että siihen käytetään hiirtä. Mutta miten? Tutkitaan mahdollisuuksia.
753732
754733- Tuo [[TMemo/fi|TMemo]]-komponentti lomakkeelle, TPaintBox pbPeg:n vasemmalla puolen (TMemo löytyy Standard välilehdeltä komponenttipaletilta).
755734- Komponenttimuokkaimessa muuta Align arvoon *alClient*. Se vie kaiken jäljellä olevan tilan, joka on jäljellä TPaintbox.
756735- Vaihda BorderSpacing.Around arvoon *4*.
757736- Tyhjennä Lines ominaisuus (klikkaa kolme pistettä painiketta (...) ja poista teksti). Tuloksena pitäisi näyttää tältä:
758737
759-<figure>
760-<img src="tutpeg_with_memo.png" title="tutpeg_with_memo.png" />
761-<figcaption>tutpeg_with_memo.png</figcaption>
762-</figure>
738+![](/wiki-images/1/11/Tutpeg_with_memo.png)
763739
764740- Valitse TPaintBox pbPeg.
765741- Komponenttimuokkaimessa valitse *Tapahtumat*-välilehti.
766742
767743On kaksi tapahtumaa, jotka ovat mielenkiintoisia: OnMouseDown ja OnMouseUp. Katsotaan mitä tapahtuu OnMouseDown tapahtumassa.
768744
769745- Komponenttimuokkaimessa valitse OnMouseDown tapahtuma.
770746- Klikkaa kolme pisteettä painiketta (tämä luo rungon tapahtuman aliohjelmalle).
771747
772748Syntyvään aliohjelman otsikkoon sisältyy useita muuttujia. Kaksi niistä ovat X ja Y. Ne sisältävät TPaintBox:n paikan jossa hiirtä painettiin. Tehdään ne näkyviksi lisäämällä joitakin tietoja TMemo-komponenttiin joka on lisätty lomakkeelle.
773749
774750- Lisää seuraavat lauseet aliohjelmaan; se lisää muotoillun rivin TMemo-komponentin näyttämään paikkaa, missä hiirtä painettiin:
775751
776752``` pascal
777753Memo1.Append( format('Mouse down @ %dx%d',[X,Y]) );
778754```
779755
780-- Suorita ohjelma. (Paina <span class="kbd">F9</span>).
756+- Suorita ohjelma. (Paina `F9`).
781757- Klikkaa hiirellä pelilautaa useissa eri paikoissa. Muistion (TMemon) ruutu näyttää missä hiiri painettiin.
782758- Lopeta ohjelma.
783759
784760Ilmeisesti ei voi käyttää "raakaa" X ja Y-koordinaatteja; ne ovat liian isoja 7x7 pelilaudalle. Ne täytyy sovittaa solun rivin ja sarakkeen koordinaattuin. Sitä varten tarvitaan toiminto, joka sovittaa X / Y-koordinaatin solun koordinaattiin. Tähän tarvitaan paintbox:n leveys ja korkeus, solujen lukumäärä ruudukossa ja yksittäisen solun leveys ja korkeus. On yksi paikka, jossa kaikki tämä tulee yhdessä ... pn Paint luokka. Tämä on siis selvä paikka tehdä tämä laskelma.
785761
786762- Avaa PegDatastructures käännösyksikkö.
787763- Lisää *TCellPosition* tietuetyyppi johon tallennetaan solun koordinaatit, tyyppien esittelyosioon:
788764
789765``` pascal
790766type
791767 TCellNums = 1..C_MAX;
792768 TCellType = (ctNoAccess, ctEmpty, ctPeg);
793769 TPegCells = array[TCellNums, TCellNums] of TCellType;
794770
795771 TCellPosition = record
796772 Row: TCellNums;
797773 Col: TCellNums;
798774 end;
799775```
800776
801777- Avaa PegSolPainter käännösyksikkö.
802778- Lisää luokan julkiseen (public)osioon funktio CanvasXYtoCell (...):
803779
804780``` pascal
805781 public
806782 constructor Create(pPegSol: TPegSolitaire; pCanvas: TCanvas);
807783
808784 procedure Repaint(const pCanvasWidth, pCanvasHeight: integer);
809785 function CanvasXYtoCell(const pX, pY: integer): TCellPosition;
810786```
811787
812-- Luo funktion runko. Paina <span class="kbd">Ctrl</span>+<span class="kbd">Shift</span>+<span class="kbd">C</span>.
788+- Luo funktion runko. Paina `Ctrl`+`Shift`+`C`.
813789- Lisää seuraava koodi:
814790
815791``` pascal
816792function TPegSolPainter.CanvasXYtoCell(const pX, pY: integer): TCellPosition;
817793begin
818794 result.Col := (pX div CellWidth) + 1;
819795 result.Row := (pY div CellHeight) + 1;
820796end;
821797```
822798
823799Edellä koodi kartoittaa suuret X / Y-koordinaatit vastaamaan solun rivi ja sarake numeroita. Yksi ongelma on kuitenkin: Täällä CellWidth ja CellHeight ei ole saatavilla. Ne ovat välituloksia Repaint aliohjelman eikä niitä tallenneteta. Tämä pitää korjata.
824800
825801- Lisää *CellWidth* ja *CellHeight* yksityisinä muuttujina *TPegSolPainter* luokkaan:
826802
827803``` pascal
828804 TPegSolPainter = class
829805 private
830806 PegSol : TPegSolitaire;
831807 Canvas : TCanvas;
832808 CellWidth : integer;
833809 CellHeight : integer;
834810```
835811
836812- Poista muuttujat *CellWidth* and *CellHeight* aliohjelman Repaint muuttujien esittelystä:
837813
838814``` pascal
839815procedure TPegSolPainter.Repaint(const pCanvasWidth, pCanvasHeight: integer);
840816var
841817 iRow, iCol : TCellNums;
842818 CellArea : TRect;
843819begin
844820```
845821
846822Nyt voidaan muuttaa aliohjelmaa, missä hiiren napin alaspainamisen koordinaattia käsiteltiin. Uuden funktion X / Y-paikka voidaan nyt sovittaa solun koordinaatteihin.
847823
848824- Avaa ufrmmain käännösyksikkö.
849825- Paikallista *pbPegMouseDown* aliohjelma.
850826- Muuta koodi:
851827
852828``` pascal
853829procedure TfrmMain.pbPegMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
854830var CellRC: TCellPosition;
855831begin
856832 CellRC := pegpaint.CanvasXYtoCell(X,Y);
857833 Memo1.Append( format('Mouse down @ %dx%d',[CellRC.Row, CellRC.Col]) );
858834end;
859835```
860836
861837Tehdään sama OnMouseUp tapahtumaan:
862838
863839- Luo aliohjelman runko OnMouseUp tapahtumaan.
864840- Lisää tämä koodi:
865841
866842``` pascal
867843procedure TfrmMain.pbPegMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
868844begin
869845 with pegpaint.CanvasXYtoCell(X,Y) do
870846 Memo1.Append( format('Mouse up @ %dx%d',[Row, Col]) );
871847end;
872848```
873849
874850Huomaa, että tämä menetelmä tekee täsmälleen sama kuin OnMouseDown, mutta käyttäen *with*-rakennetta säästetään vaivaa määrittää paikallinen muuttuja (vähemmän on enemmän ...).
875851
876852Testataan tätä:
877853
878854- Suorita ohjelma.
879855- Klikkaa ylhäällä vasemman puolista solua ja pidä hiiren nappi alhaalla.
880856- Siirrä hiiren kohdistin toiseen soluun.
881857- Vapauta hiiren painike.
882858
883859Joka kerta kun painaa hiiren painiketta ja vapauttaa sen, niin solu, jossa hiiren painiketta painettiin tai vapautettiin näkyy muistiossa.
884860
885861## Liimataan asioita yhteen
886862
887863Tämä ohjelma toimii vähän kuin laskin ohjelma:
888864
8898651. Käyttäjä valitsee pelinappulan jota siirretään painamalla hiiren painiketta.
8908662. Käyttäjä siirtää pelinappulan toiseen pelinappulan yli tyhjään soluun (hyppy).
8918673. Käyttäjä vapauttaa hiiren painikkeen ja siirto tapahtuu.
892868
893869Tällä ohjelma ei muista mitä solua painettiin. Joten kun käyttäjä painaa hiiren painiketta solun päällä, meidän täytyy säilyttää tämä paikka jonnekin.
894870
895871- Avaa ufrmmain käännösyksikkö.
896872- Lisää muuttuja *FromCell* lomakkeen yksityiseksi muuttujaksi:
897873
898874``` pascal
899875
900876private
901877 { private declarations }
902878 pegsol : TPegSolitaire; // The game data
903879 pegpaint: TPegSolPainter; // The paint class for the game
904880 FromCell: TCellPosition; // The peg that is going to leap
905881```
906882
907883- Mene OnMouseDown tapahtumankäsittelijään.
908884- Lisää seuraava rivi tähän aliohjelmaan:
909885
910886``` pascal
911887 FromCell := pegpaint.CanvasXYtoCell(X,Y);
912888```
913889
914890Nyt kun käyttäjä vapauttaa hiiren painikkeen, on suoritettava hyppy (myös tarkistettava, onko se ok ja päivittää pelilautaa). Ollaan optimistisia (muista Top Down huomautus?) Ja olettaa, on aliohjelma, joka tekee sen meille: Leap (\<FromCell\>, \<ToCell\>).
915891
916892- Paikallista OnMouseUp tapahtumakäsittelijä ja lisää seuraava rivi:
917893
918894``` pascal
919895 pegsol.Leap(FromCell, pegpaint.CanvasXYtoCell(X,Y));
920896```
921897
922898*FromCell* oli jo pelinappula kun hiiren näppäintä painettiin. Kohdesolun lasketaan yksinkertaisesti kutsumalla pegpaint.CanvasXYToCell (...). Voisimme ottaa käyttöön paikallinen muuttuja sitä, mutta se ei ole välttämättä tarpeen.
923899
924900- Lisää seuraava rivi aliohjelmaan:
925901
926902``` pascal
927903 pbPeg.Repaint;
928904```
929905
930906Tämä pakottaa paintbox:n piirtämään itsensä, joten kaikki päivitetyt solut näyttävät oikean sisällön.
931907
932908Täydellinen OnMouseDown aliohjelma nyt näyttää tältä:
933909
934910``` pascal
935911procedure TfrmMain.pbPegMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
936912begin
937913 with pegpaint.CanvasXYtoCell(X,Y) do
938914 Memo1.Append( format('Mouse up @ %dx%d',[Row, Col]) );
939915 pegsol.Leap(FromCell, pegpaint.CanvasXYtoCell(X,Y));
940916 pbPeg.Repaint;
941917end;
942918```
943919
944920Ennenkuin mennään Leap aliohjelmaan niin vähän lisätoimintoja otetaan käyttöön. Muista, että voidaan noutaa solun tila (tyhjä, pelinappula tai ei pääsyä) TPegSolitaire:n Cell ominaisuuden kautta! Esimerkiksi pegsol.Cell \[2,2\] antaisi rivin 2 ja sarakkeen 2 solun tilan. Mutta tähän väliin, on otettu käyttöön uusi tietorakenne: TCellPosition. Niinpä esimerkiksi, jos halutaan saada tila *FromCell*:stä tarvitaan seuraava hankala lause:
945921
946922``` pascal
947923 state := pegsol.Cell[ FromCell.Row, FramCell.Col ]
948924```
949925
950926Olisi mukavaa, jos voisi kirjoittaa jotain:
951927
952928``` pascal
953929 state := pegsol.GetCell(FromCell)
954930```
955931
956932Lisätään tämä peli luokkaan.
957933
958934- Avaa käännösyksikkö PegDatastructures.
959935- Lisää yksityinen (private) funktio:*GetCell (const pPosition: TCellPosition): TCellType;*
960936
961937``` pascal
962938 TPegSolitaire = class
963939 private
964940 FSize: TCellNums;
965941 PegCells: TPegCells;
966942 function GetCell(const pRow, pCol: TCellNums): TCellType;
967943 procedure SetCell(const pRow, pCol: TCellNums; const pValue: TCellType);
968944 function GetCell(const pPosition: TCellPosition): TCellType;
969945```
970946
971947Nyt on kaksi samannimistä GetCell funktiota, mutta niiden parametriluettelo on erilainen. Joten Lazarus tietää tarkalleen, milloin kutsua kyseistä funktiota.
972948
973-- Luo funktion runko (Paina <span class="kbd">Ctrl</span>+<span class="kbd">Shift</span>+<span class="kbd">C</span>).
949+- Luo funktion runko (Paina `Ctrl`+`Shift`+`C`).
974950- Lisätään seuraava koodi:
975951
976952``` pascal
977953 result := Cell[pPosition.Row, pPosition.Col];
978954```
979955
980956Takaisin "pääjuoneen". On otettu käyttöön aliohjelma *Leap (...)*, mutta sitä ei vielä ole. Se on aliohjelma, joka muuttaa peliä pelilaudalla, joten paikka mihin laittaa se on TPegSolitaire luokka.
981957
982958- Avaa käännösyksikkö PegDatastructures.
983959- Lisää aliohjelma Leap luokan TPegSolitaire public osioon.
984960
985961``` pascal
986962 public
987963 constructor Create(const pSize: TCellNums);
988964 procedure InitializeBoard(const pBoard: ansistring);
989965 procedure Leap(const pFromCell, pToCell: TCellPosition);
990966```
991967
992-- Luo aliohjelman runko (Paina <span class="kbd">Ctrl</span>+<span class="kbd">Shift</span>+<span class="kbd">C</span>).
968+- Luo aliohjelman runko (Paina `Ctrl`+`Shift`+`C`).
993969
994970Nyt tämä aliohjelma tekee kaiken kovan työn: tarkistaa, että solut ovat voimassa ja onko hyppy on suinkin mahdollista. Tämä ei ole vaikeaa, mutta tarkastusten määrä on varsin laaja jotain, joka näyttää yksinkertaista. Koodi on melko itsestään selvä, ja jos ei, toivottavasti kommentit selittää mitä tapahtuu. Huomaa, että aliohjelma käyttää GetCell (\<cellposition\>) funktiota joka luotiin aikaisemmin.
995971
996972``` pascal
997973procedure TPegSolitaire.Leap(const pFromCell, pToCell: TCellPosition);
998974var dx, dy: integer;
999975 JumpedCell: TCellPosition;
1000976begin
1001977 // Verify that the start cell is occupied and the target cell is empty
1002978 // If not, leave the procedure via the EXIT.
1003979 if (GetCell(pFromCell) <> ctPeg) or
1004980 (GetCell(pToCell) <> ctEmpty) then
1005981 EXIT;
1006982
1007983 // Calculate the horizontal and vertical distance between the cells
1008984 dx := abs(pFromCell.Col - pToCell.Col);
1009985 dy := abs(pFromCell.Row - pToCell.Row);
1010986
1011987 // A valid move has one direction equal to zero and the other equal to 2
1012988 if ((dx = 2) and (dy = 0))
1013989 or ((dx = 0) and (dy = 2)) then
1014990 begin
1015991 // Determine the position of the jumped cell; it's in the middle
1016992 JumpedCell.Col := (pFromCell.Col + pToCell.Col) div 2;
1017993 JumpedCell.Row := (pFromCell.Row + pToCell.Row) div 2;
1018994
1019995 // Final check: is there a peg in the jumped cell?
1020996 if GetCell(JumpedCell) = ctPeg then
1021997 begin
1022998 // Jump: clear the FromCell, empty the jumped cell and populate the ToCell
1023999 Cell[pFromCell.Row, pFromCell.Col] := ctEmpty;
10241000 Cell[JumpedCell.Row, JumpedCell.Col] := ctEmpty;
10251001 Cell[pToCell.Row, pToCell.Col] := ctPeg;
10261002 end;
10271003 end;
10281004end;
10291005```
10301006
10311007Usko tai älä, mutta nyt on toimiva Peg Solitaire lautapasianssi peliohjelma!
10321008
10331009- Suorita ohjelma.
10341010- Paina hiiren painiketta yhden pelinappula solun päällä.
10351011- Hyppää yli toisen pelinappula solun tyhjään soluun.
10361012- Vapauta hiiren painike.
10371013- Toista tätä...
10381014
10391015## Puhdistusta
10401016
10411017Lomakkeelle meillä on vielä muistio komponentti, joka näyttää hiiren klikkauksella. Sitä enää todellakaan tarvita.
10421018
10431019- Poista muistio lomakkeelta.
10441020- Poista muistion päivitykset MouseDown ja MouseUp tapahtumat.
10451021
10461022``` pascal
10471023procedure TfrmMain.pbPegMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
10481024begin
10491025 FromCell := pegpaint.CanvasXYtoCell(X,Y);
10501026end;
10511027
10521028procedure TfrmMain.pbPegMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
10531029begin
10541030 pegsol.Leap(FromCell, pegpaint.CanvasXYtoCell(X,Y) );
10551031 pbPeg.Repaint;
10561032end;
10571033```
10581034
1059-- Siirry lomakkeelle (<span class="kbd">F12</span>).
1035+- Siirry lomakkeelle (`F12`).
10601036- Valitse TPaintBox pbPeg
10611037- Komponenttimuokkaimessa vaihda ominaisuus Align arvoon *alClient* (Ominaisuudet välilehti).
10621038- Poista käännösyksikkö *stdctrls* uses luettelosta. Muuten kääntäjä antaa vihjeen "Kääntäjän viestit" ikkunassa ettei sitä käytetä (Se lisättiin automaattisesti kun TMemo komponentti tuotiin lomakkeelle).
10631039
10641040### Mitä seuraavaksi?
10651041
10661042Jotta tämä olisi täysin toimiva peli tarvitsemme tapa muuttaa pelilautaa ilman että kääntää sovellus uudelleen. Ja grafiikka voitaisiin parantaa. aletaan käsitellä ensinmäistä kysymystä ensin.
10671043
10681044## Luodaan enemmän pelilautoja
10691045
10701046Olisi mukavaa, jos voidaan lisätä pelilautoja peliin ilman että joutuisi kääntämään uudelleen sovelluksen. Ilmeinen paikka tallentaa pelilaudan kaavat olisi ulkoiset tekstitiedosto. Käyttäjä voi sitten aloittaa uuden pelin avaamalla jonkun tekstitiedoston. Hauska asia on, se on helppo lisätä, koska ollaan jo tehty suurimman osan kovasta työstä. Katsotaanpa ensin tehdä kaksi pelilaudan kaavoista.
10711047
10721048- Valitse valikosta Tiedosto / Uusi ...; Tämä avaa "Uusi..."- ikkunan.
10731049- Valitse vaihtoehto Moduuli / Teksti ja valitse OK.
10741050- Kirjoita seuraava teksti (sen pitäisi näyttää tutulta :-)):
10751051
10761052``` pascal
10771053 ooo
10781054 ooo
10791055ooooooo
10801056ooo.ooo
10811057ooooooo
10821058 ooo
10831059 ooo
10841060```
10851061
10861062- Valitse valikosta Tiedosto / Tallenna.
10871063- Tallenna tiedosto projektin bin kansioon nimellä *classic.txt*.
10881064
10891065Lisää toinen tiedosto:
10901066
10911067- Valitse valikosta Tiedosto / Uusi ....
10921068- Valitse vaihtoehto Moduuli / Teksti ja valitse OK.
10931069- Kirjoita seuraava teksti:
10941070
10951071``` pascal
10961072 ...
10971073 .o.
10981074..ooo..
10991075.ooooo.
11001076ooooooo
11011077 ...
11021078 ...
11031079```
11041080
11051081- Valitse valikosta Tiedosto / Tallenna.
11061082- Tallenna tiedosto bin kansioon nimellä *triangle.txt*.
11071083
11081084On monia tapoja luoda ja avata uusia pelilautoja. Tässä opetusohjelmassa käytetään valikko lähestymistapaa (perusteellisempi kuvaus valikosta on jossain toisessa opetusohjelmassa).
11091085
11101086- Avaa ufrmmain käännösyksikkö.
11111087- Valitse TMainMenu-komponentti komponenttipaletin Standard-välilehdeltä.
11121088- Klikkaa lomakkeella (sillä ei ole väliä, jos osut paintbox:n). Kuvake näkyy osoittaa, että valikko on nyt saatavilla olevat.
11131089- Tuplaklikkaa MainMenu1 kuvaketta. Tämä avaa valikkomuokkaimen. Yksi kohde on jo käytettävissä, nimeltään *New Item1*.
11141090- Komponenttimuokkaimella muutaa sen Caption tekstiksi *&File* (sisältyy et-merkillä, sitä käytetään vetämään alaviivat kun painat Alt päävalikkoon).
11151091- Klikkaa hiiren oikealla File kohdasta valikkomuokkaimessa ja valitse *Luo alivalikko* ponnahdusikkunasta.
11161092- Muuta Caption tekstiksi *E&xit* (tämä on tuttu sovelluksen lopeta kohta).
11171093- Klikkaa hiiren oikealla File kohtaa.
11181094- Valitse *Lisää uusi kohta (jälkeen)* ponnahdusikkunasta.
11191095- Muuta Caption tekstiksi kyseisen kohtaan *&Game*.
11201096- Klikkaa hiiren oikealla Game kohdasta valikkomuokkaimessa ja valitse *Luo alivalikko* ponnahdusikkunasta.
11211097- Muuta Caption tekstiksi *Load from file...*.
11221098
11231099Valikko nyt näyttää tältä:
11241100
1125-<figure>
1126-<img src="tutpeg_mainmenu.png" title="tutpeg_mainmenu.png" />
1127-<figcaption>tutpeg_mainmenu.png</figcaption>
1128-</figure>
1101+![](/wiki-images/4/4e/Tutpeg_mainmenu.png)
11291102
11301103Valikko on myös näkyvissä lomakkeen yläosassa.
11311104
11321105- Klikkaa *File*-valikosta kohtaa; Tämä avaa alivalikon ja *Exit* on näkyvissä.
11331106- Tuplaklikkaa *Exit*. Kuten arvata saattaa tämä luo tapahtumakäsittelijän. Toisin sanoen aliohjelman, joka suoritetaan heti, kun käyttäjä klikkaa tätä valikkokohtaa.
11341107- Lisää seuraava rivi luotuun koodin runkoon:
11351108
11361109``` pascal
11371110 Close;
11381111```
11391112
11401113Tämä sulkee lomakkeen. Ja koska se on ainoa lomake niin myös sovellus loppuu.
11411114
11421115Ok, nyt on aika tarkastella, miten avata pelilauta tiedostoja. On olemassa vakiokomponentteja ja valikko käytettävissä tehdä tämä, mutta tehdään se manuaalisesti.
11431116
11441117- Mene lomakkeelle.
11451118- Komponentti paletulta valitse *Dialogs* välilehti.
11461119- Valitse TOpenDialog komponentti (klikkaa sitä).
11471120- Klikkaa lomaketta (missä tahansa). OpenDialog1 komponentti on nyt näkyvissä lomakkeella. Tämä komponentti tarjoaa meille eräänlainen selailuikkunan, jolla voimme valita tiedostoja. Lomake näyttää nyt tältä:
11481121
1149-<figure>
1150-<img src="tutpeg_mainform.png" title="tutpeg_mainform.png" />
1151-<figcaption>tutpeg_mainform.png</figcaption>
1152-</figure>
1122+![](/wiki-images/5/51/Tutpeg_mainform.png)
11531123
11541124- Komponenttimuokkaimessa klikkaa Filter ominaisuutta ja sitten 3-piste (...) painiketta. Tämä avaa suodattimen muokkain dialogi-ikkunan. Tämä on paikka, jossa kerrotaan minkä tyyppisiä tiedostoja käyttäjälle on mahdollisuus valita.
11551125- Nyt halutaan vain tekstitiedostoja joten lisätään tälläinen suodatinrivi: *Peg Solitaire TextFiles (* .txt) \| * .txt* (katso kuva alla).
11561126- Paina OK.
11571127
1158-<figure>
1159-<img src="tutpeg_filterdialog.png" title="tutpeg_filterdialog.png" />
1160-<figcaption>tutpeg_filterdialog.png</figcaption>
1161-</figure>
1128+![](/wiki-images/1/13/Tutpeg_filterdialog.png)
11621129
11631130- Komponenttimuokkaimessa muuta Options.ofFileMustExist totta. Tämä pakottaa dialogi sallii vain nykyiset tiedostot voidaan valita.
11641131
11651132Hyvä niin. Nyt todella avata tiedoston, kun valikko on valittuna:
11661133
11671134- Lomakkeella klikkaa Game valikosta. Tämä avaa pudotusvalikon.
11681135- Klikkaa *Load from file...*. Odotetusti tämä luo .... tapahtumankäsittelijänä.
11691136- Lisää seuraava koodi tapahtumakäsittelijään:
11701137
11711138``` pascal
11721139 if OpenDialog1.Execute then
11731140 ShowMessage(OpenDialog1.FileName);
11741141```
11751142
11761143Muista: edetä pienin askelin. Nyt on lisätty valikko lomakkeelle josta voi poistua sovelluksesta tai ladata pelilaudan pohjan levyltä. Vielä ei ole ??koodattu latausosaa, mutta yritetään ensin testata koodia joka on jo tehty.
11771144
11781145- Suorita sovellus.
11791146- Valitse valikosta *Game/Load from file...*.
11801147- Valitse *triangle.txt* ja paina Avaa.
11811148- Ikkuna ponnahtaa joka osoittaa meille valitun tiedostonimen.
11821149- Lopeta ohjelma.
11831150
11841151Nyt viimeistellään latauskoodi. Koodi on melko itsestään selvä ja käyttää uudelleen joitakin aliohjelmia jotka on jo luotu.
11851152
11861153- Mene lomakkeella ja klikkaa Game valikosta. Tämä avaa pudotusvalikon.
11871154- Klikkaa *Load from file...*. Odotetusti tämä avaa tapahtumankäsittelijän.
11881155- Korvaa koodin tällä:
11891156
11901157``` pascal
11911158procedure TfrmMain.MenuItem4Click(Sender: TObject);
11921159begin
11931160 // Open the pop up dialog
11941161 if OpenDialog1.Execute then
11951162 begin
11961163 // Start with a new empty board
11971164 StartNewGame;
11981165
11991166 // Dynamically create a stringlist to load the board layout
12001167 with TStringList.Create do
12011168 begin
12021169 // Load the board layout from the textfile
12031170 LoadFromFile(OpenDialog1.FileName);
12041171
12051172 // Initialize the board with the file's contents
12061173 pegsol.InitializeBoard(Text);
12071174
12081175 // Clean up the stringlist
12091176 Free
12101177 end;
12111178
12121179 // After loading the new board update the paintbox
12131180 pbPeg.Repaint;
12141181 end;
12151182end;
12161183```
12171184
12181185Ja se kaikki on siinä!
12191186
12201187Suorita ohjelma, avaa pelilaudan pohjatiedosto ja pelaa peliä!
12211188
12221189## Silmänruokaa
12231190
12241191Nyt on toimiva Peg Solitaire sovellus. Siellä on vielä paljon asioita parannettavaksi, mutta peli itsessään toimii hienosti. Viimeinen osa tätä opetusohjelmaa on parantaa pelin ulkonäköä. Toki peli toimii, mutta hieman näyttävämpi grafiikka olisi mukava. Ja se on melko helppo lisätä. Kaikki mitä tarvitaan on kolme kuvaa solutyyppejä varten, päivittää TPegSolPainter-luokkaa ja tärkein muoto, kerro maalari käyttää kuvia. Joten lisää kolme kuvaa TPegSolPainter luokkaan:
12251192
12261193- Avaa PegSolPainter käännösyksikkö.
12271194- Lisää kolme (3) kuvamuuttujaa private osioon:
12281195
12291196``` pascal
12301197 TPegSolPainter = class
12311198 private
12321199 PegSol : TPegSolitaire;
12331200 Canvas : TCanvas;
12341201 CellWidth : integer;
12351202 CellHeight : integer;
12361203
12371204 ImgNoAccess: TPicture;
12381205 ImgEmpty : TPicture;
12391206 ImgPeg : TPicture;
12401207```
12411208
12421209- Lisää kuvan latausaliohjelma public osioon.
12431210
12441211``` pascal
12451212 public
12461213 constructor Create(pPegSol: TPegSolitaire; pCanvas: TCanvas);
12471214 procedure Repaint(const pCanvasWidth, pCanvasHeight: integer);
12481215 function CanvasXYtoCell(const pX, pY: integer): TCellPosition;
12491216 procedure LoadImage(const pCellType: TCellType; const pFilename: string);
12501217```
12511218
12521219- Luo aliohjelman runko.
12531220- Lisää koodi:
12541221
12551222``` pascal
12561223procedure TPegSolPainter.LoadImage(const pCellType: TCellType; const pFilename: string);
12571224
12581225 procedure UpdateImage(var pImg: TPicture; const pNewImage: TPicture);
12591226 begin
12601227 pImg.Free;
12611228 pImg := pNewImage
12621229 end;
12631230
12641231var pic: TPicture;
12651232begin
12661233 // Make sure the file exists
12671234 if FileExists(pFilename) then
12681235 begin
12691236 // First load the picture in a local variable
12701237 pic := TPicture.Create;
12711238 pic.LoadFromFile(pFilename);
12721239
12731240 // Now update the required image based on the pCelltype parm
12741241 case pCelltype of
12751242 ctNoAccess: UpdateImage(ImgNoAccess, pic);
12761243 ctEmpty : UpdateImage(ImgEmpty, pic);
12771244 ctPeg : UpdateImage(ImgPeg, pic);
12781245 end;
12791246 end;
12801247end;
12811248```
12821249
12831250Koodi on taas aika itsestään selvä. Huomaa, että käytetään lyhyttä paikallista aliohjelmaa päivittämään kuvaa. Jos emme tekisi sitä sitten case-lause ((*case pCellType of*) olisi monimutkaisempi (eli sisältäisi ylimääräistä koodia). Nyt kukin solutyyppi tarvitsee vain yhden rivin päivittäkseen oikean kuvan.
12841251
12851252Nyt kun kuvia on lisätty luokkaan, täytyy käyttää niitä ja se tietenkin tapahtuu Repaint aliohjelmassa. Jokaista celltype tarkistetaan, onko kuva on saatavilla. Ja jos on niin käytetäään tavallisen piirustuksen sijasta kuvaa.
12861253
12871254- Paikallista Repaint aliohjelma.
12881255- Case lauseessa, muuta ctNoAccess, ctEmpty ja ctPeg osiot seuraavanlaiseksi:
12891256
12901257``` pascal
12911258
12921259// And now draw the cell based on the cell's contents
12931260 case pegsol.Cell[iRow,iCol] of
12941261
12951262 ctNoAccess: // Draw cells that are not accessible
12961263 if not assigned(ImgNoAccess) then
12971264 begin
12981265 Canvas.Brush.Color := clGray;
12991266 Canvas.Rectangle(CellArea);
13001267 end
13011268 else with ImgNoAccess do
13021269 Canvas.CopyRect(CellArea, Bitmap.Canvas, Rect(0,0,Width,Height));
13031270
13041271 ctEmpty: // Draw cells that are currently empty
13051272 if not assigned(ImgEmpty) then
13061273 begin
13071274 Canvas.Brush.Color := clBlue;
13081275 Canvas.Rectangle(CellArea);
13091276 end
13101277 else with ImgEmpty do
13111278 Canvas.CopyRect(CellArea, Bitmap.Canvas, Rect(0,0,Width,Height));
13121279
13131280 ctPeg: // Draw cells that are occupied
13141281 if not assigned(ImgPeg) then
13151282 begin
13161283 Canvas.Brush.Color := clBlue;
13171284 Canvas.Rectangle(CellArea); // Erase the background first
13181285 Canvas.Brush.Color := clGreen;
13191286 Canvas.Ellipse(CellArea);
13201287 end
13211288 else with ImgPeg do
13221289 Canvas.CopyRect(CellArea, Bitmap.Canvas, Rect(0,0,Width,Height));
13231290
13241291 end;
13251292```
13261293
13271294Lisätään kuva latauskoodi piirtoluokkaan.
13281295
13291296- Avaa ufrmmain -käännösyksikkö.
13301297- Paikallista aliohjelma StartNewGame.
13311298- Lisää LoadImage kutsu *pegpaint* olion luomisen jälkeen:
13321299
13331300``` pascal
13341301 // Start with a new 7x7 game
13351302 pegsol := TPegSolitaire.Create(7);
13361303 pegpaint := TPegSolPainter.Create(pegsol, pbPeg.Canvas);
13371304
13381305 pegpaint.LoadImage(ctNoAccess, 'tutpeg_cellforbidden.jpg');
13391306 pegpaint.LoadImage(ctEmpty, 'tutpeg_cellempty.jpg');
13401307 pegpaint.LoadImage(ctPeg, 'tutpeg_celloccupied.jpg');
13411308```
13421309
13431310Varmista, että kuvat ladataan ja laitetaan ohjelman *bin* kansioon, tai vielä parempaa, luot omat kuvat. Huom. kun lataat allaolevia kuvia, klikkaa niitä ensin.
13441311
13451312![](/wiki-images/1/1c/Tutpeg_cellforbidden.jpg) ![](/wiki-images/5/51/Tutpeg_cellempty.jpg) ![](/wiki-images/9/9c/Tutpeg_celloccupied.jpg)
13461313
13471314- Nyt kun testataan Peg Solitaire peliä. Toivottavasti se näyttää suunnilleen samanlaiselta kuin kuva tämän opetusohjelman alussa ...
13481315
13491316## Viimeinen "helmi"
13501317
13511318Useimmilla ohjelmilla on oma kuvake, joka näkyvät valikon ja tiedoston selaus ikkunoissa. On helppo lisätä oma kuvake sovellukseen.
13521319
13531320- Valitse valikosta Projekti / Projektikohtaiset asetukset ....
13541321- Klikkaa Projektin asetukset/ Sovellus. Tämä näyttää ikkunassa sovelluksen kuvaketta.
13551322- Klikkaa Lataa kuvake ja lataa siihen sopiva kuvake tai ladata marmorikuvan joka on tässä alla:
13561323
1357-<figure>
1358-<img src="tutpeg_marble.png" title="tutpeg_marble.png" />
1359-<figcaption>tutpeg_marble.png</figcaption>
1360-</figure>
1324+![](/wiki-images/e/eb/Tutpeg_marble.png)
13611325
13621326- Paina OK.
13631327
13641328Sovelluksella on nyt oma kuvake, joka näkyy valikossa ja tiedoston selaus ikkunassa.
13651329
13661330---
13671331*From the Free Pascal wiki, page "Peg Solitaire tutorial/fi", as it stood on 2019-07-13 after a change by Djzepi, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history