Welcome to the Croatian Language Corpus   Croatian
   home |  Riznica |  documentation |   
Ivan Hladni [2004], Paskal i Delphi programiranje (Školska knjiga, Zagreb), 299 pp. [word count] [Hladni_Pascal].
Previous page

Next page

-- 3 --

Sadržaj

1. Osnove Pascala 10

1.1. Uvod 10

1.2. Povijest programskog jezika Pascal 10

1.3. Struktura Pascal programa 11

1.4. Prvi pravi Pascal program 13

1.5.3. Osnovna komunikacija s korisnikom 14

1.6. Tipovi podataka 15

1.7. Varijable 16

1.7.1. Deklaracija varijabli 16

1.7.2. Identifikatori 17

1.7.3. Operator pridjeljivanja vrijednosti 18

1.7.4. Osnovni aritmetički operatori 20

1.7.5. Dodatni načini rada s podacima 22

1.7.6. Učitavanje podataka 23

1.8. Konstante 27

1.9. Komentari 28

1.10. Sažetak 28

2. Grananje i ponavljanje 32

2.1. Naredba if 32

2.1.1. Naredba if then else 34

2.1.2. Višestruka if provjera vrijednosti 38

2.2. Logički operatori 40

2.2.1. Operator not 40

2.2.2. Operator and 41

2.2.3. Operator or 43

2.2.4. Operator xor 43

2.3. Case provjera 46

2.3.1. Case-else 47

2.3.2. Višestruka case provjera 48

2.4. For petlja 51

2.5. Repeat-until petlja 58

2.6. While petlja 61

2.7. Iskakanje iz petlji 62

2.8. Sažetak 64

3. Strukturirano programiranje 68

3.1. Uvod u strukturirano programiranje 68

3.2. Korištenje standardnih procedura i funkcija 69

3.2.1. Korištenje standardnih procedura 69

3.2.2. Korištenje standardnih funkcija 72

3.3. Stvaranje procedura 75

<pb n="4"/>

3.3.1. Lokalne i globalne varijable 76

3.3.2. Lista parametara 78

3.3.3. Prijenos podataka putem vrijednosti i

putem reference 80

3.3.4. Korištenje većega broja procedura 82

3.4. Stvaranje funkcija 85

3.4.1. Rekurzivne procedure i funkcije 87

3.5. Sažetak 88

4. Polja i stringovi 92

4.1. Polja podataka 92

4.1.1. Dvodimenzionalna polja 96

4.1.2. Konstantno polje 97

4.1.3. Polje kao parametar procedure 98

4.2. String 99

4.2.1. Provjeravanje duljine stringa 102

4.2.2. Definiranje kratke string varijable 104

4.2.3. Standardne string procedure i funkcije 104

4.2.4. Jednostavno pretraživanje stringova 105

4.2.5. Ubacivanje teksta u string 107

4.2.6. Brisanje dijelova stringa 108

4.2.7. Kopiranje dijelova stringa 109

4.3. Sažetak 110

5. Enumeracije, zapisi i tekstualne datoteke 114

5.1. Stvaranje novih tipova podataka 114

5.2. Enumeracije 115

5.2.1. Podtip enumeriranog tipa podataka 117

5.2.2. Setovi podataka 118

5.3. Zapisi 120

5.4. Tekstualne datoteke 123

5.5. Sažetak 128

6. Pokazivači 132

6.1. Osnove rada s pokazivačima 132

6.1.1. Stvaranje dinamičkih varijabli 135

6.1.2. Generički pokazivači 138

6.1.3. Aritmetika pokazivača 140

6.2. Jednostruko povezana lista 142

6.3. Stvaranje povezane liste – reda 142

6.3.1. Dodavanje podataka u listu 144

6.3.2. Prikazivanje sadržaja liste 146

6.3.3. Brisanje cijele povezane liste 147

6.3.4. Brisanje jednog podatka liste 148

6.4. Sažetak 153

<pb n="5"/>

7. Osnove Delphi programiranja 156

7.1. Delphi razvojna okolina 156

7.1.1 . Elementi razvojne okoline 156

7.1.2. Glavni izbornik 157

7.1.4. Paleta komponenata 158

7.1.5. Stablo objekata 158

7.1.7. Dizajner forme 159

7.1.8. Editor koda 160

7.2. Stvaranje Delphi aplikacije 160

7.2.1. Kompiliranje i pokretanje aplikacije 162

7.3. Što je uopće Delphi 163

7.4. Stvaranje Windows aplikacija pomoću Delphija 164

7.4.1. Događajima upravljano programiranje 164

7.4.2. Objektno-orijentirano programiranje 165

7.5. Prva Delphi aplikacija 165

7.5.2. Pisanje odgovora na događaj 168

7.6. Sažetak 170

8. Stvaranje korisničkog sučelja 174

8.1. Dodavanje komponenata na formu 174

8.1.1. Dodavanje komponente na željeno mjesto na formi 174

8.1.2. Dodavanje komponente uz promjenu veličine 174

8.1.3. Dodavanje većega broja komponenata 175

8.2. Osnovne komponente i njihova svojstva 175

8.2.1. Upoznavanje osnovnih komponenata 176

8.2.2. Osnovni događaji komponenata 177

8.2.3. Korištenje događaja 178

8.3. TCheckBox i TRadioButton komponente 182

8.3.3. Delphi komentari 185

8.3.4. TCheckBox komponenta 185

8.4. Mali trikovi Delphi programiranja 187

8.4.1. Brisanje postojećih procedura 187

8.4.2. Korištenje jedne procedure na više mjesta 189

8.4.3. Osnovno korištenje RTTI-a 190

8.4.4. Fenomenalno svojstvo Tag 192

8.5. Sažetak 193

9. Stvaranje naprednijih aplikacija 196

9.1. Grupiranje komponenata 196

9.1.2. Usidravanje komponente radi boljeg

vizualnog efekta 199

9.1.3. Parent i Owner svojstva komponenata 201

9.1.4. TPanel komponenta 202

9.1.5. TBevel komponenta 203

<pb n="6"/>

9.2. Liste podataka 204

9.2.1. Aplikacija za rastavljanje rečenica 206

9.2.2. Fokusiranje komponenata 207

9.2.3. Nastavak rastavljanja rečenica 208

9.2.4. Odabir većega broja podataka u listi 211

9.2.5. Snimanje liste na disk 212

9.3. Sažetak 212

10. Izbornici i alatne trake216

10.1. Glavni izbornik aplikacije 216

10.1.1. Dizajniranje izbornika 216

10.2. Standardni dijaloški okviri 218

10.2.2. TFontDialog komponenta 222

10.2.3. TOpenDialog i TSaveDialog komponente 223

10.3. TImageList komponenta 225

10.4. Alatne trake – TToolbar komponenta 227

10.5. TXPManifest komponenta 228

10.6. Editor teksta – DelphiPad aplikacija 229

10.6.1. Dizajn izbornika 230

10.6.2. Postavke komponenata 230

10.6.3. Osnovni dijelovi izvornog koda 231

10.6.4. Izvorni kôd File izbornika 234

10.6.5. Otvaranje postojećeg dokumenta 234

10.6.6. Snimanje dokumenta na disk 236

10.6.7. Zatvaranje glavne forme editora 238

10.6.8. Nadopuna koda za stvaranje novog dokumenta 242

10.6.9. Izvorni kôd Edit izbornika 242

10.6.10. Podešavanje alatne trake 246

10.6.11. Izvorni kôd Format izbornika 248

10.6.12. Snimanje postavki korisničkog sučelja 249

10.6.13. Dodavanje kratke pomoći korisnicima 252

10.7. Sažetak 253

11. Stvaranje baze podataka pomoću zapisa 256

11.1. Rad s više formi 256

11.2. HomeDVD aplikacija 257

11.2.1. Korisničko sučelje aplikacije 258

11.2.2. Korisničko sučelje dijaloškog okvira 260

11.2.3. Osnovni dijelovi izvornog koda 261

11.2.4. Prikazivanje informacija o odabranom filmu 263

11.2.5. Otvaranje i zatvaranje baze podataka 265

11.2.6. Dodavanje novog filma u bazu podataka 265

11.2.7. Mijenjanje zapisa u bazi podataka 269

<pb n="7"/>

11.2.8. Navigacija baze podataka 270

11.2.9. Brisanje podataka 270

11.2.10. Eksportiranje podataka iz baze 272

11.3. Sažetak 274

12. Dodatak A – Osnove DOS grafike 276

12.1. Inicijaliziranje grafike 276

12.2. Mod 13H 278

13. Pitanja i odgovori284

Poglavlje 1 – Osnove Pascala 284

Poglavlje 4 – Polja i stringovi 292

Poglavlje 5 – Enumeracije, zapisi i tekstualne datoteke 294

Poglavlje 6 – Pokazivači 295

Poglavlje 7 – Osnove Delphi programiranja 296

Poglavlje 8 – Stvaranje korisničkog sučelja 296

Poglavlje 9 – Stvaranje naprednijih aplikacija 297

Poglavlje 10 – Izbornici i alatne trake 298

<pb n="8"/>

<pb n="9"/>

1. Osnove Pascala

1.1. Uvod 10

1.2. Povijest programskog jezika Pascal 10

1.3. Struktura Pascal programa 11

1.4. Prvi pravi Pascal program 13

1.5.3. Osnovna komunikacija s korisnikom 14

1.6. Tipovi podataka 15

1.7. Varijable 16

1.7.1. Deklaracija varijabli 16

1.7.2. Identifikatori 17

1.7.3. Operator pridjeljivanja vrijednosti 18

1.7.4. Osnovni aritmetički operatori 20

1.7.5. Dodatni načini rada s podacima 22

1.7.6. Učitavanje podataka 23

1.8. Konstante 27

1.9. Komentari 28

1.10. Sažetak 28

<pb n="10"/>

1. Osnove Pascala

1.1. Uvod

Evo nas na početku vrlo zanimljivog putovanja — putovanja kroz programiranje programskim jezicima Pascal i Delphi. Iako je svaki programski jezik u mogućnosti ponuditi određenu količinu zabave i zadovoljstva, većini ljudi upravo Pascal i Delphi pružaju najveću količinu zabave.

Programiranje se ne može svrstati nikamo posebno, ono pokriva područja znanosti, umjetnosti, matematike i informatike. Pascal i Delphi programiranje oduvijek je bilo više zabava i užitak nego suhoparno programiranje.

Ova je knjiga rezultat mojega dugogodišnjeg hobija i ljubavi prema programskim jezicima Pascal i Delphi. Namijenjena je svim programerima i neprogramerima koje zanima detaljan i dubinski opis Pascala te detaljan uvod u svijet programiranja jezikom Delphi.

Područja programiranja koja su pokrivena u knjizi doista su stvarno raznolika. Knjiga započinje osnovnim uvodom u programiranje koji se katkada može učiniti i patronizirajućim, ali to nikako nije. Nakon uvoda u programiranje, tempo knjige malo se ubrzava, a ponovno se usporava kod jednog od najvećih neprijatelja programera diljem svijeta — pokazivača.

Dio knjige koji opisuje programski jezik Delphi temelji se na znanju stečenom u prvom dijelu knjige. U tom se dijelu proučavaju razne tehnike programiranja koje se primjenjuju danas. Na kraju toga dijela prikazano je stvaranje dvije dosta kompleksne Delphi aplikacije. Upravo ova dva poglavlja prikazuju osnovu današnjega programiranja profesionalnih aplikacija.

S obzirom na to da je ovo jedini dio knjige u kojemu imam slobodne ruke, htio bih to iskoristiti i zahvaliti Borlandu što nam je poklonio Delphi 7 Personal.

Nakon što se naoružamo dobrom voljom, entuzijazmom i logikom, jedino što još ostaje je da naučimo kako se pišu Pascal naredbe, gdje se pišu i što one rade, a za sve to zajedno treba manje vremena nego što je trebalo da se pročita ovaj odlomak.

I da ne zaboravim, dobrodošli u tim od tri milijuna Pascal i Delphi programera.

1.2. Povijest programskog jezika Pascal

Idejni tvorac programskog jezika Pascal bio je Niklaus Wirth, koji je osnovnu strukturu Pascala napravio još davne, 1968. godine. No, tek 1973. godine, pojavom prvoga priručnika za korisnike, Pascal postaje šire prihvaćen programski jezik. Prvotna zamisao jezika Pascal bila je da on bude programski jezik pomoću kojeg će se studenti i učenici moći jednostavno upoznati s programiranjem. Wirthov Pascal bio je poprilično jednostavan programski jezik s ograničenim mogućnostima za kreiranje samo jednostavnih programa. Doduše, imao je on i svojih prednosti u tome što je zahtijevao malo memorije i moglo ga se, u svakom slučaju, jednostavnije naučiti od assemblera.

Pascal je unaprjeđivan godinama i nakon mnogo godina napokon izlazi iz granica učionica. Pojavom Borlandove verzije Pascala, Turbo Pascal, 1984. godine, Pascal je doista postao jezik s kojim ste mogli profesionalno raditi i odmah, čim se pojavio, imao je jedan od najbržih kompilatora na svijetu.

<pb n="11"/>

Danas je Pascal, odnosno Object Pascal, programski jezik koji je ugrađen u najkvalitetnije okruženje za brzi razvoj aplikacija na svijetu, Borland Delphi. Današnji Pascal ima vrlo malo veze s originalnim Pascalom i ima nevjerojatan broj novih obilježja koje ćete proučavati u poglavljima ove knjige.

1.3. Struktura Pascal programa

Svaki Pascal program ima istovjetnu strukturu koje se moramo pridržavati da bi Pascal programi mogli funkcionirati. U starijim verzijama Pascal kompilatora, programeri su se u potpunosti morali držati te strukture. Turbo Pascal omogućuje lagano odstupanje od osnovne strukture programa kako bi omogućio jednostavnije pisanje izvornog koda (pisanje naredbi programskog jezika Pascal).

Struktura Pascal programa prikazana na slici 1.1. sadrži dosta opcionalnih dijelova, a samo je vrlo mali broj linija koda potreban da bi se napravio osnovni Pascal program. U primjeru 1.1, prikazan je najosnovniji Pascal program. To znači da je prigodom stvaranja novog Pascal programa najpametnije najprije utipkati te linije koda jer one čine osnovu baš svakog programa pisanog u Pascalu.

Ako malo bolje pogledamo primjer 1.1, vidjet ćemo da se on sastoji od vrlo malenoga broja riječi, neke su napisane masnim slovima, dok je jedna jedina riječ napisana normalnim slovima. Riječi koje su napisane masnim slovima nazivaju se rezerviranim ili ključnim riječima.

Rezervirane riječi dio su samog programskog jezika Pascal. One imaju određeno značenje i način na koji se koriste tijekom programiranja. Rezervirane riječi također tvore najosnovniji materijal koji treba svladati tijekom učenja nekog programskog jezika. U tablici 1.1. popisane su sve rezervirane riječi koje postoje u Pascalu.

<pb n="12"/>

Vratimo se sada primjeru 1.1. i osnovnom Pascal programu. Prva linija koda, program macak_Garfield, obvezna je u standardnom Pascalu, iako će Turbo Pascal bez ikakvih problema moći kompilirati i pokrenuti program čak i bez te linije koda. Rezervirana riječ program ima u Pascal programu samo informativno značenje. Rezerviranom riječi program definiramo ime programa, u ovom slučaju “macak_Garfield”. Svaka naredba završava točkom sa zarezom (;), osim naredbi koje se mogu pisati u više linija koda, poput if-then-else provjere.

Na kraju primjera 1.1. nalaze se još dvije linije koda: begin i end s točkom. Begin i end. čine osnovni blok Pascal programa. Begin označuje početak programa, a end. označuje kraj cijeloga programa. Sve naredbe kojima ćemo se koristiti tijekom programiranja pišu se između begin i end. linija koda.

Program prikazan u primjeru 1.1. potpuno je funkcionalan Pascal program, što znači da ga se bez ikakvih problema može kompilirati i pokrenuti. Ako želite, u to se možete uvjeriti odabirom izborničke opcije Run -> Run u Turbo Pascal editoru, ali se još uvijek ništa pametno neće prikazati na ekranu. Želimo li ispisati kakav podatak ili neku poruku na ekran, moramo naučiti kako se to radi.

<pb n="13"/>

1.4. Prvi pravi Pascal program

U Pascalu postoji naredba pomoću koje se podaci mogu prikazivati na ekranu, a zove se Writeln. Writeln se može koristiti u više svrha: ispis podataka na ekran, zapis podataka u datoteku, ispis vrijednosti, izraza i povratnih vrijednosti funkcija na ekran. O svemu tome moći ćete pročitati na vrijeme, a sada ćemo vidjeti samo jedan oblik korištenja naredbe Writeln — ispis jednostavnih tekstualnih poruka na ekran.

Na slici 1.2. prikazana je struktura naredbe Writeln, kada se njome koristimo za ispis tekstualnih poruka. Struktura naredbe Writeln promjenljiva je i ovisi o načinu korištenja.

Ako pogledate primjer 1.2, vidjet ćete vrlo jednostavan Pascal program koji ilustrira najjednostavnije korištenje naredbe Writeln.

Dakle, kao što je već spomenuto ranije, sve naredbe kojima ćemo se koristiti tijekom programiranja pišu se između begin i end. linija koda. Kada se pokrene ovaj program, ali i bilo koji drugi Pascal program, izvršavanje samog programa kreće od linije begin. Nakon begin linije koda, program se izvršava jednu po jednu liniju (točnije, jednu po jednu naredbu) sve dok ne dođe do end. linije. Kad se dosegne end. linija, završava se izvršavanje programa.

Trenutačno, u programu postoji samo jedna jedina linija koda — naredba Writeln. Pri korištenju naredbe Writeln, zagrade su obvezne, a sve što želimo ispisati kao tekst na ekran moramo staviti unutar jednostrukih navodnika.

Ako sada pokrenemo taj program, rezultat njegova izvršavanja bit će poruka Moj prvi Pascal program. No, ako pokrenemo program iz Turbo Pascal editora, rezultat izvršavanja programa nećemo vidjeti na ekranu jer će program prebrzo završiti, Turbo Pascal editor prekrit će rezultat izvršavanja programa. Da bismo vidjeli rezultat izvršavanja programa dok se nalazimo i radimo u Turbo Pascal <pb n="14"/>editoru, moramo pritisnuti kombinaciju tipaka Alt + F5 ili iskoristiti opciju Userscreen na izborniku Debug.

1.5.3. Osnovna komunikacija s korisnikom

Osnovna komunikacija s korisnikom postiže se korištenjem četiri različite naredbe. Dvije se koriste za ispis podataka ili poruka na ekran, a dvije za korisnički unos, kada mi (autori programa) želimo da korisnik unese podatak s kojim će program dalje raditi. Naredbe za učitavanje podataka upoznat ćemo nešto kasnije.

Naredbe koje se koriste za ispis podataka na ekran su Write i Writeln. Writeln smo već upoznali i znamo da se može koristiti za ispis jednostavnih tekstualnih poruka na ekran. Write je nova naredba koju još nismo upoznali, ali gotovo da i jesmo. Naime, naredbe Write i Writeln razlikuju se samo u jednom malom detalju.

Kad radimo s tekstom na računalu, neovisno o tome je li riječ o DOS ili Windows operativnom sustavu, za potrebe ispisa teksta na ekran, uvijek se koristi kursor tipkovnice, odnosno, kursor unosa teksta. Tijekom programiranja u Pascalu naredbom Write služimo se kada tekst želimo ispisati na ekran, ali kursor unosa ostaviti u istoj liniji. Ako tekst želimo ispisati na ekran i pomaknuti kursor u novi redak, koristit ćemo se naredbom Writeln (čiji je naziv kratica od Write Line).

Primjer 1.3. ilustrira funkcioniranje naredbe Write. Iako su sve naredbe Write napisane u zasebnim linijama koda, tekst koji će se prikazati na ekranu (rezultat izvršavanja programa) bit će ispisan u jednoj jedinoj liniji. Primijetite da na kraju prvih dviju tekstualnih poruka postoji jedan razmak viška. On nije potreban za funkcioniranje programa, nego za ljepši izgled poruke pri ispisu. Ako ne vjerujete, obrišite razmak i ponovno pokrenite program.

Zajedno s ovim primjerom bilo bi korisno zapamtiti još nešto: oblikovanje izvornog koda dodavanjem razmaka i praznih linija između naredbi nema nikakve veze s rezultatom izvršavanja programa, nego služi za poboljšanje preglednosti izvornog koda.

<pb n="15"/>

U primjeru 1.4. prikazan je način kombiniranja naredbi Write i Writeln, ali i jedan dodatni način korištenja naredbe Writeln.

Naredba Writeln, korištena bez teksta poruke i zagrada, služi za pomicanje kursora unosa u novi redak, čime dobivamo jednu praznu liniju pri ispisu.

Sad kad smo svladali ispisivanje podataka na ekran, možemo krenuti dalje, prema varijablama i učitavanju podataka.

1.6. Tipovi podataka

Prije nego zaronimo u svijet podataka, moramo znati s kojim sve tipovima podataka možemo raditi u Pascalu. Svaki tip podataka ima određen raspon vrijednosti s kojima radi, a također definira skup operacija koje tim podatkom možemo izvesti.

Korištenje raznih tipova podataka može se vrlo jednostavno usporediti sa svakodnevnim korištenjem raznih namirnica u kuhinji. Na primjer, kokošja su jaja prije potreban sastojak za palačinke, a banane su u tu svrhu potpuno neiskoristive. U suprotnom, banane su savršene za pravljenje frapea ili sladoleda, dok su kokošja jaja ovdje potpun promašaj. Ista je situacija i s tipovima podataka u Pascalu. Jedan je tip podataka prikladan za rad s tekstovima, dok je drugi pogodan za računanje.

U tablici 1.2. slijedi popis tipova podataka u Pascalu. Uz imena tipova podataka koji se koriste, također su navedeni raspon vrijednosti koje prepoznaje određeni tip podataka i količina bajtova koje zauzima varijabla tog tipa (o varijablama nešto kasnije, ali ubrzo).

<pb n="16"/>

Vrlo se rijetko u manjim programima koristi više od tri ili četiri tipa podataka, pa nema potrebe sada detaljno proučavati sve navedene tipove podataka. Najvažnije tipove podataka detaljno ćemo obraditi u ovom i sljedećim poglavljima.

1.7. Varijable

Došli smo do jednog od temeljnih pojmova u programiranju, a to su varijable. Varijable su pojednostavnjena imena za mjesta u radnoj memoriji računala u koja spremamo podatke. Varijable su temeljni alat koji koristimo da bismo sačuvali i radili s podacima tijekom izvršavanja programa.

Želimo li raditi s varijablama u programu, najprije ih moramo deklarirati.

1.7.1. Deklaracija varijabli

Varijable se deklariraju (stvaraju) da bismo u njih mogli spremati razne vrijednosti kojima se koristimo tijekom rada programa. Želimo li deklarirati varijable, moramo koristiti rezerviranu riječ var i poznavati pravila identifikatora.

Općenito, u Pascalu vrijedi pravilo da se sve mora definirati prije nego što se smije koristiti. To je pogotovo istinito za varijable. Ako se prisjetimo slike 1.1, koja <pb n="17"/>prikazuje strukturu Pascal programa, vidjet ćemo da za deklariranje varijabli postoji poseban dio, odmah iznad glavnoga bloka programa.

U primjeru 1.5, koji slijedi, prikazan je program u kojemu je deklarirana varijabla Integer tipa.

Iz prije navedenog primjera vidljivo je da se varijable deklariraju prije nego se iskoriste. Varijable se mogu navesti u istoj liniji gdje je i rezervirana riječ var, ali se obično pišu ispod rezervirane riječi var. Radi bolje preglednosti, najbolje bi se bilo držati oblikovanja deklaracija kojeg se pridržava ova knjiga – sve se varijable deklariraju ispod rezervirane riječi var.

Nakon što se navede rezervirana riječ var, možemo deklarirati onoliko varijabli koliko je potrebno. Nakon navedene rezervirane riječi var, Pascal kompilator sve će linije koda koje ne sadržavaju rezerviranu riječ prepoznati kao deklaraciju varijable. U slučaju programa u primjeru 1.5, Pascal kompilator će kao deklaracije varijabli prepoznati sve naredbe između linija koda koje sadržavaju rezervirane riječi var i begin.

Sad kad znamo gdje se deklariraju varijable, moramo znati kako se one deklariraju. Varijable imaju mnogo svojstava koja ćete naučiti tijekom programiranja. Neka moramo definirati odmah, a neka, skrivenija svojstva otkrit ćemo u daljnjim poglavljima. Svojstva varijabli koje moramo odmah postaviti (dakle, prije korištenja tim varijablama) su ime i tip podataka kojemu pripada varijabla.

Na slici 1.3. prikazan je način kako se deklariraju sve varijable.

1.7.2. Identifikatori

Identifikatori su riječi kojima imenujemo različite elemente naših programa: varijable, konstante, polja, tipove podataka, svojstva, procedure, programe i datoteke izvornog koda (unite ili module).

Postoji nekoliko pravila kojih se moramo pridržavati pri definiranju identifikatora:

— identifikatori su riječi bilo koje duljine, ali Pascal razumije samo prva 63 znaka (Delphi razumije 255 znakova)

— identifikatori se mogu stvarati pomoću svih slova engleske abecede (“a” -> “z” i “A” -> “Z”), brojeva (0 – 9) i znaka podvlake ( _ )

— prvo slovo u identifikatoru ne smije biti broj

— identifikator ne smije sadržavati ni jedan razmak (identifikator mora biti jedna riječ)

— identifikator ne smije biti jednak nekoj od rezerviranih riječi Pascala

— identifikatori se mogu pisati i velikim i malim slovima (ako definiramo identifikator <pb n="18"/>“pas”, Pascalu će biti svejedno napišemo li “PAS”, “Pas”, “pas” ili “pAS”.

Slijedi upozorenje za nepažljive: nakon što se u programu deklarira varijabla pod imenom “i” više ne smijemo deklarirati varijablu istog imena, nego moramo odabrati drugo ime.

U tablici 1.3. navedeni su primjeri dobrih i loših identifikatora, odnosno primjeri dobrih i loših imena varijabli.

Završili smo s deklaracijama varijabli. Vrijeme je da naučimo najosnovniji način rada s varijablama — zapisivanje vrijednosti u varijablu.

1.7.3. Operator pridjeljivanja vrijednosti

Operator pridjeljivanja vrijednosti najosnovniji je operator koji moramo naučiti da bismo mogli raditi s varijablama. Operator pridjeljivanja u Pascalu čine dva znaka, dvotočje iza kojeg odmah slijedi znak jednakosti “:=”. Operator pridjeljivanja koristimo u naredbi za pridjeljivanje kada određenu vrijednost želimo upisati u varijablu. Program u primjeru 1.6. koristi operator pridjeljivanja da bi u varijablu “i” zapisao broj 20.

Varijable se mogu smatrati kutijama u kojima se nalaze neke vrijednosti. Mi kao programeri radimo s varijablama tako da ih “pozivamo” i koristimo preko njihovih imena, dok program radi s podatkom koji je zapisan u samoj varijabli — nešto poput žumanjka i ljuske jajeta. Slika 1.4. prikazuje jedan od načina na koji se mogu prikazati varijable.

<pb n="19"/>

Sad kad smo svladali pridjeljivanje vrijednosti nekoj varijabli, svladat ćemo i način kako se vrijednosti varijabli ispisuju na ekran. Naredbe za ispisivanje već su poznate, a ispisivanje vrijednosti varijabli nije teško — naredbi Writeln samo se kaže ime varijable čiju vrijednost treba ispisati i ona će to napraviti bez problema. Primjer 1.7. prikazuje jednostavno ispisivanje vrijednosti varijable na ekran.

<pb n="20"/>

1.7.4. Osnovni aritmetički operatori

Svaki programski jezik ima skup znakova (operatora) koji se koriste za jednostavne aritmetičke operacije, pa tako i Pascal. Aritmetički operatori programskog jezika Pascal su:

1. + (zbrajanje),

2. – (oduzimanje),

3. div (dijeljenje cijelih brojeva),

4. * (množenje),

5. / (dijeljenje realnih brojeva),

6. mod (ostatak cjelobrojnog dijeljenja).

Operatori, varijable, konstante i funkcije služe za stvaranje izraza. Sljedeća linija koda vrlo je jednostavan izraz, a označuje naredbu za pridjeljivanje vrijednosti:

i := i + 5;

Ovom se naredbom vrijednost varijable i povećava za 5. Izrazi se čitaju slijeva nadesno.

Uz poznavanje operatora, također je potrebno znati njihovu hijerarhiju, odnosno redoslijed po kojemu će se obavljati operacije unutar nekog izraza. Kod aritmetičkih operatora, s kojima se sada upoznajemo, postoje dvije kategorije. Višoj kategoriji operatora pripadaju operatori *, /, div i mod, dok u nižu se kategoriju ubrajaju + i –.

Pogledajmo izraz:

i := 20 + 9 * 2;

Već je navedeno da se izrazi izračunavaju slijeva nadesno. To je istina sve dok se u izrazu ne pojavljuju operatori različitih važnosti ili dok se ne pojavljuju zagrade. U navedenom izrazu, najprije će se (po važnosti) izvršiti množenje brojeva 9 i 2, a tek će se tada taj rezultat zbrojiti s brojem 20 i na kraju pridijeliti varijabli “i”.

Slika 1.5. prikazuje način na koji se izvršavaju naredbe za pridjeljivanje. Na slici se može vidjeti da se za potrebe računanja stvara privremena memorijska lokacija u koju se zapisuju rezultati tijekom izračunavanja vrijednosti. Tek nakon što se obave sve aritmetičke operacije u izrazu dobivena se vrijednost pridjeljuje varijabli naredbe.

<pb n="21"/>

Sad ćemo vidjeti kako se u Pascal programu mogu koristiti aritmetički operatori. Program u primjeru 1.8. zbraja i ispisuje rezultat zbrajanja na ekran.

<pb n="22"/>

1.7.5. Dodatni načini rada s podacima

Ako želimo deklarirati više od jedne varijable istog tipa (recimo Integer), onda ih sve možemo deklarirati u jednoj liniji koda na sljedeći način:

U primjeru 1.9. vidimo da se aritmetički izrazi mogu pisati čak i unutar naredbe za ispis.

Naredba Writeln može odjednom ispisati više vrijednosti, samo je bitno da se različite vrijednosti odvoje zarezima. Dakle, ispis više vrijednosti odjednom korištenjem naredbe Writeln izgleda ovako:

Writeln(prvi_podatak, drugi_podatak, treci_podatak);

<pb n="23"/>

Program koji slijedi u primjeru 1.10. prikazuje korištenje svih aritmetičkih operatora.

1.7.6. Učitavanje podataka

Nešto prije u knjizi rečeno je da se osnovna komunikacija s korisnikom u Pascalu postiže korištenjem četiri naredbe, dvije za ispisivanje koje smo već naučili, te dvije za učitavanje koje ćemo upravo naučiti. Te dvije naredbe, kojima ćemo se koristiti za učitavanje podataka, su Read i Readln.

Naredba Read koristi se kada korisnik u istoj liniji treba utipkati više vrijednosti (vrijednosti su odvojene razmacima), dok se Readln najčešće koristi kada želimo učitavati tekstualne vrijednosti. No, naredba Read također se može koristiti za učitavanje tekstualnih vrijednosti, pri čemu će Read nakon učitavanja ostaviti kursor unosa u istoj liniji, dok će naredba Readln prebaciti kursor unosa u novu liniju.

Učitavanje vrijednosti nije veliki problem. Naredbi Read potrebna je varijabla u koju će spremiti vrijednost. Pri izvršavanju aplikacije, korištenje naredbi Read i Readln privremeno zaustavlja program — sve dok korisnik ne utipka potrebne <pb n="24"/>vrijednosti i pritisne tipku Enter na tipkovnici. Pritiskom tipke Enter korisnik potvrđuje da je učitavanje potrebnih vrijednosti završeno, a time se završava i posao koji radi Read naredba.

Sada ćemo pokušati napraviti jedan jednostavan program koji će od korisnika tražiti unos tri različita broja: dana, mjeseca i godine rođenja. Nakon što korisnik unese sve tri potrebne vrijednosti, program ih mora lijepo formatirati i ispisati na ekran.

Sad kada znamo učitavati i ispisivati vrijednosti pomoću Pascala, možemo krenuti na rješavanje nekih jednostavnijih svakodnevnih problema. Prvi problem koji ćemo riješiti je izračunavanje PDV-a za artikle u trgovini. Ni jedan problem koji rješavamo na računalu nema neki strogo definirani put kojim se dolazi do rješenja. Uzevši to u obzir, pogledajmo što nam je potrebno za rješavanje ovoga problema.

Najprije, program od korisnika mora tražiti veleprodajnu cijenu. Cijene različitih artikala izražene su u kunama i lipama, a to zahtijeva korištenje realnih brojeva — recimo Real tip podataka. Nakon što se učita veleprodajna cijena, mora joj se dodati još 22% i ispisati vrijednost na ekran.

U primjeru 1.12. vidjet ćemo rješenje navedenoga problema, ali i nekolicinu novosti koje ću objasniti nakon što pogledamo primjer.

<pb n="25"/>

Cijeli program nije velik ni kompliciran. Samo je jedna linija koda potrebna da se riješi računski dio problema,

cijenaPDV := cijena * 1.22, pomoću koje u varijablu cijenaPDV upisujemo 122% originalne cijene.

Naredba Writeln ponovno nas iznenađuje s još dodataka. Dodaci koji se vide u primjeru 1.12. služe samo za formatiranje ispisa podataka na ekran, a mogu se predstaviti ovako:

vrijednost:broj_decimala

Program u primjeru 1.13. prikazuje način korištenja ovog, dodatnog znaka za formatiranje ispisa. Vidljivo je da umjesto jednog mjesta, koliko je predviđeno za brojeve korištene u primjeru, naredba Writeln ispisuje znamenke tako da zauzimaju 6 mjesta. Dakle, ako ispisujemo podatak koji je veći od onoga koji postavimo, formatiranje koje smo naveli u potpunosti se zanemaruje.

<pb n="26"/>

Oznakama za formatiranje možemo se koristiti i za ispisivanje realnih brojeva, kao što je vidljivo u primjeru 1.12. Broj iza prvog dvotočja označuje broj znakova koji se ispisuju ispred decimalnog zareza (decimalne točke), dok broj iza drugog dvotočja označuje broj znakova koji će se ispisivati iza decimalnog zareza.

Obratimo pažnju na predzadnju liniju koda u primjeru 1.13. Riječ je o pozivu naredbe Readln. Iako smo prije naveli da naredbi Readln trebamo uvijek u zagradi navesti varijablu u koju će učitati vrijednost, Readln se može koristiti, kao i naredba Writeln, bez zagrada. Koristeći se naredbom Readln bez zagrada, natjerat ćemo program da stane i čeka sve dok korisnik ne pritisne tipku Enter na tipkovnici. Ako se koristimo naredbom Readln na kraju cijeloga programa, kao što je navedeno u primjeru 1.13, program se neće prestati izvršavati sve dok ne pritisnemo tipku Enter. Naredbu Readln koristimo kada želimo pogledati rezultat cijeloga programa, pa više nećemo morati toliko često koristiti Alt + F5 da bismo vidjeli rezultat.

Primjer koji moramo pogledati prije kraja prvog poglavlja je primjer učitavanja teksta, a slijedi u primjeru 1.14.

<pb n="27"/>

1.8. Konstante

Prije nego što završimo s prvim poglavljem, moramo upoznati još jedan vrlo mali dio Pascala, a to su konstante. Konstante su vrlo korisna stvar jer u nekim situacijama (čitaj: bilo kojem malo većem projektu) mogu uštedjeti mnogo vremena i riješiti nas mnogo glavobolje. Konstante bismo najjednostavnije mogli nazvati identifikatorima čija je vrijednost nepromjenljiva tijekom izvršavanja programa (za razliku od varijabli). U posebnim okolnostima konstantama možemo, kao varijablama, mijenjati vrijednosti.

Konstante se deklariraju u posebnom dijelu programa, koji započinje rezerviranom riječi const. Evo kako izgleda deklaracija nekoliko jednostavnih konstanti.

const

BrojPonavljanja = 10;

PseceGodine = 7;

MjeseciUGodini = 12;

AE = ‘Albert Einstein’;

Ono što je bitno zapamtiti je da se za deklaraciju konstante ne koristi operator pridjeljivanja, nego samo znak jednakosti.

Nešto prije u ovom poglavlju napravili smo program koji računa maloprodajnu cijenu nekog artikla. Recimo da želimo napraviti program koji će vrijednost PDV-a koristiti na više mjesta. Ako napišemo direktnu vrijednost na više mjesta, u većini slučajeva sami ćemo sebi napraviti problem — moguće je da će se vrijednost PDV-a promijeniti. Recimo da se vrijednost PDV-a smanji na 18%. Tada bismo na svim tim mjestima 22% morali promijeniti u 18%.

Evo kako izgleda program koji se koristi konstantama umjesto direktnim vrijednostima.

<pb n="28"/>

U primjeru 1.15. naveden je program koji vrijednost PDV-a koristi pet puta. Recimo da se kojim slučajem PDV promijeni ili ukine, korištenjem konstante ne moramo mijenjati algoritam. Recimo da se PDV ukine, cijeli bi se program mogao promijeniti u vrlo kratkom vremenu, tako što bismo liniju PDV = 1.22 promijenili u PDV = 1.

1.9. Komentari

Komentari su dijelovi izvornog koda koji se potpuno izbjegavaju tijekom kompilacije programa i služe programerima za objašnjavanje dijelova koda i stvaranje osnovne dokumentacije projekta.

Komentari u Pascalu mogu se pisati unutar vitičastih zagrada

{ Pascal komentar }

ili unutar zagrada sa zvjezdicama

(* Pascal komentar, verzija 2 *)

1.10. Sažetak

Ovo je poglavlje bilo namijenjeno najosnovnijim elementima programskog jezika Pascal. U njemu su predstavljene samo najosnovnije informacije koje je jednostavno zapamtiti i na kojima će se temeljiti sadržaj svih ostalih poglavlja. Prije nego što krenemo na sljedeće poglavlje, riješimo nekoliko zadataka koji služe za ponavljanje i utvrđivanje naučenog.

Pitanja i zadaci

Pitanje 1: Kojom rezerviranom riječi imenujemo cijeli program?

Pitanje 2: Pripada li dio u kojem deklariramo varijable obveznom ili opcionalnom dijelu programa Pascal?

Pitanje 3: Nabrojite najmanje pet rezerviranih riječi Pascala.

Pitanje 4: Kojom se naredbom koristimo za prikaz neke tekstualne informacije na ekranu?

<pb n="29"/>

Pitanje 5: Kojom kombinacijom tipaka na tipkovnici možemo prikazati rezultat izvršenja programa?

Pitanje 6: Koja naredba ispisuje tekst na ekran bez pomicanja kursora u novi redak?

Pitanje 7: Nabrojite najmanje tri Pascalova tipa podataka.

Pitanje 8: Što je to varijabla?

Pitanje 9: Kojom se rezerviranom riječi koristimo za stvaranje varijabli?

Pitanje 10: Čemu služi operator pridjeljivanja i kako on izgleda?

Pitanje 11: Ako na ekran želimo ispisati vrijednost neke varijable, moramo li ime varijable napisati unutar jednostrukih navodnika? Zašto?

Pitanje 12: Koji su identifikatori netočni?

a) krumpir

b) begin

c) 1slovo

d) prvi broj

e) x!

f) movie

Zadatak 1: Napišite program koji ispisuje poruku “Ovo je Pascal program.” na ekran.

Zadatak 2: Pronađite pogrešku:

progrem MojPrviProgram

begin.

Writeln(Moj prvi Pascal program.):

end.

Zadatak 3: Napišite program koji će ispisivati zbroj dviju Integer varijabli na ekran. Varijable se zovu “prvi_broj” i “drugi_broj”. U varijabli “prvi_broj” mora biti zapisan broj 10, a u varijabli “drugi_broj” mora biti zapisan broj 12.

<pb n="30"/>

<pb n="31"/>

2. Grananje i ponavljanje

2.1. Naredba if 32

2.1.1. Naredba if then else 34

2.1.2. Višestruka if provjera vrijednosti 38

2.2. Logički operatori 40

2.2.1. Operator not 40

2.2.2. Operator and 41

2.2.3. Operator or 43

2.2.4. Operator xor 43

2.3. Case provjera 46

2.3.1. Case-else 47

2.3.2. Višestruka case provjera 48

2.4. For petlja 51

2.5. Repeat-until petlja 58

2.6. While petlja 61

2.7. Iskakanje iz petlji 62

2.8. Sažetak 64

<pb n="32"/>

2. Grananje i ponavljanje

U ovom ćemo se poglavlju baviti malo zabavnijim stvarima. Vidjet ćemo kako provjeriti razne vrijednosti koje nam korisnici programa mogu unijeti i kako neke operacije ponoviti desetke ili stotine puta.

2.1. Naredba if

Provjera vrijednosti varijable ili izraza u Pascalu izvršava se pomoću naredbe if. Naredba if služi uvjetnom izvršavanju jedne ili više naredbi, a takvo ćemo uvjetno izvršavanje naredbi upravo vidjeti.

Unutar naredbe if koriste se relacijski operatori pomoću kojih utvrđujemo kakva se vrijednost nalazi zapisana u nekoj varijabli. Relacijski operatori Pascala su:

Najjednostavnija provjera koja utvrđuje istinitost nekog uvjeta može se prikazati ovako:

if uvjet_istinit then

naredba_koja_se_izvršava_ako_je_uvjet_istinit;

Sada ćemo vidjeti program koji prikazuje način primjene if provjere. Program prikazan u primjeru 2.1. provjeravat će broj koji korisnik unese. Ako korisnik unese broj 5, program će mu prikazati poruku o točno unesenom broju, služeći se if provjerom da bi to postigao.

<pb n="33"/>

Kao što je vidljivo u primjeru 2.1, program će ispisati poruku na ekran ako je učitani broj 5. Ako se ne unese broj 5, program neće učiniti ništa jer se linija koda Writeln(‘Unijeli ste tocan broj!’); poziva i izvršava samo ako je broj jednak 5. Slika 2.1. prikazuje tijek izvršenja programa u primjeru 2.1.

Ako korisniku želimo napisati poruku o tome da je unio pogrešan broj, sa sadašnjom razinom znanja to možemo učiniti primjenom još jedne if provjere.

Program koji slijedi u primjeru 2.2. rješava problem ispisivanja poruke ako korisnik unese pogrešan broj. Postoji brži i bolji način rješavanja ovoga problema, a program u primjeru 2.2. može se smatrati samo prikazom jednog od načina kako se neki problem može riješiti.

<pb n="33"/>

Bolji način na koji možemo riješiti program prikazan u primjeru 2.2. bio bi primjenom malo drukčije verzije if naredbe.

2.1.1. Naredba if-then-else

Naredba if-then-else koristi se kada želimo da program reagira na ispunjen i neispunjen uvjet. if-then-else provjera izgleda ovako:

if uvjet_istinit then

naredba_ako_je_sve_u_redu

else

poruka_o_pogrešci_ili_sličan_kod;

Sad ćemo, koristeći se if-then-else provjerom, napraviti program koji provjerava unos jednog slova abecede. Provjeravat ćemo je li korisnik dobro unio veliko slovo “A” ili nije.

Program u primjeru 2.3. prikazuje nam dosta novosti koje ćemo morati zapamtiti jer su bitne. U tom se primjeru može vidjeti korištenje char tipa podataka. Char tip podataka koristimo kada želimo raditi sa samo jednim jedinim znakom. Ako trebamo raditi s više znakova, onda se za takav podatak koristi varijabla tipa string. Svi tekstualni podaci u Pascalu pišu se unutar jednostrukih navodnika.

Uz primjer korištenja char tipa podatka, program u primjeru 2.3. također prikazuje način na koji se koristi rezervirana riječ else. Najbitnija stvar koju moramo zapamtiti je da se linija ispred else NE SMIJE ZAVRŠITI točkom sa <pb n="35"/>zarezom. Pogledamo li liniju koda Writeln('Hvala'), vidimo da ona ne završava točkom sa zarezom. Stavimo li točku sa zarezom na kraj te linije, napravit ćemo sintaktičku pogrešku i naš se Pascal program više neće moći pokrenuti.

U primjeru 2.4, koji slijedi, možemo vidjeti program koji provjerava koji je od dvaju brojeva veći primjenom if-then-else provjere.

Ako pogledamo dosadašnje primjere, svi naši odgovori na razne uvjete sastojali su se od jedne jedine linije koda. Kada krenemo s ozbiljnijim primjerima, bit će potrebno i desetak linija koda za dobro rješenje problema. U tom slučaju, kada je više linija koda logički povezano, te linije koda stavljamo u blok. Da bolje razumijemo zašto i kada je potrebno koristiti blok, pogledajmo program u primjeru 2.5. Taj primjer nije iskoristiv u pravom programu jer sadrži jednu logičku pogrešku (a te su najgore). Program u primjeru traži unos jednoga broja manjeg od 10. Nakon unosa, program ispisuje poruku od dviju linija teksta.

<pb n="36"/>

Ako pokrenemo ovaj program i unesemo broj 2 kada nas to program zatraži — sve će biti u redu. Nakon što se pomoću if provjere utvrdi da je broj 2 manji od 10, izvršit će se linija koja na ekran ispisuje da je broj 2 manji od 10, a odmah za njom i linija koja ispisuje status.

Ako pokrenemo program i unesemo broj 24, što će se dogoditi? S obzirom na to da je 24 očito veći od 10, ništa se ne bi trebalo ispisati — ali ipak će se nešto ispisati. If provjera vezana je samo uz jednu liniju koda. Linija koda koja ispisuje status izvršit će se apsolutno uvijek, neovisno o tome što je zapisano u varijabli broj. Želimo li povezati liniju koda koja ispisuje status s if provjerom, onda ćemo sve Writeln linije nakon if provjere morati staviti u blok naredbi.

I, napokon, blok naredbi piše se ovako:

begin

naredba_1;

naredba_2;

naredba_n;

end;

Popravljeni program iz primjera 2.5. smješta obje linije koda u zaseban blok naredbi, čime obje naredbe Writeln povezuje s if provjerom.

Naravno, blok naredbi možemo pisati i kada koristimo else dio if provjere, uz napomenu da se takva if-then-else provjera piše ovako:

if uvjet then

begin

naredba_1;

<pb n="37"/>

naredba_2;

end else

begin

else_naredba_1;

else_naredba_2;

end;

U primjeru koji slijedi prikazana je primjena većeg broja if provjera. Pisanjem if provjera unutar drugih if provjera postiže se filtriranje podataka koje je vrlo često nužno u programima. Filtriranje podataka povećava složenost programa.

<pb n="38"/>

2.1.2. Višestruka if provjera vrijednosti

Uz jednostavne provjere vrijednosti, kada testiramo je li uvjet ispunjen ili nije, if nam nudi stvaranje kompleksnije (višestruke) provjere. Višestruka nam provjera omogućuje da pomoću jedne if provjere testiramo više uvjeta i po potrebi odgovorimo na svaki uvjet koji provjeravamo. Višestruka if provjera vrijednosti piše se ovako:

if uvjet1 then

naredba_ako_je_uvjet1_točan

else if uvjet2 then

naredba_ako_je_uvjet2_točan

else if uvjet3 then

naredba_ako_je_uvjet3_točan

else

naredba_ako_nijedan_uvjet_nije_bio_točan.

Zadnja provjera nije obvezna. Nju možemo dodati višestrukoj if provjeri kao sigurnosnu mjeru protiv korisnika koji slučajno ili namjerno utipkaju pogrešne vrijednosti. Krajnji else izvršava se samo ako ni jedan raniji uvjet nije bio točan.

Program u primjeru 2.8. ilustrira primjenu višestruke if provjere. Program traži od korisnika unos broja od 1 do 5 i ispisuje tekstualnu vrijednost toga broja.

<pb n="39"/>

Sljedeći će se program koristiti if provjerom kako bi korisniku zadao zagonetku. Program u primjeru 2.9. nešto je veći, ali nije težak i potrebno ga je cijelog pročitati i proučiti jer prikazuje razne načine i primjene if provjera.

<pb n="40"/>

2.2. Logički operatori

Logičke operatore koristimo kada trebamo stvoriti složenije uvjete za izvršenje određenog dijela koda. U Pascalu postoje četiri logička operatora, a to su: and, or, xor i not.

Logički operatori se koriste s logičkim (Boolean) vrijednostima i kao rezultat svojeg rada vraćaju programu logičku vrijednost. Prvi i najjednostavniji logički operator koji ćemo obraditi je operator not.

2.2.1. Operator not

Operator not predstavlja logičku operaciju NE. On je unarni operator, što znači da ga koristimo s jednom jedinom logičkom vrijednosti. Korištenjem operatora not invertiramo jednu logičku vrijednost. Ako je logička vrijednost False, korištenjem operatora not dobit će se rezultat True. Tablica 2.2. prikazuje djelovanje operatora not:

<pb n="41"/>

Vrlo jednostavan program opisan u primjeru 2.10. prikazuje korištenje operatora not.

Ako pogledamo program u primjeru 2.10, možemo vidjeti da se not operator može primjenjivati u if provjeri i unutar naredbe za pridjeljivanje vrijednosti. U komentarima je točno objašnjeno što znači svaki od načina pisanja koda. Korištenje not operatora za provjeru False vrijednosti smatra se poprilično elegantnim jer skraćuje pisanje koda.

Svi ostali logički operatori koriste dvije vrijednosti, odnosno dva uvjeta. Nakon operatora not, upoznat ćemo operator and.

2.2.2. Operator and

Operator and predstavlja logičku operaciju I. On se koristi u slučajevima kada provjeravamo dva uvjeta i kada oba uvjeta moraju biti točna. U profesionalnom se programiranju operator and koristi kada se želimo osigurati da su svi potrebni uvjeti točni prije nego se pokrene određeni dio koda. Tablica 2.3. prikazuje <pb n="42"/>djelovanje operatora and.

Kao što vidimo u tablici 2.3, krajnji rezultat and operatora bit će True samo ako su oba uvjeta istinita.

Program u primjeru 2.11. ilustrira jedan od mogućih načina korištenja operatora and. Program će od korisnika zahtijevati unos dvaju brojeva koji moraju biti različiti od 0. Ako su različiti od nule, program će na ekran ispisati njihov zbroj, a ako je jedan od njih jednak nuli, program će ispisati poruku o pogrešci. Pri korištenju operatora and treba zapamtiti da se svaki uvjet mora staviti unutar zagrada. Ako svaki uvjet ne stavimo unutar zagrada, kompilator će prijaviti pogrešku. Dakle, kada koristimo operator and unutar if provjere, sintaksa if provjere izgleda ovako:

if (uvjet1) and (uvjet2) then

begin

naredbe_ako_su_oba_uvjeta_istinita;

end;

Slika 2.2. ilustrira funkcioniranje programa prikazanog u primjeru 2.11.

<pb n="43"/>

Sljedeći logički operator koji moramo naučiti koristiti je operator or.

2.2.3. Operator or

Operator or predstavlja logičku operaciju ILI. On se koristi kada želimo provjeriti više uvjeta, ali kada je dovoljno da samo jedan od njih bude istinit. Operator or u profesionalnom se programiranju koristi kada je potrebno provjeriti nekoliko uvjeta i kada je samo jedan jedini od tih uvjeta dovoljan da bi se izvršio određeni dio koda. Tablica 2.4. prikazuje operator or.

Kao što je vidljivo iz tablice 2.4, operator će vratiti False vrijednost samo u slučaju ako se ne ispuni ni jedan navedeni uvjet. Sad ćemo vidjeti program koji ilustrira korištenje višestruke if provjere uz primjenu operatora or.

<pb n="44"/>

2.2.4. Operator xor

Zadnji logički operator koji ćemo upoznati je operator xor. Operator xor se još naziva ekskluzivnim or operatorom jer je nešto malo zahtjevniji od običnog operatora or. Obični operator or zahtijeva da bar jedan od uvjeta bude istinit.

Operator xor zahtijeva da samo jedan od uvjeta bude istinit. Ako su oba uvjeta <pb n="45"/>istinita, xor će vratiti False vrijednost. Tablica 2.5. prikazuje istinitosnu tablicu operatora xor.

Sljedeći primjer prikazuje način na koji funkcionira operator xor. Taj se operator ne koristi često u programiranju. Dok ne postanete bolji u programiranju (dok ne krenete proučavati razne optimizacijske tehnike), operator xor u većini će vam slučajeva biti nepotreban.

Program koji slijedi u primjeru 2.13. zahtijeva od korisnika da unese dva broja, no želimo li da se izvrši kod vezan uz if provjeru i operator xor, jednu od vrijednosti morat ćemo unijeti pogrešno.

<pb n="46"/>

Sad smo napokon došli do kraja if provjere. If provjere vrlo su brze (govorimo o vremenu izvršavanja) i veoma korisne kada moramo provjeravati malen broj vrijednosti. No, kad moramo provjeriti pet ili više vrijednosti, višestruka if provjera vrijednosti polagano postaje prevelika, nečitljiva i spora. Srećom, Pascal ima rješenje i za taj problem. Kada želimo brzo, učinkovito i uz što manje pisanja koda provjeriti veći broj vrijednosti, koristit ćemo se drugim načinom provjeravanja vrijednosti — case provjerom.

2.3. Case provjera

Case provjera koristi se umjesto if provjere kada želimo provjeriti više vrijednosti neke varijable ili izraza. Case provjera se izvršava malo brže od if provjere i jednostavnija je za pisanje (i kasniju analizu). Želimo li napraviti program koji će učitati broj od 1 do 5 i ispisati ga u tekstualnom obliku na ekran, možemo iskoristiti if provjeru, ali će cijeli program izgledati nepotrebno kompliciran. Ako pogledamo primjer 2.14, vidjet ćemo kako izgleda taj program napisan pomoću if provjere.

Za rješavanje ovakvoga problema mnogo je bolje koristiti case provjeru. Case provjera izgleda ovako:

<pb n="47"/>

case Varijabla of

Vrijednost1: naredba;

Vrijednost2: naredba;

Vrijednost3: begin

naredba1;

naredba2;

end;

end; { end; se obavezno piše na kraju case provjere }

Isti program koji ispisuje tekstualni naziv brojeva od 1 do 5 prikazan je u primjeru 2.15, no ovaj put program je napisan pomoću case provjere.

2.3.1. Case-else

Isto kao što if provjerom možemo testirati različite uvjete i stanja varijabli, tako i case provjera ima nekoliko kvalitetnih svojstava, koja nam život čine jednostavnijim. Case provjera može također imati else dio pomoću kojeg možemo reagirati na vrijednosti koje nismo uključili u provjeru.

Struktura case provjere, kada se u njoj nalazi i else, izgleda ovako:

case Varijabla of

Vrijednost1: naredba;

Vrijednost2: naredba;

Vrijednost3: naredba;

else

naredba;

end;

Bitna karakteristika else dijela case provjere je ta što u ovom slučaju rezervirana riječ else dopušta da se u liniji koda ispred nje nalazi točka sa zarezom na kraju. Sljedeći program zahtijevat će od korisnika unos prvog ili <pb n="48"/>zadnjeg slova engleske abecede (a ili z). Program mora provjeravati samo mala slova i, u slučaju pogrešno unesene vrijednosti, mora ispisati odgovarajuću poruku.

2.3.2. Višestruka case provjera

Kao što postoji i višestruka if provjera, tako i case provjerom možemo provjeriti više vrijednosti istodobno. Sljedeći problem najprije ćemo riješiti korištenjem if provjere. Program koji treba napraviti traži od korisnika unos prvog, drugog ili trećeg slova abecede. Slova mogu biti mala ili velika. Rješenje problema korištenjem if provjere prikazano je u primjeru 2.17.

<pb n="49"/>

Case provjera posjeduje još jedan način provjere vrijednosti, a to je primjenom liste vrijednosti koje su međusobno odvojene zarezom. Case provjera kojom možemo provjeriti više vrijednosti odjednom izgleda ovako:

case Varijabla of

Vrijednost1, Vrijednost2: naredba;

Vrijednost3, Vrijednost4, Vrijednost5: naredba;

Vrijednost6: naredba;

else

naredba;

end;

Program koji slijedi u primjeru 2.18. rješava isti problem kao i program prikazan u primjeru 2.17. Jedna stvar koju možemo uočiti je da je primjenom case provjere program mnogo jednostavniji za čitanje, razumijevanje i eventualno kasnije održavanje i unaprjeđivanje.

Naredba case omogućuje i provjeravanje raspona vrijednosti. Program kojim ćemo ilustrirati provjeru raspona vrijednosti mora provjeriti veći broj raspona. Program zahtijeva unos podatka o dobi neke osobe i na temelju toga broja ispisuje kojoj dobnoj skupini otprilike pripada osoba te dobi (dijete, učenik, srednjoškolac, <pb n="50"/>student, zaposlenik, umirovljenik). Slijedi tablica vrijednosti kojima ćemo se koristiti u if i case verzijama ovoga programa.

<pb n="51"/>

Kao što je vidljivo u primjeru 2.19, provjera raspona moguća je bez poteškoća s if provjerom, ali bez malo većeg staža u Pascal programiranju nije ju jednostavno napisati, a niti izmijeniti ako se za to pokaže potreba. Jednostavnije pisanje koda opet nam omogućuje case provjera pomoću koje se raspon vrijednosti provjerava ovako:

case Varijabla of

PocetnaVrijednost1..KrajnjaVrijednost1: naredba;

PocetnaVrijednost2..KrajnjaVrijednost2: naredba;

end;

Kod provjere raspona vrijednosti korištenjem case provjere bitno je ne ponoviti već postojeću provjeru jer će se kompilator pobuniti (ako se Pascal kompilator kojim slučajem ne pobuni — Delphi kompilator će to sigurno napraviti). Korištenjem provjere raspona 0..6 ne smijemo provjeriti vrijednosti 6..15, nego 7..15 jer se vrijednost 6 već provjerava u prvom rasponu vrijednosti. U primjeru 2.20, koji slijedi, točno je prikazano korištenje case provjere raspona vrijednosti.

2.4. For petlja

Do sada smo se susretali s programima u kojima su se naredbe izvršavale samo jednom. Sada je vrijeme da se pozabavimo ponavljanjem operacija, odnosno petljama bez kojih nema ni jednog imalo složenijeg programa.

<pb n="52"/>

Prva petlja koju ćemo obraditi zove se for petlja. Od svih petlji koje postoje u Pascalu, ona je najjednostavnija. For petljom koristimo se kada nam je broj ponavljanja unaprijed poznat. Uz for petlju obvezno moramo koristiti jednu varijablu (obično Integer tipa) koja će for petlji služiti kao brojač ponavljanja. For petlja izgleda ovako:

for brojac := pocetna_vrijednost to krajnja_vrijednost do

naredba;

Program u primjeru 2.21. koristi se for petljom da bi na ekran ispisao brojeve od 1 do 20.

For petlja napisana u Pascalu izgleda vrlo jednostavno, ali interno — ona je poprilično kompleksna i mnogo toga radi umjesto programera.

Pri izvršavanju for petlje prvo što se dogodi je početna inicijalizacija vrijednosti brojača. Brojač se na početku for petlje postavlja na vrijednost koja je zapisana odmah iza operatora pridjeljivanja, a u ovom primjeru to je vrijednost 1. Nakon što se zapiše početna vrijednost, for petlja izvršava naredbu koja joj je zadana, u ovom primjeru ispisuje tekst “Ovo je ponavljanje broj 1.”. Nakon što se naredba izvrši, for petlja provjerava stanje brojača, točnije, for petlja provjerava je li vrijednost u brojaču jednaka krajnjoj vrijednosti koju smo zadali. Ako for petlja utvrdi da je vrijednost brojača jednaka krajnjoj vrijednosti, to će značiti da je for petlja završena i program može nastaviti s izvršavanjem ostalih naredbi iza petlje (ako ih ima). Ako for petlja utvrdi da je brojač još uvijek manji od krajnje vrijednosti, to će značiti da for petlja ima još posla. Tada for petlja povećava vrijednost brojača za jedan i ponovno izvršava naredbu koja joj je zadana. Ovaj se krug ponavlja sve dok brojač ne postane jednak krajnjoj vrijednosti.

Funkcioniranje for petlje prikazano je na slici 2.3.

<pb n="53"/>

For petlja navedena u primjeru 2.21. izgleda vrlo jednostavno i ponavlja jednu jedinu liniju koda. Želimo li ponoviti više linija koda, njih ćemo smjestiti u blok naredbi. Struktura for petlje, kada želimo ponoviti više operacija, izgleda ovako:

for varijabla := početak to kraj do

begin

naredba1;

naredba2;

naredba3;

end;

Sada ćemo vidjeti program koji će pomoću for petlje izračunati zbroj prvih deset brojeva. Tijekom zbrajanja program će nas obavještavati o broju s kojim trenutačno radi i o vrijednosti zbroja. Taj je program prikazan u primjeru 2.22.

<pb n="54"/>

Sad ćemo for petlju upotrijebiti zajedno s nekom provjerom. Nismo valjda pročitali mnoštvo stranica o provjerama a da ih sad ne iskoristimo? Sljedeći program ima zadatak da na ekran ispiše imena svih mjeseci u godini primjenom for petlje i case provjere. Pažljivo proučite ovaj primjer.

Program u primjeru 2.23. koristi se naredbom Writeln za ispisivanje imena mjeseca, koja je napisana čak dvanaest puta. Da bismo ubrzali pisanje programa, u takav program obično dodajemo string varijablu u koju zapisujemo podatke.

<pb n="55"/>

Uvođenjem te, dodatne varijable, naredbu Writeln morat ćemo napisati samo jednom. Malo unaprijeđena verzija programa iz primjera 2.23. nalazi se u primjeru 2.24.

For petlja je prikladna za upoznavanje ASCII tablice znakova koja se često koristi u programiranju. ASCII (American Standard Code for Information Exchange) tablica je tablica koja raznim znakovima, slovima i brojevima dodjeljuje numeričke vrijednosti. ASCII tablica sastoji se od 256 znakova (0 do 255).

Program koji slijedi u primjeru 2.25. koristit će se funkcijom Chr, koju još nismo upoznali, da iz numeričke vrijednosti, ASCII koda, stvori znak.

<pb n="56"/>

For petlja može se pisati na dva načina, tako da broji unaprijed i unatrag. Do sada smo upoznali for petlju koja pomoću rezervirane riječi to broji unaprijed. For petlja koja broji unatrag koristi se rezerviranom riječi downto i izgleda ovako:

for varijabla := početna downto krajnja_vrijednost do

naredba;

ili

for varijabla := početna downto krajnja_vrijednost do

begin

naredba1;

naredba2;

end;

Pri korištenju for-to petlje, početna vrijednost uvijek mora biti manja od krajnje vrijednosti ako želimo da petlja funkcionira. Kod obrnute petlje početna vrijednost mora biti veća od krajnje vrijednosti ako želimo da petlja funkcionira. Ako su početna i krajnja vrijednost identične, petlja će se izvršiti samo jednom.

Uzmimo u obzir jednostavan programčić koji će odbrojavati sekunde, zadnjih 10 sekunda prije početka leta na Mars. Ako bismo ga radili for-to petljom, izgledalo bi ružno. Taj je programčić prikazan u primjeru 2.26.

<pb n="57"/>

Ako iskoristimo obrnutu for petlju za rješenje gornjega problema, nećemo se morati koristiti jednom privremenom Integer varijablom za kalkuliranje obrnutog odbrojavanja jer će sama for petlja to učiniti za nas. U primjeru 2.27. prikazano je nešto kraće i jasnije rješenje istoga problema.

Dio poglavlja vezan uz for petlju zaključit ćemo s pravim, korisnim i funkcionalnim programom — programom koji ispisuje tablicu temperatura u Fahrenheitovim i Celzijevim stupnjevima.

Program mora ispisivati tablicu temperatura od –20 do 120 Celzijevih stupnjeva (–20, –10, 0, 10 ...). Uz ispisivanje Celzijevih stupnjeva, Celzijeve stupnjeve mora konvertirati u Fahrenheitove i njih također ispisati na ekran. Formula za preračunavanje Celzijevih stupnjeva u Fahrenheitove glasi: Fahrenheit := 32 + Celzijus * 9 div 5.

Uz ispis tablice, program mora naglasiti da je voda u smrznutom stanju na 0 Celzijevih stupnjeva, a da je u plinovitom stanju na 100 Celzijevih stupnjeva.

<pb n="58"/>

2.5. Repeat-until petlja

Repeat-until još je jedna petlja kojom se možemo koristiti u Pascalu. Za razliku od for petlje kojom se koristimo kada znamo koliko se puta određeni dio koda mora izvršiti, repeat-until petlju koristimo kada ne znamo točan broj ponavljanja. Repeat-until petlja funkcionira tako da ponavlja zadane operacije dok je neki uvjet netočan. Repeat-until ponavlja operacije sve dok <pb n="59"/>se ne dosegne vrijednost zadana u uvjetu.

Ona izgleda ovako:

repeat

naredba1;

naredba2;

until uvjet;

Repeat-until petlja posebna je po tome što u sebi ima ugrađen (nevidljiv) begin-end blok, pa je automatski između repeat i until rezerviranih riječi moguće pisati neodređeni broj naredbi. Još jedno od bitnih svojstava repeat-until petlje je to što se uvjet petlje provjerava tek na kraju petlje — a to znači da će se pomoću repeat-until petlje zadane operacije UVIJEK izvršiti sigurno jednom, neovisno o točnosti ili netočnosti uvjeta.

Ako želimo, pri pisanju repeat-until petlje možemo uvesti brojač ponavljanja. Pritom sami moramo paziti na stanje brojača (za razliku od for petlje koja to čini sama). Ako zaboravimo inkrementirati brojač (povećavati njegovu vrijednost, obično za 1), dobit ćemo beskonačnu petlju iz koje nema bijega, osim isključivanjem računala.

Na slici 2.4. možemo točno vidjeti što je potrebno da bi repeat-until petlja funkcionirala.

Prvi problem koji ćemo riješiti pomoću repeat-until petlje bit će ispisivanje prvih deset brojeva na ekran. Ovaj vrlo jednostavan program točno prikazuje osnovnu strukturu repeat-until petlje i kako se ona mora pisati da bi funkcionirala.

<pb n="60"/>

Repeat-until petlja ne mora, kao for petlja, povećavati vrijednost brojača za 1. Kao što je vidljivo iz ispisa, mi možemo sami definirati korak povećavanja brojača. Sljedeći primjer prikazuje kako pomoću repeat-until petlje možemo vrlo jednostavno ispisati samo neparne brojeve do 20.

A sad je na redu jedno svojstvo repeat-until petlje koje smo već spomenuli. Riječ je o najmanje jednom izvršenju čak i kada je uvjet već na početku netočan. Ovu funkcionalnost možemo vrlo lijepo i jednostavno provjeriti na prije viđenom programu za ispis neparnih brojeva manjih od 20. Program za ispis funkcionira savršeno samo zato što je početna vrijednost dobro definirana, nep:= 1;. Ako pokrenemo program iz ispisa 2.30, vidjet ćemo da on bez ikakvih problema ispisuje brojeve 1, 3, 5, 7, 9, 11, 13, 15, 17 i 19. Program u primjeru 2.31. ispisat će broj 30, iako broj 30 nije neparan niti je manji od 20.

<pb n="61"/>

Prikaz funkcioniranja repeat-until petlje za primjer 2.31. vidljiv je na slici 2.5.

2.6. While petlja

While petlja zadnja je petlja koju moramo naučiti i onda smo završili i s petljama, ali i s cijelim poglavljem. While petlja vrlo je slična repeat-until petlji po ponašanju. Broj ponavljanja while petlje nije unaprijed poznat. While petlja ponavljat će se sve dok je zadani uvjet istinit, dakle, obrnuto od repeat-until petlje. Za razliku od repeat-until petlje, while petlja provjerava uvjet na početku svojeg izvršavanja. Isto kao i kod repeat-until petlje, možemo uvesti brojač ponavljanja. Pritom sami moramo paziti na stanje brojača. Ako unutar while petlje zaboravimo mijenjati brojač petlje, ona će se ponavljati <pb n="62"/>poprilično dugo (tj. dok ne resetiramo računalo).

Struktura while petlje izgleda ovako:

while uvjet do

naredba;

ili

while uvjet do

begin

naredba1;

naredba2;

end;

Program u primjeru 2.32. prikazuje kako se može koristiti while petlja.

2.7. Iskakanje iz petlji

Petljama je katkad potrebno zaustaviti izvršavanje prije normalnog završetka. Jedan način promjene tijeka izvršavanja petlji postiže se rezerviranom riječi break kojom se koristimo za iskakanje iz petlje. Program u primjeru 2.33, koji <pb n="63"/>slijedi, koristi rezerviranu riječ break kako bi iskočio iz petlje nakon što se petlja izvrši 5 puta.

Još zabavnija petlja, koju ne bismo smjeli napisati bez dijela koda za iskakanje iz petlje, zove se beskonačna petlja. Najlakše je možemo napisati primjenom while ili repeat-until petlje:

while True do

begin

naredba1;

naredba2;

end;

repeat

naredba1;

naredba2;

until False;

Ako napišemo ovakvu petlju i pokrenemo program, a nismo napisali kod za iskakanje iz petlje, ona će se izvršavati sve dok ne nestane struje ili ne isključimo računalo jer je njezin uvjet uvijek ispunjen — istina je uvijek istina, a laž je uvijek laž.

Zadnji primjer u ovom poglavlju ilustrira beskonačnu petlju. Program u primjeru 2.34. unutar beskonačne petlje zahtijeva unos nekoga broja i ispisuje je li broj paran ili neparan. Nakon što korisnik dobije informaciju o broju, program će ga upitati želi li unijeti još jedan broj. Ako unese “d” da želi, beskonačna će se petlja nastaviti sve dok korisnik ne utipka “n”, čime će se izvršiti break naredba i iskočiti iz beskonačne petlje.

Primjer 2.34.

program unos_brojeva;

var

broj: Integer;

ostatak: Integer;

odgovor: Char;

<pb n="64"/>

begin

while True do

begin

Write(‘Unesite broj: ‘);

Readln(broj);

{ provjera neparnog i parnog broja

pomocu ostatka cjelobrojnog

dijeljenja, ako je ostatak = 1

onda je broj neparan }

ostatak := broj mod 2;

if ostatak = 1 then

Writeln(‘Broj koji ste unijeli je neparan.’)

else

Writeln(‘Broj koji ste unijeli je paran.’);

{ provjeri zeli li korisnik unijeti

jos jedan broj }

Write(‘Zelite li unijeti drugi broj (d/n): ‘);

Readln(odgovor);

if (odgovor = ‘n’) or (odgovor = ‘N’) then break;

end;

Readln;

end.

A sad je vrijeme da iskočimo iz ovog poglavlja u malo mirnije vode.

2.8. Sažetak

U ovom smo poglavlju upoznali varijable i načine kako ih možemo koristiti. Uz if provjeru pomoću koje možemo mijenjati tijek programa, prikazane su i razne petlje Pascala. Poznavanje for petlje i najosnovnije if provjere vrlo je bitno za daljnji nastavak rada, jer bez njih nećemo poslije moći rješavati ni najjednostavnije probleme.

Pitanja i zadaci

Pitanje 1: Čemu služi rezervirana riječ if?

Pitanje 2: Nabrojite tri relacijska operatora.

Pitanje 3: Je li sljedeća provjera varijable “a” u redu?

var

a: Integer;

begin

if a := 6 then;

Writeln(‘a jednako 6’);

end.

<pb n="65"/>

Pitanje 4: Što će ispisati sljedeći program na ekranu?

var

i: Integer;

begin

i := 2;

i := i + 3;

if i = 5 then

Writeln(‘Broj i = 5.’)

else

Writeln(‘Broj i nije jednak 5.’)

end.

Pitanje 5: Pogledajte sljedeći program:

var

i: Integer;

begin

i = ?;

if i = 7 then

Writeln(‘Sedam samuraja’)

else if i = 42 then

Writeln(‘Smisao života’)

else if i = 9 then

Writeln(‘Devet krugova pakla’)

else

Writeln(‘Ništa pametno’);

end.

Ako u prvoj liniji koda umjesto upitnika utipkamo broj 9, što će se nakon pokretanja programa ispisati na ekranu? Ako napišemo 101 umjesto upitnika, što će se sve u tom slučaju ispisati na ekranu?

Pitanje 6: Čemu služi operator not?

Pitanje 7: Što će ispisati ova case provjera?

var

i: Integer;

begin

i := 4;

select case i of

case 1: Writeln(‘Jedan’);

case 2: Writeln(‘Dva’);

case 3: Writeln(‘Tri’);

case 4: Writeln(‘Četiri’);

end select

end.

Pitanje 8: Što radi sljedeći dio koda?

var

i: Integer;

const

tekst_poruke = ‘Pascal’;

begin

for i := 1 to 5 do

Writeln(‘tekst_poruke’);

end.

<pb n="66"/>

Pitanje 9: Što će napraviti sljedeći program nakon što ga pokrenemo?

var

i: Integer;

begin

i := 10;

while i < 20 do

begin

Writeln(‘Pascal’);

end;

Pitanje 10: Što radi sljedeći program?

var

i: Integer;

begin

i := 60;

repeat

i := i + 1;

Writeln(i);

until i >= 60;

end.

Zadatak 1: Napišite program koji će od korisnika tražiti unos broja i provjeravati je li uneseni broj pozitivan, negativan ili je jednak nuli.

Zadatak 2: Napišite program koji će od korisnika tražiti unos broja i provjeravati je li uneseni broj paran ili neparan.

Zadatak 3: Napišite program koji će pomoću for petlje dvadeset puta na ekran ispisati poruku “Turbo Pascal petlja”.

Zadatak 4: Napišite program koji će pomoću repeat-until petlje ispisati na ekran brojeve od 1 do 10, ali obrnutim redoslijedom –10, 9,8, .., 1.

Zadatak 5: Napišite program koji će iskoristiti beskonačnu while petlju kako bi od korisnika stalno tražio unos nekog imena. Program mora završiti s radom nakon što korisnik utipka riječ “kraj” (sve malim slovima).

<pb n="67"/>

3. Strukturirano programiranje

3.1. Uvod u strukturirano programiranje 68

3.2. Korištenje standardnih procedura i funkcija 69

3.2.1. Korištenje standardnih procedura 69

3.2.2. Korištenje standardnih funkcija 72

3.3. Stvaranje procedura 75

3.3.1. Lokalne i globalne varijable 76

3.3.2. Lista parametara 78

3.3.3. Prijenos podataka putem vrijednosti i

putem reference 80

3.3.4. Korištenje većega broja procedura 82

3.4. Stvaranje funkcija 85

3.4.1. Rekurzivne procedure i funkcije 87

3.5. Sažetak 88

<pb n="68"/>

3. Strukturirano programiranje

3.1. Uvod u strukturirano programiranje

U ovom ćemo se poglavlju baviti malo naprednijim stvarima kao što su procedure i funkcije. Procedure i funkcije su potprogrami, odvojeni i samostalni dijelovi izvornog koda koji se često ponavljaju i koji su često potrebni.

Nakon što smo svladali najosnovniji rad s podacima i razne načine provjere podataka, obvezno moramo naučiti korištenje i stvaranje vlastitih procedura i funkcija. Procedure i funkcije vrlo su bitne jer pomoću njih program možemo razlomiti u manje dijelove koje je lakše razumjeti i jednostavnije se njima koristiti. Usto, stvaranjem procedura i funkcija omogućujemo sebi (ali i drugim programerima) ponovno korištenje istog izvornog koda, čime se dobiva na brzini kreiranja novih programa.

Do sada smo se koristili samo vrlo malim brojem procedura i nazivali smo ih naredbama. Writeln, Readln, Read i Write zapravo su procedure, dijelovi koda koji služe točno određenoj svrsi i koje možemo iskoristiti gdje god i koliko god mi to želimo.

Kad radimo s procedurama i funkcijama, moramo se držati nekih najosnovnijih pravila komunikacije s njima. Osnovna stvar koju moramo znati o nekoj proceduri ili funkciji da bismo se njome mogli koristiti je njezino ime. Drugo, moramo znati trebaju li toj proceduri ili funkciji neke dodatne informacije za rad.

Ako su proceduri ili funkciji potrebni neki dodatni podaci s kojima će raditi (kao što je Writeln naredbi u većini slučajeva potrebna lista podataka koje će ispisati na ekran), onda mi te podatke dajemo proceduri ili funkciji preko njezine LISTE PARAMETARA. Lista parametara naziv je za podatke koje pišemo unutar zagrada kada pozivamo neku proceduru. Slika 3.1. prikazuje poziv procedure Writeln kakvim smo se koristili do sada.

<pb n="69"/>

3.2. Korištenje standardnih procedura i funkcija

Procedure Read, Write, Readln i Writeln standardne su procedure koje su ugrađene u sam programski jezik Pascal i vrlo su fleksibilne. Da bismo znali koristiti ostale funkcije i procedure, moramo znati gdje su skrivene i koje podatke moramo napisati u listi parametara. Uz Turbo Pascal, ali i svaki drugi Pascal kompilator, sigurno ćemo dobiti nekoliko dodatnih datoteka u kojima su skrivene procedure i funkcije. Takve se datoteke nazivaju uniti, jedinice izvornog koda ili biblioteke funkcija.

Osim toga, programeri imaju mogućnost da sami stvaraju biblioteke funkcija i procedura pa time iz programa u program neće morati stalno iznova izmišljati kotač, odnosno neće iznova morati pisati isti kod. Sve što trenutačno moramo znati je kako u našem programu iskoristiti te prije napisane procedure i funkcije.

Želimo li iskoristiti neku prije napisanu proceduru u našem programu, moramo se upoznati s listom unita (uses listom) koja se piše na početku koda. Ako se prisjetimo slike s početka knjige koja prikazuje osnovnu strukturu Pascal programa, uses lista vidljiva je odmah na samom početku.

Lista biblioteka funkcija koje se koriste u programu stvara se pomoću rezervirane riječi uses koja ima ovu strukturu:

uses unit1;

ili

uses unit1, unit2, unit3, unit4, unitN;

3.2.1. Korištenje standardnih procedura

Najosnovniji unit koji sadrži nekoliko jednostavnih procedura zove se crt. U crt unitu nalazi se procedura pod imenom ClrScr. Procedura ClrScr vrlo je jednostavna, čak toliko da uopće ne posjeduje listu argumenata. Procedure koje ne posjeduju listu argumenata pozivaju se tako da se napiše samo njihovo ime praćeno točkom sa zarezom. ClrScr procedura koristi se kada želimo obrisati sve podatke s ekrana, <pb n="70"/>točnije, korištenjem ClrScr procedure cijeli će se ekran obrisati, a kursor teksta postavit će se u gornji lijevi kut ekrana.

Evo kako izgleda program koji se koristi dodatnom bibliotekom funkcija i procedurom ClrScr.

Primjer 3.1.

program koristenje_crt_unita;

uses crt;

begin

ClrScr; { poziv procedure za brisanje ekrana }

Writeln(‘Ovo je jedini tekst na ekranu.’);

Readln;

end.

Unit crt ima još nekolicinu procedura kojima se možemo koristiti u svakodnevnom programiranju. Jedna od tih, vrlo jednostavnih procedura je i procedura TextColor koja je u Turbo Pascal pomoći deklarirana ovako:

procedure TextColor(Color: Byte);

U prikazu TextColor procedure možemo vidjeti još novosti. U listi parametara definiran je jedan parametar, a ta definicija parametra vrlo nalikuje na deklaraciju varijable. Svaki parametar mora (isto kao i varijabla) imati svoje ime i tip podataka koji zahtijeva. Ime parametra potrebno je programeru koji stvara proceduru, a tip podataka potreban je svim programerima koji će se koristiti procedurom jer tip podataka označuje raspon vrijednosti koje procedura može razumjeti.

Slika 3.2. detaljnije objašnjava strukturu procedure TextColor.

TextColor procedura primjenjuje se kada želimo promijeniti boju kojom će se tekst ispisivati na ekranu. Ta procedura ima jedan jedini parametar Byte tipa <pb n="71"/>pomoću kojeg mijenjamo boju teksta na ekranu. U Turbo Pascal pomoći navedeno je da TextColor procedura razumije samo brojeve od 0 do 15, a svaka od tih vrijednosti označuje jednu boju. Uz mogućnost korištenja tih vrijednosti, u crt unitu postoji i kolekcija konstanti koje označuju iskoristive boje. Te su konstante prikazane u tablici 3.1.

Na kraju tablice prikazana je posebna vrijednost Blink. Vrijednost Blink možemo iskoristiti ako želimo natjerati tekst da treperi na ekranu. U primjeru 3.2, koji slijedi, prikazan je program koji koristi ClrScr i TextColor procedure crt unita.

Primjer 3.2.

program crt_textcolor;

uses crt;

begin

ClrScr;

{ promijeni boju u zelenu }

TextColor(Green);

Writeln(‘Ovaj je tekst prikazan zelenom bojom!’);

{ promijeni boju u crvenu }

TextColor(4);

Writeln(‘Ovaj je tekst prikazan crvenom bojom!’);

{ promijeni boju u tamnosivu }

<pb n="72"/>

TextColor(Blink + DarkGray);

Writeln(‘Ovaj je tekst TREPERI.’);

Readln;

end.

Kao što je vidljivo iz programa u primjeru 3.2, korištenje procedura vrlo je jednostavno. Kod procedura je dobro zapamtiti da se one moraju pisati samostalno u jednoj liniji koda, kao što se i vidi — svi pozivi TextColor procedure nalaze se u zasebnim linijama koda. Procedure se pišu u zasebnim linijama koda, ponajviše radi preglednosti. Uz preglednost, procedure ne možemo napisati unutar izraza kao što možemo funkcije.

3.2.2. Korištenje standardnih funkcija

Druga vrsta potprograma koja postoji u Pascalu su funkcije. Funkcije su potprogrami koji nam vraćaju neku vrijednost. Funkcije vraćaju rezultat svojeg izvršavanja. One se obično (vrlo često) koriste kao dio nekog izraza. Pozivi funkcija moraju se nalaziti u naredbi za pridjeljivanje (tj. desno od operatora pridjeljivanja).

Pascal ima popriličan broj funkcija kojima se možemo koristiti tijekom svakodnevnoga programiranja. Sad ćemo vidjeti kako se koristi jedna od najjednostavnijih funkcija, a zove se ReadKey i također se nalazi skrivena u crt unitu.

Funkcija ReadKey se koristi kada želimo od korisnika programa zatražiti unos jednog znaka koji se neće prikazati na ekranu. Funkcija ReadKey deklarirana je ovako:

function ReadKey: Char;

Ta je funkcija vrlo jednostavna jer nema listu argumenata, što znači da sve potrebne podatke za funkcioniranje ona ima sama u sebi. Najbitnija informacija koju trebamo pročitati iz ovakve definicije funkcije je njezin povratni tip, u ovom slučaju Char. Program u primjeru 3.3. koristi ReadKey funkciju da učita znak i onda ga sprema u varijablu tipa Char.

<pb n="73"/>

Prije smo naveli da Pascal već posjeduje poveći broj standardnih funkcija kojima se možemo koristiti tijekom svakodnevnog programiranja. U tablici 3.2. navedene su neke od tih funkcija.

<pb n="74"/>

Program u primjeru 3.4. prikazuje način kako se koristi nekoliko funkcija iz tablice 3.2. Posebno je bitno zapamtiti razliku između Trunc i Round zaokruživanja brojeva.

<pb n="75"/>

Zadnje četiri funkcije koje su navedene u tablici 3.2. mogu se koristiti i sa znakovima. Program u primjeru 3.5. ilustrira kako rade funkcije Ord, Chr, Succ i Pred.

Vjerujem da je korištenje procedura i funkcija jasna stvar i da bez problema možemo krenuti dalje na stvaranje vlastitih procedura i funkcija.

3.3. Stvaranje procedura

Procedure stvaramo kada neki dio koda želimo iskoristiti na više od jednog mjesta ili kada jedan veliki program želimo podijeliti na manje, razumljivije cjeline. Struktura najjednostavnije procedure izgleda ovako:

procedure ImeProcedure;

begin

end;

Isto kao što se varijable moraju unaprijed deklarirati prije nego što ih možemo koristiti, tako se i procedure moraju deklarirati i napisati prije nego što ih možemo koristiti. Sve procedure koje stvaramo moraju se obvezno pisati ispred glavnog begin-end bloka. U primjeru 3.6. prikazana je vrlo jednostavna procedura koja na ekran ispisuje kratku tekstualnu poruku.

<pb n="76"/>

Ovaj je program ponešto drukčiji od programa s kojima smo se do sada susretali.

Izvorni kod koji je napisan unutar glavnog begin-end bloka je kod koji se izvršava uvijek kada pokrenemo program. Izvorni kod koji napišemo unutar neke procedure ili funkcije neće se nikad izvršiti ako ne pozovemo tu proceduru i funkciju. U slučaju programa u primjeru 3.6, izvorni kod procedure Poruka sigurno će se izvršiti jer ga glavni program poziva čak 10 puta unutar for petlje.

Svaka je procedura koju napišemo samostalna i može imati vlastite konstante i varijable koje ni jedan drugi dio programa ne može vidjeti niti iskoristiti. U primjeru 3.7, koji slijedi, prikazana je procedura koja sadrži vlastite varijable i konstante. Takve se varijable i konstante nazivaju lokalnim varijablama i lokalnim konstantama.

U primjeru 3.7. prikazana je procedura koja ima vlastite varijable i konstante. Lokalne varijable i konstante mogu se koristiti samo unutar funkcije ili procedure u kojoj su definirane. U ovom slučaju konstantom MOJA_PORUKA moći ćemo se koristiti samo unutar begin-end bloka procedure IspisPoruke. Pokušamo li unutar glavnog begin-end bloka napisati Writeln(MOJA_PORUKA), Pascal kompilator prikazat će nam pogrešku u kojoj nam govori da konstanta MOJA_PORUKA nije deklarirana.

3.3.1. Lokalne i globalne varijable

Pri stvaranju većih i kvalitetnijih programa, moramo težiti što manjem broju globalnih varijabli i što većem dijelu koda unutar procedura i funkcija. U prethodnoj rečenici spomenuo sam jedan novi termin — globalna varijabla. Globalna varijabla je varijabla koja je vidljiva i iskoristiva iz cijeloga programa, iz glavnog begin-end bloka i iz bilo koje procedure i funkcije. Globalne varijable traju koliko traje i izvršavanje cijeloga programa jer se stvaraju u memoriji čim se program pokrene, a brišu se iz memorije tek kada se cijeli program završi.

<pb n="77"/>

Do sada smo se u programima koristili samo globalnim varijablama. Njih smo deklarirali na početku programa, iza rezervirane riječi var.

Globalnim varijablama ne treba se često koristiti zbog činjenice da ih bilo koji dio programa može promijeniti u bilo koje vrijeme. Lokalne varijable, koje se deklariraju unutar procedura i funkcija, nisu vidljive iz cijeloga programa i stoga nema straha da će se u takvoj varijabli nalaziti vrijednost koja može izazvati pogrešku.

Lokalne varijable, kao što je varijabla brojPoruka u primjeru 3.7, vrlo kratko traju, odnosno traju onoliko vremena koliko treba da se izvrše sve linije unutar procedure u kojoj je lokalna varijabla deklarirana.

Kad se pokrene program iz primjera 3.7, prvo što se izvršava je procedura ClrScr koja briše sadržaj ekrana. Nakon toga slijedi poziv procedure IspisPoruke. Kad glavni program pozove proceduru IspisPoruke ili bilo koju drugu proceduru ili funkciju, on joj prepušta tijek izvršavanja. Nakon što se cijeli tijek izvršavanja programa prebaci u potprogram, u proceduru IspisPoruke, procedura stvara lokalnu varijablu brojPoruka kojom se koristi.

Nakon što procedura stvori sve lokalne varijable kojima se koristi, počinju se izvršavati linije koda koje su napisane u begin-end bloku procedure. Izvršava se for petlja koja pet puta ispisuje poruku na ekran. Kad for petlja završi svoj posao, program dolazi do kraja bloka procedure, dakle, do kraja same procedure. Kada se procedura do kraja izvrši, ona će pobrisati sve lokalne varijable iz memorije kako bi se napravilo mjesta za nove podatke.

U primjeru 3.8. prikazan je program u kojem su deklarirane i lokalne i globalne varijable.

<pb n="78"/>

3.3.2. Lista parametara

S obzirom na to da ćemo se dalje u knjizi sve više baviti procedurama, morat ćemo se naviknuti na rad s lokalnim varijablama i smanjiti korištenje globalnih varijabli. Doduše, globalne varijable nećemo zaboraviti u potpunosti, samo ćemo njihovo korištenje smanjiti što je to više moguće. Moguće je da katkada uopće nećemo uspjeti izbjeći korištenje globalnih varijabli.

Ako se ne koristimo globalnim varijablama za držanje podataka, jedini način kako nekoj proceduri ili funkciji proslijediti neku vrijednost je preko liste parametara. Listu parametara smo do sada vidjeli samo kao korisnici procedure. Kao autori procedure moramo znati kako se definira lista parametara i što nam uopće treba.

Recimo da u nekom programu često trebamo ispisivati tekstualne poruke zelenom bojom. Obično za takav ispis trebamo tri linije koda, TextColor liniju koja će promijeniti boju kojom se tekst ispisuje, Writeln koja ispisuje samu tekstualnu poruku, te ponovno TextColor liniju koja će vratiti normalnu (svijetlosivu) boju teksta. Ako ovakav posao moramo ponoviti više puta u programu, onda je najbolje napraviti proceduru koja će raditi taj posao.

Dakle, trebamo napraviti proceduru koja zna sve što treba napraviti, osim teksta koji mora ispisati na ekran. Tekst koji ispisuje na ekran dobit će od glavnog programa, a za prosljeđivanje teksta iz glavnog programa u proceduru trebat će nam jedan parametar tipa string.

Parametri procedura definiraju se isto kao i varijable, samo bez rezervirane riječi var. Deklaracija naše procedure trebala bi izgledati otprilike ovako:

procedure ZeleniWriteln(MojTekst: string);

Tom smo deklaracijom napravili proceduru ZeleniWriteln kojoj je za rad potreban jedan string podatak. Taj string podatak procedura će dobiti od glavnoga programa u obliku parametra MojTekst. Parametar MojTekst vrlo je specifična varijabla koja je potpuno neiskoristiva izvan procedure (mogli bismo je nazvati automatskom lokalnom varijablom). Ako se koristimo procedurom, ime parametra nije bitna informacija, bitan nam je samo tip podatka parametra kako bismo znali koji podatak proslijediti proceduri. Ako stvaramo proceduru, bit će nam bitne obje informacije — ime parametra i tip podatka. Tip podatka označivat će nam što možemo napraviti s vrijednošću koju dobijemo od glavnog programa, a MojTekst će označivati samu vrijednost koja je zapisana u pozivu procedure.

Program u primjeru 3.9. ilustrira korištenje procedure ZeleniWriteln, a odmah nakon primjera slijedi slika 3.3. koja detaljnije prikazuje funkcioniranje procedure ZeleniWriteln, ali i cijeloga programa prikazanog u ispisu 3.9.

<pb n="79"/>

<pb n="80"/>

Kao što je vidljivo iz slike 3.3, poprilično mnogo stvari se događa u pozadini naših poziva procedura. Iskreno, ima toga još više, samo što te informacije nisu bitne za naš rad, a nisu niti pretjerano jednostavne za razumijevanje, pogotovo na početku programerske karijere.

3.3.3. Prijenos podataka putem vrijednosti i putem reference

Način prijenosa podataka u procedure koji smo do sada vidjeli naziva se prijenosom putem vrijednosti (pass by value). Kada koristimo takav način prijenosa podataka u proceduru, procedura prima kopiju vrijednosti, čime se onemogućuje mijenjanje originalne vrijednosti. Prijenos podataka putem vrijednosti standardni je način prijenosa podataka u procedure. Takvim načinom povećavamo sigurnost podataka i cijeloga programa jer originalnim vrijednostima (koje mogu biti vrlo bitne) ne možemo pristupiti izravno.

Uz prijenos podataka putem vrijednosti, postoji i prijenos putem reference. Ako podatke u procedure prenosimo putem reference, tada izravno pristupamo originalnim podacima. Kada se koristimo takvim načinom prijenosa podataka, u proceduru se uopće ne prenosi vrijednost varijable, nego izravna memorijska adresa varijable. Ovo treba objasniti.

Svaka varijabla koju deklariramo je prostor određene veličine unutar radne memorije računala. Prigodom deklariranja varijable postavljamo joj ime i tip podataka. Tip podataka određuje koliko će veliku količinu radne memorije zauzeti ta varijabla, a ime varijable koristimo da bismo u nju zapisivali razne podatke. Ime varijable u programu samo je krinka za memorijsku adresu varijable.

Evo kako izgledaju deklaracije procedura koje primaju podatak putem vrijednosti i putem reference:

procedure PutemVrijednosti(broj: Integer);

procedure PutemReference(var broj: Integer);

Kad u listi parametara ispred imena parametra navedemo rezerviranu riječ var, to će značiti da taj parametar prima podatak putem reference. Usto što postoje razlike u načinu definiranja parametara, postoje i razlike u korištenju tih procedura.

Parametri koji primaju podatak putem vrijednosti mogu primiti vrijednost, varijablu, izraz ili povratnu vrijednost neke funkcije:

var

a: Integer;

b: Integer;

procedure PutemVrijednosti(broj: Integer);

begin

end;

begin

PutemVrijednosti(10);

PutemVrijednosti(200 + b);

PutemVrijednosti(b + 10 + Round(2.5));

end.

Parametri koji primaju referencu podatka primaju samo adresu varijable i zbog toga se za takav parametar uvijek mora navesti ime neke varijable. U parametar koji prima referencu podatka ne možemo navesti vrijednost, izraz ili povratnu vrijednost funkcije, nego možemo navesti samo varijablu:

var

<pb n="81"/>

a: Integer;

procedure PutemReference(var broj: Integer);

begin

end;

begin

PutemReference(a);

end.

Slijedi primjer koji pobliže prikazuje funkcioniranje prijenosa podataka putem vrijednosti i reference. Nakon primjera 3.10. slijedi slika 3.4. koja prikazuje način na koji funkcionira prenošenje podataka putem reference.

<pb n="82"/>

3.3.4. Korištenje većega broja procedura

Ako želimo napraviti program koji će se sastojati od većega broja procedura, a pogotovo ako jednu proceduru želimo koristiti unutar druge, moramo se sjetiti onoga starog pravila Pascala da se sve mora deklarirati prije nego što se može iskoristiti. Pogledajmo sljedeći primjer:

program dvije_procedure;

procedure Ime;

begin

Write(‘Albert ‘);

<pb n="83"/>

end;

procedure Prezime;

begin

Ime;

Writeln(‘Einstein’);

end;

begin

Prezime; { na ekran se ispisuje tekst "Albert Einstein" }

end.

Nakon izvršavanja ovoga programa, na ekran se ispisuje "Albert Einstein". To se bez problema događa jer procedura Prezime najprije poziva proceduru Ime koja ispisuje Albertovo ime, a tek nakon toga ispisuje i prezime. Drugi je razlog u poretku kojim su procedure napisane. Kad bismo proceduru Ime napisali ispod procedure Prezime, cijeli program ne bi funkcionirao jer procedura Prezime više ne bi “vidjela” proceduru Ime. Kratki ispis koji slijedi prikazuje tu situaciju:

{ Paznja. Ovaj program ne funkcionira!!! }

program dvije_procedure;

procedure Prezime;

begin

Ime;

Writeln(‘Einstein’);

end;

procedure Ime;

begin

Write(‘Albert ‘);

end;

begin

Prezime; { na ekran se ispisuje tekst “Albert Einstein” }

end.

Ako želimo deklarirati procedure bez prevelikih muka oko redoslijeda deklariranja, morat ćemo iskoristiti rezerviranu riječ forward koja se koristi za prijevremenu deklaraciju procedure. Rezervirana riječ forward koristi se na kraju deklaracije procedure (ili funkcije), ali se ta deklaracija piše odvojeno od cijele procedure i stavlja se što više na početak programa:

program dvije_procedure;

procedure Ime; forward; { Ovo nije procedura, samo njena

prijevremena deklaracija. Ova

nam linija treba da bi procedura

Prezime mogla koristiti proceduru

Ime. }

procedure Prezime;

begin

Ime;

<pb n="84"/>

Writeln(‘Einstein’);

end;

procedure Ime;

begin

Write(‘Albert ‘);

end;

begin

Prezime; { na ekran se ispisuje tekst “Albert Einstein” }

end.

Slijedi malo veći program koji ilustrira prijevremenu deklaraciju procedure.

<pb n="85"/>

Na posljednjih nekoliko stranica mogli smo vidjeti popriličan broj stvari koje se događaju u pozadini naočigled vrlo jednostavnih poziva procedura. Sav ovaj materijal vrlo je bitan za kvalitetno programiranje, ali ovog trena detalji nisu nužni.

3.4. Stvaranje funkcija

Funkcije su potprogrami (poseban tip procedure) koji vraćaju rezultat svojeg rada onom dijelu programa koji ih je pozvao. Poziv funkcije možemo napisati u bilo kojem dijelu programa gdje možemo napisati varijablu, kao što su izrazi, poziv neke procedure, funkcije i sl. Funkcije se stvaraju pomoću rezervirane riječi function iza koje slijedi ime funkcije, eventualna lista parametara i povratni tip podataka. Sve u svemu, osim rezervirane riječi function i povratnog tipa podataka, riječ je o istim pravilima kao i pri kreiranju procedure.

Struktura najosnovnije funkcije izgleda ovako:

function MojaFunkcija: Integer;

U unutrašnjosti, funkcija se samo u malenim detaljima razlikuje od procedure. Funkciju stvaramo da bismo nekom dijelu programa vratili rezultat neke kalkulacije ili neke operacije. Kada određenu vrijednost želimo vratiti iz funkcije, vrijednost koju vraćamo zapisujemo u samo ime funkcije (ali ovo se radi samo unutar bloka funkcije, kao što je prikazano):

function MojaFunkcija: Integer;

begin

MojaFunkcija := NekiIntegerBroj;

end;

U primjeru 3.12, koji slijedi, prikazana je vrlo jednostavna funkcija čiji je rezultat uvijek broj 5.

<pb n="86"/>

Funkcije mogu, isto kao i procedure, imati listu parametara i raditi s vrijednostima koje dobiju iz programa. Svaka imalo korisna funkcija morala bi primati vrijednosti iz nekog drugog dijela programa (iako postoje neke kojima nisu potrebni korisnički podaci).

Sad ćemo vidjeti funkciju koja pronalazi najveći od tri broja koja dobije preko liste parametara. Taj je program prikazan u primjeru 3.13.

<pb n="87"/>

3.4.1. Rekurzivne procedure i funkcije

Rekurzivne procedure su procedure koje mogu pozvati same sebe. Točnije, svaka procedura može pozivati samu sebe, samo što bismo u tom slučaju dobili beskonačnu petlju, odnosno dobili bismo pogrešku u programu jer bi takav program “smrznuo” računalo. Rekurzivne procedure pozivaju same sebe, a kao osiguranje da se procedura neće ponavljati beskonačno one se koriste jednom kontrolnom varijablom (točnije, jednim kontrolnim parametrom). Program u primjeru 3.14. koristi rekurzivnu proceduru da bi nekoliko puta na ekran ispisao tekstualnu poruku.

Ako pogledamo unutrašnjost procedure IspisPoruke, možemo vidjeti nekoliko novosti. Procedura IspisPoruke koristi parametar odbrojavanje kao kontrolnu varijablu na temelju koje odlučuje hoće li se procedura završiti ili će ponovno <pb n="88"/>pozvati sama sebe. Ako je vrijednost u varijabli odbrojavanje jednaka 0, procedura se završava, a, ako nije, procedura će ponovno pozvati samu sebe.

Da bi se osiguralo smanjivanje varijable odbrojavanje, ova procedura koristi se procedurom Dec za smanjivanje vrijednosti varijable za 1. Ako napišemo Dec(broj);, to je isto kao da napišemo broj := broj - 1;, samo što primjenom procedure Dec kompilator stvara malo optimiziraniji (brži i bolji) program.

Rekurzivne procedure i funkcije ne koriste se često, ali katkada mogu vrlo dobro doći.

3.5. Sažetak

Ovo je poglavlje bilo prepuno teorije koja točno objašnjava što se događa u pozadini linija koda koje pišemo u Pascalu. Procedure i funkcije (zajedno sa svim sitnim detaljima prijenosa podataka putem vrijednosti i reference) osnovni su i prijeko potrebni dio u budućem razumijevanju (ili nerazumijevanju) objektno-orijentiranog programiranja u Delphiju. Lokalne i globalne varijable dvije su verzije istoga zmaja, a bitno je zapamtiti da se broj globalnih varijabli uvijek treba svesti na apsolutni minimum (osim u slučaju programiranja igrice).

Pitanja i zadaci

Pitanje 1: Čemu služi uses lista?

Pitanje 2: Kojom procedurom možemo izbrisati cijeli sadržaj ekrana? U kojem se unitu nalazi ta procedura?

Pitanje 3: Što je funkcija?

Pitanje 4: Nabrojite tri standardne funkcije Pascala.

Pitanje 5: Koliko parametara ima sljedeća procedura?

procedure Ispis;

begin

end;

Pitanje 6: Ako varijablu deklariramo unutar neke procedure, kako se zove takva varijabla i možemo li tu varijablu koristiti u nekoj drugoj proceduri?

Pitanje 7: Gdje se deklariraju globalne varijable?

Pitanje 8: Kako se vrijednosti prenose u neku proceduru ili funkciju?

Pitanje 9: Kojom rezeviranom riječi stvaramo prijevremenu deklaraciju procedure ili funkcije?

Pitanje 10: Što radi sljedeća funkcija?

function Max(broj: Integer): Integer;

begin

Max := broj;

end;

Zadatak 1: Napišite proceduru koja se zove “Ime” i koja će vaše ime i prezime ispisivati na ekran.

Zadatak 2: Napišite proceduru koja će preko liste parametara primati jedan broj. Procedura mora na ekran tekstualno ispisati je li riječ o negativnom broju, pozitivnom ili o nuli.

Zadatak 3: Napišite funkciju koja će preko liste parametara primati dva cijela broja. Funkcija mora obvezno provjeriti jesu li oba broja u rasponu Byte vrijednosti (0 — 255). Ako su oba broja u tom rasponu, funkcija mora provjeriti i <pb n="89"/>vratiti veći od dvaju brojeva. Ako je neki od brojeva izvan Byte raspona, funkcija mora ispisati poruku o pogrešci i završiti s radom.

Zadatak 4: Napišite proceduru koja će od korisnika tražiti unos triju imena. Procedura mora spremiti učitana imena u tri različite globalne varijable.

Zadatak 5: Napišite funkciju koja će preko liste parametara primati dva cijela broja. Funkcija mora vratiti rezultat dijeljenja tih dvaju brojeva. Prije nego ih krene dijeliti, funkcija se mora osigurati da su oba broja veća od nule.

<pb n="90"/>

<pb n="91"/>

4. Polja i stringovi

4.1. Polja podataka 92

4.1.1. Dvodimenzionalna polja 96

4.1.2. Konstantno polje 97

4.1.3. Polje kao parametar procedure 98

4.2. String 98

4.2.1. Provjeravanje duljine stringa 102

4.2.2. Definiranje kratke string varijable 104

4.2.3. Standardne string procedure i funkcije 104

4.2.4. Jednostavno pretraživanje stringova 105

4.2.5. Ubacivanje teksta u string 107

4.2.6. Brisanje dijelova stringa 108

4.2.7. Kopiranje dijelova stringa 109

4.3. Sažetak 110

<pb n="92"/>

4. Polja i stringovi

U ovom ćemo poglavlju vidjeti kako s vrlo velikim brojem varijabli možemo raditi vrlo efikasno i uz vrlo malo pisanja koda. Počet ćemo od rada s velikim brojem varijabli, od polja podataka. Uz polja podataka, obradit ćemo vjerojatno najkorišteniji tip podataka u Pascalu, string.

4.1. Polja podataka

Poljem podataka (engl. array) koristimo se kada moramo raditi s većim brojem podataka. Uzmimo u obzir da u programu trebamo pamtiti informacije o dobi ljudi nekog grada koji ima 3460 stanovnika. Zar ne bi bilo lijepo deklarirati 3460 različitih varijabli s 3460 različitih imena: stanovnik1, stanovnik2, stanovnik3, stanovnik4, stanovnik5, stanovnik6 itd.?

Kad radimo s većim brojem podataka istog tipa (najmanje dva), najbolje je rješenje napraviti jedno polje u kojem ćemo čuvati sve te podatke. Kada deklariramo određeno polje podataka, točnije, polje varijabli, svim varijablama u polju ne možemo izravno pristupiti. Za pristup pojedinom elementu polja (čitaj: za pristup varijabli) moramo koristiti njezin indeks.

Polja se deklariraju ovako:

ime_polja: array[raspon] of tip_podataka;

Kao što je vidljivo iz prikaza deklaracije, za stvaranje polja koristi se rezervirana riječ array. U uglatim zagradama piše se broj elemenata polja, a iza rezervirane riječi of piše se tip podatka varijabli u polju. Ako sami definiramo raspon vrijednosti (što ćemo najčešće raditi), onda se u uglatim zagradama pišu početni i krajnji indeksi podataka, a između njih se navode dvije točke.

Evo kako izgleda polje koje se zove Ocjena i sastoji se od 5 elemenata Integer tipa:

var

Ocjena: array[1..5] of Integer;

Iako deklaracija polja izgleda vrlo slično deklaraciji jedne varijable, u ovoj jednoj deklaraciji stvorili smo 5 različitih varijabli. Navedena deklaracija polja zamjenjuje pet samostalnih varijabli:

var

Ocjena1: Integer;

Ocjena2: Integer;

Ocjena3: Integer;

Ocjena4: Integer;

Ocjena5: Integer;

Deklaracija samostalnih varijabli i deklaracija polja varijabli razlikuje se po načinu na koji se koriste, ali i po načinu na koji ih operativni sustav raspoređuje u memoriji. Ako zamislimo da je radna memorija računala dugačka traka memorijskih lokacija, samostalne će se varijable po memoriji rasporediti nasumično, kao što je prikazano na slici 4.1.

<pb n="93"/>

Nasumični raspored varijabli onemogućuje Pascal kompilatoru optimiziranje koda, ali, ako napravimo polje varijabli, Pascal kompilator moći će optimizirati pristup takvim varijablama, a ujedno stvaranjem polja dobivamo mogućnost pristupa golemom broju podataka putem petlji. Slika 4.2. prikazuje raspored varijabli unutar polja.

Pogledajmo kako se koriste pojedine varijable u polju. Pristup pojedinačnoj varijabli unutar polja moguć je samo putem indeksa polja. S obzirom na to da je navedeni raspon vrijednosti u polju Ocjena od 1 do 5, prvi element ima indeks 1, zadnji element ima indeks 5. Indeksi elemenata polja uvijek se pišu u uglatim zagradama. Pojedinom elementu polja pristupa se ovako:

imePolja[indeks] := vrijednost;

Ako u prvi element polja Ocjene želimo upisati broj 4 i nakon toga ispisati prvi element polja na ekran, kôd će izgledati ovako:

Ocjena[1] := 4;

Writeln(‘Prva ocjena je ‘, Ocjena[1], ‘.’);

Prvi primjer koji će se koristiti poljem bit će program koji će tražiti od korisnika unos triju ocjena koje će zapisati u polje od 3 elementa. Nakon što se sve tri <pb n="94"/>vrijednosti unesu, program mora izračunati srednju vrijednost tih triju unesenih ocjena. Za računanje srednje vrijednosti napravit ćemo posebnu funkciju.

Najkompleksniji dio u primjeru 4.1. je procedura UcitavanjeVrijednosti. U toj se proceduri pojavljuje poziv procedure Inc koju do sada nismo upoznali. Isto kao što procedura Dec smanjuje numeričku varijablu za 1, tako procedura Inc povećava <pb n="95"/>vrijednost varijable za 1. Linija koda Inc(brojPonavljanja) daje isti rezultat kao i izraz brojPonavljanja := brojPonavljanja + 1, samo što primjenom procedure Inc dobivamo optimiziraniji i bolji program.

Druga bitna linija u toj proceduri je linija Readln(Ocjene[brojPonavljanja]) koja kroz repeat-until petlju izravno učitava vrijednosti u polje.

S obzirom na to da se pristup polju najčešće radi pomoću for petlje, sad ćemo vidjeti još jedan primjer rada s poljima.

Prva je petlja vrlo jednostavna jer smo za pristup elementima polja naveli da je riječ o elementima u rasponu od 1 do 10. Druga je for petlja nešto malo kompleksnija jer se za pristup elementima polja koristi funkcijama High i Low koje računaju početne i završne indekse polja. Uz korištenje High i Low funkcija, drugo polje ima indekse od 100 do 110. Ovo polje prikazuje da se rasponi vrijednosti mogu definirati po potrebi — nisu limitirani da počinju od 0 ili od nekog <pb n="96"/>drugog broja (kao što je slučaj u nekim drugim programskim jezicima — poglavito C i C++).

Za one koji se brinu oko brzine rada programa i optimizacije – možete mirno spavati jer korištenje funkcija High i Low nikako ne usporava pristup polju. Rezultat funkcija kalkulira se tijekom kompiliranja programa i sama je brzina programa identična ako koristimo direktne vrijednosti ili funkcije High i Low. Ako pristupamo svim podacima polja, preporučljivo je koristiti se funkcijama High i Low jer će nam njihovo korištenje skratiti muke ako ikad poželimo promijeniti broj elemenata polja.

4.1.1. Dvodimenzionalna polja

Uz polja koja smo do sada vidjeli (jednodimenzionalna polja jer imaju samo jedan indeks), u Pascalu je moguće napraviti i višedimenzionalna polja. Jedino što nas trenutačno treba zanimati su dvodimenzionalna polja. Dvodimenzionalna polja, kao što je vjerojatno očito, imaju – dva indeksa. Da bi se pristupilo određenom elementu dvodimenzionalnog polja, moramo navesti oba indeksa.

Dvodimenzionalna se polja deklariraju ovako:

imePolja: array[prvaDimenzija, drugaDimenzija] of tipPodataka;

Recimo da želimo raditi simulaciju šaha na računalu i potreban nam je prikaz šahovske ploče. Šahovsku bismo ploču bez problema mogli predstaviti kao dvodimenzionalno polje (matricu) 8x8. Broj varijabli u tom polju iznosi 64.

ploca: array[1..8, 1..8] of Integer;

Ako vrijednost želimo zapisati u prvi element polja, onda moramo navesti oba indeksa:

ploca[1, 1] := 29;

Slijedi ozbiljniji primjer u kojem je prikazano korištenje dvostruke (ugniježđene) for petlje kojom se koristimo kada pristupamo elementima dvodimenzionalnog polja.

<pb n="97"/>

4.1.2. Konstantno polje

Tijekom programiranja koristit ćemo se vrijednostima koje se kod izvršavanja programa ne mijenjaju. Takve vrijednosti, kao što već znamo, deklariramo kao konstante. Do sada smo kao konstante deklarirali samo jednostavne vrijednosti, no kao konstantu možemo deklarirati i cijelo polje. Način na koji se deklarira konstantno polje je ovaj:

const

imePolja: array[raspon] of tipPodataka = (vrijednost1,

vrijednost2, vrijednost3, vrijednostN);

Želimo li deklarirati polje od 5 brojeva, to bismo mogli napisati ovako:

const

MojiBrojevi: array[1..5] of Integer = (11, 13, 15, 17, 19);

Na početku drugog poglavlja rješavali smo problem tekstualnog ispisa imena mjeseca. Nakon što korisnik unese broj od 1 do 12, program mu na ekran mora ispisati naziv toga mjeseca u godini. Rješenje toga problema prikazano je u primjeru 2.23. u kojem je vidljiva for petlja i poprilično velika case provjera unutar for petlje.

Mnogo kraće i razumljivije rješenje možemo dobiti ako napravimo funkciju koja će rješavati ovaj problem i ako za imena mjeseci u godini deklariramo konstantno polje imena. Rješenje ispisa imena mjeseci prikazano je u primjeru 4.4.

<pb n="98"/>

4.1.3. Polje kao parametar procedure

Kod stvaranja procedura i funkcija, kao parametar, osim pojedinačnih varijabli, možemo navesti i polje. Kad navodimo polje kao parametar procedure ili funkcije, onda ne navodimo i raspon, nego navodimo samo tip podataka. Procedura koja kao parametar prima polje brojeva izgledala bi ovako:

procedure NekaProcedura(brojevi: array of Integer);

Kada se koristimo poljem kao parametrom, unutar same procedure ili funkcije moramo obvezno koristiti High i Low funkcije za pristup graničnim indeksima polja. Drugi način (manje profesionalan) je da se, uz polje, u listi parametara navedu još dvije zasebne varijable u koju će programer koji se koristi procedurom morati navesti koji je početni, a koji je završni indeks. Takav bi postupak doveo do nepotrebne kompleksnosti, ali je moguć.

Slijedi program koji pomoću posebne procedure računa srednju vrijednost svih brojeva u nekom polju.

<pb n="99"/>

Izvorni kod programa prikazanog u primjeru 4.5. trebao bi biti razumljiv, osim jednog jedva vidljivog dijela — dvostruke deklaracije varijable pod imenom “i”. U programu ne smiju postojati dvije varijable istog imena — a to je sasvim točno. No, taj program uspijeva sasvim lijepo funkcionirati s dvije varijable istog imena.

Razlog normalnog funkcioniranja tog programa je u “vidljivosti” varijabli. Varijabla “i” u glavnom var dijelu programa je globalna, dok je druga varijabla “i” unutar funkcije Srednja i ona je lokalna. Ako se koristimo varijablom pod imenom “i” unutar funkcije Srednja, Pascal će uvijek koristiti prvu varijablu koja mu je u blizini, a u funkciji je to lokalna varijabla “i”. Ako ne pronađe lokalnu varijablu pod imenom “i”, pretražit će glavni var blok i iskoristiti globalnu varijablu pod imenom “i”. Tek ako nigdje u programu ne pronađe varijablu, prikazat će pogrešku o korištenju nepoznatog identifikatora.

4.2. String

String je definitivno najkorišteniji tip podataka koji postoji u Pascalu jer programerima omogućuje vrlo brz, jednostavan i kvalitetan rad s tekstualnim podacima. String je poseban tip podataka koji služi kao zamjena za polja znakova. String koji koristimo u Pascalu najnormalnije je polje znakova, ali je konstantne veličine od 256 elemenata. Za tekstualne podatke možemo koristiti samo 255 znakova pod indeksima od 1 do 255. Znak pod indeksom 0 je rezerviran. U prvom elementu Pascal čuva duljinu stringa.

<pb n="100"/>

Svi string podaci koje pišemo u Pascalu moraju se navoditi unutar jednostrukih navodnika. Ako u tekstu trebamo napisati i jednostruke navodnike, onda dvaput pišemo jednostruke navodnike. Evo kako izgledaju dva string podatka:

Da bismo pobliže upoznali strukturu string podatka u Pascalu, na slici 4.3. prikazano je kako varijabla prviString izgleda u memoriji nakon što u nju zapišemo “Tekst”.

<pb n="101"/>

String je vrlo učinkovit i kvalitetan tip podataka koji se koristi vrlo jednostavno. Pridjeljivanje teksta nekoj string varijabli najosnovnija je operacija koju moramo moći napraviti — i možemo pomoću standardnog operatora pridjeljivanja vrijednosti. Druga najosnovnija operacija zove se konkatenacija stringova (spajanje dvaju stringova, točnije — dodavanje jednoga stringa na kraj drugog). Za konkatenaciju stringova koristi se operator plus.

A evo i razloga zašto svi vole Pascalov string tip podataka. U sljedećem je primjeru vidljiv isti program koji je prikazan u primjeru 4.7. Jedina je razlika što je sljedeći program napisan u programskom jeziku C.

<pb n="102"/>

Stringovi su varijabilan tip podataka. Kad deklariramo string varijablu, ona zauzima 256 bajtova memorije, ali ne moramo uvijek koristiti svih 256 znakova. String koristi samo onoliko znakova koliko mu treba, a ostatak ostaje neiskorišten. Kad radimo sa stringovima, onda radimo točno s onim brojem znakova koliko je zapisano u nultom elementu stringa.

4.2.1. Provjeravanje duljine stringa

Ako želimo saznati točnu duljinu stringa, to možemo napraviti na dva načina. Možemo pročitati broj zapisan u nultom elementu stringa ili možemo iskoristiti funkciju Length. U Pascalu su iskoristiva oba načina, ali u Delphiju (zbog drukčije arhitekture stringa) možemo se koristiti samo funkcijom Length.

S obzirom na to da je string samo malo naprednije polje znakova (pogotovo string tip podataka u Delphiju), pojedinačnim slovima možemo pristupiti na isti način na koji koristimo i normalna polja podataka. U sljedećem primjeru možemo vidjeti funkciju koja okreće string tako što kroz petlju pristupa svakom pojedinom znaku i zapisuje znak na drugo mjesto.

<pb n="103"/>

<pb n="104"/>

Funkcija Okreni ilustrira neke novosti oko rada sa stringovima. Vrijednost '' (dva jednostruka navodnika) označuje prazan string koji možemo koristiti kad želimo navesti da u stringu nema podataka, ili kada želimo provjeriti ima li u stringu teksta ili nema.

Funkcija Okreni koristi se procedurom Exit kako bi ranije izašla iz procedure. Proceduru Exit ovdje koristimo samo kada je string prazan. Ako provjera na početku funkcije utvrdi da je string prazan, procedura Exit odmah će završiti izvršavanje funkcije jer nema potrebe izvršavati daljnje naredbe, kao računanja duljine stringa i slično. Korištenjem procedure Exit, u slučaju praznog stringa, ubrzava se rad cijele funkcije i sprječava se izvršavanje linija koda koje nam nisu potrebne.

Prije nego krenemo dalje, proučite komentare koji su prikazani u primjeru 4.10. Oni dosta dobro objašnjavaju dijelove funkcije i čemu određeni dijelovi služe.

4.2.2. Definiranje kratke string varijable

Tijekom programiranja možemo normalno koristiti string tip podataka sa svih svojih 256 znakova. No, ako želimo biti malo štedljiviji s radnom memorijom (ili, što je bitnije — ako string podatke želimo zapisati u binarnu datoteku (datoteku zapisa), kao što ćemo napraviti nešto kasnije u knjizi), stringove možemo definirati tako da zauzimaju manje od 256 bajtova.

Recimo da radimo program za evidenciju korisnika. Imena svih korisnika vrlo su vjerojatno kratka pa bi za čuvanje informacije o imenu bilo dovoljno samo 20 znakova. Očito je da je višak od 230-ak bajtova po jednom korisniku poprilično velik, pa u Pascalu taj problem rješavamo tako da limitiramo veličinu stringa na 20 znakova. Stringovi s određenom veličinom deklariraju se ovako:

imeStringa: string[veličina];

odnosno

var

ime: string[20];

Korištenje stringova limitirane veličine vidjet ćemo nešto kasnije. Za sada nam ostaje da se upoznamo s procedurama i funkcijama koje možemo koristiti sa stringovima.

4.2.3. Standardne string procedure i funkcije

Pascal ima mali broj funkcija i procedura koje rade sa stringovima, ali te funkcije i procedure dovoljne su da sami pomoću njih razvijamo naprednije metode za rad sa stringovima. Slijedi tablica najosnovnijih procedura i funkcija koje možemo primjenjivati u radu sa stringovima.

<pb n="105"/>

Počet ćemo s funkcijom koju je najjednostavnije razumjeti jer smo je na neki način već koristili tijekom rada sa stringovima. Funkcija Concat može se koristiti tijekom programiranja za konkatenaciju (spajanje) stringova. Funkcija Concat vraća istovjetan rezultat kao i operator konkatenacije stringova. Pri programiranju u Delphiju preporučeno je ne koristiti se funkcijom Concat za spajanje stringova jer je operator konkatenacije brži. U sljedećem kratkom primjeru može se vidjeti način korištenja Concat funkcije.

4.2.4. Jednostavno pretraživanje stringova

Druga funkcija koju ćemo obraditi je vrlo jednostavna funkcija Pos kojom se možemo koristiti kada želimo provjeriti nalazi li se jedno slovo ili čak kraći dio teksta unutar nekog stringa. Pos funkcija se dosta često koristi da bi se provjerilo postoji li ili ne postoji u stringu neki znak. Funkcija Pos kao rezultat svojeg pretraživanja vraća broj. Ako funkcija ne pronađe znak ili tekst unutar stringa koji smo pretraživali, vratit će nulu, a ako pronađe slovo ili tekst, vratit će poziciju prvog pojavljivanja slova u stringu.

<pb n="106"/>

U primjeru koji slijedi koristit ćemo se funkcijom Pos da bismo utvrdili je li neki string dobra e-mail adresa ili nije. Ono što jednostavno možemo provjeriti u e-mail adresi je ima li u njoj “.” i “@”. Ako ta dva znaka (točka i at znak) postoje, e-mail adresa je vjerojatno točna.

Pri kreiranju ovakvih jednostavnijih funkcija koje vraćaju Boolean vrijednost, Pascal nam dopušta igranje s izrazima. Pogledajmo sljedeći vrlo kratki primjer koda koji je sasvim u redu i daje nam Boolean rezultat.

var

tocno: Boolean;

<pb n="107"/>

broj: Integer;

begin

broj := 65;

tocno := broj = 64; { tocno ce biti False }

end.

U naredbi tocno := broj = 64; ne koriste se dva operatora pridjeljivanja jer je to u jednoj naredbi nemoguće. U ovom se izrazu koriste operator pridjeljivanja i relacijski operator. Korištenjem znaka jednakosti dio izraza broj = 64 označuje zapravo jednu Boolean vrijednost. Ako je u varijabli broj zapisan broj 64, dio izraza broj = 64 vratit će vrijednost True, a u trenutačnoj situaciji u varijablu broj zapisuje vrijednost False.

Funkcija Email_Adresa može se napisati na mnogo kraći (jednostavniji?) način, a ako ga trenutačno ne razumijete — nema problema. Evo kako bi izgledala potpuno funkcionalna funkcija Email_Adresa od samo jedne linije koda:

function Email_Adresa2(email: string): Boolean;

begin

Email_Adresa2 := (Pos(‘.’, email) <> 0) and

(Pos(‘@’, email) <> 0);

end;

Ovako napisana funkcija jednostavna je onomu s malo više iskustva u programiranju, ali niti početnicima koji su svladali and operator ne bi smjela biti problem. Kada se pozove ta funkcija, funkcija Pos najprije provjerava postoji li točka unutar stringa email. Ako postoji, u privremeno mjesto u memoriji zapisuje True, a ako točka ne postoji, zapisuje False. Ista se operacija događa i sa znakom at (obvezno zapamtite da će se u izrazu uvijek prvi izvršiti onaj dio koda koji se nalazi unutar većega broja zagrada). Kad se provjeri postojanje obaju znakova, onda se obje vrijednosti provjere pomoću and operatora i rezultat and operatora zapisuje se kao rezultat cijele funkcije. Upravo to nam i treba, jer and operator vraća True samo ako su oba uvjeta True (dakle, ako postoji i točka i at znak unutar stringa).

4.2.5. Ubacivanje teksta u string

Sljedeća procedura koju ćemo obraditi je procedura Insert kojom se možemo koristiti za precizno ubacivanje jednog stringa u drugi. Sljedeći primjer će koristiti proceduru Insert kako bi popravio pogrešno napisanu abecedu. Program će na ekran namjerno pogrešno ispisati abecedu, a korisnik mora napisati koje slovo nedostaje i na kojem se mjestu to slovo treba nalaziti. Kada unese te vrijednosti, procedura Insert ubacit će slovo na točno tu poziciju koju je korisnik odabrao.

<pb n="108"/>

4.2.6. Brisanje dijelova stringa

Procedura Delete još je jedna od procedura koja se poprilično često primjenjuje u radu sa stringovima. Procedurom Delete koristimo se kada iz stringa želimo obrisati određen broj znakova, i to s točno određenog mjesta. Uzmimo u obzir ponovno unos e-mail adresa. Recimo da nam u stringu više ne treba cijela e-mail adresa, nego samo korisničko ime (sav tekst do znaka at “@”). Najlakši način da se riješimo viška je da iskoristimo proceduru Delete i jednostavno odbacimo višak. No, to je možda jednostavnije reći nego napraviti.

<pb n="109"/>

Poziv procedure Delete izgleda poprilično glomazno zbog računanja broja slova koja je potrebno pobrisati. Prvi parametar procedure Delete je string čije ćemo dijelove brisati. Drugi je parametar pozicija od koje krećemo s brisanjem slova. Jedina stvar koju moramo saznati je broj znakova koje želimo obrisati. Ako želimo obrisati samo 2, onda ćemo jednostavno u treći parametar zapisati broj 2, no, ako nam treba varijabilni broj znakova, onda se moramo nekako snaći, kao što je slučaj u primjeru 4.14.

4.2.7. Kopiranje dijelova stringa

Zadnja funkcija koju moramo upoznati je funkcija Copy kojom se koristimo kada jedan dio originalnog stringa želimo kopirati u drugi string. Funkciju Copy možemo primjerice iskoristiti kada iz nekog popisa koji sadrži redne brojeve i imena želimo izvaditi samo imena. Funkcija Copy i procedura Delete razlikuju se u tome što procedura Delete radi s originalnim stringom dok funkcija Copy stvara duplikat onog dijela stringa koji želimo kopirati.

Recimo da nam je popis imena zadan u formatu: “1. Sir Anthony Hopkins”. Zadatak nam je u novom stringu dobiti samo ime, bez rednoga broja. Najjednostavniji način nije reći funkciji Copy da kopira sav tekst od trećeg slova pa do kraja stringa jer bi to vrijedilo samo za brojeve od 0 do 9. Najbolje je rješenje pomoću funkcije Pos naći poziciju razmaka koja se nalazi odmah ispred prvoga slova imena. Nakon što nađemo poziciju razmaknice, dalje je jednostavno. U prvi parametar funkcije Copy navedemo string iz kojeg kopiramo podatke, drugi je parametar mjesto od kojeg kreće kopiranje, a zadnji parametar označuje koliki će se broj znakova kopirati.

<pb n="110"/>

Funkcijom Copy stigli smo do kraja rada sa stringovima, ali i do kraja ovog poglavlja.

4.3. Sažetak

Ovo je poglavlje predstavilo najkorišteniji tip podataka u Pascalu i Delphiju, string. String koristimo u većini programa koje stvaramo, a to će posebno vidljivo biti pri stvaranju Windows aplikacija u Delphiju.

Pitanja i zadaci

Pitanje 1: U kojoj se situaciji obično koristimo poljem?

Pitanje 2: Kojom rezerviranom riječi deklariramo polje?

Pitanje 3: Sastoji li se sljedeće polje od 6 ili 7 elemenata?

var

mojiPodaci: arrey[1..6] of Integer;

Pitanje 4: Ako deklariramo polje pod imenom “brojevi” od 6 Integer varijabli s rasponom indeksa od 1 do 6, kako ćemo u prvu varijablu polja upisati broj 100?

Pitanje 5: Ako deklariramo polje od 5 Integer varijabli:

<pb n="111"/>

var

polje: array[1..5] of Integer;

kako ćemo ispisati zbroj prva tri elementa polja?

Pitanje 6: Kojim se funkcijama možemo koristiti kada želimo dobiti indeks prvog i zadnjeg elementa polja?

Pitanje 7: Od koliko se Char elemenata sastoji string u Pascalu?

Pitanje 8: Čemu služi prvi znak Pascal stringa, znak pod indeksom 0?

Pitanje 9: Na koja dva načina možemo provesti konkatenaciju stringova?

Pitanje 10: Na koja dva načina možemo provjeriti duljinu stringa?

Zadatak 1: Napišite proceduru koja će sva velika slova “A” u nekom stringu pretvoriti u mala slova “a”.

Zadatak 2: Napišite proceduru koja će na ekran ispisivati samo prvo i zadnje slovo stringa.

<pb n="112"/>

<pb n="113"/>

5. Enumeracije, zapisi i tekstualne datoteke

5.1. Stvaranje novih tipova podataka 114

5.2. Enumeracije 115

5.2.1. Podtip enumeriranog tipa podataka 117

5.2.2. Setovi podataka 118

5.3. Zapisi 120

5.4. Tekstualne datoteke 123

5.5. Sažetak 128

6. Pokazivači 132

<pb n="114"/>

5. Enumeracije, zapisi i tekstualne datoteke

U ovom nas poglavlju očekuje rad s enumeriranim (pobrojenim) tipovima podataka pomoću kojih uz malo znanja možemo sasvim lijepo optimizirati Pascal i Delphi programe. Na kraju poglavlja, kao šećer na kraju, čeka nas rad s tekstualnim datotekama.

5.1. Stvaranje novih tipova podataka

Prije nego što krenemo na enumerirane tipove podataka moramo znati kako napraviti vlastiti tip podataka. Novi tip podataka možemo stvoriti pomoću rezervirane riječi type na sljedeći način:

type

Ime_Novog_Tipa = Bilo_Koji_Postojeci_Tip;

Ime_Novog_Tipa = Područje_Vrijednosti;

Rezerviranu riječ type možemo koristiti za stvaranje novog objekta, brojeva s manjim rasponom vrijednosti, stringa s manjim brojem znakova ili bilo što potrebno. Kad pomoću rezervirane riječi type stvorimo novi tip podataka, prema njemu se Pascal ponaša jednako kao što se ponaša prema standardnim tipovima podataka: poljima, string ili Integer tipu podataka. Nakon što stvorimo vlastiti tip podataka, da bismo ga iskoristili, moramo deklarirati varijablu tog tipa. Program u primjeru 5.1. prikazuje definiciju i načine korištenja triju novih tipova podataka.

<pb n="115"/>

Program u primjeru 5.1. prikazuje definiciju triju novih tipova podataka. Sva imena novih tipova podataka počinju velikim slovom T. Ovo nije obveza, ali je Borlandov svjetski prihvaćen način označivanja tipova podataka. U Pascalu i Delphiju svi tipovi podataka počinju velikim slovom T i apsolutno se svi Pascal i Delphi programeri na svijetu koriste ovim načinom označivanja.

Drugi poseban način pisanja koda vidljiv je u listi parametara procedure PrikaziPopis. Vrlo često se pri stvaranju liste parametara parametar naziva samim imenom tipa podatka, samo što se slovo T zamjenjuje s A.

5.2. Enumeracije

Enumerirani tip podataka stvaramo kada nam tijekom programiranja zatreba vrlo efikasna i malena lista podataka. Enumerirani tip definiramo tako da nabrajamo sve njegove vrijednosti. Jedna od najjednostavnijih i najrazumljivijih lista vrijednosti je lista dana u tjednu.

Listu dana u tjednu definirali bismo ovako:

type

TDan = (Pon, Uto, Sri, Cet, Pet, Sub, Ned);

Kada definiramo enumerirani tip podataka, vrijednosti navodimo bez navodnika, jer te vrijednosti nisu tekstualnog tipa, nego brojevne konstante. Kada na ovaj način definiramo vrijednosti, elementi enumeracije dobivaju redne brojeve. Pon ima redni broj 0, Uto ima redni broj 1 i tako dalje.

Ako želimo dobiti redni broj nekog elementa enumeracije, onda se koristimo funkcijom Ord.

var

broj: Integer;

begin

broj := Ord(Cet);

end.

Ako pokrenemo navedeni dio koda, u varijablu broj zapisat će se redni broj četvrtka, u našem slučaju to je broj 3.

<pb n="116"/>

S obzirom na to da možemo dobiti redni broj elementa enumeracije, mora postojati i način da od rednoga broja stvorimo element enumeracije. Naravno, to je moguće, ali za to moramo znati kako napraviti konverziju tipova podataka. Konverzija tipova podataka radi se ovako:

varijabla := Ime_Enumeriranog_Tipa(Vrijednost);

Program u primjeru 5.2. mnogo bolje objašnjava postupak konverzije vrijednosti iz jednog u drugi tip podataka.

Tijekom rada s enumeriranim tipovima podataka bez problema se možemo koristiti funkcijama Pred i Succ koje će nam dati prethodni i sljedeći enumerirani podatak u listi. Program u primjeru 5.3. ilustrira vrlo velik broj načina na koje možemo iskoristiti enumerirane podatke. Pažljivo proučite ovaj primjer.

<pb n="117"/>

5.2.1. Podtip enumeriranog tipa podataka

Nakon što definiramo novi enumerirani tip podataka, njega možemo iskoristiti za definiranje novih tipova podataka koji će biti podtip glavnog tipa. Takav tip podataka može imati samo određene vrijednosti, a to su sve vrijednosti glavnog tipa podataka ili samo određeni raspon vrijednosti koje se nalaze u glavnom enumeriranom tipu podataka. U primjeru koji slijedi vidjet ćemo kako se stvaraju podtipovi tipa TDan. Definirat ćemo TVikend i TRadniDan tipove podataka kao podtipove s limitiranim skupom vrijednosti.

Podtip enumeriranog tipa podataka definira se ovako:

type

ImePodTipa = PocetnaVrijednost..KrajnjaVrijednost;

<pb n="118"/>

5.2.2. Setovi podataka

Kod enumeriranih tipova podataka možemo se odjednom koristiti samo jednom vrijednošću. Ako želimo koristiti više od jedne vrijednosti, od enumeriranog tipa podataka moramo stvoriti set ili skup podataka. Set podataka stvara se pomoću rezervirane riječi set, a izgleda otprilike ovako:

type

TSetTipPodataka = set of TEnumeriraniTip;

Ako želimo napraviti set dana u tjednu, to bismo napravili ovako:

type

TDani = (Pon, Uto, Sri, Cet, Pet, Sub, Ned);

TSetDana = set of TDani;

Nakon što definiramo set dana kao tip podataka TSetDana, taj se tip podataka koristi poprilično drukčije od enumeriranog tipa podataka. Kada deklariramo varijablu nekog seta podataka, taj će set biti prazan. Prazan set označuje se uglatim zagradama.

var

MojiDani: TSetDana;

begin

MojiDani := []; { ovo je prazan set }

end.

Ako u set podataka želimo dodati jednu ili više vrijednosti, to možemo napraviti pomoću operatora +. Pritom moramo paziti da set vrijednosti pišemo unutar uglatih zagrada. Želimo li u set MojiDani uključiti ponedjeljak, to ćemo napisati na sljedeći način:

MojiDani := MojiDani + [Pon];

Drugi način na koji možemo ponedjeljak uključiti u set MojiDani je da iskoristimo proceduru Include. Procedura Include uključuje podatak u set podataka brže i bolje od operatora + pa je preporučljivo češće koristiti proceduru <pb n="119"/>Include. Procedura Include prima dva parametra, prvi je naziv set varijable, a drugi je enumerirana vrijednost koju želimo uključiti u set podataka. Pri korištenju procedure Include, unutar liste parametara nije potrebno navoditi uglate zagrade oko enumerirane vrijednosti.

Include(MojiDani, Pon);

Ako u set podataka želimo uključiti više podataka, to ponovno možemo napraviti na dva načina. Operatorom + možemo u istoj liniji koda uključiti sve potrebne vrijednosti, dok pomoću procedure Include možemo uključivati jednu po jednu vrijednost. Evo kako bi izgledalo uključivanje utorka i srijede pomoću operatora +, te uključivanje četvrtka i petka pomoću procedure Include.

MojiDani := MojiDani + [Uto, Sri];

Include(MojiDani, Cet);

Include(MojiDani, Pet);

Ako nam više ne trebaju četvrtak i petak, u Pascalu postoje dva načina kako ih možemo izostaviti. Jedan je od načina korištenje operatora — kojim možemo izostaviti jednu ili više vrijednosti. Drugi (malo brži) način je primjena procedure Exclude koja ima iste parametarske zahtjeve kao i procedura Include. Prvi je parametar ime set varijable s kojom radimo, a drugi je parametar vrijednost koju želimo isključiti iz seta podataka.

MojiDani := MojiDani - [Pet];

Exclude(MojiDani, Cet);

Uz dodavanje i brisanje podataka iz seta, moguće je provjeriti postoji li neki podatak u setu ili ne postoji. Za tu provjeru služi nam rezervirana riječ in, a ona se koristi na sljedeći način:

if enumerirana_vrijednost in set then

Program u primjeru 5.5. ilustrira razne načine korištenja setova podataka i enumeriranih vrijednosti.

<pb n="120"/>

5.3. Zapisi

Poznavanje stvaranja i rada sa zapisima (engl. record) neophodno je za programiranje profesionalnih Pascal i Delphi programa. Zapisi se koriste za grupiranje više podataka (varijabli) u jednu logičku cjelinu. S obzirom na to da stvaranjem zapisa stvaramo novi tip podataka, stvaranje zapisa navodimo iza rezervirane riječi type. Novi zapis kreira se ovako:

type

ImeZapisa = record

deklaracija_varijable_1;

deklaracija_varijable_2;

deklaracija_varijable_n;

end;

Pri definiranju novog zapisa koristi se rezervirana riječ record koju na kraju moramo obvezno popratiti s end; (čak iako nigdje nije navedena rezervirana riječ begin) jer se sve pripadajuće varijable deklariraju unutar bloka zapisa. Ako zaboravimo navesti end;, program se neće moći uspješno kompilirati.

Nakon što definiramo novi zapis, varijablama koje su definirane unutar zapisa ne možemo pristupiti izravno. Pri korištenju zapisa najprije moramo stvoriti varijablu tog tipa.

type

TAuto = record

Tip: string;

MaxBrzina: Integer;

end;

var

MojAuto: TAuto;

Nakon što stvorimo varijablu MojAuto, na raspolaganju imamo jednu kompleksnu varijablu (zapis) koja se sastoji od dvaju elemenata, Tip i MaxBrzina. Želimo li definirati brzinu i tip tog automobila, izvorni kôd moramo pisati ovako:

ImeZapisa.Element := vrijednost;

Točka iza imena zapisa označuje da pristupamo podelementu. Varijable Tip i MaxBrzina nisu varijable u pravome smislu i njih ne možemo koristiti izravno u kodu. Varijable Tip i MaxBrzina elementi su deklaracije zapisa. Jedini način kako ih možemo iskoristiti je da deklariramo varijablu tipa zapisa TAuto i onda preko <pb n="121"/>te varijable pristupimo elementima samog zapisa. Ovu je sintaksu posebno važno zapamtiti zbog objektno-orijentiranog programiranja u Delphiju.

Želimo li promijeniti sve vrijednosti unutar zapisa MojAuto, izvorni kôd će izgledati ovako:

MojAuto.MaxBrzina := 245;

MojAuto.Tip := ‘Peugeot’;

Program u primjeru 5.6. pobliže ilustrira definiranje i korištenje zapisa.

<pb n="122"/>

Osim toga što možemo deklarirati pojedinačni zapis i njime se koristiti na prije prikazani način, katkad ćemo imati potrebu definirati i cijelo polje zapisa. Sintaksa pristupa polju zapisa izgleda ovako:

ImeZapisa[IndexPolja].ElementZapisa := vrijednost;

<pb n="123"/>

Pri radu sa zapisima koji se sastoje od velikoga broja elemenata bilo bi vrlo zamorno stalno ponavljati ime zapisa, pa točku, pa tek onda ime elementa koji nas zanima. Pascal, naravno, omogućuje skraćeni način na koji možemo pristupati elementima zapisa a da stalno ne ponavljamo ime zapisa. Takav, skraćeni način dobivamo korištenjem rezervirane riječi with. Ona se koristi na sljedeći način:

with Zapis do

begin

ImeElementa := Vrijednost;

ImeElementa2 := Vrijednost;

ImeElementaN := Vrijednost;

end;

Prikazano na primjeru, korištenje rezervirane riječi with izgleda ovako:

type

TAuto = record

Ime: string;

Brzina: Real;

end;

var

MojAuto: TAuto;

begin

with MojAuto do

begin

Ime := ‘Hrvatski shuttle’;

Brzina := 9.81;

end;

end.

Nakon rada sa zapisima, u ovom nas poglavlju očekuje još samo šećer na kraju, a to je rad s tekstualnim datotekama.

5.4. Tekstualne datoteke

Tekstualne su datoteke jedan od najkorištenijih tipova datoteka na osobnim računalima. Uz sve što smo naučili do sada, ovo je vrlo bitno i to mora znati svaki ozbiljni programer — kako snimiti ili učitati podatke s diska. Cijeli postupak oko pristupa disku i podacima na njemu nije težak.

Prvo što moramo znati oko rada s tekstualnim datotekama je da za pristup tekstualnim datotekama koristimo novi tip podataka pod imenom Text. Dakle, želimo li pristupiti nekoj datoteci na disku, to ćemo moći napraviti pomoću varijable tipa Text.

var

datoteka: Text;

<pb n="124"/>

Prvi korak kod pristupa datoteci na disku je spajanje imena datoteke na disku s varijablom tipa Text. Za ovaj (apsolutno najbitniji) korak primjenjuje se procedura Assign. Procedura Assign prima dva parametra. Prvi parametar je varijabla tipa Text kojom se koristimo za pristup datoteci, a drugi je parametar string u kojem je zapisano ime datoteke na disku. Odabir datoteke koja se zove “imena.txt” na disku C izgleda ovako:

Assign(datoteka, ‘C:\imena.txt’);

Nakon što pomoću procedure Assign odaberemo s kojom ćemo datotekom na disku raditi moramo odabrati što ćemo s tom datotekom raditi. Postoje tri operacije koje možemo napraviti s datotekom jednom kada je odaberemo. Datoteku možemo otvoriti za čitanje, možemo je otvoriti za zapisivanje, a možemo je otvoriti u svrhu dodavanja podataka na kraj datoteke.

Kada datoteku želimo otvoriti za čitanje, onda se koristimo procedurom Reset. Ako datoteku želimo otvoriti za zapisivanje podataka, koristimo se procedurom Rewrite. Za dodavanje podataka na kraj datoteke koristi se procedura Append.

U prvom ćemo primjeru otvarati datoteku za zapisivanje podataka. Procedura Rewrite, kojom se koristimo za taj posao, prima samo jedan parametar, a to je ime Text varijable koja označuje datoteku na disku.

Rewrite(datoteka);

Nakon što iskoristimo proceduru Rewrite, nekoliko se stvari može dogoditi na disku s odabranom datotekom. Ako datoteka s istim imenom već postoji na disku, njezin će se sadržaj korištenjem procedure Rewrite u potpunosti izbrisati. Ako datoteka s odabranim imenom ne postoji na disku, procedura Rewrite stvorit će potpuno praznu datoteku (veličine 0 bajta).

Kad se datoteka napokon stvori ili otvori, procedura Rewrite postavlja kursor datoteke na početak. Kao i tekst na ekranu, datoteke imaju kursor koji služi za čitanje i pisanje podataka.

Nakon naredbe Assign i Rewrite možemo krenuti zapisivati podatke u datoteku. Za zapisivanje podataka u datoteku koriste se naši stari prijatelji, procedure Write i Writeln. Kod tekstualnih datoteka premoć ima procedura Writeln. Iako se primjenjuju stare, već dobro poznate procedure, one se koriste na malo drukčiji način. Pri zapisivanju podataka u datoteku na disku procedura Writeln ima ovu strukturu:

Writeln(imeDatoteke, string1, string2, ...., stringN);

Naredbu Writeln možemo iskoristiti koliko god puta želimo za zapisivanje podataka u datoteku na disku. Kad zapišemo sve potrebne podatke u datoteku na disku, OBVEZNO moramo napraviti još jedan jedini korak, a to je zatvaranje datoteke. Ako ne zatvorimo datoteku, vrlo je vjerojatno da je ni jedan drugi program, pa ni naš, neće moći ponovno otvoriti sve dok se ne resetira računalo. Razlog tomu je što operativni sustav prigodom otvaranja zaključa datoteku.

Datoteka se nakon rada zatvara pomoću procedure Close koja prima samo jedan parametar, a to je datoteka koju treba zatvoriti. Taj je parametar također tipa Text. Evo kako bi izgledao jedan vrlo kratki, ali funkcionalni primjer zapisivanja jedne rečenice na disk.

<pb n="125"/>

Učitavanje podataka iz datoteke nije ništa veći problem nego što je zapisivanje. Postupak je potpuno isti, samo se razlikuju procedure koje se koriste za obavljanje posla. Pri otvaranju datoteke za čitanje ne smijemo se koristiti procedurom Rewrite jer bi nam ona uspješno obrisala sve podatke. Za čitanje koristimo proceduru Reset koja otvara datoteku bez mijenjanja njezina sadržaja i postavlja kursor na početak datoteke. Nakon što, pomoću procedure Reset, otvorimo datoteku, za učitavanje podataka koristimo se procedurama Read ili Readln. Kod tekstualnih datoteka najčešće se koristi procedura Readln. Kao i kod procedure Writeln, kod procedure Readln kao prvi parametar moramo navesti datoteku iz koje se čitaju podaci. No, drugi je parametar nešto drukčiji. Kao drugi parametar procedure Readln navodi se ime varijable u koju će se spremiti vrijednost koja je učitana iz datoteke.

Učitavanje teksta “Turbo Pascal” iz prije stvorene datoteke izgleda ovako:

<pb n="126"/>

Tijekom rada s datotekama nećemo se susretati s datotekama u kojima je zapisana samo jedna riječ ili jedna rečenica. Ako želimo učitati mnogo više linija teksta i prikazati ih na ekranu, moramo se koristiti funkcijom Eof koja nam vraća Boolean informaciju o kraju datoteke. Kada kursor dosegne kraj datoteke, funkcija Eof vraća vrijednost True, čime nas obavještava da iz datoteke više nemamo što učitati. Funkcija Eof se obično koristi kao dio while petlje unutar koje se učitavaju podaci. Sljedeći primjer će najprije zapisati 20 linija teksta u datoteku, nakon toga će ih pomoću funkcije Eof i while petlje učitati iz datoteke i prikazati na ekranu.

<pb n="127"/>

<pb n="128"/>

Kao što je vidljivo iz svih ovih primjera, rad s tekstualnim datotekama uopće nije problem. Jednostavnom primjenom osnovnog kostura za pristup datotekama moguće je napraviti program koji bez poteškoća radi s podacima na disku. Za kraj ovog poglavlja slijedi primjer koji kopira datoteku.

Apsolutno najzabavniji dio ovoga primjera je procedura KopiranjeDatoteke. Unutar bloka procedure vrlo brzo nailazimo na linije koda s kojima se do sada nismo nikad susreli. Prva takva linija glasi {$I-}. Takva linija, obično formata {$naredba} naziva se kompilatorskom direktivom (naredbom) kojom možemo utjecati na rad samog Pascal (i Delphi) kompilatora. Naredbom {$I-} koristimo se kada želimo prekinuti provjeru I/O (input/output) rada (zapisivanja i čitanja podataka s diska). Kada je I/O provjera isključena, procedure poput Reset i Rewrite nam pomoću funkcije IOResult vraćaju informaciju o svojem radu.

Funkcija IOResult vraća status zadnje I/O operacije koju smo napravili. Ako je rezultat funkcije IOResult jednak nuli, znači da je sve uspješno odrađeno. U proceduri KopiranjeDatoteke rezultat funkcije IOResult provjeravamo nakon procedura Reset i Rewrite kako bismo se osigurali da su i izvorna i destinacijska datoteka uspješno otvorene. Nakon što se izvrši dio koda koji želimo provjeriti, obično se provjera I/O operacija ponovno aktivira. Za aktiviranje provjere I/O operacija koristi se kompilatorska direktiva {$I+}.

5.5. Sažetak

S obzirom na to da je računalo uređaj koji služi za pohranu i obradu podataka, rad s podacima na disku vrlo je bitan dio života i rada svakoga programera. Apsolutno svaka aplikacija koja postoji danas na svijetu radi s datotekama na ovaj ili onaj način. Programi za obradu teksta otvaraju i snimaju razne tipove datoteka (tekstove, binarne datoteke ili programerski definirane datoteke), različite multimedijalne aplikacije otvaraju slike, glazbu i filmove, igrice učitavaju mape i spriteove.

Tekstualne su datoteke najjednostavniji i najosnovniji tip datoteka koji postoji na računalu. Rad s tekstualnim datotekama može mnogo puta dobro doći i to ćemo znanje kasnije poprilično dobro iskoristiti.

Pitanja i zadaci

Pitanje 1: Kojom rezerviranom riječi stvaramo novi tip podataka u Pascalu?

Pitanje 2: Što nije u redu sa sljedećom listom vrijednosti?

TMjesec = Sijecanj, Veljaca, Ozujak;

Pitanje 3: Kako stvaramo set podataka?

<pb n="129"/>

Pitanje 4: Koju proceduru možemo iskoristiti pri korištenju set varijable ako neku vrijednost želimo uključiti u set?

Pitanje 5: Kojom rezerviranom riječi stvaramo novi zapis?

Pitanje 6: Što mora obvezno pisati na kraju definicije zapisa?

Pitanje 7: Kojim se tipom podataka koristimo kada želimo pristupiti tekstualnoj datoteci na disku?

Pitanje 8: Kojom procedurom odabiremo datoteku kojom se želimo koristiti?

Pitanje 9: Nakon što otvorimo datoteku, koju proceduru moramo pozvati na kraju rada s datotekom?

Pitanje 10: Što je to {$tekst}?

Zadatak 1: Napišite program koji će deset puta u datoteku “C:\Lista.txt” upisati tekst “Linija 1”, “Linija 2”, “Linija 3” itd.

Zadatak 2: Napišite program koji će učitavati tekst iz neke datoteke na disku i prikazivati ga na ekranu. No, program ne smije prikazivati samo tekst iz datoteke na ekranu nego ispred svake linije teksta mora navesti redni broj linije, te na kraju učitavanja datoteke mora ispisati poruku “Kraj.”.

<pb n="130"/>

<pb n="131"/>

6. Pokazivači

6.1. Osnove rada s pokazivačima 132

6.1.1. Stvaranje dinamičkih varijabli 135

6.1.2. Generički pokazivači 138

6.1.3. Aritmetika pokazivača 140

6.2. Jednostruko povezana lista 142

6.3. Stvaranje povezane liste – reda 142

6.3.1. Dodavanje podataka u listu 144

6.3.2. Prikazivanje sadržaja liste 146

6.3.3. Brisanje cijele povezane liste 147

6.3.4. Brisanje jednog podatka liste 148

6.4. Sažetak 153

<pb n="132"/>

6. Pokazivači

Sad smo napokon došli do poglavlja koje sva ostala poglavlja ostavlja daleko u prašini. Ne po kvaliteti teksta, nego po količini glavobolja koje pokazivači zadaju učenicima, studentima i profesionalcima kad ne paze što rade. Uz osnove rada s pokazivačima, vidjet ćemo i kako se stvara dosta teški i malčice apstraktni sustav pokazivača poznat pod imenom povezana lista. No, prije nego se tko od nas uplaši, nastavimo s poglavljem.

Upozorenje za one sa slabim srcem. Slijedi mnogo teorije.

6.1. Osnove rada s pokazivačima

Za početak, prvo što je potrebno objasniti u vezi s pokazivačima je što su uopće pokazivači. Najjednostavnije objašnjeno, pokazivač je posebna varijabla koja sadrži memorijsku adresu neke druge varijable (pokazuje na drugu varijablu), ali može pokazivati i na sebe. Zbog te karakteristike varijabli da pokazuju na neku drugu varijablu dobile su poseban naziv — pokazivači.

U Pascalu postoje dvije vrste pokazivača, tipizirani pokazivači i generički pokazivači. Tipizirani pokazivači su pokazivači koji pokazuju na varijable samo određenog tipa podataka, dok su generički pokazivači oni koji pokazuju na dio memorije i nemaju informaciju o podacima koji se nalaze spremljeni na tom dijelu memorije.

Pokazivači su, iako se sada možda ne čini tako, vrlo važan tip podataka, jer uz razne optimizacije koje je moguće postići njihovom primjenom, omogućuju nam korištenje velikih područja memorije i rad s velikom količinom podataka.

Ono što je bitno znati prije nego krenemo na pokazivače je što se događa s varijablama koje smo do sada učili. Varijable kojima smo se do sada koristili tijekom programiranja nazivaju se statičkim varijablama. Takve se varijable spremaju u poseban dio memorije zvan stack. Stack memorijom se Pascal program koristi za zapisivanje vrijednosti statičkih varijabli. Stack memorija je dio radne memorije koju si program osigurava za rad sa statičkim varijablama.

Pri stvaranju Pascal programa, glavni program ima na raspolaganju samo 64 KB memorije za varijable, a svaki dodatni unit ima na raspolaganju još 64 KB memorije. Te su vrijednosti premalene za većinu programa koji danas postoje.

S obzirom na to da smo podosta limitirani veličinom memorije koju imamo na raspolaganju za varijable, u spas nam dolaze pokazivači, odnosno varijable kreirane pomoću pokazivača (ovo će biti uskoro prikazano). Varijable koje se kreiraju na taj način, pomoću pokazivača, nazivaju se dinamičkim varijablama.

Dinamičke se varijable stvaraju u glavnom dijelu memorije koji se još zove i heap memorija. Heap memorije imamo na raspolaganju poprilično mnogo (to može biti fizička memorija ili virtualna memorija, ali to sada nije bitno). Pri programiranju u operativnom sustavu Windows svaki program ima na raspolaganju 4 GB virtualne memorije, dakle, sasvim dovoljno prostora za rad.

Glavna karakteristika dinamičkih varijabli je mogućnost njihova stvaranja (alokacije memorije) i brisanja (dealokacije memorije) tijekom izvršavanja programa. Zato se i zovu dinamičke varijable jer ih tijekom izvršavanja programa možemo stvarati i brisati po potrebi.

Jedini manji problemčić vezan uz dinamičke varijable je potreba njihove eksplicitne dealokacije. Jednostavnije rečeno, statičke varijable zauzimaju određeni dio memorije, ali taj se dio memorije oslobađa kada program završi <pb n="133"/>s radom. Dinamičke varijable također zauzimaju određeni dio memorije, no njih program ne briše automatski na kraju izvršavanja. Programeri moraju sami osloboditi memoriju koju zauzimaju dinamičke varijable.

Svaki pokazivač koji deklariramo u Pascalu zauzima 4 bajta memorije (stack memorije), ali on može bez ikakvih problema pokazivati na početak slike u memoriji koja je velika 20 MB i više.

Krenimo sada na tipizirane pokazivače, pokazivače koji pokazuju samo na varijable određenog tipa. Takav se pokazivač deklarira gotovo istovjetno kao i normalna (statička) varijabla:

var

broj: Integer; { normalna, statička Integer varijabla }

pokBroj: ^Integer; { pokazivač na varijablu tipa Integer }

Pokazivači se definiraju pomoću operatora ^, koji se kod deklaracije pokazivača piše ispred naziva tipa podataka.

Ako pokrenemo program u kojem su deklarirana varijabla broj i pokazivač pokBroj, varijablu broj moći ćemo koristiti bez problema jer je njoj osiguran memorijski prostor u koji zapisujemo podatke. Pokazivačem pokBroj nećemo se moći koristiti jer on trenutačno ne pokazuje na neki dio memorije.

Rješenje ovoga problema je usmjeravanje pokazivača prema nekoj varijabli. Da bismo povezali varijablu s pokazivačem, u pokazivač zapisujemo adresu te varijable. Da bismo dobili adresu neke varijable, koristimo se operatorom @ na sljedeći način:

pokazivač := @varijable;

Da bismo razumjeli ovu sintaksu i ono što se u programu događa, najbolje bi bilo pogledati jedan jednostavan primjer rada s pokazivačem.

<pb n="134"/>

Prva zanimljiva linija u ovom primjeru je linija koda u kojoj u pokazivač PokBroj zapisujemo adresu varijable Broj, PokBroj := @Broj. Nakon što se ta linija koda izvrši, kod korištenja varijable Broj i pokazivača PokBroj mijenjat će se samo vrijednost varijable Broj jer pokazivač pokazuje na tu varijablu.

U sljedećoj liniji koda, PokBroj^ := 20, operator ^ se više ne koristi za deklaraciju pokazivača. Kada se operator ^ napiše iza imena pokazivača, onda se taj postupak naziva dereferenciranjem pokazivača. Dereferenciranjem pokazivača, pokazivač nam iz memorije vraća vrijednost na koju pokazuje. S obzirom na to da smo ranije pokazivaču PokBroj rekli da pokazuje na varijablu Broj, dereferenciranjem pokazivača dobit ćemo vrijednost zapisanu u varijabli Broj.

Situacija u ovom programu izgleda ovako:

<pb n="135"/>

Pogledajmo kako pokazivači funkcioniraju na malo složenijem primjeru.

Program u primjeru 6.2. prikazuje korištenje dva pokazivača koji na početku programa pokazuju i mijenjanju dvije različite varijable, a na kraju programa pokazuju i mijenjaju istu varijablu.

6.1.1. Stvaranje dinamičkih varijabli

Pri radu s velikom količinom podataka jedino što nam ostaje kao izbor je stvaranje dinamičke varijable. Nova dinamička varijabla stvara se pomoću procedure New. Procedura New alocira određeni dio memorije (onoliko koliko zahtijeva tip podataka) i povezuje pokazivač s tom memorijom. Nakon što se stvori dinamička varijabla, njome se koristimo kao najnormalnijom varijablom (s minimalnom sintaktičkom razlikom).

<pb n="136"/>

Kad završimo s korištenjem dinamičke varijable, nikako ne smijemo zaboraviti obrisati (dealocirati) memoriju koju zauzima dinamička varijabla, jer to neće nitko napraviti umjesto nas. Ako ne obrišemo memoriju koju zauzima dinamička varijabla, dobit ćemo curenje u memoriji (memory leak), a to znači da će nakon svakog pokretanja programa ostati nekoliko bajtova slobodne memorije manje.

Program u primjeru 6.3. ilustrira stvaranje, korištenje i obvezno brisanje dinamičke varijable.

Sama sintaksa korištenja dinamičke varijable nije pretjerano komplicirana, no razlog korištenja dinamičkih varijabli može biti nešto problematičniji.

Uzmimo sada u obzir jedan standardni program koji će držati informacije o nazivima nekoliko stotina ili tisuća artikala. Ako sve artikle želimo smjestiti u normalno polje, loše nam se piše jer će Pascal već pri kompiliranju dići ruke od cijelog programa zato što podaci ni teoretski neće stati u raspoloživu memoriju. Ako sve te podatke želimo smjestiti u memoriju, onda nam kao rješenje ostaje da stvorimo dinamičko polje stringova i da u dinamičko polje zapisujemo podatke. Evo kako bi izgledalo dinamičko polje varijabli:

<pb n="137"/>

U gornjem primjeru možemo vidjeti kako se u memoriji može kreirati i raditi s poljem pokazivača. Jedina potpuna novost u primjeru je rezervirana riječ SizeOf. Rezervirana riječ SizeOf koristi se kada želimo dobiti informaciju o prostoru koji neka varijabla zauzima u memoriji.

Kao što bez problema možemo stvoriti dinamičku varijablu jednostavnog tipa podataka, tako možemo stvoriti i dinamičku varijablu nekog zapisa. Deklariranje zapisa može vrlo brzo dovesti do pomanjkanja raspoložive slobodne memorije, pa je često najpametnije zapise stvarati u dinamičkoj memoriji. U primjeru koji slijedi zapis TOsoba zauzima čak 1 026 bajtova memorije, dakle, svaka varijabla tipa TOsoba zauzima 1 026 bajtova.

<pb n="138"/>

U ovom primjeru vidljiva je jedna zanimljiva definicija tipa podataka POsoba. Tip podataka POsoba predstavlja nam kraticu pri kasnijem programiranju. Deklariranje varijable kao POsoba rezultirat će pokazivačem, isto kao da smo varijablu deklarirali kao ^TOsoba. Deklariranjem varijable kao POsoba poslije u programu smanjujemo zavrzlamu s operatorom dereferenciranja i izvorni kôd izgleda mnogo jasnije. Iako je sada ova sintaksa opcionalna, kad krenemo na povezane liste, postat će nužna.

6.1.2. Generički pokazivači

Generički pokazivači su pokazivači koji se ne deklariraju pomoću operatora ^, nego se deklariraju pomoću tipa podataka Pointer.

var

P: Pointer;

Ovako stvoreni pokazivač može pokazivati na varijablu bilo kojeg tipa, ili ga se može koristiti za pristup većim blokovima memorije. Ako se ovakvim pokazivačem koristimo za pokazivanje na varijable različitih tipova podataka, sve funkcionira besprijekorno. Ako preko generičkog pokazivača želimo upisati vrijednost u varijablu prema kojoj pokazivač pokazuje, sam ćemo pokazivač morati pretvoriti u tip varijable prema kojoj pokazuje. Primjer koji slijedi ilustrira kako se povezuju generički pokazivač i varijable različitih tipova.

<pb n="139"/>

Generički se pokazivači obično koriste pri radu s privremenim bufferima podataka, kada želimo upotrijebiti neku naprednu optimizacijsku tehniku ili kada želimo zaviriti u neki dio memorije koji nam običnim tehnikama nije na raspolaganju.

Ako želimo stvoriti dinamičku varijablu pomoću generičkog pokazivača, više ne možemo koristiti procedure New i Dispose. Kada se koristimo generičkim pokazivačem, njega povezujemo s blokom memorije koji može biti bilo koje veličine koja nam treba (odnosno, postoji maksimum i iznosi 65 528 bajtova). Da bismo alocirali blok memorije za naše potrebe, koristimo se procedurom GetMem. Za brisanje alociranoga bloka memorije primjenjuje se procedura FreeMem.

Obje procedure primaju dva parametra, generički pokazivač koji će pokazivati na alocirani blok memorije, te veličinu bloka koji želimo alocirati.

procedure GetMem(var P: Pointer; Size: Word);

procedure FreeMem(var P: Pointer; Size: Word);

Korištenje ovih procedura izgleda otprilike ovako:

<pb n="140"/>

6.1.3. Aritmetika pokazivača

Aritmetika pokazivača naziv je za operaciju pomicanja pokazivača po memoriji, odnosno naziv za inkrementiranje i dekrementiranje pokazivača u memoriji. Kada deklariramo pokazivač, možemo ga koristiti na dva načina: možemo se koristiti operatorom dereferenciranja, a možemo ga i izostaviti.

Ako iza imena pokazivača navedemo operator ^, to će značiti da želimo pristupiti vrijednosti na koju pokazivač pokazuje. Ako napišemo samo naziv pokazivača, dobit ćemo memorijsku adresu na koju pokazivač pokazuje.

Program u primjeru 6.8. vrlo je detaljno komentiran i točno prikazuje što se događa inkrementiranjem varijable. Dobro proučite komentare.

<pb n="141"/>

Program u primjeru 6.8. služi samo kao ilustracija sintakse i objašnjenje aritmetike pokazivača. Sama inkrementacija pokazivača katkada može dobro poslužiti. U primjeru koji slijedi koristit ćemo se aritmetikom pokazivača da bismo dva velika slova unutar stringa promijenili u dva mala slova.

Izvorni kôd programa u primjeru 6.9. izgleda dosta kompleksno. Prva linija rada s pokazivačem, CharPtr := @s[1], već je razumljiva. Tom linijom pokazivač CharPtr usmjeravamo prema prvom slovu u stringu s. Linija nakon toga poprilično je kompleksna.

Kao što je navedeno u komentaru, ta linija koda mijenja veliko slovo B u malo <pb n="142"/>slovo b. Prvo što nam treba pri toj izmjeni je samo slovo unutar stringa. Na slovo unutar stringa pokazuje CharPtr^. Kad imamo slovo unutar stringa, za promjenu slova treba nam njegova pozicija unutar ASCII tablice. To dobijemo korištenjem funkcije Ord: Ord(CharPtr^). Kada poziciju velikoga slova inkrementiramo za 32, dolazimo u dio ASCII tablice u kojoj su popisana mala slova. Na kraju, zbroj rezultata funkcije Ord i 32 pomoću funkcije Chr konvertiramo u znak i zapisujemo u string na mjestu pokazivača CharPtr.

Nakon što izmijenimo slovo B, sljedeća linija koda pomiče pokazivač CharPtr za osam mjesta dalje u memoriji, dakle, za osam slova unutar stringa, točno do velikoga slova D. Za promjenu velikog slova D u malo slovo d poduzimamo iste korake kao i prije.

6.2. Jednostruko povezana lista

A sad je na redu glavolomka. Ako funkcioniranje pokazivača nije dobro sjelo, dobro bi došao predah jer su povezane liste najteži materijal koji treba svladati u Pascal programiranju.

Pri radu s podacima, u profesionalnim programima, oni se spremaju u varijable, polja ili povezane liste podataka. Ako radimo s jednostavnim podacima, spremat ćemo ih u obične varijable (variablis vulgaris). Ako moramo raditi s većim brojem podataka čiji je točan broj poznat i ako do tih podataka moramo doći po brzom i kratkom postupku, deklarirat ćemo polje i zapisivati te podatke u polje. No, ako moramo raditi s promjenljivim brojem podataka, ne ostaje nam ništa drugo nego da implementiramo jednostruko povezanu listu i zapisujemo podatke u nju.

Jednostruko povezana lista je lista pokazivača koji su povezani s podacima, a ti su podaci nadalje povezani s drugim podacima. Podatak može biti povezan jednim pokazivačem na prijašnji ili na sljedeći podatak. Temeljeno na toj vezi između podataka, jednostruko povezana lista dijeli se na dva tipa: red (queue) i stog (stack).

Princip funkcioniranja reda zove se FIFO (First in, first out) jer podatak kojeg prvog zapišemo u red, prvog i dobivamo pri korištenju reda. Podaci u redu funkcioniraju kao i automobili na semaforu. Auto koji je bliži semaforu prvi će proći kroz zeleno svjetlo, a auto koji stoji na kraju proći će zadnji.

Princip funkcioniranja stoga se zove LIFO (Last in, first out) jer podatak koji zapišemo prvi u stog, pri korištenju stoga dobivamo tek na kraju, skroz zadnjeg. Podaci u stogu funkcioniraju kao listovi papira koje slažemo na stol. Prvi papir koji stavimo na stol moći ćemo vidjeti tek kad s njega maknemo sve ostale papire koje smo naknadno stavili.

U ovoj ćemo se knjizi baviti samo stvaranjem jednostruke povezane liste, i to reda. Stog neću posebno objašnjavati jer se vrlo malo razlikuje od reda. Umjesto pokazivača na sljedeći, podatak pokazuje na prethodni, ali o tome nećemo sada.

6.3. Stvaranje povezane liste – reda

Za implementaciju (stvaranje) reda potreban nam je zapis u kojemu ćemo čuvati informacije. Zapis kojim ću objašnjavati funkcioniranje držat će informacije o osobama i u svakom zapisu držat ćemo informacije o imenu, prezimenu i dobi osobe. Definicija zapisa kojim ćemo se koristiti izgleda ovako:

POsoba = ^TOsoba;

TOsoba = record

Ime: string;

Prezime: string;

<pb n="143"/>

Dob: Integer;

end;

Navedeni je zapis osnova za svaki daljnji rad s redovima. Nakon što definiramo podatke koji će biti zapisivani u zapis, na kraj zapisa stavljamo vezu na sljedeći podatak u listi, pokazivač tipa POsoba.

POsoba = ^TOsoba;

TOsoba = record

Ime: string;

Prezime: string;

Dob: Integer;

Next: POsoba;

end;

Time dobivamo zapis koji je moguće spojiti u red, odnosno možemo dobiti strukturu podataka kakva je prikazana na slici 6.3.

Nakon što do kraja sredimo zapis podataka, moramo srediti i sam red. Red se obično temelji na jednom pokazivaču koji služi kao glava cijelog reda. Uz glavu cijelog reda obično se deklarira i rep cijelog reda, jer rep služi za dodavanje podataka u red.

Prije nego krenemo dalje na implementaciju reda, moramo se upoznati s posebnom vrijednosti nil, koju koristimo samo s pokazivačima. Vrijednost nil zapisujemo u pokazivač kada želimo naglasiti da pokazivač ne pokazuje na iskoristivu vrijednost u memoriji. Ta nam vrijednost može uvelike pomoći da utvrdimo stanje pokazivača i postoji li uopće neka vrijednost u memoriji ili ne.

Pri radu s redom, na početku samog programa najbolje je vrijednosti glave i repa postaviti na nil da se osiguramo da u redu nema nikakvih podataka.

Nakon što se odmah na početku programa osiguramo da je lista (red) prazna, možemo je krenuti koristiti. Postoji vrlo velik broj operacija koje možemo izvršavati po potrebi, a neke od osnovnijih su:

1. dodavanje novog podatka u listu,

2. brisanje podatka iz liste,

3. brisanje svih podataka iz liste,

4. pretraživanje liste,

5. prikaz jednog podatka liste,

6. prikaz svih podataka liste.

Ako želimo vidjeti cijelu listu u funkcionalnom stanju, morat ćemo napisati popriličan komad izvornog koda koji radi s listom, a minimum bi bio procedura za <pb n="144"/>dodavanje podataka u listu, procedura za prikaz podataka liste i nužna procedura za brisanje memorije koju sama lista zauzima.

6.3.1. Dodavanje podataka u listu

Pri dodavanju podataka u listu najprije moramo stvoriti dinamičku varijablu i u nju zapisati podatke koje sami odredimo ili dobijemo od korisnika. Nakon što stvorimo dinamičku varijablu, moramo je dodati na kraj liste. Evo kako izgleda procedura za dodavanje jednog podatka u listu:

procedure Dodaj(AOsoba: TOsoba);

var

Temp: POsoba;

begin

New(Temp);

Temp^.Ime := AOsoba.Ime;

Temp^.Prezime := AOsoba.Prezime;

Temp^.Dob := AOsoba.Dob;

Temp^.Next := nil;

if Rep = nil then

Rep := Temp

else

begin

Rep^.Next := Temp;

Rep := Rep^.Next;

end;

if Glava = nil then Glava := Rep;

end;

Dodavanje novog podatka izgleda poprilično kompleksno, ali postoje samo dvije linije koda na koje treba posebno pripaziti.

Pogledajmo kako funkcionira cijela procedura Dodaj. Prvom linijom, New(Temp);, stvara se nova dinamička varijabla u koju zapisujemo podatke koje nam korisnik priloži u parametru AOsoba. Nakon što kopiramo podatke iz parametra (stack memorija) u heap memoriju dinamičke varijable, u element Next zapisujemo vrijednost nil. Ovo je nužna linija koda jer se sve procedure oslanjaju na činjenicu da nil vrijednost označuje kraj liste.

Temp^.Next := nil;

Zapisivanjem vrijednosti nil u element Next završava se kopiranje vrijednosti. Dinamičku varijablu sada moramo povezati s listom, odnosno moramo je prilijepiti na kraj liste. Ako govorimo o Pascalu, varijablu Temp moramo povezati s varijablom Rep koja označuje kraj liste.

No, ako je podatak koji dodajemo u listu prvi, nikako ga ne možemo povezati na Rep jer je u varijabli Rep zapisana vrijednost nil. Upravo tomu služi prva if provjera unutar procedure — provjerava dodajemo li prvi podatak ili podatak povezujemo na već postojeću listu. Ako dodajemo prvi podatak, taj je podatak onda i Glava i Rep liste.

if Rep = nil then

Rep := Temp

Ako dodajemo novi podatak, njega povezujemo na već postojeći Rep liste tako da ga spojimo s elementom Next. Na slici 6.4, koja slijedi, prikazano je kako <pb n="145"/>funkcionira lista od početka programa, preko dodavanja prvog do dodavanja daljnjih podataka.

Kao što je vidljivo na slici 6.4, dodavanjem prvog podatka u listu sve je kristalno jasno. Glava i Rep pokazuju na jedan jedini podatak i nema velikih problema. Veći se problemi pojavljuju dodavanjem sljedećeg podatka. Dodavanjem novog <pb n="146"/>podatka situacija se komplicira. S obzirom na to da je Rep sada prvi i jedini podatak, drugi će se podatak sasvim lijepo dodati na kraj liste. No, kako sada stvari stoje, Rep pokazuje na predzadnji podatak u listi. Ako želimo imati funkcionalnu listu, Rep moramo pomaknuti na zadnji podatak liste, a to vrlo jednostavno postižemo linijom koda: Rep := Rep^.Next;.

Ako slučajno izostavimo tu liniju koda, lista neće normalno funkcionirati. Dodavanjem novih podataka oni će se uvijek smještati na drugo mjesto u listi, a podatak koji je do tada bio na drugom mjestu nestaje iz liste. No, nestankom iz liste podatak nije nestao iz memorije nego samo izvan našeg dohvata. Čim jednom izgubimo pokazivač, njega se smatra upropaštenim dijelom memorije jer se tim dijelom memorije više ne može koristiti ni jedan program sve dok se ne resetira cijelo računalo. Kao što već znamo, ovakva se pogreška naziva “memory leak” (curenje memorije) i poprilično je nepopularna i kod korisnika, ali i kod programera.

Zadnja linija koda u proceduri Dodaj izvršit će se samo pri dodavanju prvog podatka u listu, ali je vrlo bitna jer bez Glave listu uopće ne bismo mogli koristiti. Glava liste služi za prilaz listi podataka.

6.3.2. Prikazivanje sadržaja liste

Nakon što sredimo dodavanje podataka u povezanu listu, moramo se osigurati da dodavanje podataka u listu funkcionira. Najjednostavniji način za provjeru funkcioniranja liste je procedura koja će prikazivati sadržaj liste na ekranu. Sama procedura funkcionira na vrlo jednostavnom principu, ali ipak treba biti na oprezu, jer, kad je riječ o pokazivačima, ništa nije jednostavno i sigurno. Evo kako izgleda procedura za prikazivanje sadržaja liste.

procedure Prikaz;

var

Count: POsoba;

begin

if Glava = nil then Exit;

Count := Glava;

while Count <> nil do

begin

Writeln(Count^.Ime);

Count := Count^.Next;

end;

end;

Prva linija u proceduri vrlo je bitna jer osigurava stabilnost cijele procedure. Ako je Glava jednaka vrijednosti nil, dakle, ako ne pokazuje na neki dio memorije, korištenje pokazivača Glava rezultirat će pogreškom i/ili padom programa. Ako pokazivač Glava ne pokazuje na prvi podatak u listi, treba odmah izaći iz procedure.

Ako u listi ima podataka, možemo krenuti dalje na prikazivanje sadržaja liste. Prikazivanje sadržaja liste radi se tako da se pomoću while petlje prikazuju svi podaci počevši od Glave liste sve dok pokazivač ne dosegne vrijednost nil koja označuje kraj cijele liste.

No, while petlja u proceduri Prikaz za prolaz kroz listu ne koristi se Glavom, nego lokalnom varijablom Count. Ovo je vrlo bitno zapamtiti. Glavu liste u ovom slučaju ne smijemo koristiti jer bismo time u potpunosti uništili listu. Kad bismo u proceduri Prikaz upotrijebili Glavu za prolaz kroz listu, nakon prvog prikaza sadržaja dobili bismo listu čija Glava pokazuje na zadnji podatak u listi (točnije: <pb n="147"/>jedini) jer bismo linijom koda Glava := Glava^.Next izgubili pokazivače na sve podatke u listi.

Da bismo izbjegli takvo jednokratno korištenje liste, koja je ujedno i katastrofalno pogrešan način funkcioniranja liste, koristimo se lokalnom varijablom čija nam je vrijednost ionako bitna samo tijekom prikaza vrijednosti liste. Linijom koda Count := Glava; povezujemo pokazivač Count s prvim elementom liste, čime mu dajemo pristup cijeloj listi. Time si osiguravamo pristup cijeloj listi preko privremenog pokazivača, ali i to da će Glava nakon cijele while petlje i dalje pokazivati na prvi podatak.

Unutar same while petlje kôd je mnogo jednostavniji. Najprije željene podatke ispisujemo na ekran te nakon ispisa pomičemo pokazivač Count na sljedeći podatak u listi, linijom Count := Count^.Next.

Nakon što uspostavimo dodavanje podataka i prikazivanje sadržaja liste na ekranu, ostaje nam da se pozabavimo brisanjem liste iz memorije.

6.3.3. Brisanje cijele povezane liste

Brisanje svih podataka, mjereno u linijama koda, najkraći je zadatak koji moramo napraviti s listom, ali nerijetko se ustanovi da je baš ova procedura velik problem pri programiranju. Pogledajmo kako izgleda procedura za brisanje povezane liste.

procedure BrisanjeListe;

var

Temp: POsoba;

begin

while Glava <> nil do

begin

Temp := Glava^.Next;

Dispose(Glava);

Glava := Temp;

end;

Glava := nil;

Rep := nil;

end;

Ukratko objašnjeno, pri brisanju podataka iz liste krećemo od Glave do zadnjeg podatka u listi. No, prije nego što obrišemo podatak iz liste, moramo sačuvati sljedeći podatak u listi tako da ga spremimo u Temp varijablu. Ako ne zapamtimo sljedeći podatak, brisanjem trenutačnog (odnosno prvog) podatka gubimo vezu sa svim ostalim podacima i opet nam ostaje hrpa smeća u memoriji.

Nakon što sačuvamo vezu sa sljedećim podatkom, možemo bez problema obrisati trenutačni podatak na koji pokazuje Glava. Nakon što obrišemo podatak, za potrebu while petlje, privremenu sačuvanu vrijednost u varijabli Temp zapisujemo natrag u Glavu, čime na poduži, ali potreban način dobivamo standardno pomicanje na sljedeći podatak: Pokazivač := Pokazivač^.Next.

Na kraju cijele procedure pokazivače Glavu i Rep ponovno, kao i na početku programa, postavljamo na vrijednost nil. Ovo je potrebno samo ako želimo omogućiti brisanje cijele liste tijekom rada programa i ponovno dodavanje podataka. Ako smo sigurni da će se brisanje cijele liste odvijati samo na kraju izvršavanja programa, ove su dvije linije višak i možemo ih slobodno obrisati.

<pb n="148"/>

6.3.4. Brisanje jednog podatka liste

Preskočit ću objašnjenje funkcije za pretraživanje liste jer nikoga ne želim udaviti velikom količinom izvornog koda, a, uostalom, sama je funkcija (uz malu pomoć hrpe komentara koje sam napisao) vrlo jednostavna i razumljiva.

Suprotno od funkcije za pretraživanje, procedura za brisanje jednog podatka iz liste može se smatrati otprilike kompleksnom. Prije nego što objasnimo kako funkcionira, idemo vidjeti kako izgleda procedura za brisanje jednog podatka iz liste:

procedure Obrisi(Podatak: POsoba);

var

Before: POsoba;

After: POsoba;

begin

if (Podatak = nil) or (Glava = nil) then Exit;

After := Podatak^.Next;

if Podatak = Glava then

begin

Dispose(Podatak);

Glava := After;

end else

begin

Before := Glava;

while (Before^.Next <> Podatak) and

(Before^.Next <> nil) do

Before := Before^.Next;

if Podatak = Rep then Rep := Before;

Before^.Next := After;

Dispose(Podatak);

end;

end;

Pri brisanju jednog podatka, moramo paziti da ne obrišemo podatak a da ne zapamtimo sljedeći podatak u listi. Ako prije brisanja ne zapamtimo sljedeći podatak u listi, svi podaci liste koji se nalaze iza podatka bit će izgubljeni.

After := Podatak^.Next;

Nakon što zapamtimo sljedeći podatak liste, možemo krenuti na brisanje podataka. No, pri brisanju podataka, ponovno moramo pripaziti što brišemo. Ako brišemo prvi podatak liste, moramo se osigurati da ćemo pokazivač Glava postaviti na novo prvo mjesto nakon brisanja.

if Podatak = Glava then

begin

Dispose(Podatak);

Glava := After;

Ako brišemo neki od ostalih podataka koji se nalaze unutar liste, prvo što moramo naći je podatak koji se u listi nalazi odmah ispred podatka koji brišemo. Taj nam je podatak potreban kako bismo nakon brisanja taj podatak mogli povezati s podatkom koji se nalazio nakon podatka koji smo obrisali.

Before := Glava;

while (Before^.Next <> Podatak) and

<pb n="149"/>

(Before^.Next <> nil) do

Before := Before^.Next;

Ali sada, kad brišemo podatak koji nije Glava, moramo paziti što se događa s Repom povezane liste. Ako brišemo zadnji podatak liste, onda će nam nakon brisanja zadnjeg podatka pokazivač Before pokazivati na zadnji podatak. Ako zaboravimo postaviti Rep liste na pokazivač Before, procedura Dodaj nove će podatke dodavati na pokazivač kojemu ne možemo nikako pristupiti (u prijevodu — opet velika pogreška koja troši resurse računala).

if Podatak = Rep then Rep := Before;

Nakon što se osiguramo da će Glava i Rep i dalje sigurno pokazivati na početak i kraj nove liste, povezujemo sljedeći s prethodnim podatkom. Ovom smo akcijom podatak koji želimo brisati potpuno izbacili iz liste.

Before^.Next := After;

S obzirom na to da nam podatak koji želimo obrisati sada “lebdi” u memoriji, moramo ga obvezno obrisati prije kraja procedure jer ćemo ga u suprotnom vjerojatno izgubiti.

Dispose(Podatak);

Eto, vidljivo je da za brisanje jednog podatka treba dosta pažnje. Isto toliko pažnje potrebno je za proceduru za ubacivanje podataka u listu, ali time se još nećemo baviti.

A sad, na kraju svih ovih silnih teorija o povezanim listama slijedi program koji se koristi povezanom listom i demonstrira kako se upotrebljavaju procedure i funkcije navedene i objašnjene do sada u ovom poglavlju.

Next: POsoba;

end;

var

Glava: POsoba; { prvi podatak liste }

Rep: POsoba; { zadnji podatak liste }

i: Integer;

TempOsoba: TOsoba;

Pretraga: POsoba;

const

IMENA: array[1..7] of string = (‘Gaston’, ‘Spirou’,

<pb n="150"/>

‘Marsupilami’, ‘Asterix’, ‘Obelix’,

‘Garfield’, ‘Oddie’);

{ procedura za dodavanje podataka u listu }

procedure Dodaj(AOsoba: TOsoba);

var

Temp: POsoba;

begin

New(Temp); { stvaramo novi zapis koji

cemo povezati u listi }

Temp^.Ime := AOsoba.Ime; { zapisujemo podatke

koji ce biti u listi }

Temp^.Prezime := AOsoba.Prezime;

Temp^.Dob := AOsoba.Dob;

Temp^.Next := nil; { temp je zadnji podatak liste }

if Rep = nil then { ako dodajemo prvi podatak,

Rep je Temp }

Rep := Temp

else

begin

Rep^.Next := Temp; { ako nije prvi podatak,

povezi ga na kraj }

{ trenutno zadnjeg podatka }

{ s obzirom da je Rep sada predzadnji,

pomakni ga na sljedeci }

{ podatak u redu }

Rep := Rep^.Next;

end;

{ ako je i Glava = nil, znaci da stvaramo prvi

podatak, pa povezi glavu i rep }

if Glava = nil then Glava := Rep;

end;

{ procedura koja prikazuje sadrzaj cijele liste na ekranu }

procedure Prikaz;

var

Count: POsoba;

BrojOsoba: Integer;

begin

if Glava = nil then Exit; { ako je lista prazna,

izadji iz proc. }

BrojOsoba := 0; { brojac podataka u listi }

Count := Glava;

while Count <> nil do

begin

Inc(BrojOsoba);

Writeln(BrojOsoba, ‘. ‘, Count^.Ime);

Count := Count^.Next;

end;

<pb n="151"/>

end;

procedure BrisanjeListe;

var

Temp: POsoba;

begin

while Glava <> nil do

begin

Temp := Glava^.Next;

Dispose(Glava);

Glava := Temp;

end;

Glava := nil; { ove dvije linije su

manje bitne ako se lista }

Rep := nil; { brise na kraju izvrsavanja programa }

end;

{ funkcija za pretrazivanje liste koja ce vratiti }

{ pokazivac na podatak u listi ako pronadje podatak }

{ s tim imenom }

function TraziIme(AIme: string): POsoba;

var

Count: POsoba;

begin

Count := Glava;

while Count <> nil do

begin

if Count^.Ime = AIme then

begin

TraziIme := Count; { ako postoji,

vrati pokazivac na podatak }

Exit; { ako je pronadjen podatak, izadji iz funkcije }

end;

Count := Count^.Next; { idi na sljedeci podatak }

end;

TraziIme := nil; { ako ime nije pronadjeno

vrati nil vrijednost }

end;

{ brisanje jednog podatka iz povezane liste }

procedure Obrisi(Podatak: POsoba);

var

Before: POsoba;

After: POsoba;

begin

if (Podatak = nil) or (Glava = nil) then Exit;

After := Podatak^.Next;

if Podatak = Glava then

begin

Dispose(Podatak);

<pb n="152"/>

Glava := After;

end else

begin

Before := Glava;

{ nadji podatak ispred onog kojeg brisemo }

while (Before^.Next <> Podatak) and

(Before^.Next <> nil) do

Before := Before^.Next;

if Podatak = Rep then Rep := Before;

Before^.Next := After;

Dispose(Podatak);

end;

end;

begin

{ prvi i zadnji podatak postavljamo

na nil vrijednost }

Glava := nil;

Rep := nil;

ClrScr;

{ dodaj imena u povezanu listu }

for i := Low(IMENA) to High(IMENA) do

begin

TempOsoba.Ime := IMENA[i];

TempOsoba.Prezime := ‘Lik iz stripa’;

TempOsoba.Dob := 0;

TempOsoba.Next := nil;

Dodaj(TempOsoba);

end;

Writeln(‘Pocetna postava liste: ‘);

Prikaz;

{ brisanje Oddiea iz liste }

Pretraga := TraziIme(‘Oddie’);

Obrisi(Pretraga);

Writeln;

Writeln(‘Nakon brisanja zadnjeg podatka: ‘);

Prikaz;

{ kraj }

Writeln;

Writeln(‘Pritisnite bilo koju tipku za kraj...’);

Readln;

BrisanjeListe; { brisanje liste iz memorije }

end.

<pb n="153"/>

6.4. Sažetak

Program u primjeru 6.10. jedan je od većih programa koji treba pročitati i razumjeti. Povezane se liste ne koriste toliko često u programiranju, osim kod dosta kompleksnih projekata. Za razliku od povezanih lista, pokazivači se dosta koriste tijekom programiranja — obično u svrhu ubrzanja rada neke procedure ili funkcije.

Ako kao alat za programiranje koristimo Delphi, povezanim listama koristit ćemo se poprilično često (možda čak i stalno), ali to neće biti ni blizu ovoliko kompleksno jer je sva funkcionalnost povezanih lista skrivena unutar raznih Delphi klasa. Pojam klase upoznat ćemo nešto kasnije u Delphi dijelu knjige.

Zadnja napomena: na CD-u u mapi “Primjeri\Poglavlje 6\Lista” nalazi se Delphi verzija programa koji radi s povezanom listom. Izvorni kôd primjenjivan u primjeru 6.10. vrlo je sličan kodu koji se nalazi u ovom Delphi primjeru pa ga neće biti teško shvatiti.

A sad, dalje na Delphi programiranje.

Pitanja i zadaci

Pitanje 1: Čemu služi operator @?

Pitanje 2: Kada iza imena pokazivača napišemo ^, što dobijemo?

Pitanje 3: Ako navedemo samo ime pokazivača, što dobijemo?

Pitanje 4: Čemu služi procedura New?

Pitanje 5: Čemu služi procedura Dispose?

Pitanje 6: Čemu služi procedura GetMem?

Pitanje 7: Čemu služi procedura FreeMem?

<pb n="154"/>

<pb n="155"/>

7. Osnove Delphi programiranja

7.1. Delphi razvojna okolina 156

7.1.1 . Elementi razvojne okoline 156

7.1.2. Glavni izbornik 157

7.1.4. Paleta komponenata 158

7.1.5. Stablo objekata 158

7.1.7. Dizajner forme 159

7.1.8. Editor koda 160

7.2. Stvaranje Delphi aplikacije 160

7.2.1. Kompiliranje i pokretanje aplikacije 162

7.3. Što je uopće Delphi 163

7.4. Stvaranje Windows aplikacija pomoću Delphija 164

7.4.1. Događajima upravljano programiranje 164

7.4.2. Objektno-orijentirano programiranje 165

7.5. Prva Delphi aplikacija 165

7.5.2. Pisanje odgovora na događaj 168

7.6. Sažetak 170

<pb n="156"/>

7. Osnove Delphi programiranja

Sada nas očekuje dio knjige u kojem je predstavljeno Delphi programiranje, odnosno razvoj Windows aplikacija. Razvoj Windows aplikacija mnogo je kompleksniji od razvoja DOS aplikacija koje smo stvarali do sada. Ali, primjenom Delphija, najkvalitetnijega razvojnog alata na svijetu, razvoj Windows aplikacija postaje jednostavan i zabavan posao.

Nakon jezika Pascal, koji smo dosta detaljno obradili u prvom dijelu knjige, ostaje nam da se upoznamo s programskim jezikom Object Pascal, koji čini osnovu Delphi razvojnog alata.

7.1. Delphi razvojna okolina

Delphi razvojnu okolinu čini skupina alata kojima se koristimo za stvaranje Delphi aplikacija. Delphi razvojna okolina pojavljuje se na ekranu odmah kada pokrenemo Delphi i izgleda otprilike (ili identično) kao razvojna okolina predstavljena na slici 7.1

Delphi razvojna okolina (Delphi IDE — Integrated Development Environment) sadrži u sebi sve alate koji su nam potrebni za stvaranje, testiranje i popravljanje pogrešaka unutar naših aplikacija. Ta razvojna okolina, koju vidimo na slici 7.1, uvelike pomaže i ubrzava stvaranje aplikacija pa je zbog toga moramo dobro upoznati.

7.1.1. Elementi razvojne okoline

Delphi razvojna okolina sastoji se od vrlo velikoga broja alata, a samo mali broj najbitnijih vidimo nakon što pokrenemo Delphi. Slika 7.1. prikazuje sve osnovne <pb n="157"/>elemente Delphija, koje po potrebi možemo sakriti ili prikazati. Osnovni elementi Delphija su:

— Glavni izbornik

— Standardne alatne trake

— Paleta komponenata (Component Palette)

— Stablo objekata (Object TreeView)

— Inspektor objekata (Object Inspector)

— Dizajner forme (Form Designer)

— Editor koda (Code Editor)

7.1.2. Glavni izbornik

Svaka Windows aplikacija koja ima veći broj opcija obično prikazuje svoje opcije i alate pomoću glavnog (i dodatnih) izbornika. Nešto kasnije u knjizi vidjet ćemo kako stvoriti vlastiti izbornički sustav. Glavni izbornik u Delphiju posjeduje sve opcije potrebne za rad s datotekama, ali i posebne opcije koje se koriste za stvaranje programa, otklanjanje pogrešaka i slično. Glavni izbornik Delphija prikazan je na slici 7.2.

3. Standardne alatne trake

Alatne trake se koriste u aplikacijama za prikaz najčešće korištenih opcija na izbornicima. Sve opcije koje se nalaze na alatnim trakama mogu se pronaći u sustavu izbornika. Delphi posjeduje šest standardnih alatnih traka s najosnovnijim opcijama. Imena naslovnih traka možemo otkriti na dodatnom izborniku koji se pojavljuje nakon što napravimo desni klik na neku od alatnih traka.

<pb n="158"/>

Delphi alatne trake možemo bez problema promijeniti primjenom opcije “Customize...”, koja je vidljiva na slici 7.3. kao zadnja opcija na izborniku, iako je vrlo upitno hoćete li ikad mijenjati alatne trake jer su vrhunski dizajnirane. Nakon što naučimo raditi s izbornicima, naučit ćemo i kako napraviti vlastite alatne trake.

Ako točno želimo saznati koju opciju predstavlja pojedina ikona, dovoljno je da pomaknemo kursor miša iznad nekog gumba i ubrzo će se na ekranu kraj gumba pojaviti tekstualni opis.

7.1.4. Paleta komponenata

Paleta komponenata prikazuje sve komponente (za sada: objekte) kojima se možemo koristiti za stvaranje naših aplikacija. Komponente koje se nalaze na paleti komponenata podijeljene su u grupe po funkcionalnosti. Komponente s palete možemo obrisati, a možemo i dodavati nove komponente — komponente drugih autora ili vlastite.

Paletu komponenata poprilično ćemo detaljno upoznati jer je poznavanje što većeg dijela palete bitno za kvalitetno programiranje u Delphiju, osobito ako želimo stvarati nove komponente.

7.1.5. Stablo objekata

Stablo objekata okvir je koji nam prikazuje hijerarhiju komponenata kojima se koristimo u izradi naših aplikacija. Stablo objekata vrlo je korisno kada želimo vidjeti koji objekt pripada nekom drugom objektu, a osobito je iskoristiv i potreban u velikim projektima kada koristimo vrlo velik broj formi. U tom će slučaju neke od komponenata biti prikrivene i nećemo ih moći jednostavno odabrati, osim pomoću stabla objekata.

<pb n="159"/>

7.1.6. Inspektor objekata

Inspektor objekata, uz editor koda i dizajner forme, najbitniji je i najkorišteniji dio cijele razvojne okoline. Inspektor objekata prikazuje svojstva i događaje objekta koji odaberemo. Za sada zapamtite ovo kao informaciju, poslije ću objasniti točno što su svojstva, a što su događaji.

Inspektor objekata sastoji se od dva dijela. Gornji dio Inspektora objekata (odmah ispod kursora miša) zove se Selektor objekata. Selektor objekata omogućuje odabir bilo kojeg objekta kojim se koristimo u aplikaciji. Uz mogućnost odabira nekog objekta, Selektor objekata prikazuje ime objekta i ime klase odabranog objekta.

Ispod Selektora objekata nalaze se dvije kartice. Kartica “Properties” prikazuje svojstva odabranog objekta, a kartica “Events” prikazuje događaje odabranog objekta. Sve ovo možda zvuči kompleksno, ali vidjet ćemo uskoro da i nije tako strašno.

7.1.7. Dizajner forme

Dizajner forme nije ništa drugo nego glavna forma aplikacije — objekt na koji dodajemo ostale komponente i pomoću kojega stvaramo korisničko sučelje Windows aplikacija. Forma se tijekom dizajna aplikacije naziva Dizajnerom forme. Kada pokrenemo program, forma se zove prozor i osnovno je sredstvo korisničkog rada s programom. Tijekom dizajna aplikacije na formi će biti iscrtana dizajnerska mreža (designer grid) koja nam uvelike pomaže da ljepše postavimo komponente na formi.

<pb n="160"/>

7.1.8. Editor koda

Editor koda je dio Delphija u kojem ćemo provoditi najveći dio vremena pišući Object Pascal izvorni kod. Editor koda u Delphiju vrlo je sofisticirani alat koji posjeduje sve opcije običnog tekstualnog editora, ali i dodatne opcije za rad s izvornim kodom koje uvelike povećavaju učinkovitost i brzinu rada.

Trenutačno, editor koda nije jasno vidljiv na ekranu jer je skriven u pozadini Dizajnera forme. Editor koda možemo vrlo jednostavno prikazati pomoću tipke F12. Tipka F12 obično se koristi za brzo prebacivanje iz Dizajnera forme u editor koda i obrnuto.

Već sada, na početku stvaranja aplikacije, u editoru možemo vidjeti nekoliko linija izvornog koda. Nešto kasnije vidjet ćemo zašto su te linije koda tu i čemu one služe.

7.2. Stvaranje Delphi aplikacije

Delphi aplikacija uvelike se razlikuje od Pascal programa koje smo do sada stvarali. Obični Pascal programi kojima smo se do sada koristili sastojali su se od samo jedne datoteke s izvornim kodom čija je ekstenzija PAS.

Kad stvaramo novu Delphi aplikaciju, mi zapravo stvaramo novi projekt koji se sastoji od nekoliko datoteka. S obzirom na to da se čak i najmanji Delphi projekt <pb n="161"/>sastoji od nekoliko datoteka, svaki Delphi projekt potrebno je obvezno snimiti u posebnu mapu kako bi se izbjegle razne pogreške i presnimavanja.

Nakon što pokrenemo Delphi, on automatski stvara novi projekt — novu aplikaciju. Prije nego što krenemo na samo programiranje aplikacije, idemo je najprije snimiti na disk. Najbrži način za snimanje svih datoteka koje čine trenutačni projekt je opcija File -> Save All. Snimite sada projekt u neku mapu. Delphi će dvaput tražiti unos imena. Prvi put će tražiti ime projekta, a drugi put za ime glavne forme. Oba puta ćemo za sada ostaviti imena koje ponudi sam Delphi, Project1 i Unit1.

Nakon što projekt snimimo na disk, Delphi stvara nekoliko datoteka. Glavna datoteka projekta ima ekstenziju DPR (Delphi Project). Ta datoteka sadrži Pascal izvorni kôd koji je neophodan za rad cijele aplikacije. Bez ove datoteke ne može se kompilirati Delphi projekt.

Druga datoteka blisko vezana uz samu projektnu datoteku je datoteka s resursima, s ekstenzijom RES. U resursnoj datoteci mogu se nalaziti razni tekstovi, slike i ikone, ali resursna datoteka s imenom projekta obično sadrži Delphi ikonu koju možemo vidjeti na glavnoj formi.

Treća datoteka vezana uz projekt je datoteka s ekstenzijom CFG. U njoj su obično spremljene informacije potrebne za kompiliranje projekta, ali te se informacije koriste samo u posebnim situacijama. Isti je slučaj i s datotekom koja ima ekstenziju DOF.

Uz te četiri datoteke koje čine sam projekt, Delphi snima glavnu formu aplikacije u dvije različite datoteke. Datoteka s ekstenzijom DFM binarna je datoteka u koju Delphi zapisuje informacije o komponentama koje se nalaze na samoj formi. Druga datoteka vezana uz formu već nam je poznata — riječ je o PAS datoteci u kojoj je zapisan izvorni kôd forme.

U Delphiju, datoteke s ekstenzijom PAS mogu označivati dvije različite datoteke — PAS datoteka može biti samostalna jedinica koda s funkcijama i procedurama, ali, kao u ovom slučaju, može biti datoteka izvornog koda u kojoj je sadržan izvorni kod forme.

Sad ćemo upoznati još nekoliko datoteka koje se pojavljuju tijekom rada s Delphijem. Datoteke koje ću sada navesti Delphi stvara tek procesom kompilacije (stvaranja izvršne datoteke — EXE). Stvaranje izvršne datoteke u Delphiju nije problem. Da bismo stvorili izvršnu datoteku, odabiremo opciju Project -> Build ImeProjekta. Ta je opcija prikazana na slici 7.9.

<pb n="162"/>

Odaberite opciju za stvaranje izvršne datoteke i u mapi pogledajte rezultat kompiliranja. U mapi projekta pojavljuju se dvije nove datoteke. Prva datoteka koju je stvorio Delphi kompilator ima ekstenziju DCU (Delphi Compiled Unit). DCU datoteka nastaje kao rezultat kompiliranja PAS datoteke s Pascal izvornim kodom. DCU datoteka prvi je korak prema potpunoj kompilaciji cijeloga projekta.

Nakon što Delphi od svih datoteka s Pascal izvornim kodom stvori kompilirane datoteke, povezuje ih u završnu datoteku s ekstenzijom EXE — naš program. Program koji je Delphi stvorio jedina je datoteka koja je potrebna da bi cijeli program funkcionirao. Ako nekom drugom želimo poslati program koji smo napravili, onda je trenutačno preko e-maila, na CD-u ili slično, potrebno poslati samo EXE datoteku.

Tijekom rada na projektu, Delphi stvara sigurnosne kopije naših datoteka (backup kopije). Sve kopije datoteka koje Delphi napravi imat će ekstenziju koja počinje s tildom (~). S tim datotekama možemo raditi što god želimo, ali obično programeri paze što rade pa te datoteke nisu potrebne. Pogotovo nisu potrebne drugim programerima kojima ćemo možda slati svoj izvorni kôd.

Pri davanju izvornog koda nekom drugom, DCU datoteke nisu nužne, ali nisu niti problem ako ih pošaljemo. Potrebne mogu biti samo ako drugi programer zbog nekog razloga ne može kompilirati naš kod. Tada možemo proslijediti samo DCU datoteku koju će Delphi bez prethodne kompilacije uključiti u krajnju izvršnu datoteku. Neki programeri imaju običaj davati samo DCU datoteke s opisom funkcija koje se nalaze u toj datoteci. Time omogućuju drugim programerima korištenje njihovih funkcija, ali i sebe osiguravaju da će njihove ideje ostati sačuvane.

7.2.1. Kompiliranje i pokretanje aplikacije

Jednu od opcija za kompiliranje aplikacije smo već vidjeli, a riječ je o opciji Project -> Build. Uz opciju Project -> Build, Delphi će stvoriti izvršnu datoteku odabirom opcija Project -> Compile i Run -> Run. U čemu je razlika?

<pb n="163"/>

Najčešće se tijekom izrade aplikacije u Delphiju koristi opcija Run -> Run, ili, još bolje, kratica F9 na tipkovnici. Odabirom te opcije Delphi će stvoriti izvršnu datoteku i pokrenuti je. Time automatski tijekom izrade aplikacije možemo provjeriti funkcionira li kôd koji smo unijeli u editoru kôda. Delphi prigodom pokretanja aplikacije radi potpunu kompilaciju projekta (Project -> Compile).

Kompilacija projekta (Project -> Compile) razlikuje se od potpune kompilacije projekta (Project -> Build). Kompilacija projekta nešto je brži postupak stvaranja izvršne datoteke koja se koristi tijekom izrade aplikacije. Tijekom kompilacije Delphi kompilator se obično koristi već prije kompiliranim datotekama. Time osigurava veću brzinu stvaranja izvršne datoteke jer neće nepotrebno kompilirati izvorni kod. No, ako smo izmijenili datoteku s izvornim kodom, Delphi će morati kompilirati izvornu datoteku kako bi u izvršnu datoteku uključio zadnje promjene koje smo napravili na projektu.

Za razliku od kompiliranja (Project -> Compile), potpuna kompilacija ne provjerava jesmo li izmijenili datoteke s izvornim kodom. Potpuna kompilacija (Project -> Build) uvijek iznova kompilira datoteke s izvornim kodom.

Pokrenimo sad projekt pomoću opcije Run. Ono što nas gotovo trenutačno dočeka na ekranu je potpuno funkcionalna Windows aplikacija.

Pri pokretanju aplikacije iz Delphi razvojne okoline dizajneri aplikacije se skrivaju da bismo dobili što bolji pregled radne površine aplikacije koju stvaramo. Na slici 7.10. možemo vidjeti glavnu formu naše potpuno funkcionalne Windows aplikacije. Uskoro ćemo vidjeti kako je možemo natjerati da radi nešto pametno.

7.3. Što je uopće Delphi

Najkraće i najjednostavnije rečeno, Delphi je najkvalitetniji programerski alat na svijetu. Pojedinost koju programeri diljem svijeta najčešće navode (uz mnoštvo ostalih) kao najbolju je fantastično brz optimizirajući kompilator.

Delphi kompilator proizvodi samostalne izvršne datoteke. Ova je izjava vrlo bitna zbog nekoliko razloga. Najbitniji razlog je potpuna samostalnost Delphi izvršnih datoteka. Neki programski jezici kreiraju mnogo manje izvršne datoteke (gledajući kilobajte same izvršne datoteke) od Delphija, ali ti jezici za funkcioniranje <pb n="164"/>aplikacija zahtijevaju dodatne datoteke instalirane na korisničkom računalu. Kod takvih programskih jezika programeri uz samu aplikaciju moraju uključiti i instalirati dodatne datoteke koje mogu prijeći i nekoliko megabajta!

Delphi odmah na početku stvara izvršnu datoteku koja je velika oko 350 kilobajta. Ovaj broj samo naočigled izgleda velik. U tih 350 kilobajta Borland je smjestio goleme količine izvornog koda (desetak tisuća linija koda) koje užasno mnogo pomažu u svakodnevnom razvoju aplikacija.

Delphi je brz. On pripada skupini alata koji se nazivaju RAD (Rapid Application Development) alatima. RAD alati današnjice temelje se na vizualnom dizajnu sučelja aplikacije i na velikom broju funkcija koje nam stoje na raspolaganju. U Delphi RAD kutiju Borland je uključio i fenomenalno brz kompilator koji vrlo brzo kompilira i najveće projekte od nekoliko tisuća linija koda. Uz stvaranje izvršne datoteke, Delphi kompilator optimizira kôd koliko god je to moguće, nekada toliko da ni vrhunski programeri ne mogu vlastoručno napisati toliko brzi kod.

Ostala obilježja Delphija upoznat ćemo usput, tijekom rada u Delphiju.

7.4. Stvaranje Windows aplikacija pomoću Delphija

Programiranje Windows aplikacija zahtijeva mnogo više znanja i pažnje nego što su zahtijevali DOS programi koje smo stvarali u dijelu knjige o Pascalu. Struktura DOS programa kakve smo stvarali ranije u knjizi određena je poprilično davno, u vrijeme kad su računala bila velika i stajala kao cijela kuća. Tih davnih dana, dok su Zemljom još hodali zmajevi i čarobnjaci, programe su stvarali i njima se koristili samo inženjeri. Njima nije bilo bitno korisničko sučelje, ikone i ostali ljepuškasti detalji aplikacija kojima se koristimo danas. Sve što je tada bilo bitno bio je proces obrade podataka.

Proces obrade podataka i danas je bitan proces jer upravo u tu svrhu i koristimo računala. Usto, današnje aplikacije moraju osigurati ugodan rad s aplikacijom putem ugodnog i kvalitetno izrađenog korisničkog sučelja. Izradu kvalitetnoga korisničkog sučelja u potpunosti olakšava Delphi razvojna okolina.

Drugi dio izrade aplikacija — pisanje izvornog koda, temelji se na dva nova termina koje moramo upoznati: događajima upravljano programiranje (event-driven programming) i objektno-orijentirano programiranje (object-oriented programming).

7.4.1. Događajima upravljano programiranje

DOS programi koje smo stvarali u dijelu knjige o Pascalu proceduralni su programi. Proceduralni programi funkcioniraju tako što potpuno preuzimaju kontrolu nad računalom od DOS-a i počinju sa svojim radom. Svaki proceduralni program počinje izvršavanje od prve linije koda i završava tek kada dosegne zadnju liniju koda. DOS programi upravljaju i korisnikom, nudeći mu opciju tek kada to odgovara programu — a i tada takvi programi nisu previše jednostavni za korištenje.

Windows aplikacije funkcioniraju potpuno drugačije od DOS aplikacija. Najvidljivija je razlika mogućnost pokretanja većega broja aplikacija unutar Windows operativnog sustava, dok DOS omogućuje pokretanje samo jedne aplikacije odjednom.

Druga bitna razlika između Windows i DOS aplikacija je u načinu na koji se same aplikacije ponašaju. Windows aplikacije se ne izvršavaju pravocrtno kao DOS aplikacije, nego se dijelovi izvornog koda izvršavaju nasumično — ovisno o događajima na računalu. Windows aplikacije programiraju se tako da se pišu odgovori na događaje — dijelovi izvornog koda koji će se izvršiti tek kada se izvrši <pb n="165"/>specifičan događaj. Zbog toga se Windows aplikacije nazivaju događajima pokretane aplikacije (event-driven applications).

Operativni sustav Windows komunicira sa svim pokrenutim aplikacijama pomoću sustava poruka (Windows messages). Svaki put kada korisnik pritisne slovo na tipkovnici, pomakne miš, aktivira drugu aplikaciju, dakle, svaki put kad se nešto dogodi na računalu, operativni sustav stvara odgovarajuću poruku i šalje je prozoru kojemu je poruka namijenjena. Nakon što prozor dobije poruku o događaju, on će pokrenuti dio koda koji se treba izvršiti kao odgovor na taj događaj. Sve ovo u teoriji zvuči poprilično komplicirano, ali u praksi nije tako strašno.

7.4.2. Objektno-orijentirano programiranje

Objektno-orijentirano programiranje nastaje kao nadogradnja na proceduralno programiranje. Objektno-orijentirano programiranje nastaje kao neposredan rezultat potrebe za ponovnim iskorištavanjem koda. Objekti, točnije rečeno — klase objekata, poseban su tip podataka koji možemo stvoriti i koristiti unutar Delphija, ali i ostalih objektno-orijentiranih programskih jezika.

Klase objekata stvaraju se s namjerom rješavanja specifičnoga problema. Nakon što se klasa stvori jednom, ona se može nebrojeno mnogo puta koristiti u razvoju aplikacija, čime se ubrzava stvaranje aplikacija.

Sam objekt je tip podataka koji sadrži varijable (svojstva), kao što zapis sadrži različite elemente u koje upisujemo podatke. Uz podatke, objekti sadrže procedure i funkcije koje rade s tim podacima. Procedure i funkcije koje su dio neke klase objekata nazivaju se metodama.

Prije objektno-orijentiranog programiranja programi su se pisali (kao što je vidljivo u dijelu knjige o Pascalu) pomoću zapisa i procedura koje su kao parametre primale zapise. U objektno-orijentiranom programiranju varijable i procedure su povezane, pa cijeli sustav funkcionira na malo razumljiviji i jednostavniji način.

Objektno-orijentirano programiranje ćemo u koracima i dosta detaljno upoznati tijekom rada s primjerima u ovom i sljedećim poglavljima, a ono što trenutačno moramo znati o korištenju objektima je ovo:

— objekti posjeduju svojstva (varijable)

— objekti posjeduju procedure i funkcije (metode)

— svojstvima i metodama objekata pristupa se kao što se pristupa

elementima zapisa (ImeObjekta.Svojstvo ili ImeObjekta).

7.5. Prva Delphi aplikacija

Sada je na redu programiranje prve Delphi aplikacije. Programiranje većine aplikacija u Delphiju svodi se na nekoliko jednostavnih koraka. Prvo što obično radimo je korisničko sučelje aplikacije. Korisničko sučelje stvara se pomoću komponenata koje se nalaze na paleti komponenata.

Za početak nam je najprije potrebna nova prazna Delphi aplikacija. Nju možemo dobiti ponovnim pokretanjem Delphija ili pomoću opcije File -> New -> Application na glavnom izborniku.

Prvi korak pri izradi aplikacije bit će promjena samog imena aplikacije. Ime aplikacije uvijek se postavlja na glavnoj formi aplikacije, a trenutačno to je forma pod imenom Form1 koju možemo vidjeti na ekranu. Da bismo to uspjeli napraviti, treba nam Inspektor objekata i svojstvo forme pod imenom Caption. U Caption svojstvo zapisuje se tekst koji će se pojaviti na naslovnoj traci forme.

<pb n="166"/>

Idemo sada promijeniti Caption svojstvo forme u “Moja prva Delphi aplikacija”, kao što je vidljivo na slici 7.11. Prigodom promjene svojstava nekog objekta, kao što je objekt Form1, treba paziti da je taj objekt i odabran. Ime objekta čija se svojstva mijenjaju prikazano je u Selektoru objekata (padajućoj listi na vrhu Inspektora objekata).

Izrada korisničkog sučelja ne može biti jednostavnija (osim da to netko drugi napravi umjesto nas). Sve što je dovoljno za izradu korisničkog sučelja je dodavanje komponente na formu i mijenjanje svojstava komponente.

Za početak ćemo na formu dodati jedan običan gumb. Gumb (klasa TButton) nalazi se na kartici Standard. Postoji mnogo načina za dodavanje komponente na formu, a za sada je najbolje iskoristiti dvostruki klik na ikonu gumba na paleti. Ikona gumba prikazana je na slici 7.12.

Nakon dvostrukog klika, na formu će se dodati jedan gumb imena Button1. Nakon dodavanja gumba, u Object TreeView prikazu možemo vidjeti hijerarhiju objekata koji postoje na formi — vidimo da dodani gumb pripada formi. Osim toga, nakon dodavanja gumb se automatski odabire i njegova se svojstva prikazuju u Object Inspectoru.

<pb n="167"/>

Gumbi, kao i forma, posjeduju svojstvo Caption. Svojstvo Caption na gumbima se obično koristi za ime opcije ili naredbe koju će gumb pokrenuti. Prije nego krenemo na pisanje i proučavanje izvornog koda ove aplikacije, idemo promijeniti Caption svojstvo gumba u “Klikni me!”.

7.5.1. Izvorni kôd glavne forme

Sad kad smo sredili cjelokupno korisničko sučelje ove vrlo jednostavne aplikacije, idemo proučiti izvorni kôd koji već postoji prikazan u editoru kôda. Taj je kôd prikazan u primjeru 7.1. i izvorni je kôd vezan uz formu Form1.

Izvorni kôd glavne forme (ali i svih ostalih formi koje mogu postojati u aplikaciji) je zasebna datoteka s izvornim kodom. Svaka takva datoteka (Pascal unit) počinje rezerviranom riječi unit, koja nam daje na znanje da je riječ o Pascal datoteci s izvornim kodom, a ujedno nam i govori kako se datoteka zove.

Identifikator koji slijedi iza rezervirane riječi unit mora biti jednak imenu datoteke. Dakle, ako iza rezervirane riječi unit piše Unit1, datoteka mora biti snimljena pod imenom Unit1.pas. Ako se ime datoteke razlikuje od imena unita, Delphi kompilator neće moći kompilirati aplikaciju. Jednom kad je postavljeno, nije preporučljivo mijenjati ime unita. Ako je promjena imena baš potrebna, najsigurniji način je pomoću opcije File -> Save As snimiti datoteku s izvornim kodom pod novim imenom.

<pb n="168"/>

Nakon rezervirane riječi unit slijede ostali dijelovi datoteke s izvornim kodom. Datoteke s izvornim kodom mogu se sastojati od četiri različita dijela: interface, implementation, initialization, finalization. Initialization (inicijalizacijski dio) i finalization (finalizacijski dio) dijelovi datoteke nisu nužni, za razliku od interface i implementation dijelova.

Datoteka s izvornim kodom započinje s rezerviranom riječi interface. Rezervirana riječ interface označuje javno vidljivo sučelje datoteke koje se proteže sve do rezervirane riječi implementation. U interface dijelu datoteke deklariraju se razni tipovi podataka (zapisi, klase, enumeracije), konstante te zaglavlja procedura i funkcija (nešto poput forward deklaracije, samo bez rezervirane riječi forward). Sve što navedemo unutar interface dijela bit će vidljivo i iskoristivo u drugim datotekama.

U interface dijelu obično postoji uses lista svih datoteka s izvornim kodom kojima se koristimo u vlastitoj datoteci. Recimo, trenutačna aplikacija mora se obvezno koristiti datotekom StdCtrls jer je u toj datoteci definirana klasa TButton, odnosno, gumb kojeg koristimo na glavnoj formi.

Unutar interface dijela možemo vidjeti i deklaraciju same glavne forme:

type

TForm1 = class(TForm)

Nakon interface dijela slijedi implementation dio. U implementation dijelu pišu se procedure i funkcije, a to je ujedno i dio izvorne datoteke u kojoj provodimo najviše vremena.

Trenutačno, ove su informacije bitne za osnovno snalaženje u izvornom kodu. Poslije, kod kompleksnijih i detaljnijih primjera, bit će prikazano kada se, zašto i kako koristi svaki pojedini dio interface i implementation dijelova datoteke.

7.5.2. Pisanje odgovora na događaj

Pisanje odgovora na događaj osnovna je aktivnost svakoga programera Windows aplikacija. Vrlo velik broj komponenata (gotovo sve) koje postavimo na formu imaju mogućnost odgovora na neki događaj. Sad ćemo napokon napisati kôd vezan u gumb koji smo stavili na formu. Da bismo napisali kôd za neki događaj gumba, gumb moramo najprije odabrati (jedan lijevi klik na gumb).

<pb n="169"/>

Nakon što gumb odaberemo, na Object Inspectoru moramo odabrati karticu Events — moramo prikazati popis događaja koje gumb prepoznaje i može iskoristiti.

Nakon što prikažemo sadržaj kartice Events, možemo odabrati događaj koji želimo iskoristiti. Najčešće se kod gumba odgovara na OnClick događaj. Poruku o tom događaju aplikacija dobiva kada korisnik klikne na gumb.

Da bismo napisali odgovor na OnClick događaj gumba “Klikni me!”, moramo dvaput kliknuti na OnClick događaj u kartici Events. Pri odabiru događaja ne klikamo na samo ime događaja, nego na prazan dio nadesno od imena.

Nakon što dvaput kliknemo na događaj koji nam treba, Delphi će napraviti nekoliko stvari. Nakon odabira događaja, Delphi će najprije stvoriti jednu novu proceduru. Svaki odgovor na događaj zasebna je procedura koju će aplikacija pozivati kad stigne poruka o događaju. Nakon dvostrukoga klika Delphi će u editor kôda ubaciti kostur naše nove procedure, a njezino će ime zapisati u Object Inspector i time povezati događaj s procedurom.

<pb n="170"/>

Nova procedura dobiva ime pomoću vrlo jednostavne formule: ImeKomponente + ImeDogađaja. Nakon što se na ekranu pojavi editor koda, Delphi će automatski postaviti kursor unosa teksta unutar begin–end bloka te procedure. Unutar begin–end bloka procedure Button1Click pišemo kôd koji se treba izvršiti kada korisnik klikne na gumb “Klikni me!”.

Za početak nećemo raditi ništa kompleksno, nego ćemo započeti kao i u Pascalu — prikaz jednostavne poruke na ekranu. Za prikazivanje jednostavne poruke na ekranu moguće je iskoristiti nekoliko procedura, ali najjednostavnija je procedura ShowMessage.

Procedura ShowMessage prima samo string vrijednost koju će prikazati na ekranu. Sad kad znamo i to, idemo na ekran prikazati poruku “Pozdrav iz Delphija 7”. Cijeli izvorni kôd naše prve aplikacije trebao bi izgledati ovako:

procedure TForm1.Button1Click(Sender: TObject);

begin

ShowMessage(‘Pozdrav iz Delphija 7’);

end;

Ako sada pokrenemo aplikaciju i kliknemo na gumb “Klikni me!”, situacija će izgledati poprilično dobro jer smo uspjeli napraviti našu prvu Delphi aplikaciju koja čak i funkcionira kao svaka prava Windows aplikacija — reagira na akcije korisnika.

7.6. Sažetak

Prvo poglavlje Delphi programiranja uvelo nas je većinom samo u teoriju samog Windows programiranja i korištenje Delphi korisničkog sučelja. Sva poglavlja koja <pb n="171"/>slijede temelje se na informacijama iz ovog poglavlja — pogotovo način stvaranja Delphi aplikacija.

Pitanja i zadaci

Pitanje 1: Kako se zove dio Delphi razvojne okoline na kojem su popisane komponente kojima se koristimo tijekom dizajna aplikacija?

Pitanje 2: Koju ekstenziju ima glavna datoteka Delphi projekta?

Pitanje 3: Koja je razlika između opcija Compile i Build pri stvaranju izvršne datoteke?

Pitanje 4: Kojom se tipkom iz razvojne okoline Delphija pokreće aplikacija?

Pitanje 5: Koja se Delphi procedura primjenjuje za prikazivanje jednostavne tekstualne poruke na ekranu?

Zadatak 1: Potrebno je napraviti program koji se zove “Info” i koji na klik gumba pomoću poruke prikazuje na ekranu autorovo ime i prezime.

<pb n="172"/>

<pb n="173"/>

8. Stvaranje korisničkog sučelja

8.1. Dodavanje komponenata na formu 174

8.1.1. Dodavanje komponente na željeno mjesto na formi 174

8.1.2. Dodavanje komponente uz promjenu veličine 174

8.1.3. Dodavanje većega broja komponenata 175

8.2. Osnovne komponente i njihova svojstva 175

8.2.1. Upoznavanje osnovnih komponenata 176

8.2.2. Osnovni događaji komponenata 177

8.2.3. Korištenje događaja 178

8.3. TCheckBox i TRadioButton komponente 182

8.3.3. Delphi komentari 185

8.3.4. TCheckBox komponenta 185

8.4. Mali trikovi Delphi programiranja 187

8.4.1. Brisanje postojećih procedura 187

8.4.2. Korištenje jedne procedure na više mjesta 189

8.4.3. Osnovno korištenje RTTI-a 190

8.4.4. Fenomenalno svojstvo Tag 192

8.5. Sažetak 193

<pb n="174"/>

8. Stvaranje korisničkog sučelja

Korisničko je sučelje apsolutno najbitnija stvar o kojoj se moraju brinuti autori Windows aplikacija, a katkada je samo sučelje čak i bitnije od koda koji pokreće cijelu aplikaciju. Najosnovnija operacija koju moramo znati napraviti je dodavanje i manipulacija komponenata na formi, a upravo to ćemo sada i proučiti.

8.1. Dodavanje komponenata na formu

Komponente se dodaju na formu radi stvaranja korisničkog sučelja. Komponente možemo dodati na formu na više načina. Do sada smo vidjeli jedan način, a to je bio dvostruki klik na ikonu komponente. Taj način i nije najprimjenjivaniji jer smješta komponentu na nasumičnu poziciju na formi. To će od nas zahtijevati još nekoliko koraka da komponentu smjestimo na željeno mjesto.

8.1.1. Dodavanje komponente na željeno mjesto na formi

Ako želimo ubrzati proces dizajna korisničkog sučelja, komponentu možemo odmah postaviti na željeno mjesto na formi. To možemo napraviti tako da najprije s palete komponenata jednim lijevim klikom odaberemo komponentu koju trebamo. Nakon što napravimo jedan lijevi klik, ikona komponente poprimit će “pritisnuti” oblik, čime označuje da je odabrana (slika 8.1).

Nakon što je komponenta odabrana, ponovno je dovoljan samo jedan jedini lijevi klik na Dizajner forme i komponenta će se pojaviti na mjestu gdje kliknemo. Točnije rečeno, gornji lijevi kut komponente postavit će se na mjesto gdje kliknemo. Ako komponentu na ovaj način postavljamo na formu, ona će nakon dodavanja poprimiti svoju prije određenu veličinu. Recimo, ako na ovaj način na formu postavimo neki gumb, on će poprimiti veličinu 75x25 piksela.

8.1.2. Dodavanje komponente uz promjenu veličine

Drugi način na koji možemo postaviti komponentu na formu uključuje automatsku promjenu veličine. Ako nam treba gumb koji će biti tri ili četiri puta veći od normalnog gumba, ne moramo ga najprije dodati na formu i tek onda mijenjati njegova svojstva. Nakon što odaberemo komponentu na paleti komponenata, komponentu dodajemo na formu tako da najprije kliknemo na mjesto gdje se komponenta treba pojaviti, ali ne otpuštamo lijevu tipku miša. Sve dok držimo lijevu tipku miša pritisnutom, možemo crtati komponentu po formi. Tek kad završimo s crtanjem možemo otpustiti lijevu tipku miša i komponenta će se dodati na formu s dimenzijama koje smo prije nacrtali na formi.

<pb n="175"/>

8.1.3. Dodavanje većega broja komponenata

Delphi omogućuje i dodavanje većega broja istih komponenata malo brže nego što smo do sada činili. Ako stvaramo aplikaciju koja na glavnoj formi treba imati dvadeset gumba, bilo bi vrlo zamorno dodati sve gumbe na formu kad bismo ih svaki put morali odabirati. Ako želimo odjednom dodati veći broj istih komponenata na formu, takvu komponentu odabiremo na paleti komponenata kombinacijom Shift tipke i lijevoga klika mišem. Nakon što napravimo Shift-klik na komponentu na paleti, ona poprima specifičan izgled — dobiva obojeni okvir.

Kad na ovaj način odaberemo komponentu, svaki klik na dizajneru forme rezultirat će dodavanjem nove komponente. Kad završimo s dodavanjem komponenata, obično želimo postaviti neka najosnovnija svojstva kako bi komponenta izgledala točno kako želimo. No prije nego što možemo nastaviti s normalnim radom, moramo isključiti ovaj način dodavanja komponenata. Ako želimo spriječiti daljnje dodavanje novih komponenata, na paleti komponenata moramo odabrati alat za rad s komponentama. Alat za rad s komponentama je uvijek vidljiv — to je ikona miša s krajnje lijeve strane palete komponenata (slika 8.2).

Tek nakon što je alat za rad s komponentama označen možemo raditi s komponentama i postavljati njihova svojstva.

8.2. Osnovne komponente i njihova svojstva

Uz sve moguće detalje koji se danas dodaju u aplikacije, najbitniji i najveći dio posla obično otpada na tri vrlo jednostavna objekta — okvir unosa teksta, gumb i običan tekst. Ako te objekte prevedemo u Delphi komponente, dobit ćemo TEdit (okvir unosa teksta), TButton (gumb) i TLabel (običan tekst).

Svaka aplikacija mora omogućiti korisniku odabir neke akcije. Glavni pokretači raznih akcija u aplikaciji su gumbi. Želimo li objasniti korisniku kada i kako se neka opcija koristi, postupak korištenja se u kratkim crticama obično objašnjava pomoću TLabel komponente. Nerijetko će nam u aplikaciji zatrebati kratak tekstualni podatak od korisnika, a takav ćemo podatak najlakše dobiti pomoću TEdit komponente.

Svaka komponenta koju postavimo na formu ima velik broj identičnih svojstava koja su nam potrebna za kvalitetno poznavanje i rad u Delphiju. Sve komponente koje postavimo na formu imaju određena fizička svojstva — poziciju na formi i veličinu. Te su dvije karakteristike komponenata zapisane u četiri svojstva: Top (gore), Left (lijevo), Width (širina) i Height (visina).

Još dva svojstva komponenata koja se dosta često koriste vezana su uz funkcionalnost aplikacije — svojstva Visible i Enabled. Svojstvom Visible koristimo se kada komponentu želimo sakriti od korisnika, a Enabled koristimo kada korisniku želimo onemogućiti korištenje komponentom. Sva ćemo ova svojstva proučiti jer su vrlo bitna.

Nekolicina komponenata kojima ćemo se vrlo često koristiti u programiranju posjeduje svojstvo Caption. Takve su komponente (među ostalima) TLabel i TButton. Pomoću Caption svojstva korisniku dajemo na znanje što neki gumb <pb n="176"/>radi ili čemu služi neka opcija. Kad postavljamo Caption svojstvo gumba, na gumb obično stavljamo ime akcije koju će on pokrenuti kad kliknemo na njega.

TLabel komponentu vrlo rijetko, ako ikad, koristimo samostalno na formi. TLabel komponenta služi za objašnjenje funkcioniranja nekog objekta koji na ekranu ne može prikazati informaciju o svojoj namjeni. Takav je objekt upravo komponenta TEdit, okvir za unos teksta, u kojemu je vidljivo samo ono što upiše korisnik ili programer aplikacije.

8.2.1. Upoznavanje osnovnih komponenata

Sad ćemo zajedničkim snagama stvoriti još jedan mali Delphi program koji će ilustrirati nešto od upravo predstavljene teorije. Napravit ćemo mali program za identifikaciju korisnika.

Za početak nam treba nova prazna forma. Nakon što napravimo novi projekt, na formu ćemo dodati jednu TLabel komponentu (slika 8.3).

Svakoj komponenti koju postavimo na formu Delphi dodjeljuje unikatno ime. Ime je komponente APSOLUTNO NAJBITNIJA informacija koja nas treba zanimati, a zapisuje se u svojstvo Name. Delphi osigurava unikatno ime svake komponente tako da pri dodavanju komponente prebroji koliko već komponenata istog tipa postoji na formi, poveća taj broj za jedan i imenuje našu komponentu.

Sad na formu treba dodati jedan okvir unosa teksta. Taj će nam okvir služiti za unos lozinke. Okvir unosa teksta obično se postavlja na formu u neposrednoj blizini neke TLabel komponente. Okvir unosa teksta najbolje je postaviti nadesno od TLabel komponente, ili ispod nje, ako je potrebno mnogo prostora za tekst (slika 8.4).

Sada imamo sve potrebne komponente za unos lozinke, ali trebaju nam još dva gumba. Pomoću jednog ćemo provjeravati unesenu lozinku, a pomoću drugoga ćemo korisniku omogućiti zatvaranje aplikacije.

Nakon što dodamo i ta dva gumba, promijenit ćemo nekoliko svojstava komponenata da bi naše sučelje izgledalo malo razumljivije. Za početak je potrebno promijeniti ime cijeloga programa. U Caption svojstvo forme Form1 <pb n="177"/>unijet ćemo “Identifikacija korisnika”.

Label1 komponenta služi nam za objašnjenje načina korištenja Edit1 komponente, odnosno korisniku tijekom korištenja programom mora biti jasno što mora unijeti u okvir unosa teksta (Edit1 komponentu). U Caption svojstvo Label1 komponente unijet ćemo “Unesite lozinku:”. Nakon što unesemo taj tekst, cijeli će program poprimiti mnogo razumljiviji izgled.

Gumbom Button1 koristit ćemo se za provjeravanje lozinke pa ćemo njegovo Caption svojstvo postaviti na “Provjera”.

Gumbom Button2 služit ćemo se za zatvaranje cijele aplikacije, pa ćemo njegovo Caption svojstvo postaviti na “Izlaz”.

Prije nego počnemo pisati kôd ove aplikacije, na formi postoji još jedan mali detalj koji poprilično smeta i narušava trenutačno poluprofesionalni izgled aplikacije — tekst “Edit1” koji je vidljiv u okviru unosa teksta.

TEdit komponenta zapisuje sve tekstualne podatke u svojstvo koje se zove Text. Pri stvaranju novog okvira unosa teksta Delphi automatski zapisuje ime komponente u Text svojstvo, kao što pri stvaranju gumba zapisuje njegovo ime u Caption svojstvo. Dakle, prije nego krenemo, pomoću Object Inspectora trebamo obrisati sve podatke iz Text svojstva.

Danas se o samom dizajnu aplikacija mogu bez problema napisati cijele knjige, a ja ću u same primjere pokušati ugurati što više dobrih dizajnerskih navika koje sam “pokupio” tijekom povećega broja godina programiranja. Sam dizajn aplikacije trebao bi sličiti ovomu prikazanom na slici 8.5.

Jednom kad je cijelo korisničko sučelje dizajnirano, izvorni kôd nije teško napisati ako znamo što treba napisati i kamo.

Prvu funkcionalnost koju ćemo dodati u ovu aplikaciju bit će izlaz iz aplikacije. Izlaz iz aplikacije moguće je postići na više načina. Prvi je način korištenjem globalnog objekta Application koji nam je uvijek na raspolaganju. Application objekt posjeduje proceduru Terminate koja služi za terminiranje (izlaz) aplikacije. Drugi je način korištenje Close procedure same forme. Close procedura forme zatvara samo formu, no, ako je ta forma i glavna forma aplikacije, zatvaranje glavne forme rezultirat će krajem izvršavanja aplikacije.

Primjenom procedure Application.Terminate osigurat ćemo kvalitetan izlaz iz aplikacije.

8.2.2. Osnovni događaji komponenata

Svaka komponenta (iako postoji nekolicina časnih iznimaka) ima neki osnovni događaj. Osnovni događaj (default event) najčešće je korišteni događaj te komponente. Za gumb, osnovni je događaj Click događaj. Pisanje odgovora na <pb n="178"/>osnovni događaj komponente može se napraviti vrlo jednostavno. Ako dvaput kliknemo na gumb tijekom dizajniranja, Delphi će stvoriti kostur OnClick odgovora na događaj (osnovnog događaja) i postavit će nas u editor koda. Svi će se ostali događaji na prije prikazani način morati odabirati pomoću Events kartice Object Inspectora.

Osnovni događaj okvira unosa teksta je Change događaj. Change događaj se aktivira svaki put kada korisnik svojom akcijom ili programer nekom naredbom promijeni sadržaj okvira unosa teksta. Change događaj iskoristit ćemo u ovoj aplikaciji da bismo postigli malo veći stupanj prijateljskog (user-friendly) sučelja.

8.2.3. Korištenje događaja

Nakon što smo napisali kôd za izlaz iz aplikacije, bilo bi dobro napisati kôd za provjeru unesene lozinke. Gumb za provjeru lozinke mora provjeriti je li korisnik utipkao “Delphi7” u okvir Edit1. Ako je utipkao “Delphi7” sve je u redu, no, ako nije utipkao ništa ili ako je utipkao pogrešnu lozinku, provjera ga o tome mora obavijestiti.

S obzirom na to da je beskorisno provjeravati prazan tekst, programeri obično na početku procedura pišu provjeru da se osiguraju ima li teksta za provjeru ili nema. To bismo vrlo jednostavno mogli napraviti ovako:

No, Delphi i Windows operativni sustav omogućuju nam drugi način za rješenje ovoga problema, a to je Change događaj. Change događaj možemo iskoristiti za onemogućavanje gumba za provjeru ako nikakav tekst ne postoji u okviru unosa teksta. Ako neki gumb onemogućimo (Enabled = False), takav gumb neće moći odgovoriti na događaj. Usto, smanjit ćemo si nepotrebne provjere unutar samog koda jer će gumb biti iskoristiv samo kada korisnik utipka neki tekst u okvir.

Unutar odgovora na Change događaj moramo mijenjati Enabled svojstvo gumba. Enabled svojstvo je Boolean tipa. Ako Enabled svojstvo postavimo na vrijednost False, gumb će poprimiti drukčiji izgled koji jasno pokazuje da je gumb trenutačno neiskoristiv.

Izvorni kôd odgovora na Change događaj možemo napisati na dva načina, u kratkoj i dugoj varijanti. Kratka je verzija vrlo elegantna, dok je duga verzija vrlo <pb n="179"/>jednostavna za razumijevanje.

Da bismo napisali odgovor na Change događaj, najprije moramo odabrati okvir unosa teksta. Nakon odabira, u Object Inspectoru odabiremo karticu Events i radimo dvostruki klik na OnChange dio. S obzirom na to da je Change događaj osnovni događaj okvira unosa teksta, brži i jednostavniji način je dvostruki klik na sam okvir.

Sama provjera lozinke nije veliki problem:

Uz sav kôd koji smo napisali, aplikacija radi savršeno — postoji samo jedan jedini detalj koji malo narušava logiku aplikacije. Isprogramirali smo aplikaciju tako da onemogućuje gumb za provjeru ako u okviru unosa teksta nema teksta. S obzirom na to da je na početku aplikacije okvir prazan, a gumb možemo koristiti, nešto očito nije u redu. Završni korak u izradi ove aplikacije je postavljanje Enabled svojstva gumba za provjeru na False u Object Inspectoru. Time ćemo u potpunosti dobiti gumb kojeg ćemo moći koristiti tek nakon što korisnik nešto utipka.

Na slici 8.6. prikazan je program odmah nakon pokretanja. Gumb “Provjera” <pb n="180"/>prikazan je nešto drukčije od gumba “Izlaz” jer ga je nemoguće iskoristiti dok korisnik ne unese tekst u okvir unosa teksta.

Nakon što korisnik unese lozinku, gumb “Provjera” ćemo moći iskoristiti za provjeru lozinke (slika 8.7).

Ova je aplikacija trenutačno dobra samo za ilustriranje načina na koji funkcioniraju dva različita događaja. Ako želimo napraviti mnogo bolju provjeru lozinke ne treba nam mnogo posla. Prvi problem koji trenutačno imamo je vidljivost lozinke. Kao što je jasno vidljivo na slici 8.7, lozinka koju utipkamo vidljiva je korisniku, ali i bilo kojoj drugoj osobi koja ima pogled na ekran.

Obično se u softveru umjesto lozinke pojavljuje string ispunjen zvjezdicama. Kako sakriti lozinku kao što to rade svi profesionalni programeri? Rješenje ne zahtijeva pisanje koda koji će umjesto slova prikazivati zvjezdice — rješenje ovoga problema zove se PasswordChar.

TEdit komponenta ima posebno svojstvo kojim se koristimo upravo u ovu svrhu, svojstvo PasswordChar. U PasswordChar svojstvo zapisuje se znak koji će se koristiti za prikaz pravih podataka na ekranu, dok će pravi podaci ostati skriveni u pozadini. Osnovna vrijednost zapisana u PasswordChar svojstvu je #0, odnosno, nulti znak. Ako je ta vrijednost zapisana u PasswordChar svojstvu, na ekranu će se prikazivati pravi podaci. Ako unesemo bilo koju drugu vrijednost, poput zvjezdice, onda će se taj znak koristiti u prikazu.

Nakon što postavimo zvjezdicu u PasswordChar svojstvo, situacija će na ekranu biti mnogo profesionalnija i kvalitetnija.

<pb n="181"/>

Sad kad smo lozinku sakrili od nepoželjnih očiju, imamo mogućnost još malo unaprijediti identifikaciju korisnika. Što će se dogoditi ako korisnik iza lozinke slučajno utipka jednu razmaknicu? Pogreška. Što će se dogoditi ako korisnik počne namjerno unositi samo razmaknice u okvir unosa teksta? Gumb “Provjera” će se aktivirati, ali neće imati što provjeriti. Ponovno pogreška.

Kako se osigurati da kod provjere u tekstu ne bude ni jedne razmaknice? Postoji više rješenja ovoga problema, no trenutačno najjednostavniji način je obrisati sve razmaknice koje možda postoje u stringu. Za brisanje viška razmaknica možemo napraviti vlastitu proceduru, ali je mnogo bolje rješenje iskoristiti Delphi funkciju Trim.

Funkcija Trim primjenjuje se za izbacivanje razmaka s početka i kraja stringa. Ti su razmaci ionako u većini slučajeva nepotreban višak. Ako iskoristimo funkciju Trim u provjeri lozinke, sa sigurnošću ćemo dobiti string koji na početku i na kraju nema viška razmaknica koje mogu dovesti do pogreške.

Zadnje što možemo uvesti u ovu provjeru ovisi posve o programerskoj zamisli — želimo li lozinku osjetljivu na velika i mala slova ili želimo lozinku u kojoj je bitan tekst, neovisno o velikim i malim slovima.

Ako želimo neosjetljivu provjeru teksta, cijeli se tekst prije provjere pretvara u velika ili u mala slova — ovisno o navici. Za pretvaranje svih slova u stringu u velika u Delphiju možemo iskoristiti funkciju UpperCase. Za pretvaranje svih slova u stringu u mala možemo iskoristiti funkciju LowerCase.

Ako iskoristimo tu funkciju u našoj provjeri, dobit ćemo algoritam koji prihvaća lozinku napisanu velikim ili malim slovima (što je dobro ako je korisnik početnik i <pb n="182"/>slučajno uključi Caps Lock) i koji odbacuje višak praznina (višak praznina moguće je dobiti prilikom Copy — Paste operacije ako korisnik nalijepi lozinku u okvir).

Ovime je završen program za identifikaciju korisnika, naš prvi program koji bi mogao bez problema dobiti prolaznu ocjenu za kvalitetu dizajna i jednostavnost korištenja.

Program za identifikaciju korisnika može se pronaći na CD-u u mapi “Primjeri\Poglavlje 8\Ident”.

8.3. TCheckBox i TRadioButton komponente

Tijekom programiranja često ćemo doći u situaciju da korisniku moramo omogućiti odabir neke opcije. Za ovaj dio posla na raspolaganju nam stoje dvije različite komponente: TCheckBox i TRadioButton.

TCheckBox komponenta (kontrolna kućica) primjenjuje se kada korisniku želimo omogućiti odabir jedne ili više opcija koje su međusobno povezane. TRadioButton komponentu koristimo kada korisniku želimo ponuditi velik broj opcija od kojih može odabrati samo jednu. Obje se komponente nalaze na kartici Standard.

U sljedećem programu koji ćemo napraviti upoznat ćemo se s još nekim svojstvima kojima ćemo se koristiti svakodnevno u Delphi programiranju.

8.3.1. Align svojstvo komponenata

Za početak nam treba nova prazna aplikacija. Program koji ćemo sada stvoriti ilustrirat će najosnovnije stilove i poravnanja teksta.

Na formi će nam trebati jedna labela. Nakon što na formu dodamo jednu TLabel komponentu, njezino svojstvo AutoSize postavit ćemo na False. AutoSize svojstvo labele omogućuje dinamičko rastezanje same labele dok unosimo ili brišemo tekst. AutoSize svojstvo ima svojih dobrih strana u programima u kojima pomoću koda mijenjamo tekst labele. Ako je AutoSize svojstvo postavljeno na True, komponenta će se uvijek razvući dovoljno da sav tekst bude vidljiv na formi.

Većina komponenata kojima se koristimo za dizajn korisničkog sučelja aplikacije posjeduje jedno vrlo korisno svojstvo pod imenom Align. Align svojstvo koristi se za poravnanje komponente na formi. Ovo je posebno bitno u aplikacijama u kojima se veličina forme može vlastoručno mijenjati. Sve komponente koje imaju podešeno Align svojstvo će se povećavati i smanjivati ovisno o veličini forme. Svojstvo Align okosnica je bilo kojeg imalo ozbiljnog dizajna.

Za sada nam labela treba na vrhu forme pa ćemo Align svojstvo labele postaviti na alTop. Forma bi nakon dosadašnjih postavki trebala izgledati ovako:

<pb n="183"/>

8.3.2. TRadioButton komponenta

Svakoj TLabel komponenti možemo postaviti tri različita poravnanja teksta: lijevo, centralno i desno poravnanje teksta. Poravnanje teksta TLabel komponente određuje se pomoću svojstva Alignment.

Alignment svojstvo je poseban, enumerirani tip podataka koji se zove TAlignment. Poravnanje teksta određuje se pomoću tri konstante: taLeftJustify, taCenter i taRightJustify.

S obzirom na to da tekst može biti poravnan samo na jednu stranu, korisniku ćemo promjenu poravnanja teksta omogućiti pomoću TRadioButton komponenata.

Na formi nam sada trebaju tri TRadioButton komponente, tri radiogumba. Komponenti RadioButton1 ćemo Caption postaviti na “Lijevo poravnanje”, komponenti RadioButton2 na “Centralno poravnanje” i komponenti RadioButton3 na “Desno poravnanje”.

RadioButton1, RadioButton2 i RadioButton3 i nisu najbolja imena za komponente. Jedna od vrlo korisnih praksi u programiranju je promjena imena samih komponenata u nešto razumljivo. Osim toga što se komponente imenuju jasnijim i korisnijim imenima od onih koje Delphi razvojno sučelje automatski stvori, programeri raznih programskih jezika koriste se jednostavnim prefiksima po kojima razlikuju ne samo komponentu nego i tip komponente.

Radiogumbi obično imaju prefiks “rad”. Nakon što se naviknemo na postavljanje prefiksa na imena komponenata, posao izrade sučelja i pisanja izvornog koda poprilično se smanjuje zbog više razloga.

Prvi, ne tako jasan razlog korištenja prefiksa u imenima komponenata je olakšan pristup tim komponentama tijekom dizajna aplikacije. Object Inspector popisuje komponente na formi abecednim redom pa ćemo pomoću prefiksa vrlo brzo moći pronaći točno onu komponentu koja nam je potrebna.

Drugo ćemo olakšanje primijetiti pri pisanju i čitanju već postojećeg koda. Korištenjem prefiksa u imenima znat ćemo kojeg je tipa komponenta koju koristimo i koja sve svojstva i metode ona posjeduje.

Prije nego nastavimo dalje, promijenit ćemo imena svih komponenata na formi, ali i ime same forme. Neki programeri u ime forme postavljaju prefiks “frm”, a neki na kraj imena dodaju “Form” pa se često glavna forma može vidjeti pod imenima “frmMain” ili “MainForm”. Name svojstvo naše glavne forme postavit ćemo na “MainForm” (naravno, bez navodnika).

TLabel komponente obično dobivaju prefiks “lab”. Komponentu Label1 preimenovat ćemo u “labPrikaz”. Radiogumbe ćemo postaviti na “radLijevo”, “radCentar” i “radDesno”.

Nakon što postavimo sva imena komponenata, Selektor objekata na Object Inspectoru trebao bi prikazivati ovakvu situaciju:

<pb n="184"/>

Sad ćemo napisati kôd za mijenjanje poravnanja teksta u labPrikaz komponenti. Sav kod koji će mijenjati poravnanje teksta bit će smješten u OnClick događaje odgovarajućih RadioButton komponenata. OnClick događaj je osnovni događaj RadioButton komponenata pa neće biti veliki problem napisati sljedeće tri procedure.

Nakon što smo napisali kod, klikom na gumb korisnik će moći definirati koje poravnanje teksta želi, a i ujedno će na samim radiogumbima moći vidjeti koji je stil poravnanja odabran. Ako govorimo u terminima Delphi svojstava, klikom na radiogumb njegovo se Checked svojstvo postavlja na True, dok se svim ostalim radiogumbima Checked svojstvo postavlja na False.

<pb n="185"/>

8.3.3. Delphi komentari

Uz kod koji mijenja tekst labele i poravnanje teksta, ovaj ispis koda prikazuje još nešto — Delphi komentare. U Delphiju možemo pisati jednolinijske i blok-komentare.

Jednolinijski komentari upravo su ovi koje možemo vidjeti u primjeru 8.8. Oni započinju korištenjem dvije kose crte // i nastavljaju se sve do kraja linije.

Blok-komentari su komentari već prije viđeni u Pascalu, a možemo ih pisati na dva različita načina. Blok-komentarima koristimo se kada želimo komentirati kod u više linija ili kada iz procesa kompilacije privremeno želimo izbaciti veći broj linija koda. Prvi način pisanja blok-komentara je korištenjem vitičastih zagrada:

{ komentar }

Drugi način pisanja blok-komentara je pomoću kombinacije zagrada i zvjezdica:

(* komentar *)

8.3.4. TCheckBox komponenta

Pola je aplikacije završeno, ako izuzmemo razne optimizacije koje je moguće upotrijebiti na ovom primjeru. S obzirom na to da je ovaj primjer savršen za prikaz raznih rješenja istoga problema, optimizacije ćemo vidjeti na kraju.

Drugi dio posla vezan je uz postavke osnovnih stilova teksta: masna, kosa i podcrtana slova. S obzirom na to da se sva tri navedena stila mogu istodobno primijeniti na tekst, RadioButton komponente ne dolaze u obzir. Za mogućnost odabira više opcija koristimo CheckBox komponente.

Pri radu s CheckBox komponentama, imenu svake CheckBox komponente možemo dodati prefiks “chk”.

Sad će nam na formi trebati tri CheckBox komponente. Caption svojstva CheckBox komponenata ćemo postaviti na “Masna slova”, “Kurziv” i “Podcrtana slova”, a imena na “chkBold”, “chkItalic” i “chkUnderline”.

Najbitnije svojstvo CheckBox komponenata je Checked svojstvo koje je Boolean tipa i pomoću kojeg možemo utvrditi (tijekom dizajna i tijekom izvršavanja aplikacije) je li neka opcija uključena ili nije.

Upravo sad ćemo Checked svojstvo upotrijebiti za postavljanje i micanje stilova teksta. Stilovi teksta koje smo spomenuli nalaze se skriveni u TLabel komponenti u svojstvu Font. Svojstvo Font nije jednostavno svojstvo koje možemo postaviti kao Caption ili Checked svojstvo komponenata. Svojstvo Font zapravo je <pb n="186"/>podobjekt u kojem se nalaze zapisane informacije o fontu koji se koristi za prikaz teksta neke komponente.

Font sadrži informacije o stilu teksta u svojstvu Style. Svojstvo Style je tipa TFontStyles, a TFontStyles je set podataka. U TFontStyles set podataka možemo uključiti četiri različite vrijednosti: fsBold (masna slova), fsItalic (kurziv), fsUnderline (podcrtana slova) i fsStrikeOut (precrtana slova).

Izvorni kôd koji, ovisno o korisnikovu odabiru mijenja stilove fonta, izgleda ovako:

Ako pokrenemo aplikaciju i malo se poigramo s komponentama koje smo postavili na formi i isprogramirali, dobit ćemo vrlo jasan pregled stilova teksta.

<pb n="187"/>

Ovaj se primjer nalazi na CD-u u mapi “Primjeri\Poglavlje 8\Tekst 1”.

8.4. Mali trikovi Delphi programiranja

Sad ćemo se malo pozabaviti optimizacijom ovoga primjera. Ako se vratimo na kôd napisan za radiogumbe, moguće je vidjeti poprilično slične linije koda, a neki se podaci čak i ponavljaju. S obzirom na to da je ovo malena aplikacija, ovo pisanje dodatnog koda ne čini velik problem, no radimo li išta ozbiljnije, morat ćemo se potruditi odmah od početka pisati što manje koda i iskoristiti ono što nam već stoji na raspolaganju.

Prvo što je moguće promijeniti su linije koda koje zapisuju novi tekst u Label komponentu:

labPrikaz.Caption := ‘Lijevo poravnanje’;

Mnogo bolje rješenje bilo bi iskoristiti tekst zapisan u Caption svojstvima radiogumba:

labPrikaz.Caption := radLijevo.Caption;

No, čak ako i iskoristimo već postojeći tekst u Caption svojstvima radiogumba, imat ćemo dosta koda jer ćemo morati promijeniti sva tri odgovora na događaj. Ali, Delphi ne bi bio Delphi da nema rješenja i za ovaj problem. Za sva tri odgovora na Click događaj možemo napisati samo jednu jedinu proceduru.

Ovaj zahvat zahtijeva nešto znanja, pažnje i rada. Naravno, treba zapamtiti jednu stvar: ni u čemu ne treba pretjerivati — pa ni u pokušajima optimizacije.

8.4.1. Brisanje postojećih procedura

Prvo što moramo napraviti je obrisati već postojeći kod koji smo napisali za Click događaje radiogumba. Ali, u brisanje koda nećemo se zaletjeti kao grlom u jagode jer ćemo si time nanijeti popriličan broj problema.

Svaka procedura kojom se koristimo kao odgovorom na događaj zapisana je u interface i u implementation dijelu forme.

<pb n="188"/>

Ako obrišemo cijelu proceduru u implementation dijelu, deklaracija procedure i dalje ostaje u interface dijelu i prigodom pokušaja kompilacije izazvat će velike probleme.

Na dnu editora koda pojavit će se “Message View” prozor s porukom o pogrešci “Unsatisfied forward or external declaration”. Ta se pogreška pojavljuje kada navedemo samo deklaraciju procedure, a ne napišemo i njezinu implementaciju.

<pb n="189"/>

Rješenje trenutačne situacije, ako smo vlastoručno pobrisali implementaciju procedure, je brisanje deklaracije iz interface dijela forme. Ovo se u rijetkim kritičnim situacijama može tolerirati, no postoji mnogo bolji način — Delphi način.

Delphi razvojna okolina posjeduje jednu vrlo korisnu naviku – automatski briše prazne kosture procedura koje sama stvori. Sve što moramo napraviti kako bismo natjerali Delphi da automatski obriše implementaciju i deklaraciju procedure je da obrišemo sav kôd koji smo vlastoručno otipkali. U ovom slučaju, to je sav kod unutar begin–end bloka.

procedure TMainForm.radLijevoClick(Sender: TObject);

begin

end;

Nakon što obrišemo kôd koji smo utipkali unutar begin–end bloka, ostaje još samo da odaberemo neku od opcija za snimanje projekta; najbolje File -> Save All. Pri snimanju datoteka na disk Delphi briše sve kosture procedura koje je sam stvorio i u koje nismo unijeli neki tekst. Želimo li pri snimanju sačuvati te kosture, dovoljno je u begin–end blok unijeti neki komentar i Delphi ih neće obrisati.

8.4.2. Korištenje jedne procedure na više mjesta

Svaki događaj može imati zasebnu proceduru koja će se pozivati kada se događaj izvrši, ali u nekim slučajevima dobro je imati jednu proceduru koja će biti povezana s većim brojem događaja.

Sad ćemo na Click događaj komponente radLijevo utipkati kôd kojim ćemo se moći koristiti za postavljanje sva tri stila poravnanja. U tu ćemo svrhu koristiti parametar Sender koji do sada nije objašnjen.

Većina procedura kojima se koristimo u odgovorima na događaj posjeduju parametar Sender. U parametru Sender uvijek je upisana komponenta koja je pozvala proceduru. S obzirom na to da je Sender tipa TObject to znači da u Sender parametru može biti zapisana bilo koja moguća komponenta s kojom radimo.

<pb n="190"/>

Nakon što napišemo sav kod u istoj proceduri, proceduru ćemo povezati sa svim komponentama koje je trebaju koristiti, a to su još gumbi za centriranje teksta i poravnanje nadesno.

Povezivanje procedure s drugim događajima napravit ćemo pomoću Object Inspectora. Najprije ćemo odabrati komponentu radCentar (jedan lijevi klik na njezinu površinu) i na Object Inspectoru odabrati karticu Events. Na kartici Events treba odabrati OnClick događaj i pomoću gumba prikazati popis postojećih procedura.

U padajućoj listi koja je vidljiva na slici 8.14. prikazane su sve procedure koje možemo odabrati za OnClick događaj radiogumba. Koju god proceduru odabrali, ta će se procedura pozivati na klik gumba. Iz padajuće liste treba nam procedura pod imenom radLijevoClick.

Iste ove korake treba poduzeti i za komponentu radDesno. Nakon što sve komponente povežemo s istom procedurom i pokrenemo program, sve bi moralo raditi savršeno jer će svaka procedura na klik pozvati proceduru radLijevoClick i u Sender parametar zapisati svoje ime.

8.4.3. Osnovno korištenje RTTI-a

Delphi RTTI (Run-Time Type Information) skupina je informacija o komponentama koje postoje u Delphiju. RTTI sadrži informacije o svojstvima i procedurama komponenata. Usto, pomoću RTTI-a možemo dobiti informacije o nasljeđivanju komponente.

<pb n="191"/>

Nasljeđivanje je termin koji je vezan uz OOP (objektno-orijentirano) programiranje. Svaka komponenta koju stvara neki programer mora se stvoriti iz nečega, a to nešto iz čega se stvara nova komponenta već je postojeća komponenta.

Ako govorimo o pravom objektno-orijentiranom programiranju, pri programiranju nove klase objekata uvijek se kao temelj koristi već postojeća klasa. Najosnovnija klasa objekata koja se koristi u Delphiju je klasa TObject, a nakon toga slijedi čitava hijerarhija raznih klasa i komponenata kojima se koristimo u programiranju.

Ova će spoznaja dobro poslužiti u radu sa Sender parametrom. Delphi posjeduje jedan poseban operator, operator as, kojim jedan tip objekta možemo pretvoriti u drugi. Sender parametar naveden je kao TObject. TObject je klasa u kojoj su definirana najosnovnija svojstva i metode svih klasa u Delphiju, a TRadioButton mnogo je “dublje” unutar hijerarhije.

Tijekom korištenja OnClick događaja radiogumba, u kodu nam je potreban objekt tipa TRadioButton. Da bismo od Sender parametra dobili objekt tipa TRadioButton, morat ćemo iskoristiti operator as.

Nakon što se izvrši ovaj kod, u varijablu RadioGumb bit će zapisana radiogumb komponenta na koju smo kliknuli. Ako kliknemo na komponentu radLijevo, RadioGumb će biti jednak komponenti radLijevo. Ako kliknemo na komponentu radDesno, RadioGumb će biti jednak komponenti radDesno. Vjerovali ili ne, ovo znači da su Delphi objekti zapravo pokazivači i ujedno znači da Delphi jako dobro skriva tu “neugodnu” činjenicu.

S obzirom na to da će RadioGumb varijabla uvijek biti jednaka radiogumb komponenti na koju korisnik klikne na formi, situacija s promjenom Caption svojstva TLabel komponente vrlo je jednostavna.

<pb n="192"/>

8.4.4. Fenomenalno svojstvo Tag

Sve komponente u Delphiju posjeduju vrlo korisno svojstvo pod imenom Tag tipa Integer. Iako se izdaleka ne čini kao nešto iskoristivo ili vrlo korisno, Tag svojstvo možemo iskoristiti za popriličan broj optimizacija i igrarija koje će rezultirati elegantnijim i boljim rješenjima.

Da bismo ovu optimizaciju koda završili do kraja, potrebno je još napisati kôd koji će mijenjati poravnanje teksta u TLabel komponenti. Mijenjanje poravnanja možemo napraviti pomoću if provjere, ali to bi rješenje opet zahtijevalo velik broj linija koda:

Ovime smo dobili za četiri linije kraći kôd procedure, ali možemo mi još bolje. Zar ne? TAlignment je enumerirani tip podataka čija deklaracija u Delphi datotekama pomoći izgleda ovako:

type TAlignment = (taLeftJustify, taRightJustify, taCenter);

Gledajući navedenu deklaraciju tipa TAlignment, redni brojevi konstanti su:

taLeftJustify = 0

taRightJustify = 1

taCenter = 2

Sad ćemo ove numeričke vrijednosti unijeti u prikladna Tag svojstva komponenata. Time ćemo dobiti osnovu za vrlo efikasnu verziju koda za mijenjanje poravnanja. U Tag svojstvo komponente radLijevo unijet ćemo 0, u Tag svojstvo komponente radCentar unijet ćemo 2 i u Tag svojstvo komponente radDesno broj 1.

Nakon toga proceduru za postavljanje poravnanja teksta možemo napisati u do sada apsolutno najkraćem izdanju:

<pb n="193"/>

Linija koda za promjenu poravnanja ne bi smjela biti problem. Ona jedino čita vrijednost Tag svojstva odabrane komponente i pretvara je u TAlignment vrijednost, čime je cijeli naš posao završen.

Inače, ova se procedura ipak može još malo skratiti. Konverzija objekata može se pisati na dva načina:

ImeKomponente as TImeKlase

ili

TImeKlase(ImeKomponente)

Još kraća verzija ove procedure (i obećavam zadnja) izgleda ovako:

Eto, s trinaest na dvije linije koda. Nije ni loše za hrvatskog programera. Optimiziranje koda za masna slova i kurziv ostavit ću za neku drugu prigodu.

Ova verzija primjera nalazi se na CD-u u mapi “Primjeri\Poglavlje 8\Tekst 2”.

8.5. Sažetak

U ovom je poglavlju bilo predstavljeno poprilično mnogo informacija o dizajnu korisničkog sučelja i o komponentama kojima se koristimo u te svrhe. Vidjeli smo TRadioButton i TCheckBox komponente i njihovu namjenu: TRadioButton komponente koristimo kada želimo omogućiti odabir samo jedne od ponuđenih opcija, a TCheckBox komponente koristimo kada želimo omogućiti odabir većega broja opcija odjednom.

Uz komponente, bilo bi dobro zapamtiti Tag svojstvo jer nam u nekim situacijama može dosta skratiti izvorni kôd i eventualno ubrzati izvršavanje aplikacije. Također, as operator, odnosno pretvaranje jednog tipa komponente u drugu, osnovni je alat svakog Delphi programera.

Pitanja i zadaci

<pb n="194"/>

Pitanje 1: Kako najbrže dodati novu komponentu na formu?

Pitanje 2: Koje je apsolutno najbitnije svojstvo svake komponente?

Pitanje 3: Navedite tri osnovna svojstva komponenata.

Pitanje 4: Za što se obično koristi TLabel komponenta?

Pitanje 5: Za što se koristimo TEdit komponentom?

Pitanje 6: Kako se zove svojstvo TEdit komponente u koje se zapisuje tekst pri unosu?

Pitanje 7: Kada ćemo Enabled svojstvo neke komponente postaviti na False?

Pitanje 8: Čemu služi TRadioButton komponenta?

Pitanje 9: Kojim operatorom možemo jedan tip objekata pretvoriti u drugi?

Pitanje 10: Za što možemo iskoristiti svojstvo Tag?

Zadatak 1: Napravite program koji će na glavnoj formi imati četiri gumba. Klikom na gumb njegov se Caption tekst mora preslikati na naslovnu traku aplikacije.

<pb n="195"/>

9. Stvaranje naprednijih aplikacija

9.1. Grupiranje komponenata 196

9.1.2. Usidravanje komponente radi boljeg

vizualnog efekta 199

9.1.3. Parent i Owner svojstva komponenata 201

9.1.4. TPanel komponenta 202

9.1.5. TBevel komponenta 203

9.2. Liste podataka 204

9.2.1. Aplikacija za rastavljanje rečenica 206

9.2.2. Fokusiranje komponenata 207

9.2.3. Nastavak rastavljanja rečenica 208

9.2.4. Odabir većega broja podataka u listi 211

9.2.5. Snimanje liste na disk 212

9.3. Sažetak 212

<pb n="196"/>

9. Stvaranje naprednijih aplikacija

U ovom ćemo poglavlju vidjeti kako se koriste još neke od standardnih komponenata pomoću kojih možemo stvoriti vrlo kvalitetne i korisne aplikacije.

9.1. Grupiranje komponenata

Razvoj aplikacija u Delphiju podrazumijeva korištenje većega broja komponenata. Najviše njih bit će vidljivo na glavnoj ili dodatnim formama u aplikaciji. Neke od njih bit će međusobno povezane. Da bismo krajnjem korisniku olakšali snalaženje u aplikaciji, komponente koje su međusobno logički povezane grupiramo zajedno. Na slici 9.1. prikazan je Delphijev dijaloški okvir za definiranje projekta. Na njemu možemo vidjeti uokvirene cjeline — grupacije komponenata “Code generation”, “Runtime errors”, “Syntax Options” i “Debugging”.

Grupiranje većega broja komponenata postiže se korištenjem neke od komponenata koja “u sebi” može držati druge komponente. Jedna od takvih komponenata je TGroupBox pomoću koje dobivamo točno ovakav izgled grupa kakav je vidljiv na slici 9.1.

Da bismo dobili grupu komponenata, prvo što moramo napraviti je dodati TGroupBox komponentu na formu. TGroupBox komponenta ima Caption svojstvo u koje zapisujemo ime grupe opcija. Ta grupa komponenata koju ćemo stvoriti zvat će se “Odabir boja”. Nakon što postavimo Caption svojstvo, pomaknut ćemo komponentu u donji desni kut glavne forme. Ako smo sve dobro postavili, aplikacija bi trebala izgledati slično ovoj na slici 9.2.

<pb n="197"/>

U komponentu GroupBox1, kako se trenutačno zove naša TGroupBox komponenta, dodat ćemo četiri radiogumba koji će nam služiti za promjenu boje glavne forme.

Pri dodavanju komponenata u TGroupBox komponentu ili neku sličnu, obvezno je prije dodavanja moramo označiti, kao što je vidljivo na slici 9.2. Nakon što je označena, dodajemo joj željene komponente. Nakon što dodamo sva četiri radiogumba u GroupBox1, promijenit ćemo im neka svojstva.

Boja komponenata zapisana je u svojstvu Color. Svojstvo Color je 32-bitna brojčana vrijednost u koju obično zapisujemo neku od prije definiranih konstanti. Pozadina većine komponenata bit će obojena posebnom bojom koja se zove clBtnFace (naličje gumba). Boja clBtnFace je boja koja je istovjetna trenutačnim postavkama na cijelom računalu pa će njenim korištenjem naša aplikacija izgledati identično svim ostalim aplikacijama na korisničkom računalu.

Popis svih konstanti boja možemo provjeriti u Object Inspectoru, a za sada će nam trebati samo četiri: clBtnFace, clBlue, clRed, clGreen. RadioButton1 će nam trebati za vraćanje boje na standardnu boju pozadine pa ćemo njegovo svojstvo Caption postaviti na “Standardna boja” i Checked svojstvo na True. Svi ostali radiogumbi imat će promijenjena samo Caption svojstva: “Crvena boja”, “Plava boja”, “Zelena boja”.

<pb n="198"/>

9.1.1. Pristupanje svojstvima forme pomoću koda

Izvorni bi kôd trebao biti vrlo jednostavan, zar ne? Sve linije koda “na isti kalup”:

ImeObjekta.Svojstvo := Vrijednost;

Postavljanje standardne boje na formu izgledalo bi ovako:

Pokušamo li kompilirati program, sve će proći u najboljem redu, pokrenemo li program, ovaj će kôd sasvim lijepo promijeniti boju u standardnu boju prozora. Ali u tom kôdu postoji jedan potencijalni problemčić koji možemo vrlo jednostavno riješiti malo drukčijom sintaksom.

Ono što je preporučeno i što treba napraviti je promijeniti ime forme (i ostalih komponenata) u razumljivije ime. Ako sada promijenimo ime forme Form1 u MainForm, program više neće funkcionirati. Razlog tomu je što u kodu mi želimo promijeniti boju objekta koji se zove Form1, a takav više ne postoji u aplikaciji.

Da bismo izbjegli ove probleme, svojstva forme možemo pisati bez imena forme, dakle, navodimo samo ime svojstva koje nas zanima.

Ako izvorni kôd napišemo na način prikazan u primjeru 9.2, Name svojstvo možemo promijeniti kako god želimo, ali ovako napisani kôd uvijek će se uspješno kompilirati i uspješno obaviti svoj posao.

Postoji i drugi način na koji možemo pristupiti formi, iako se on češće primjenjuje pri programiranju komponenata, a to je korištenjem rezervirane riječi Self. Rezervirana riječ Self upućuje na objekt u kojem pišemo kôd. Ako pišemo kôd za neku komponentu koja se nalazi na formi MainForm, Self će biti MainForm. Ako pišemo kôd na formi FormaZaUnos, Self će biti FormaZaUnos.

Ostatak koda potpuno je jasan, pa ga ovdje nećemo navoditi.

<pb n="199"/>

9.1.2. Usidravanje komponente radi boljeg vizualnog efekta

Komponenta GroupBox1 namjerno je postavljena u donji desni kut forme kako bi izazvala što više problema u području dizajniranja aplikacije. Ako pokušamo malo rastegnuti formu (povećati je ili smanjiti) pojavljuju se problemi koji nisu nimalo ugodni oku, a katkada mogu i onemogućiti normalan rad s aplikacijom.

Nakon rastezanja forme, ona mijenja svoj izgled, a komponente ostaju na svojem mjestu. Razlog tomu je što su sve komponente usidrene na svojoj gornjoj lijevoj poziciji. Pri rastezanju komponentu GroupBox1 možemo natjerati da se drži donjega desnog kuta na dva načina: korištenjem koda ili korištenjem svojstava.

Prvi i teži način je korištenje izvornog koda. Kada korisnik krene s rastezanjem forme (ili neke druge komponente) generira se OnResize događaj. Unutar odgovora na OnResize događaj forme napisat ćemo kôd koji će pomicati GroupBox1 komponentu tako da se uvijek nalazi 10 piksela ulijevo od donjega desnog kuta forme. Izvorni kôd za ovu akciju prikazan je u primjeru 9.4.

U samom izvornom kodu korištena su dva nova svojstva forme, ClientWidth i ClientHeight. Zašto postoje ClientHeight i ClientWidth kad već ionako na raspolaganju imamo Width i Height svojstva?

Svaki prozor (svaka forma) sastoji se od dva dijela: klijentskog (client) i neklijentskog (nonclient) prostora. Klijentski prostor čini radna površina forme, a neklijentski prostor čine rubovi forme, glavni izbornik, naslovna traka i klizne trake. Slika 9.5. prikazuje klijentski i neklijentski prostor u aplikaciji Notepad.

<pb n="200"/>

ClientWidth i ClientHeight svojstva koriste se tijekom kalkulacije nove pozicije jer komponente ne možemo postaviti na neklijentski dio forme. Ako bismo koristili Width i Height svojstva, dobili bismo višak od 6 ili 7 piksela (veličina ruba forme) i komponenta ne bi bila smještena na točnu poziciju.

S obzirom na to da se vrlo velik broj komponenata u aplikacijama mora ponašati na sličan način: pomicati zajedno s formom ili mijenjati svoju veličinu ovisno o veličini forme, Delphi za taj posao nudi jednostavnije rješenje od pisanja koda. Rješenje automatskog pomicanja i rastezanja komponenata je svojstvo Anchors.

Svojstvo Anchors je set četiri vrijednosti: akLeft, akTop, akRight, akBottom. Svako sidro označuje jednu od osnovnih pozicija komponente. Svaka standardna komponenta (a tako je u principu s većinom komponenata) ima odmah uključene opcije akLeft i akTop. Zahvaljujući tim sidrima sve se komponente “drže” svoje gornje lijeve pozicije, što je standardni način ponašanja svih objekata unutar cijeloga Windows operativnog sustava.

Ako želimo natjerati GroupBox1 da se uvijek nalazi uz desni donji rub cijele forme, morat ćemo uključiti vrijednosti akRight i akBottom, a isključiti akTop i akLeft.

<pb n="201"/>

Prije nego što testiramo kako funkcionira Anchors svojstvo, potrebno je obrisati kôd iz OnResize događaja forme jer on sada ne koristi ničemu.

Svojstva akLeft i akTop isključena su jer bi njihov ostanak rezultirao rastezanjem komponente. Komponenta bi se i dalje poravnavala uz svoju gornju lijevu koordinatu, ali bi se rastezala i do krajnje donje desne koordinate, a to u ovoj situaciji ne bi izgledalo profesionalno.

Cijeli primjer nalazi se na CD-u u mapi “Primjeri\Poglavlje 9\Promjena Boje\”.

9.1.3. Parent i Owner svojstva komponenata

Svaka klasa objekata posjeduje jednu posebnu proceduru koja se zove konstruktor. Konstruktor je procedura koja stvara komponentu, a to uključuje alokaciju memorije. Uz konstruktor, svaka klasa objekata posjeduje i destruktor. Destruktor je procedura koja je odgovorna za brisanje komponente iz memorije.

Pri dodavanju komponente s palete komponenata na formu Delphi automatski poziva konstruktor odabrane komponente, što znači da mi tijekom dizajna radimo s pravim objektima. No, uz stvaranje komponente, Delphi tijekom dodavanja komponente na formu mora posebno pripaziti na dva svojstva.

Prigodom dodavanja komponente na formu Delphi postavlja Owner i Parent svojstva nove komponente. Ako se prisjetimo prošloga primjera s TGroupBox komponentom, nakon što na formu dodamo TGroupBox komponentu, Delphi izjednačuje Owner svojstvo TGroupBox komponente s glavnom formom. Svakoj komponenti koju dodamo na formu, Owner će biti sama forma. Samo ćemo pri stvaranju komponenata pomoću koda moći odabrati neku drugu Owner komponentu.

U Owner svojstvo zapisuje se vlasnik komponente. Vlasnik komponente je komponenta koja je odgovorna za brisanje drugih komponenata iz memorije. U ovom slučaju, glavna je forma odgovorna za brisanje GroupBox1 komponente iz memorije. Sve komponente koje dodamo na formu tijekom dizajna bit će obrisane iz memorije tek pri zatvaranju aplikacije.

Parent svojstvo bitno je za dizajn aplikacije. U Parent svojstvo komponente zapisuje se komponenta roditelj. Komponenta roditelj odgovorna je za prikaz komponente djeteta. Nakon što smo na formu dodali GroupBox1 komponentu, njezin je roditelj postala glavna forma. GroupBox1 komponenta je komponenta dijete glavne forme, što znači da se GroupBox1 komponenta prikazuje na površini glavne forme.

Parent komponente mogu biti samo one komponente koje u sebi mogu držati druge komponente. TForm, TGroupBox i TPanel su najkorištenije Parent komponente. Ako se ponovno prisjetimo prošloga primjera, radiogumbe smo dodali u GroupBox1 komponentu. S obzirom na to da se ti radiogumbi prikazuju na površini GroupBox1 komponente, Parent komponenta je GroupBox1, a Owner komponenta je glavna forma. Ova se tvrdnja može provjeriti i pomoću izvornog koda.

<pb n="202"/>

Ako testiramo ovu proceduru, dobit ćemo potvrdu prije navedene teorije:

Odnos između komponenata roditelja i komponenata djece uvijek je vrlo jasno vidljiv u Object TreeView prozoru. Na slici 9.8. može se vidjeti odnos između komponenata na formi: roditelj komponente Button1 glavna je forma, dok je roditelj svih radiogumba GroupBox1 komponenta.

9.1.4. TPanel komponenta

Još jedna komponenta koja se vrlo često koristi za grupiranje komponenata je TPanel komponenta. TPanel komponenta se kao i TGroupBox komponenta koristi za grupiranje komponenata. Razlika između TGroupBox i TPanel je u tome što se TPanel komponenta može podesiti tako da korisnik i ne zna da su komponente grupirane jer TPanel ne prikazuje naziv grupe.

Sada bi bilo dobro stvoriti novu aplikaciju i na formu dodati jednu TPanel komponentu. Panel1 komponenta pojavljuje se na formi s tankim okvirom i Caption tekstom na svojoj površini. Caption tekst TPanel komponenata obično se postavlja na prazan string.

Izgled TPanel komponente određuju dva svojstva: BevelInner i BevelOuter; vanjski i unutrašnji rub. Iako postavke ta dva svojstva ovise o ukusu i potrebama <pb n="203"/>programera, vrlo velika većina aplikacija koristi postavke BevelInner = bvRaised i BevelOuter = bvLowered, čime TPanel komponenta poprima lijepi okvir.

Postoji još nešto vezano uz rad s komponentama što trebamo naučiti — rad s više komponenata odjednom. Odabir više komponenata na formi može se napraviti vrlo jednostavno: držimo tipku Shift pritisnutom i klikamo po komponentama koje želimo odabrati. Drugi, ali mnogo jednostavniji način je da ih odaberemo pomoću okvira za odabiranje (lijevi klik na formu i bez otpuštanja tipke miša povlačimo okvir preko komponenata). Taj je način odabira prikazan na slici 9.9.

Nakon što otpustimo lijevu tipku miša sve se komponente unutar ovog iscrtanog okvira odabiru. Ovakav način odabira funkcionira na površini forme. Ako pokušamo odabrati komponente unutar komponente Panel1 dočekat će nas problem jer ćemo samo moći pomicati cijelu Panel1 komponentu zajedno sa svih pet gumba koji se nalaze unutar nje.

Želimo li unutar neke TPanel ili TGroupBox komponente odabrati više komponenata, pri odabiru moramo držati pritisnutu tipku Ctrl na tipkovnici.

9.1.5. TBevel komponenta

TBevel komponenta vrlo je jednostavna komponenta koja služi samo za dizajn aplikacija. TBevel komponenta nalazi se na Additional kartici komponenata (slika 9.10).

TBevel komponenta može se koristiti u dizajnu aplikacija umjesto TPanel komponente, ali je razlika između tih komponenata golema. TPanel komponenta pripada grupi komponenata koje mogu držati druge komponente i zbog toga zauzimaju dosta kompjuterskih resursa. TBevel komponenta potpuno pripada drugoj grupi komponenata — grafičkim komponentama. Grafičke komponente <pb n="204"/>ne mogu držati druge komponente i zbog toga zahtijevaju manje kompjuterskih resursa.

TBevel komponente se često koriste umjesto TPanel komponente na formama s vrlo velikim brojem komponenata, kako bismo uštedjeli malo računalnih resursa. Ovo treba obvezno zapamtiti: TBevel komponenta ne drži druge komponente, nego samo iscrtava okvir na formi. Pomicanjem TBevel komponente ne pomiču se i ostale komponente koje se nalaze unutar njezina okvira.

9.2. Liste podataka

Liste podataka se u Delphiju ne rješavaju pomoću hrpe pokazivača, nego pomoću gotovih komponenata. Komponenta TListBox omogućuje nam vrlo jednostavan rad s listom stringova.

Sad nam treba nova prazna aplikacija i jedna TListBox komponenta na formi. Kad dodamo TListBox komponentu, ona izgleda poprilično neugledno, samo jednostavan bijeli okvir, ali iza toga jednostavnog izgleda krije se vrlo kompleksna funkcionalnost.

TListBox komponenta ima vrlo velik broj svojstava i metoda, a za početak nam je najbitnije svojstvo Items. Ako pogledamo na Object Inspector, Items svojstvo definirano je kao TStrings. Dakle, Items svojstvo je poseban objekt koji čini listu. Items svojstvo je najzabavnije jer se u tom svojstvu nalaze zapisani svi podaci koje lista prikazuje na ekranu.

Podatke unutar Items svojstva možemo mijenjati tijekom dizajna aplikacije, ali, naravno, i tijekom izvršavanja aplikacije pomoću izvornog koda. Ako želimo promijeniti Items svojstvo tijekom dizajna, najprije ga moramo odabrati u Object Inspectoru (slika 9.11).

Objekti se unutar komponenata ne konfiguriraju pomoću Object Inspectora, nego pomoću specijaliziranih editora svojstava. Editor svojstva pokreće se klikom na gumb s tri točkice. Na taj gumb pokazuje strelica miša na slici 9.11. Nakon što kliknemo na njega, na ekranu će se pojaviti editor liste stringova (slika 9.12).

<pb n="205"/>

Unesite linije kao što je prikazano na slici 9.12. i pritisnite OK da se zapišu u Items svojstvo ListBox1 komponente.

Pristup podacima unutar Items svojstva izvodi se na isti način kao što se pristupa elementima polja:

ListBoxIme.Items[Indeks] :=

‘Podatak na <Indeks> mjestu liste’;

Indeks može biti bilo koji broj između 0 i ListBox.Items.Count - 1. U Count svojstvu Items svojstva zapisan je broj podataka koji se nalaze u listi.

TListBox komponenta posjeduje još jedno vrlo bitno svojstvo: ItemIndex. U ItemIndex svojstvu zapisan je indeks odabranog podatka u listi. Ako ni jedan podatak nije odabran, u ItemIndex svojstvu bit će zapisan –1.

Sad ćemo na formu dodati jedan gumb i njegovo svojstvo Caption postaviti na “Odabrani podatak”. Taj bi gumb na OnClick trebao prikazivati odabrani podatak liste pomoću ShowMessage procedure. Prije samoga prikazivanja najprije moramo provjeriti je li uopće neki podatak odabran.

Ako sve ispadne kako treba, klikom na gumb “Odabrani podatak” trebamo dobiti prikaz odabranog podatka:

<pb n="206"/>

Ovaj se kratki primjer može naći na CD-u u mapi “Primjeri\Poglavlje 9\Osnovna Lista\”.

9.2.1. Aplikacija za rastavljanje rečenica

Sljedeći primjer s listom stringova bit će nešto kompleksniji. U tom ćemo primjeru napraviti program koji će rastavljati cijelu rečenicu na zasebne riječi, a te ćemo riječi zapisivati u listu. Uz rastavljanje rečenice, vidjet ćemo i kako se podaci iz liste mogu spremiti na disk. Ovakav se program popularnije zove “parser” podataka.

Za taj će nam program trebati potpuno nova aplikacija. Na formi nam trebaju po jedna labela, gumb, lista i okvir unosa teksta. Sredite sučelje kao što je prikazano na slici 9.14.

Prvo što moramo napraviti je napisati metodu za dodavanje novog podatka u listu. Items svojstvo ima metodu Add pomoću koje se u listu može dodati novi string podatak:

ImeListe.Items.Add(‘Novi string’);

Sam algoritam za rastavljanje rečenice na riječi sastoji se od nekoliko koraka. U principu, riječ je o petlji unutar koje provjeravamo pozicije razmaknica unutar <pb n="207"/>rečenice i kopiramo tekst između dvaju razmaknica u listu.

Početak OnClick događaja gumba “Rastavi rečenicu” glasi ovako:

if Edit1.Text = ‘’ then

begin

ShowMessage(‘Nedostaje rečenica!’);

Edit1.SetFocus;

Exit;

end;

Izvorni kôd u prije navedenom primjeru provjerava ima li teksta u okviru i reagira pogreškom i prekidom izvršavanja procedure ako je okvir prazan. Sve je jasno, osim linije Edit1.SetFocus. Nakon prikazivanja poruke poziva se SetFocus metoda okvira za unos teksta.

9.2.2. Fokusiranje komponenata

SetFocus metoda postavlja fokus u neku komponentu. Fokus je posebno svojstvo nekih vrsta komponenata. Fokus je svojstvo komponenata koje mogu raditi s tipkovnicom. Iako na ekranu mogu biti prikazani desetci aplikacija sa doslovno stotinama prozora i objekata, samo jedan jedini objekt (komponenta prema Delphi terminologiji) može imati fokus. Kada komponenta ima fokus, to znači da se svi podaci s tipkovnice usmjeruju prema toj komponenti.

U našem slučaju, nakon što pomoću ShowMessage procedure prikažemo informaciju o pogrešnom korištenju aplikacije, SetFocus procedurom postavit ćemo fokus u Edit1 okvir unosa teksta kako bismo korisniku olakšali rad i objasnili mu kamo treba unijeti podatke.

Fokus ne mogu primiti sve komponente, a za početnike postoji jedan dosta jednostavan način provjere koje komponente mogu primiti fokus, a koje ne mogu. Za ovu provjeru trebat će nam Delphijeve datoteke pomoći.

TEdit komponenta sigurno može primiti fokus, kao što smo se uvjerili. Da bismo to provjerili, odabrat ćemo opciju Help -> Delphi Help. Na dijaloškom okviru Delphi pomoći odabrat ćemo karticu Index i u okvir za pretraživanje utipkati TEdit kako bismo dobili informacije o TEdit komponenti (slika 9.15).

<pb n="208"/>

Nakon što odaberemo dio Delphi pomoći vezan uz TEdit komponentu, na prozoru koji se pojavljuje odabrat ćemo opciju Hierarchy. Ta će nam opcija prikazati stablo komponenata od kojih je TEdit komponenta naslijedila svoju funkcionalnost. Ako unutar ove hijerarhije pronađemo TWinControl, to znači da naša komponenta može primiti fokus. Ako unutar hijerarhije pronađemo TGraphicControl, to znači da komponenta ne može primiti fokus.

9.2.3. Nastavak rastavljanja rečenica

Nakon što se osiguramo da je korisnik unio potrebne podatke u okvir unosa teksta, možemo krenuti s algoritmom. Evo kako izgleda cijeli algoritam:

<pb n="209"/>

Ako pokrenemo program i upišemo neku rečenicu, vidljivo je da algoritam funkcionira.

Sad bismo ovaj program mogli malo unaprijediti opcijama za prebacivanje odabranih riječi u drugu listu i snimanje podataka na disk. Za to će nam biti potrebna dva gumba čija ćemo Caption svojstva postaviti na “Prebaci” i “Snimi na disk” te još jedna lista u koju ćemo prebacivati podatke (slika 9.18).

<pb n="210"/>

Najprije ćemo napisati kôd za gumb “Prebaci”. Gumb “Prebaci” bi trebao prebacivati odabrani podatak iz liste ListBox1 u novu listu, ListBox2. Taj je kôd vrlo kratak i jednostavan i izgleda ovako:

Spomenuti kôd može poslužiti za neke vrlo jednostavne programe. Najveći problem tog koda je taj što dopušta udvostručavanje podataka; jednom označeni podatak može se prebaciti u tisućama kopija u drugu listu. Kako natjerati gumb “Prebaci” da u drugu listu prebacuje samo jednu jedinu kopiju odabranog stringa? Uvijek imamo na raspolaganju vlastoručnu metodu:

<pb n="211"/>

Naravno, zar postoji itko tko sumnja da Delphi nema već gotovo rješenje za ovako čestu akciju? Items svojstvo posjeduje funkciju IndexOf koja prima jedan string parametar i služi za provjeravanje postoji li već neki string unutar liste. Ako podatak postoji, IndexOf funkcija vraća indeks podatka u listi, a ako podatak ne postoji, IndexOf funkcija vraća vrijednost –1.

Dodavanje unikatnog podatka u listu korištenjem funkcije IndexOf izgleda ovako:

9.2.4. Odabir većega broja podataka u listi

U standardnim okolnostima TListBox komponenta nudi mogućnost odabira samo jednoga jedinog podatka. U većini slučajeva to je sasvim dovoljno, no katkada je ipak potrebno odabrati i raditi s većim brojem podataka.

Za odabiranje većega broja podataka moramo postaviti MultiSelect svojstvo liste na True. Nakon toga ćemo na formu postaviti još jedan gumb kojim ćemo se koristiti za prebacivanje svih odabranih podataka u drugu listu. Njegovo ćemo Caption svojstvo postaviti na “Prebaci odabrane”.

Kad radimo s većim brojem odabranih podataka u listi, ItemIndex svojstvo nije nam od velike koristi. Da bismo saznali koji su sve podaci odabrani, morat ćemo <pb n="212"/>napisati jednu for petlju i provjeriti svaki pojedini podatak u listi. Informacija o tome je li podatak odabran ili nije nalazi se u svojstvu Selected. Svojstvo Selected deklarirano je ovako:

property Selected[Index: Integer]: Boolean;

Petlja koja prebacuje sve odabrane podatke liste u drugu izgleda ovako:

9.2.5. Snimanje liste na disk

Zadnji dio koda koji moramo napisati vezan je uz snimanje podataka liste na disk. Cijeli posao snimanja podataka iz liste može se smatrati vrlo teškim jer je riječ o Windows operativnom sustavu (kompleksniji OS od DOS-a), varijabilnoj listi stringova (pokazivači) itd. Jesam li uspio nekoga prevariti? Ipak je ovdje riječ o Delphiju, a Items svojstvo ima jednu vrlo zanimljivu proceduru za snimanje svojih podataka na disk:

ImeListe.Items.SaveToFile(ImeDatoteke: string);

Iako postoje načini za odabiranje imena datoteke za snimanje, trenutačno ćemo listu snimati na disk C pod imenom “Podaci.txt”. Cijeli kôd za snimanje liste na disk je vjerojatno najteža stvar koju neki Delphi programer može napisati.

Ovaj se program može naći na CD-u u mapi “Primjeri\Poglavlje 9\Rijec”.

9.3. Sažetak

Grupiranje komponenata bitan je dio većine aplikacija. Najveća prednost grupiranja komponenata vidljiva je kod velikih aplikacija s velikim brojem komponenata, pogotovo kada nekoliko komponenata moramo pomaknuti na drugo mjesto. S obzirom na to da se sve komponente unutar grupe pomiču zajedno s komponentom na kojoj se nalaze, grupiranje će smanjiti vrijeme potrošeno na pomicanje i ostale <pb n="213"/>dizajnerske zahvate.

TListBox komponenta jedna je od komponenata koja se vjerojatno koristi u gotovo svim aplikacijama. U ovom poglavlju nismo se ni približno dotakli svih mogućnosti liste. Nešto ipak mora ostati za osobno istraživanje.

Pitanja i zadaci

Pitanje 1: Koje dvije komponente mogu sadržavati druge komponente, a koristimo ih za grupiranje komponenata?

Pitanje 2: Kojim prefiksom započinju konstante boja u Delphiju?

Pitanje 3: Kako se zove boja koja se koristi u cijelom operativnom sustavu za bojenje površine komponenata?

Pitanje 4: Kako se zove svojstvo u kojemu je zapisana boja forme?

Pitanje 5: Što će se dogoditi ako unutar procedure koja pripada formi Form2 napišemo:

Self.Color := clRed;

Pitanje 6: Ako želimo podesiti ponašanje komponente prigodom promjene veličine forme, kojim ćemo se svojstvom morati koristiti?

Pitanje 7: Ako želimo natjerati da se tijekom promjene veličine forme mijenjaju i visina i širina, koje vrijednosti moramo odabrati u Anchors svojstvu?

Pitanje 8: U koja su dva svojstva zapisane širina i visina klijentskog dijela forme?

Pitanje 9: Ako na TPanel komponentu dodamo gumb, hoće li TPanel komponenta biti Owner ili Parent gumba?

Pitanje 10: U kojem su svojstvu TListBox komponente zapisani tekstualni podaci koje vidimo na ekranu?

Pitanje 11: Pomoću kojeg alata možemo tijekom dizajniranja aplikacije dodati podatke u listu?

Pitanje 12: U kojem su svojstvu zapisane informacije o odabranim podacima liste?

Zadatak 1: Ministarstvu za usavršavanje brojenja na prste do 10 potreban je program koji će na klik gumba u jednu listu upisati brojeve od 1 do 10. Uz tu opciju, te vitalne podatke program mora moći spremiti na disk u datoteku “C:\TopSecret.txt”.

Zadatak 2: Hrvatski institut za istraživanje neparnih brojeva (HIINB) treba prerađenu verziju programa iz zadatka 1. Ta verzija programa mora imati gumb koji će sve neparne brojeve prebaciti u drugu listu i spremiti te podatke na disk u datoteku “C:\Neparni.txt”.

<pb n="214"/>

<pb n="215"/>

10. Izbornici i alatne trake

10.1. Glavni izbornik aplikacije 216

10.1.1. Dizajniranje izbornika 216

10.2. Standardni dijaloški okviri 218

10.2.2. TFontDialog komponenta 222

10.2.3. TOpenDialog i TSaveDialog komponente 223

10.3. TImageList komponenta 225

10.4. Alatne trake – TToolbar komponenta 227

10.5. TXPManifest komponenta 228

10.6. Editor teksta – DelphiPad aplikacija 229

10.6.1. Dizajn izbornika 230

10.6.2. Postavke komponenata 230

10.6.3. Osnovni dijelovi izvornog koda 231

10.6.4. Izvorni kôd File izbornika 234

10.6.5. Otvaranje postojećeg dokumenta 234

10.6.6. Snimanje dokumenta na disk 236

10.6.7. Zatvaranje glavne forme editora 238

10.6.8. Nadopuna koda za stvaranje novog dokumenta 242

10.6.9. Izvorni kôd Edit izbornika 242

10.6.10. Podešavanje alatne trake 246

10.6.11. Izvorni kôd Format izbornika 248

10.6.12. Snimanje postavki korisničkog sučelja 249

10.6.13. Dodavanje kratke pomoći korisnicima 252

10.7. Sažetak 253

<pb n="216"/>

10. Izbornici i alatne trake

Ovo je poglavlje u kojem ćemo se koristiti najbitnijim elementima Windows aplikacija – izbornicima. Uz glavni i pomoćne izbornike, vidjet ćemo i kako stvoriti alatne trake. Stvaranje izbornika i alatnih traka bit će popraćeno informacijama o standardnim dijaloškim okvirima koji postoje u Windows operativnom sustavu i listama slika koje se koriste u izbornicima i na alatnim trakama.

10.1. Glavni izbornik aplikacije

Većina programa koje smo do sada stvarali bila je dosta jednostavne prirode, bez velikog broja opcija. Takvi se programi ne mogu često pronaći u svijetu, osim u sferi jednostavnih primjera. Svaka aplikacija koja nudi veći broj usluga korisnicima predstavlja te opcije na najlogičniji mogući način — pomoću glavnog izbornika.

Glavni je izbornik obično traka s grupom opcija koja se nalazi odmah ispod naslovne trake prozora. Samo se u rijetkim aplikacijama glavni izbornik nalazi na nekoj alatnoj traci.

Na samoj površini glavnog izbornika nalaze se samo grupe opcija. Da bi dobio potpuni uvid u opcije koje se nalaze u nekoj grupi, korisnik mora kliknuti na grupu. Na slici 10.1. može se vidjeti vrlo jednostavan izbornik s najčešće korištenim grupama opcija. Najčešće korištene grupe opcija su File, Edit, View, Window i Help.

10.1.1. Dizajniranje izbornika

Delphi posjeduje vrlo jednostavan alat za stvaranje glavnog izbornika — dizajner izbornika. Dizajner izbornika je alat kojim stvaramo glavni, ali i dodatne izbornike (koji se pojavljuju na prozoru nakon desnog klika mišem).

Glavni izbornik aplikacije stvara se pomoću TMainMenu komponente koja se nalazi odmah na početku Standard kartice. Kad na formu dodamo TMainMenu komponentu, dočekat će nas malo iznenađenje. Glavni izbornik aplikacije predstavljen je malom ikonom!?

<pb n="217"/>

Delphi posjeduje razne vrste komponenata — vizualne komponente, pseudo–vizualne komponente i nevizualne komponente. Do sada smo se koristili samo vizualnim komponentama poput gumba i okvira unosa teksta. Takve se komponente još nazivaju i kontrolama. TMainMenu komponenta pripada pseudovizualnim komponentama jer se tijekom dizajna aplikacije prikazuje u ikonici (ali i vizualno), a tijekom izvršavanja aplikacije glavni je izbornik potpuno vidljiv dio prozora.

Za stvaranje izbornika trebat će nam dizajner izbornika. Njega možemo prikazati pomoću Items svojstva TMainMenu komponente prikazane u Object Inspectoru ili možemo napraviti dvostruki klik na ikonu TMainMenu komponente na formi. Nakon aktiviranja, dizajner izbornika prikazuje se kao poseban prozor.

Čim se pojavi na ekranu, dizajner izbornika nudi nam mogućnost stvaranja opcija na izborniku. Svaka opcija na izborniku poseban je objekt tipa TMenuItem. TMenuItem svojim je osnovnim ponašanjem vrlo sličan TButton komponenti, no, uz neka podešenja, svaki TMenuItem objekt može se koristiti i kao TCheckBox komponenta ili kao TRadioButton komponenta.

<pb n="218"/>

Pri stvaranju nove opcije na izborniku najprije se postavlja vrijednost Caption svojstva, odnosno naziv opcije koja će se prikazivati na izborniku. S obzirom na to da se trenutačno nalazimo na samom početku (ili vrhu) izbornika, potrebno je unijeti naziv grupe opcija. Prva grupa opcija koju ćemo stvoriti ima naziv “Datoteka”. Nakon što u Caption unesemo “Datoteka” i potvrdimo tipkom Enter, Delphi će odmah na glavnoj formi prikazati promjene koje smo napravili na izborniku.

Usto, Delphi automatski postavlja Name svojstvo nove opcije koristeći se našim tekstom koji smo unijeli u Caption svojstvo pa će se ovaj objekt zvati “Datoteka1”. Ovakvi nazivi objekata nisu nimalo poželjni jer mogu izazvati pomutnju u malo većim aplikacijama. Imena komponenata pogotovo je bitno promijeniti ako su ti objekti dio izbornika. Jedno od mogućih rješenja za imenovanje je u svako ime izborničke opcije postaviti prefiks “mnu”. Još jedno od rješenja, kojim ću se koristiti u knjizi je dodatak “Menu” za ime cijele grupe opcija, a dodatak “Item” na svim ostalim opcijama na izborniku.

Nakon što unesemo naziv prve grupe opcija, Delphi izbornik omogućuje dodavanje nove grupe opcija (okvir odmah desno od opcije “Datoteka” na slici 10.4) i omogućuje dodavanje opcije unutar trenutačne grupe (okvir odmah ispod opcije “Datoteka” na slici 10.4).

Na izborniku, unutar grupe “Datoteka” trenutačno je potrebna samo opcija “Izlaz”. Nakon što dodamo i opciju Izlaz, bit će potrebno napisati kôd za tu opciju. S obzirom na to da je svaka opcija na izborniku poseban objekt, odabirom opcije na izborniku njezina će se svojstva zapisati u Object Inspector. Uz Object Inspector, potreban kostur procedure možemo stvoriti i dvostrukim klikom na opciju unutar dizajnera izbornika.

10.2. Standardni dijaloški okviri

Operativni sustav Windows posjeduje nekoliko dijaloških okvira koji pomažu programerima i korisnicima programa. U standardne se dijaloške okvire ubrajaju:

1. dijaloški okvir za otvaranje datoteka (TOpenDialog komponenta),

2. dijaloški okvir za snimanje datoteka (TSaveDialog komponenta),

3. dijaloški okvir za odabir fonta (TFontDialog komponenta),

<pb n="219"/>

4. dijaloški okvir za odabir boje (TColorDialog komponenta),

5. dijaloški okvir za pretraživanje (TFindDialog komponenta),

6. dijaloški okvir za zamjenu teksta (TReplaceDialog komponenta),

7. dijaloški okvir za ispis (TPrintDialog komponenta).

U Delphiju možemo koristiti još dva standardna dijaloška okvira vezana uz slike:

1. dijaloški okvir za otvaranje slika (TOpenPictureDialog komponenta),

2. dijaloški okvir za snimanje slika (TSavePictureDialog komponenta).

Sve navedene komponente nalaze se na Dialogs kartici palete komponenata. Usto, svi su dijaloški okviri pseudovizualne komponente koje u punome svjetlu vidimo samo tijekom izvršavanja aplikacije.

Svi se dijaloški okviri ponašaju na istovjetan način, ali imaju još neke zajedničke točke. Svi dijaloški okviri od korisnika traže daljnje upute za rad. Zbog toga svi dijaloški okviri moraju korisniku ponuditi dvije opcije — nastavak rada ili prekid daljnjeg rada. Te su dvije opcije najčešće predstavljene gumbima OK i Cancel.

Sav rad sa standardnim dijaloškim okvirima počinje pozivom funkcije Execute koja prikazuje dijaloški okvir i omogućuje rad s njim. Dijaloške okvire započet ćemo proučavati počevši od TColorDialog komponente.

10.2.1. TColorDialog komponenta

TColorDialog komponenta je standardni Windows dijaloški okvir kojim se koristimo za odabir boje (slika 10.5).

TColorDialog komponenta u većini slučajeva ima samo jedno svojstvo koje nam je potrebno — svojstvo Color u kojem je zapisana odabrana boja.

Za testiranje ponašanja svih dijaloških okvira trebat će nam posebna grupa na glavnom izborniku: “Dijaloški okviri”. Unutar grupe “Dijaloški okviri” za početak će nam trebati samo opcija “Odabir boje” (slika 10.6) i jedna <pb n="220"/>TColorDialog komponenta na formi.

Nadam se da tri točke koje su dodane na kraj opcije “Odabir boje” jako bodu u oči jer su vrlo bitne. Bilo koja opcija na izborniku koja prikazuje neki dijaloški okvir mora imati te tri točkice. To je dogovoreni način označivanja opcija koje prikazuju dijaloške okvire i vrlo je bitno pridržavati se toga.

Opcija “Odabir boje” mora omogućiti korisniku odabir pozadinske boje glavne forme. Da bismo to uspjeli napraviti, morat ćemo pozvati funkciju Execute za prikaz dijaloškog okvira.

procedure TMainForm.BojaItemClick(Sender: TObject);

begin

ColorDialog1.Execute;

end;

Rezultat ove procedure sada će biti samo prikazivanje dijaloškog okvira za odabir boje, ali ništa se nakon toga neće dogoditi. Nakon što se dijaloški okvir prikaže na ekranu i korisnik odabere neku boju, ta će se boja zapisati u Color svojstvo dijaloškog okvira.

procedure TMainForm.BojaItemClick(Sender: TObject);

begin

ColorDialog1.Execute;

Color := ColorDialog1.Color;

end;

Ako proceduru napišemo na način upravo prikazan, ona će uvijek promijeniti boju forme, neovisno o tome je li korisnik odabrao gumb “OK” ili “Cancel”. Izvorni kôd za mijenjanje boje trebao bi se izvršiti samo ako korisnik odabere gumb “OK”.

Informaciju o tome koji je gumb odabran daje nam funkcija Execute. Povratni tip funkcije Execute je Boolean: ako je korisnik odabrao “OK”, funkcija Execute vraća True, a ako je korisnik odabrao “Cancel” ili zatvorio dijaloški okvir na bilo koji drugi način, funkcija Execute vraća vrijednost False.

Uz provjeru povratne vrijednosti funkcije Execute, prije samog poziva obično se u dijaloški okvir zapisuje već postojeća boja objekta koji mijenjamo. Time se izbjegavaju moguće pogreške u brzopletih korisnika.

<pb n="221"/>

Cijeli kôd za promjenu boje forme trebao bi izgledati ovako:

Vidljivo je da je korištenje standardnih dijaloških okvira poprilično jednostavno, ali da bismo ih potpuno svladali, ipak postoji još nekoliko svojstava i metoda koje moramo upoznati.

Dijaloški okvir za odabir boja prikazuje se na dva različita načina. Osnovni prikaz tog dijaloškog okvira vrlo je malena paleta prije određenih boja. Taj je izgled vidljiv na slici 10.5. No, uz odabir prije određenih boja, on nam omogućuje i odabir bilo koje nijanse boja, što je vidljivo ako kliknemo na gumb “Define Custom Colors >>”. Time će se prikazati dodatni dio dijaloškog okvira (slika 10.7).

Ako želimo, dodatne (custom) boje možemo prikazivati uvijek, ali ćemo za to morati mijenjati Options svojstvo dijaloškog okvira. Unutar Options svojstva na Object Inspectoru potrebno je uključiti opciju cdFullOpen (slika 10.8).

<pb n="222"/>

10.2.2. TFontDialog komponenta

TFontDialog komponenta prikazuje standardni Windows dijaloški okvir za odabir fonta (slika 10.9). Najbitnije svojstvo koje TFontDialog komponenta posjeduje je svojstvo Font. Tijekom primjene dijaloškog okvira za odabir fonta, u Font svojstvo će se zapisivati sve postavke koje korisnik odabere.

TFontDialog ni po čemu nije komplicirana komponenta, a trenutačno će vrlo dobro poslužiti za prikazivanje načina na koji se može promijeniti objektno svojstvo neke komponente.

Za mijenjanje fonta najprije nam treba dodatna opcija “Odabir fonta...” unutar grupe “Dijaloški okviri”. Nakon dodavanja opcije na izborniku, na formi će nam trebati obvezno jedna TFontDialog komponenta te jedna TLabel komponenta na kojoj ćemo testirati promjenu fonta.

Izvorni kôd za mijenjanje fonta može se napisati na dva različita načina. Prvi i jednostavniji izgleda ovako:

U ovom primjeru za promjenu fonta koristi se najosnovniji operator pridjeljivanja. Na taj se način promjena izvodi tako da Font svojstvo TLabel komponente pokazuje na Font svojstvo TFontDialog komponente. Time se nije dogodilo <pb n="223"/>potpuno kopiranje novih svojstava, nego samo postavljanje pokazivača na novi objekt.

Iako je ova metoda rada potpuno u redu, katkada je ipak potrebno napraviti potpuno kopiranje svojstava (kada ne želimo mnogo petljati s time tko kamo pokazuje i tko što koristi). Za potpuno kopiranje svih svojstava jednog objekta u drugi primjenjuje se procedura Assign. Ovo nije procedura Assign koja se u Pascalu koristi za rad s datotekama. Procedura Assign za rad s datotekama u Delphiju se zove AssignFile.

Proceduru Assign koja se koristi za kopiranje svojstava objekta posjeduju apsolutno sve komponente s kojima radimo u Delphiju. Pri radu s Assign procedurom moramo pripaziti da su oba objekta s kojima radimo istog tipa. Općenito, sintaksa korištenja Assign procedure izgleda ovako:

CiljniObjekt.Assign(IzvorniObjekt)

Nakon što se izvrši navedena linija koda, CiljniObjekt će poprimiti sva svojstva IzvornogObjekta.

10.2.3. TOpenDialog i TSaveDialog komponente

TOpenDialog komponenta se koristi za prikaz standardnoga dijaloškog okvira za odabir datoteke. Taj dijaloški okvir neće sam otvoriti datoteku ili prikazati sadržaj datoteke tamo gdje bi to programer želio, ali na vrlo jednostavan način može omogućiti korisniku odabir neke datoteke koja se nalazi na lokalnom ili mrežnom disku.

TOpenDialog i TSaveDialog komponente odradit ćemo u jednom dahu jer se razlikuju u vrlo sitnim detaljima (ali to su detalji koji su vidljivi samo pri izvršavanju aplikacije, i to kad zaškripi).

Obje komponente imaju poveći broj dosta bitnih svojstava. Prvo od tih svojstava je Filter. Filter svojstvo posebno je formatiran string u kojemu su popisane sve ekstenzije datoteka koje će aplikacija moći otvoriti (u slučaju TSaveDialog komponente sve ekstenzije pod kojima aplikacija može snimiti podatke). Filter svojstvo možemo postaviti vlastoručno ili primjenom editora filtra.

<pb n="224"/>

Editor filtra prikazuje se na ekranu pomoću Object Inspectora i svojstva Filter (slika 10.10).

U Filter Name stupac uvijek se upisuje jasan i razumljiv naziv tipa datoteka kao što je “Tekstualne datoteke”. Uz naziv, obično se u zagradi navodi ekstenzija kako bi krajnji korisnik znao o kojem je tipu datoteka riječ. Nakon što se definira naziv tipa datoteka, u Filter stupac zapisuje se sama ekstenzija. Potrebno je malo pažnje pri unosu same ekstenzije jer će se ta ekstenzija koristiti za prikazivanje datoteka u samom dijaloškom okviru. Ako pogrešno unesemo ekstenziju, dijaloški okvir neće moći prikazati potrebne datoteke.

Drugo vrlo bitno svojstvo TOpenDialog i TSaveDialog komponenata je svojstvo FileName. U FileName svojstvo TOpenDialog komponente zapisuje se ime datoteke koju je korisnik odabrao i koju želi otvoriti (slika 10.11). U FileName svojstvo TSaveDialog komponente zapisat će se ime datoteke u koje korisnik želi spremiti podatke.

Izvorni kod koji je potrebno napisati da bi se odabrala neka datoteka pomoću TOpenDialog komponente vrlo je jednostavan.

<pb n="225"/>

Ovaj se primjer može naći na CD-u u mapi “Primjeri\Poglavlje 10\Dijalozi”.

10.3. TImageList komponenta

TImageList komponenta je komponenta koja se koristi kao spremnik za male slike (glyphove) koji se mogu koristiti na izbornicima ili gumbima alatnih traka. TImageList komponenta potpuno je nevizualna komponenta i nalazi se na Win32 kartici palete komponenata.

TImageList komponentom koristimo se u golemoj većini slučajeva samo tijekom dizajna, i to samo dok joj dodajemo slike. Nakon što u TImageList komponentu dodamo sve potrebne slike, sav daljnji rad obavljat ćemo na komponentama poput izbornika i alatnih traka koje se koriste tom listom slika.

Slike dodajemo u TImageList komponentu pomoću editora TImageList komponente, koji prikazujemo dvostrukim klikom na komponentu (slika 10.12).

Na cijelom editoru najčešće neće biti potrebno koristiti ništa, osim gumba Add za dodavanje novih slika u listu. Sve je jednostavno, osim slika koje dodajemo. Slike koje dodajemo u listu moraju biti određenog formata – prikladnog za korištenje na izbornicima i alatnim trakama. To su obično slike veličine 16x16 ili 24x24 piksela.

Uz Delphi dolazi i skup (poprilično starih) slika koje se mogu koristiti s listom slika, a nalaze se u mapi “C:\Program Files\Common Files\Borland Shared\Images\Buttons”. Jedini problemčić je to što pri korištenju tih starih slika Delphi pita želimo li da nam razlomi sliku na dva dijela. Odgovor je pozitivan, jer te slike posjeduju dva stanja: normalnu sliku i posivljenu sliku koja se koristi kada je Enabled svojstvo komponente postavljeno na False. U današnje vrijeme to nije potrebno jer komponente same iscrtavaju posivljeno stanje slike kada je to potrebno.

Slike koje se koriste na alatnim trakama ili izbornicima najveći su problem programerima diljem svijeta jer vrlo velika većina programera ili nema smisla za crtanje ili im to vrijeme ne dopušta, a ja pripadam prvoj grupi :). Da bih riješio jedan dio problema, na CD-u sam priložio oko 300 glyphova u mapi Glyphs. Svi su glyphovi skinuti s Interneta s raznih free i/ili programerskih stranica i može ih se <pb n="226"/>bez ikakvih ustručavanja koristiti za stvaranje aplikacija.

Slika 10.13. prikazuje kako TImageList komponenta prikazuje dodane glyphove. Svi glyphovi prikazani na slici 10.13. nalaze se na CD-u.

Nakon što dodamo slike u TImageList komponentu, najveći je dio posla završen. Sada na formu treba dodati glavni izbornik (ili drugu komponentu koja koristi listu slika). Glavni izbornik (TMainMenu komponenta) posjeduje svojstvo Images pomoću kojeg spajamo glavni izbornik i stvorenu listu slika te glavnom izborniku omogućujemo korištenje slikama iz liste slika.

No, još nije sve gotovo. Sada trebamo dizajnirati izbornik i nekako odlučiti na kojoj će se opciji prikazivati koja slika. Za ovaj nam posao ponovno treba dizajner izbornika. Ali, ovaj put nećemo vlastoručno dodavati opcije koje nam trebaju na izborniku — iskoristit ćemo neku od prije stvorenih grupa opcija.

Da bismo pristupili prije stvorenim grupama opcija, na dizajneru izbornika napravit ćemo desni klik i s izbornika koji se pojavljuje odabrati opciju Insert From Template. U Insert Template dijaloškom okviru trebat će nam File Menu. Kao što je vidljivo, u dvije sekunde možemo napraviti cijeli glavni izbornik (slika 10.14).

<pb n="227"/>

Delphijev dizajner izbornika omogućuje i snimanje gotovih izbornika. Nakon što napravimo neki izbornik ili samo jednu grupu opcija, možemo je vrlo jednostavno spremiti za daljnje korištenje: desni klik i odabir opcije Save As Template.

Sada već imamo opcije koje možemo podesiti. Svaka opcija na izborniku posjeduje svojstvo ImageIndex pomoću kojeg određujemo koja će se slika iz TImageList komponente prikazivati. Na slici 10.13. vidljivo je da svaka slika unutar TImageList komponente ima svoj jedinstveni indeks (brojevi ispod slika).

Osnovna vrijednost zapisana u ImageIndex svojstvu je –1. Broj –1 koristi se globalno za označivanje da “nečeg” nema ili da “nešto nije u redu”. Ako smo prije povezali glavni izbornik i listu slika, odabirom svojstva ImageIndex trebali bismo vidjeti sve slike koje se nalaze u listi. Sve što ostaje je odabir neke od slika i onda je stvar riješena. Delphi će na glavnom izborniku odmah prikazati odabranu sliku (slika 10.15).

10.4. Alatne trake – TToolbar komponenta

Već dugo su alatne trake osnovni dio svih aplikacija. Alatne trake služe za prikaz opcija koje se nalaze na izbornicima. Kvaliteta alatnih traka je u tome što su opcije na alatnim trakama uvijek vidljive, za razliku od izbornika koji zahtijevaju nešto više posla u pronalaženju opcija.

Alatne trake služe za prikaz najčešće korištenih opcija koje se nalaze na glavnom izborniku. Najbitniji dio prošle rečenice jest: opcije na glavnom izborniku. Alatne trake ne smiju sadržavati nijednu opciju koju korisnik ne može pronaći na glavnom izborniku. Alatne se trake uvijek koriste samo kao kratica prema nekoj od opcija na glavnom izborniku.

Nakon što na formu dodamo TToolbar komponentu (nalazi se pri kraju Win32 <pb n="228"/>kartice) ona se pojavljuje na vrhu forme. Rad s TToolbar komponentom vrlo je jednostavan. Sastoji se od dodavanja gumba i separatora (separatori su praznine na alatnim trakama pomoću kojih možemo dobiti dojam grupa gumba).

Gumbi i separatori dodaju se desnim klikom na alatnu traku i odabirom opcija New Button ili New Separator. Osnovni stil gumba je trodimenzionalan izgled kakav je bio popularan u vrijeme Windowsa 95 ili 98, no danas se najčešće u aplikacijama mogu vidjeti ravni (flat) gumbi. TToolbar komponenta omogućuje postavljanje ravnog izgleda gumba, a za taj izgled svojstvo Flat moramo postaviti na True.

Gumbi na alatnim trakama mogu prikazivati tekst (Caption) i/ili sliku kojom se objašnjava funkcioniranje gumba. Prikazivanje teksta na gumbima vrlo je jednostavno: svojstvo ShowCaptions TToolbar komponente treba postaviti na True.

Prikazivanje slika na gumbima zahtijeva povezivanje alatne trake s nekom listom slika (TImageList komponenta). Kao i kod TMainMenu komponente, lista slika odabire se u Images svojstvu.

Svi gumbi na alatnim trakama poprimaju automatsku veličinu koju je moguće promijeniti pomoću opcija ButtonHeight i ButtonWidth. Uz promjenu veličine gumba, koja nije uvijek potrebna, AutoSize svojstvo alatne trake je dobro postaviti na True. Time će nestati višak praznoga prostora koji se trenutačno može vidjeti ispod gumba.

Vizualno dosta dojmljiv dio alatne trake u nekim situacijama može biti okvir oko cijele alatne trake. Okvir oko alatne trake definira se u EdgeBorders svojstvu.

Nakon što postavimo tih nekoliko opcija, dobit ćemo kvalitetnu i dobro dizajniranu alatnu traku kakvu smo navikli vidjeti u najbolje dizajniranim aplikacijama.

<pb n="229"/>

10.5. TXPManifest komponenta

Alatna traka kakvu smo uspjeli napraviti izgleda kao alatna traka koju možemo vidjeti u verzijama Windows operativnog sustava prije verzije XP. Windows XP iscrtava prozore i elemente prozora koristeći se posebnim temama (poznatijima pod imenom Visual Styles) pomoću kojih se izgled Windowsa može potpuno promijeniti.

Delphi 7 aplikacije također mogu prikazivati komponente isto kao što ih prikazuje ostatak Windows XP operativnog sustava. Ako želimo takav prikaz, formi je dovoljno dodati komponentu TXPManifest s kraja Win32 kartice i sve će komponente tijekom izvršavanja aplikacije imati Windows XP izgled.

10.6. Editor teksta – DelphiPad aplikacija

Sada slijedi zadnji dio ovog poglavlja, u kojem ćemo stvarati editor teksta. <pb n="230"/>Editor teksta vrlo je zahvalna aplikacija jer je vrlo jednostavan za korištenje. S programerskog aspekta, editor teksta je razmjerno jednostavno napraviti, a tijekom rada programer se upoznaje sa svim koracima potrebnima za stvaranje potpuno funkcionalne i profesionalne aplikacije.

Slika 10.19. prikazuje potpuno završen DelphiPad projekt koji ćemo morati zajedno napraviti u idućih desetak stranica.

10.6.1. Dizajn izbornika

Dizajn glavnog izbornika za editor teksta pravi je pothvat jer je izbornik povelik. Upravo zbog toga na CD-u u mapi “Primjeri\Poglavlje 10\DelphiPad — Kostur” postoji osnovni kostur editora teksta koji se može iskoristiti za daljnji rad. Izbornik koji se nalazi u kosturu DelphiPad editora teksta napravljen je primjenom nekih opcija koje još nisu viđene u ovoj knjizi.

Za stvaranje ovog izbornika korišteni su hotkeyevi, tipkovničke kratice (shortcut) i separatori. Definiranjem hotkeya omogućujemo korisniku pristup opcijama na izborniku pomoću tipkovnice. Hotkey slovo je jedino podcrtano slovo unutar naziva neke opcije, kao slovo F u izborniku File. Hotkey tipka koristi se u kombinaciji s tipkom Alt — u DelphiPad aplikaciji kombinacijom Alt + F prikazuje se izbornik File.

Hotkey kratica postavlja se pomoću dizajnera izbornika tako da se u Caption svojstvo ispred slova koje želimo koristiti kao hotkey postavi znak & (ampersand, kao u Tom & Jerry): &File. Želimo li dodati opciju na izbornik koja će na ekranu prikazivati “Tom & Jerry”, u Caption svojstvo ćemo morati napisati dva znaka &: Tom && Jerry.

Za primjer opcije koja ima definirane hotkey i shortcut kratice dovoljno je pogledati opciju New na izborniku File. Na desnoj strani opcije New nalazi se tipkovnička kratica (shortcut) Ctrl+N. Tipkovnička kratica postavlja se u dizajneru izbornika pomoću Shortcut svojstva.

Separatori su linije koje se mogu vidjeti na izbornicima na slici 10.20. Separatori su vrlo korisni ako ih se koristi umjereno jer pomoću njih možemo vizualno odvojiti različite grupe opcija. Svaki je separator posebna opcija na izborniku, samo što se separatori nikada ne koriste tijekom rada aplikacije. Jedina im je svrha vizualno odvajanje različitih grupa opcija. Način stvaranja separatora vrlo je jednostavan: u Caption svojstvo upisuje se samo minus (–). Delphi automatski preuzima na sebe odgovornost oko imenovanja separatora pa će svi separatori biti imenovani velikim slovom N i brojem.

<pb n="231"/>

10.6.2. Postavke komponenata

Na početku stvaranja aplikacije potrebno je dodati neophodne komponente. Najprije ćemo na formu dodati alatnu traku. Alatnu ćemo traku za sada ostaviti praznu. Odmah nakon alatne trake na formi nam treba jedna TMemo komponenta (TMemo komponenta nalazi se na Standard kartici).

TMemo komponenta veliki je okvir unosa teksta koji nam omogućuje prikazivanje i rad s većim brojem linija teksta. Radi lakšeg snalaženja u izvornom kodu, ime Memo1 komponente promijenit ćemo u Editor i postavit ćemo Align svojstvo na alClient, čime će se Editor komponenta razvući preko cijele površine forme.

S obzirom na to da je TMemo komponenta namijenjena radu s velikim količinama teksta, razumljivo je da se neki dokumenti neće moći prikazati odjednom na ekranu. Zbog toga, TMemo komponenta ima vertikalnu i horizontalnu kliznu traku koje možemo iskoristiti po potrebi za prikaz svih dijelova velikih dokumenata. Klizne se trake podešavaju u svojstvu Scrollbars. Početna vrijednost u Scrollbars svojstvu je ssNone — obje su klizne trake skrivene. Ovo nije najbolja postavka pa ćemo je uskoro morati promijeniti.

Postavke kliznih traka usko su vezane uz još jedno svojstvo TMemo komponente — svojstvo WordWrap. Svojstvo WordWrap je Boolean tipa i pomoću toga svojstva definiramo hoće li se tekst unutar TMemo komponente automatski prelamati ili neće. Ako se tekst automatski prelama u sljedeću liniju, onda nam horizontalna klizna traka uopće nije potrebna. Ako se tekst ne prelama automatski u novu liniju bit će nam potrebna i vertikalna i horizontalna klizna traka.

S obzirom na to da je prelamanje automatski postavljeno na True, vrijednost ScrollBars svojstva morat ćemo postaviti na ssVertical.

Zadnja stvar koju trenutačno moramo napraviti je izbrisati sve podatke iz Lines svojstva TMemo komponente jer uopće nisu potrebni.

10.6.3. Osnovni dijelovi izvornog koda

Za početak moramo definirati nekoliko konstanti i napisati malo koda kojeg ćemo iskoristiti na više mjesta u aplikaciji. Za editor teksta najbitnija je jedna string varijabla u koju će se zapisivati ime dokumenta koji je trenutačno otvoren u editoru. Naša će se varijabla zvati FImeDokumenta i, s obzirom na to da ona mora uvijek biti vidljiva iz bilo koje procedure, moramo je deklarirati na mjestu vidljivom iz cijele forme. Ako varijablu želimo koristiti iz bilo koje procedure na <pb n="232"/>formi, takvu ćemo varijablu deklarirati unutar private ili public dijela forme. Trenutačno će sasvim dobro poslužiti deklaracija unutar private dijela glavne forme.

Uz varijablu za spremanje imena otvorenog dokumenta, trebat će nam nekoliko konstanti tijekom rada. Te konstante moramo ponovno definirati na nekom javno vidljivom dijelu, a najbolje mjesto za konstante nalazi se ispod var dijela forme, kao što je vidljivo u primjeru 10.6. Popis konstanti prikazan u primjeru 10.6. potrebno je kopirati u izvorni kôd jer će nam trebati na nekoliko mjesta u izvornom kodu.

<pb n="233"/>

Tijekom rada aplikacija će editirati postojeće dokumente s diska, ali i potpuno nove dokumente koji nisu snimljeni na disk i koji još nemaju svoje ime. Svaka imalo dobro napravljena aplikacija na naslovnoj traci ispisuje svoje ime, ali i ime dokumenta koji je trenutačno otvoren. Ovu funkcionalnost razdvojit ćemo u jednu funkciju i jednu proceduru.

Funkcija će biti odgovorna za definiranje imena dokumenta koji je trenutačno prikazan u editoru. Svaka funkcija ili procedura koju pišemo mora se obvezno nalaziti u implementation dijelu forme.

Funkcija DajIme, prikazana u primjeru 10.7, odgovorna je za definiranje imena koje će biti prikazano na naslovnoj traci u situaciji kada dokument postoji i kada dokument ne postoji. Za provjeru postojanja dokumenta dovoljno je provjeriti varijablu FImeDokumenta. Ako je FImeDokumenta prazan string, onda dokument ne postoji. U suprotnom, dokument postoji. Ali, ako je FImeDokumenta prazan string, radi boljeg dizajna, funkcija DajIme će vratiti tekst “Untitled”.

Ako je dokument otvoren, u varijabli FImeDokumenta bit će prikazano cijelo ime dokumenta, zajedno s cijelom putanjom. S obzirom na to da su putanje često velike i ne stanu cijele na naslovnu traku, aplikacije obično prikazuju samo ime dokumenta. Za dobivanje imena dokumenta iz stringa koji sadrži cijelu putanju datoteke koristi se funkcija ExtractFileName.

Funkcija ExtractFileName nalazi se u SysUtils unitu, jedini parametar kojeg prima je string koji sadrži cjelokupnu putanju neke datoteke i kao rezultat svog izvršavanja vraća ime i ekstenziju datoteke.

Uz sve funkcije i procedure koje se napišu unutar implementation dijela forme ide jedna napomena: njihova se deklaracija mora navesti u private ili public dijelu forme. Pri pisanju deklaracije funkcije ili procedure u interface dijelu forme izbacuje se ime forme i navodi se samo ime funkcije ili procedure te <pb n="234"/>pripadna lista parametara.

Tekst koji vraća funkcija DajIme zapisuje se u varijablu Result. Varijabla Result je posebna varijabla koju osigurava Delphi i koja se koristi za vraćanje vrijednosti iz funkcije. Varijabla Result zamijenila je potrebu za zapisivanjem povratne vrijednosti u ime funkcije. Tip varijable Result uvijek je identičan povratnom tipu funkcije koji definiramo sami.

Tekst koji vraća funkcija DajIme ispisivat ćemo na naslovnu traku pomoću posebne procedure koja će u aplikaciji služiti samo za to — ispis informacija o trenutačno otvorenom dokumentu.

Kao i funkcija DajIme, procedura IspisNaslovnaTraka piše se u implementation dijelu forme s obveznom deklaracijom u private dijelu forme.

Ako je bilo što krenulo po zlu, na CD-u u mapi “Primjeri\Poglavlje 10\DelphiPad — Osnove” nalazi se DelphiPad aplikacija na ovom stupnju razvoja.

10.6.4. Izvorni kôd File izbornika

Sada je na redu izvorni kôd za stvaranje, otvaranje i snimanje dokumenata. Najjednostavniji od svih je početni kôd za stvaranje novog dokumenta, opcija File -> New.

Izvorni kôd u primjeru 10.10. zahtijeva vrlo malo objašnjenja. Clear procedura TMemo komponente služi za brisanje cijelog sadržaja. Svojstvo SelStart upućuje na poziciju kursora tipkovnice (točke unosa). Ako SelStart svojstvo postavimo na 0, kursor će se postaviti na početak okvira.

Linija kôda najbitnija za logiku aplikacije je postavljanje varijable FImeDokumenta na prazan string. Time aplikaciji dajemo na znanje da je riječ o novom dokumentu koji nije spremljen na disk, a sami sebi olakšavamo posao praćenja promjena u dokumentima.

Zadnje što procedura NewItemClick radi je ispis teksta “Untitled – DelphiPad” na naslovnu traku, čime jasno dajemo na znanje korisniku da je riječ o potpuno novom dokumentu.

<pb n="235"/>

Nešto kasnije morat ćemo malo unaprijediti proceduru za stvaranje novog dokumenta, ali za sada će ova verzija poslužiti.

10.6.5. Otvaranje postojećeg dokumenta

Druga opcija koju treba napraviti je opcija za otvaranje postojećeg dokumenta. Za ovu će nam proceduru trebati jedna TOpenDialog komponenta. TMemo komponenta može prikazivati samo jednostavne tekstualne datoteke i zbog toga moramo podesiti filtar TOpenDialog komponente tako da omogućuje odabir samo tekstualnih datoteka.

Uz ekstenzije datoteka koje aplikacija može otvoriti, uvijek je dobro navesti i opciju All Files kako bismo omogućili odabir datoteka s drugom ekstenzijom. S obzirom na to da se opcija All Files mora posebno odabrati, ovo će korisnik učiniti svjesno i vrlo je vjerojatno da zna što radi.

<pb n="236"/>

Nakon što korisnik odabere neki dokument pomoću TOpenDialog komponente, obvezno moramo zapisati ime dokumenta u varijablu FImeDokumenta. Varijabla FImeDokumenta je vrlo bitna za snimanje dokumenata.

Podaci se učitavaju u Lines svojstvo TMemo komponente. Lines svojstvo učitava podatke s diska pomoću procedure LoadFromFile koja prima samo jedan string parametar — ime datoteke čije podatke treba učitati. Tek je u ovoj proceduri malo jasnije zašto nam je trebala procedura IspisNaslovnaTraka.

10.6.6. Snimanje dokumenta na disk

Sve aplikacije nude dvije različite opcije za snimanje podataka na disk — opciju Save i opciju Save As. Opcija Save koristi se za snimanje promjena na postojećem dokumentu, dok opcija Save As uvijek prikazuje dijaloški okvir u kojem se mora odabrati mjesto snimanja i ime dokumenta.

Prva opcija koju treba riješiti je opcija File -> Save As jer opcija Save ovisi o opciji Save As. Za snimanje dokumenata pomoću dijaloškog okvira trebat će nam jedna TSaveDialog komponenta. TSaveDialog komponenti moramo promijeniti nekoliko svojstava, ali ni jedno nije toliko bitno koliko svojstvo DefaultExt. Svojstvo DefaultExt se koristi za datoteke kojima se posebno ne odabire neka ekstenzija. U Default svojstvo treba unijeti samo ekstenziju “txt”, bez zvjezdice i točke.

Nakon svojstva DefaultExt, svojstvo Filter treba biti jednako filtru dijaloškog okvira za otvaranje dokumenata. Najbrži način da se cijeli filtar doda SaveDialog1 komponenti je da se pomoću Copy i Paste opcija postojeći filtar <pb n="237"/>kopira iz Filter svojstva OpenDialog1 komponente i nalijepi u Filter svojstvo SaveDialog1 komponente.

Uz ova dva postavljena svojstva, poželjno je promijeniti situaciju unutar svojstva Options. Unutar svojstva Options postoji vrijednost ofOverwritePrompt koju možemo uključiti ako želimo da dijaloški okvir za snimanje dokumenata pripazi da korisnik ne presnimi već postojeću datoteku. Kao što samo ime vrijednosti kaže, ako korisnik pokuša presnimiti već postojeći dokument, dijaloški će mu okvir postaviti dodatno pitanje želi li korisnik to doista učiniti (slika 10.23).

Odabirom opcije File -> Save As, aplikacija uvijek mora prikazati dijaloški okvir za snimanje dokumenata. Save As opcija koristi se u dva slučaja: kada korisnik želi snimiti novi dokument ili kada želi snimiti kopiju već postojećeg dokumenta. Kao i kod opcije za otvaranje dokumenata, u ovoj proceduri moramo zapisati novo ime dokumenta u varijablu FImeDokumenta.

Uz snimanje dokumenta na disk procedurom SaveToFile, opcija Save As postavlja svojstvo Modified na False. Pomoću svojstva Modified možemo saznati je li korisnik promijenio sadržaj editora ili nije. Opcije za snimanje trebaju uvijek postavljati Modified na False jer sve opcije za snimanje snimaju trenutačnu kopiju dokumenta koju korisnik, sigurno, nije mogao promijeniti. Modified svojstvo će se promijeniti na True kada korisnik unese ili obriše tekst iz editora ili odabere Clipboard opcije Cut ili Paste koje mijenjaju sadržaj editora.

Opcija Save koristi se za snimanje promjena na postojećem dokumentu. Ova je tvrdnja samo teoretski moguća, ako ignoriramo mogućnost da će korisnik odabrati tu opciju kada ima prikazan dokument koji ne postoji na disku. Ako dokument ne postoji na disku, opcija Save korisniku mora omogućiti snimanje dokumenta pod novim imenom, a upravo to i rade sve aplikacije kojima se svakodnevno koristimo na računalima.

<pb n="238"/>

Dakle, unutar Save opcije najprije moramo provjeriti postoji li dokument na disku. Ako dokument postoji, morat ćemo snimiti dokument na disk, a ako ne postoji, onda moramo pozvati opciju Save As koja će natjerati korisnika da unese ime novog dokumenta.

Opcija File -> Save koristi se nekim novitetima koje još nismo vidjeli u prijašnjim primjerima. Prvi od tih noviteta je funkcija FileExists.

Funkcija FileExists deklarirana je u unitu SysUtils. Funkcija FileExists se koristi kada želimo provjeriti postoji li neka datoteka na disku. Ona prima samo jedan string parametar — ime datoteke čije postojanje provjeravamo. Ako funkcija FileExists vrati vrijednost True, datoteka postoji.

Nakon što opcija Save provjeri postoji li datoteka, ona će iskoristiti ime datoteke zapisano u varijabli FImeDokumenta za snimanje promjena na postojećem dokumentu. Ali, ako FileExists funkcija utvrdi da datoteka ne postoji, ne ostaje nam ništa drugo nego da pomoću dijaloškog okvira zatražimo korisnika da unese ime za novi dokument. Kopiranje i dupliciranje kôda ne dolazi u obzir — sve što moramo napraviti je pozvati proceduru koja se poziva na Click događaj opcije Save As — SaveAsItemClick. U listu parametara SaveAsItemClick procedure trenutačno je zapisana vrijednost Sender. Vrijednost Sender najsigurnija je vrijednost koju možemo poslati kao parametar kada zovemo neku proceduru koja je ujedno i odgovor na događaj.

Zadnja opcija na izborniku File koju treba isprogramirati je Exit. Iako se opcija Exit čini vrlo jednostavnom, ovaj put nećemo koristiti Application.Terminate, nego proceduru Close glavne forme. Primjenom procedure Close dobit ćemo nešto što ne možemo dobiti primjenom procedure Application.Terminate — aktiviranje OnCloseQuery događaja.

OnCloseQuery je događaj forme koji se aktivira kada korisnik ili izvorni kôd pokušaju zatvoriti formu. Zašto nam treba OnCloseQuery događaj? Editor teksta još nismo razradili do kraja — nedostaje provjeravanje treba li snimiti dokument na disk tijekom zatvaranja aplikacije. Sve dobro isprogramirane aplikacije reagiraju upitom o snimanju dokumenta ako korisnik pokuša zatvoriti aplikaciju a da nije snimio sve promjene na trenutačno otvorenom dokumentu. Točno takav <pb n="239"/>upit mora postaviti i naša aplikacija, a jedino sigurno mjesto gdje se takav kôd može napisati je odgovor na OnCloseQuery događaj.

Uz ovu iznimno kratku proceduru za zatvaranje aplikacije dolazi dosta veliki odgovor na OnCloseQuery događaj.

10.6.7. Zatvaranje glavne forme editora

Unutar OnCloseQuery događaja forme moramo provjeriti je li trenutačno otvoreni dokument promijenjen. Ako je promijenjen, moramo pitati korisnika želi li snimiti taj dokument i, ako želi, moramo mu to i omogućiti prije nego dopustimo zatvaranje aplikacije. Tako ćemo dobiti potpuno funkcionalnu aplikaciju koja se brine o krajnjem korisniku i njegovim/njenim podacima, a to korisnici vole.

OnCloseQuery događaj ima uz Sender parametar još jedan dodatan varijabilni parametar CanClose. Parametrom CanClose koristimo se za kontroliranje zatvaranja aplikacije. Postavimo li varijablu CanClose na False, kao što je to napravljeno u prvoj liniji, aplikacija se neće moći zatvoriti.

Nakon što smo s prvom linijom procedure onemogućili zatvaranje aplikacije, to nam daje dovoljno vremena da provjerimo treba li i želi li korisnik snimiti podatke na disk. Nakon provjere Modified svojstva, pomoću jedne dosta kompleksne case provjere postavljamo korisniku pitanje o snimanju dokumenta i, ovisno o odabiru, pozivamo potrebnu liniju koda. Evo kako izgleda pitanje postavljeno pomoću funkcije MessageDlg.

<pb n="240"/>

Funkcija MessageDlg omogućuje nam prikazivanje dijaloškog okvira kojemu možemo promijeniti tekst, ikonu i set gumba, koje će korisnik moći vidjeti i iskoristiti. Deklaracija funkcije MessageDlg izgleda ovako:

function MessageDlg(const Msg: string; DlgType: TMsgDlgType;

Buttons: TMsgDlgButtons; HelpCtx: Longint): Word;

Prvi je parametar jednostavan, njime definiramo tekst koji će se prikazati na dijaloškom okviru. Drugi je parametar popis konstanti kojim možemo promijeniti ikonu koja se prikazuje na dijaloškom okviru (slika 10.25). Treći parametar je set gumba koje možemo prikazati na dijaloškom okviru: mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore, mbAll, mbNoToAll, mbYesToAll, mbHelp. Uz samostalne gumbe, u Delphiju su već definirane neke konstante češće primjenjivanih kombinacija gumba kao što je mbYesNoCancel koja se koristi u kodu OnCloseQuery događaja. Zadnji parametar, HelpCtx, koristi se u radu s datotekama pomoći. U programima koji se ne koriste Windows datotekama pomoći ovu je vrijednost najbolje postaviti na 0.

Povratnu vrijednost MessageDlg funkcije lako je zapamtiti. Ako korisnik klikne gumb OK, povratna je vrijednost konstanta mrOK. Ako korisnik odabere gumb Yes, povratna je vrijednost mrYes i tako je za sve gumbe koji se mogu prikazati na dijaloškom okviru MessageDlg funkcije.

Uz funkciju MessageDlg, novost je i funkcija Format koja se koristi za kvalitetno formatiranje stringova. Funkcija Format deklarirana je u SysUtils unitu, a deklaracija izgleda ovako:

function Format(const Format: string;

const Args: array of const): string;

Priznajem, deklaracija izgleda poprilično čudno. Svi su parametri navedeni kao konstantni parametri. Konstantni su parametri uz varijabilne parametre još jedna verzija parametara. Običan parametar funkcionira tako da u funkciju ili proceduru proslijedi kopiju varijable. Kad radimo sa string tipom podatka u kojem mogu doslovno biti megabajti podataka, prosljeđivanje varijable kroz parametar koji nije var tipa rezultirat će vrlo sporim izvršavanjem. Zato se obično pri radu sa stringovima ili nekim drugim podatkom koji procedura smije mijenjati koriste var parametri.

Ali što je s podacima koje ne smijemo mijenjati, a ne želimo njihovu dodatnu kopiju koja će usporiti program? Za takav parametar definira se konstantni, const parametar. Const parametar je parametar koji, ako je ikako moguće, prosljeđuje <pb n="241"/>pokazivač u proceduru, ali ne dopušta mijenjanje varijable koju proslijedimo. Za razliku od var parametara, kao const parametar možemo čak proslijediti i svojstvo komponente ili vrijednost koja nije zapisana u nekoj varijabli.

Drugi je parametar još bolji, array of const. Polje konstanti? Zamalo. Ovo je način na koji Delphi govori da je riječ o varijabilnom broju argumenata, koji se pri korištenju pišu unutar uglatih zagrada.

Funkcija Format se koristi na specifičan način koji je dosta poznat C programerima kroz funkciju printf. Prvi parametar Format funkcije je string unutar kojeg se nalaze posebni znakovi za formatiranje stringa koje funkcija Format razumije. U drugom se parametru unose razne vrijednosti koje su vezane uz znakove za formatiranje navedene u prvom parametru. Da to bude malo jasnije, evo jedan primjer koji se koristi brojevima.

Ako pokrenemo gornju proceduru, ona će na ekran prikazati poruku “a = 5, b = 3. Zbroj je 8.”. Kao što je vidljivo u primjeru 10.16, poprilično je zamorno stvoriti čak i najmanji ispis koji mora pretvarati brojeve u string i dodavati ih na određenu poziciju unutar stringa.

Kod ovakve situacije u pomoć vrlo efikasno pristiže funkcija Format pomoću koje proceduru iz primjera 10.16. možemo napisati mnogo jednostavnije i razumljivije.

<pb n="242"/>

Procedura u primjeru 10.17. prikazat će potpuno istovjetnu poruku kao i procedura u primjeru 10.16. Iz ovog je primjera vidljivo koliko pisanja kôda skraćuje upotreba funkcije Format, ali i koliko je ovo sofisticiranije rješenje. Funkcija Format postavit će vrijednost varijable a na prvo %znak mjesto koje nađe, vrijednost varijable b u drugi %znak koji nađe i tako sve do zadnjeg podatka unutar drugog parametra.

Znak %d koristi se za brojeve (decimalne brojeve), ali funkcija Format razumije veći broj takvih znakova za formatiranje, koji su popisani u datotekama pomoći pod imenom “Format strings”, a uz %d najčešće se koristi %s za kombiniranje većega broja string vrijednosti.

10.6.8. Nadopuna koda za stvaranje novog dokumenta

Sad kad znamo koristiti MessageDlg funkciju i pitati korisnika želi li spremiti podatke koje je unio u editor, morat ćemo nadopuniti proceduru za stvaranje novog dokumenta. Trenutačna verzija automatski stvara novi dokument, odnosno briše informacije o dokumentu koji je trenutačno prikazan.

Isto kao što se i pri zatvaranju može dogoditi da korisnik nije snimio zadnje promjene na dokumentu, tako to možemo bez problema očekivati i pri stvaranju novog dokumenta. Prije nego što stvorimo novi dokument, moramo se osigurati da je korisnik sve svoje podatke sigurno snimio na disk. Ako to nije učinio, kao i pri zatvaranju forme, moramo mu omogućiti snimanje zadnje promjene na dokumentu.

Provjera za snimanje gotovo je istovjetna provjeri koja se provodi u OnCloseQuery događaju. Case provjera jedino izlazi iz procedure za stvaranje <pb n="243"/>novog dokumenta kada korisnik odabere Cancel. Ako korisnik odabere ili No ili Yes, kôd za stvaranje novog dokumenta morat će se pokrenuti. S obzirom na to da je vrlo loša navika kopirati izvorni kôd kada to nije potrebno, opcije Yes i No oslanjaju se na to da će se izvorni kôd nakon if provjere uvijek izvršiti.

10.6.9. Izvorni kôd Edit izbornika

Izvornog kôda Edit izbornika ima nešto manje nego kôda vezanog uz File izbornik, ali opet — opcija za pretraživanje dokumenta je ponešto komplicirana. Prva opcija na izborniku Edit, opcija Undo, nudi korisniku poništavanje zadnje akcije koju je poduzeo. TMemo komponenta (koja je isti editor kôda koji se koristi u Notepad programima i ostalima) nudi samo jedan Undo korak. Poništavanje zadnjeg koraka, kao i većina opcija na Edit izborniku jednolinijske su procedure.

Druga opcija koju nudi izbornik Edit je opcija za isijecanje teksta iz editora. Prigodom isijecanja teksta iz editora kopija tog teksta sprema se u Clipboard.

Prije nego nastavimo dalje bilo bi lijepo razjasniti što je Clipboard. Clipboard (spremnik, međuspremnik, međumemorija) prostor je unutar radne memorije računala koji je potpuno neovisan o aplikacijama. Clipboard je dinamički promjenljiv dio memorije u koji opcije Cut i Copy spremaju podatke koji se naknadno mogu nalijepiti u neku aplikaciju pomoću opcije Paste. U Clipboard <pb n="244"/>možemo spremiti bilo koji podatak koji želimo.

Evo kako izgleda Delphi izvorni kôd za Cut, Copy i Paste opcije.

Nakon ovih, osnovnih Clipboard operacija slijedi opcija Delete. Opcija Delete po rezultatu u dokumentu totalno je identična opciji Cut, ali da je stvarno potpuno identična, ne bismo je morali dodatno navesti.

Vrlo je lako moguće da se u Clipboardu nalaze podaci koje želimo nalijepiti u svoj dokument, ali unutar dokumenta postoji tekst koji želimo pobrisati prije samog naljepljivanja. Ako odaberemo opciju Cut za brisanje teksta iz editora, ovaj, novoobrisani tekst će u Clipboardu zamijeniti tekst koji nam treba. Programi za potrebu brisanja podataka bez prethodnog spremanja u Clipboard koriste opciju Delete. U DelphiPad aplikaciji opcija Delete mora izbrisati odabrani dio teksta u TMemo komponenti.

Zadnja od vrlo jednostavnih opcija na Edit izborniku je opcija Select All koja <pb n="245"/>se koristi za odabir cijelog sadržaja dokumenta. Opcija Select All još je jedan jednolinijski biser.

Sad ćemo napraviti zadnju opciju na Edit izborniku, Insert Time & Date, koja donekle simulira ovu opciju u standardnom programu Notepad. Opcija Insert Time & Date koristi dvije nove funkcije: Now i FormatDateTime.

Funkcija Now vraća trenutačno vrijeme na računalu u varijablu tipa TDateTime. TDateTime tip podataka koristi se za spremanje datuma u Delphiju. Opcija FormatDateTime koristi se za pretvaranje numeričkog TDateTime podatka u string koji je korisniku razumljiv.

Sada je na redu zadnja i najteža opcija na Edit izborniku. Za pretraživanje dokumenata obično se koristi standardni dijaloški okvir za pretraživanje (TFindDialog komponenta) pa ćemo je dodati na formu.

Gumb Find Next na dijaloškom okviru koristi se za traženje pojma u dokumentu. Klikom na gumb Find Next pokreće se OnFind događaj TFindDialog komponente unutar kojeg moramo napisati izvorni kôd za pretraživanje dokumenta.

Pretraživanje dokumenta bilo bi mačji kašalj kad bi nam trebalo lociranje samo <pb n="246"/>prve pojave pojma u dokumentu. Korisnik možda želi pronaći samo jednu kopiju pojma, ali možda želi vidjeti koliko se puta neki pojam ponavlja, ili mu pak treba pojam, ali ne prva pojava pojma na početku, nego negdje na kraju dokumenta.

Samo pretraživanje dokumenata može se napisati na vrlo velik broj načina, ali ovdje je predstavljen jedan od osnovnijih načina koji može pronaći bilo koju pojavu pojma od početka do kraja dokumenta.

Prije samog kôda za pretraživanje treba nam još jedna privatna varijabla pod imenom FTextPos tipa Integer. Ta će nam varijabla trebati za pamćenje zadnje pozicije u dokumentu do koje je izvorni kôd za pretraživanje stigao.

Svaki put kada korisnik odabere opciju Edit -> Find, vrijednost varijable FTextPos moramo postaviti na 0, čime zadnju pretraženu poziciju izjednačavamo s početkom dokumenta.

Nakon što osiguramo varijablu i kôd koji će prikazati dijaloški okvir za pretraživanje moći ćemo unijeti kôd za pretraživanje.

Prva linija procedure za pretraživanje kopira cijeli sadržaj editora u lokalnu varijablu. Ovaj je korak potreban jer ćemo iz ovoga stringa morati brisati višak teksta, ali zbog pretrage ne smijemo obrisati dio korisnikova dokumenta.

U drugoj se liniji provjerava vrijednost FTextPos varijable. Ako je FTextPos jednak nuli, ne postoji višak teksta. Ako je vrijednost FTextPos varijable veća od nule, to znači da je korisnik već jednom pretražio dokument i da trenutačno traži sljedeću kopiju pojma unutar dokumenta.

Zbog pretraživanja, sav tekst koji se nalazi ispred FTextPos pozicije mora se obrisati, a upravo to čini poziv procedure Delete.

Te prve dvije linije služe za određivanje dijela teksta koji je preostao za pretraživanje. Tekst koji je u ranijem postupku pretražen može se slobodno izbaciti iz pretrage.

Treća linija se koristi funkcijom Pos za pronalaženje pojma unutar teksta koji je ostao za pretraživanje. Ako funkcija Pos pronađe pojam, onda neke podatke moramo zapamtiti za sljedeće pretraživanje (sljedeći klik na gumb Find Next).

FTextPos varijabla sadrži zadnju poziciju do koje je pretraga došla. FTextPos uvijek drži informaciju o poziciji koja je vezana uz korisnikovu kopiju teksta koju vidi na ekranu. S obzirom na to da je pretraga našla još jednu kopiju istog pojma nešto dalje u tekstu, vrijednost FTextPos varijable moramo inkrementirati do trenutačne pozicije pronađenog pojma.

Mijenjanjem svojstva SelStart mijenjamo poziciju točke unosa unutar editora, što nam omogućuje kasniju selekciju jednog dijela teksta. Svojstvo SelLength uvijek postavljamo na duljinu pojma koji se traži, čime dobivamo označeni dio teksta koji potpuno odgovara pojmu. Da bismo vidjeli okvir teksta u kojem se nalazi traženi pojam, morat ćemo fokusirati editor koristeći se procedurom SetFocus. I to je sve. Unutar else dijela if provjere ostaje nam samo da prikažemo poruku korisniku ako pojam uopće ne postoji ili ako se ni jedna kopija pojma više ne može pronaći u dokumentu.

10.6.10. Podešavanje alatne trake

Na alatnu traku dodat ćemo najčešće primjenjivane opcije s glavnog izbornika: <pb n="247"/>stvaranje novog dokumenta, otvaranje postojećeg dokumenta, snimanje promjena na dokumentu te opcije za editiranje: Cut, Copy, Paste i Undo.

S obzirom na to da je već prije viđeno kako se gumbi na alatnoj traci koriste glyphovima, trebat će nam i jedna TImageList komponenta. Sve slike kojima se koristi DelphiPad aplikacija mogu se pronaći na CD-u u mapi “Glyphs\DelphiPad”.

Prije nego što krenemo na dodavanje slika u TImageList komponentu obvezno moramo provjeriti veličinu slika koje ćemo dodati. Po osnovnoj postavci, TImageList komponenta prima slike veličine 16x16. S obzirom na to da su sve slike koje se prikazuju na alatnoj traci DelphiPad aplikacije veličine 24x24, najprije moramo promijeniti svojstva Height i Width TImageList komponente na 24. Ako prvo dodamo slike, a tek onda promijenimo veličinu, TImageList komponenta će obrisati sve slike koje sadrži jer te slike više nemaju potrebne dimenzije.

Gumbi koji se nalaze na alatnoj traci vidljivi su na slici 10.27, a imena su im NewButton, OpenButton, SaveButton. Nakon SaveButton komponente ide separator, a onda gumbi CutButton, CopyButton, PasteButton pa drugi separator i zadnji gumb UndoButton.

Najbolja karakteristika alatne trake je ta što ona uopće nema vlastitog koda, nego pomoću Events kartice Object Inspectora spajamo OnClick događaj gumba i opciju File -> New i to radimo sa svim ostalim opcijama.

<pb n="248"/>

Vrlo usko povezan s velikom većinom opcija u Edit izborniku je i OnChange događaj TMemo komponente. Svaka korisnička izmjena dokumenta ili primjena Clipboard Cut i Paste opcija rezultirat će aktiviranjem OnChange događaja.

Svaka dobro dizajnirana aplikacija vodit će računa o korisniku i nudit će mu samo opcije koje korisnik u tom trenutku može i smije odabrati. Opcije čije pokretanje nije potrebno obično se onemogućuju. To onemogućivanje korištenja opcija na izborniku (ali i opcija na alatnim trakama) posebno je bitno kod Clipboard operacija jer korisnik ne može napraviti Cut i Copy prije nego što odabere dio dokumenta, ili ne može napraviti Paste prije nego što u nekom ranijem koraku kopira određeni tekst u Clipboard.

Najbolji način kako se riješiti dijela problema oko onemogućivanja opcija je OnChange događaj TMemo komponente. Time ćemo maknuti s pameti Paste i Undo. Opcije Cut i Copy riješit ćemo koristeći se događajima vezanim uz miš.

Procedura vezana uz OnChange događaj koristi HasFormat funkciju Clipboard objekta koji nije standardno vidljiv u aplikacijama. Ako želimo uspješno kompilirati ovaj kod, u uses listu na početku datoteke moramo dodati unit Clipbrd.

Funkcija CanUndo TMemo komponente daje nam informaciju oko mogućnosti korištenja opcije Undo. Ako funkcija CanUndo vrati True, izvorni kod mora omogućiti Undo opciju i Undo gumb na alatnoj traci.

Svojstvo SelLength TMemo komponente možemo iskoristiti kada želimo saznati je li korisnik odabrao određeni dio teksta. Ako korisnik odabere dio teksta, na izborniku i alatnoj traci moramo omogućiti opcije Cut i Copy. Opcije Cut i Copy onemogućene su samo tada kada ni jedno slovo unutar dokumenta nije odabrano. Također, ni Delete opcija ne funkcionira ako korisnik ne odabere određeni dio teksta.

Funkcija Clipboard.HasFormat funkcija je koja provjerava kojeg je formata podatak koji je spremljen u Clipboardu. Ako je riječ o običnom tekstu (CF_TEXT), tek tada smijemo omogućiti korištenje opcije Paste.

Proceduru koja služi kao odgovor na OnChange događaj moramo pozvati i unutar OnMouseUp događaja. OnMouseUp događaj aktivira se nakon što korisnik pritisne i otpusti bilo koju tipku miša. Pozivom procedure EditorChange moći ćemo aktivirati Cut i Copy gumbe čim korisnik otpusti neku od tipaka miša.

procedure TMainForm.EditorMouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

EditorChange(Sender);

end;

<pb n="249"/>

10.6.11. Izvorni kôd Format izbornika

Format izbornik zadnji je izbornik u DelphiPad aplikaciji za koji ćemo pisati izvorni kôd. Iako postoji i Help -> About opcija, to ostavljam na izbor onomu tko će je implementirati. Izbornik Format obično sadrži opcije za rad (formatiranje) sa sadržajem dokumenata ili slične opcije koje su vezane uz izgled podataka.

Prva opcija, Word Wrap, služi za uključivanje automatskoga prelamanja rečenica. Svaki TMenuItem objekt ima svojstvo Checked koje omogućuje korištenje opcije na izborniku na isti način na koji se koristi TCheckBox komponenta. Svojstvo Checked je pomoću Object Inspectora još tijekom dizajna postavljeno na True jer je svojstvo WordWrap TMemo komponente po osnovnoj postavci na True.

Pri postavljanju WordWrap svojstva moramo pripaziti na klizne trake. Uključivanjem ili isključivanjem automatskoga prelamanja moramo i prikazati odgovarajuće klizne trake. Izvorni kôd za promjenu WordWrap svojstva na izborniku izgleda ovako:

Postavljanje WordWrap svojstva i kliznih traka nalazi se u proceduri PostaviWordWrap jer ćemo isti ovaj kôd koristiti za postavke WordWrap svojstva na još jednom mjestu u aplikaciji.

Zadnja opcija na izborniku, opcija za promjenu fonta editora, već je poznata i vrlo jednostavna. Jedino što je potrebno napraviti prije pisanja koda je dodati jednu TFontDialog komponentu na formu.

10.6.12. Snimanje postavki korisničkog sučelja

<pb n="250"/>

Vrlo bitna, iako često zanemarena osobina u velikom broju aplikacija je mogućnost spremanja postavki aplikacije. Program Notepad koji se nalazi u Windows operativnom sustavu bez problema snima položaj na ekranu, u koji ga je korisnik zadnji put postavio, a isto tako snima i postavke fonta koje je korisnik odabrao. Ja poprilično volim Courier New font veličina 10 i 12. Ako program ne može zapamtiti postavke fonta i stalno me tjera da koristim Times New Roman ili Lucida Console font, hoću li ga dugo koristiti? Ne, čak i da mi kuha kavu ujutro.

Upravo zbog toga DelphiPad aplikaciji obvezno moramo dodati mogućnost spremanja korisnički definiranih postavki. Takve se informacije obično spremaju u INI datoteke ili u Windows Registry. Registry je interna baza podataka Windows operativnog sustava u kojem se nalaze vitalni podaci o konfiguraciji računala i operativnog sustava, te dodatni podaci aplikacija koje snimaju svoje postavke u <pb n="251"/>Registry. S obzirom na to da i najmanjom nepažnjom možemo vrlo lako totalno uništiti operativni sustav, u ovoj knjizi nećemo koristiti Registry. Sve informacije o DelphiPad aplikaciji spremat ćemo u INI datoteku.

INI datoteke obične su tekstualne datoteke koje grupiraju podatke u sekcije. Svaki podatak unutar sekcije ima svoje ime (keyname) i vrijednost, a to unutar INI datoteke izgleda ovako:

DelphiPad aplikacija sprema osnovne informacije o korisničkom sučelju u dvije sekcije: Editor i Font. Imena sekcija nalaze se unutar uglatih zagrada. Sva imena opcija koje ćemo snimati u INI datoteku vidljiva su u glavnom popisu konstanti na početku datoteke s izvornim kodom.

Delphi pruža mogućnost korištenja INI datoteka pomoću TIniFile klase koja je definirana u IniFiles unitu. Nakon što dodamo IniFiles u uses listu glavne forme, napisat ćemo kôd za snimanje postavki u INI datoteku. S obzirom na to da se postavke snimaju na samom kraju korištenja aplikacije, najbolje mjesto za taj kôd je OnClose događaj koji se aktivira samo jednom — tijekom zatvaranja glavne forme.

Iako namjena ove knjige nije detaljan prikaz objektno-orijentiranog programiranja, izvorni kôd u primjeru 10.30. prikazuje dinamičko stvaranje objekata. TIniFile klasa kojom se koristimo za snimanje informacija u INI datoteku samo je nacrt. Da bismo tu klasu mogli iskoristiti, moramo stvoriti jedan objekt (opipljiv element) na temelju te klase. Dakle, moramo stvoriti objekt tipa TIniFile.

Ovaj problem oko stvaranja objekata za nas tijekom dizajna rješava postupak dodavanja komponenata na formu. S obzirom na to da sada stvaranje objekta radimo vlastoručno, treba nam jedna posebna funkcija koju posjeduju sve klase: konstruktor. Konstruktor je funkcija koja se u vrlo velikoj većini slučajeva zove Create, a služi stvaranju novog objekta koji možemo iskoristiti u izvornom kodu.

Konstruktor se uvijek koristi na isti način:

ImeObjekta := ImeKlase.Create(Lista parametara konstruktora);

Nakon što se konstruktor izvrši, varijabla ImeObjekta pokazuje na potpuno funkcionalan objekt.

Nakon što prva linija unutar OnClose odgovora na događaj stvori objekt Ini, tim se objektom koristimo za zapisivanje informacija o aplikaciji u INI datoteku. Jedini parametar konstruktora TIniFile klase je string u kojemu je zapisano ime INI datoteke s kojom radimo. Unutar stringa FPostavke zapisano je ime INI datoteke kojom se koristi DelphiPad aplikacija.

TIniFiles klasa omogućuje zapisivanje raznih tipova podataka, kao što su Boolean, String, Integer pomoću procedura WriteBool, WriteString, WriteInteger. Svaka od navedenih procedura ima tri parametra. Prva dva su string tipa; prvi je parametar ime sekcije u koje se zapisuje podatak, a drugi je parametar ime podatka. Jedino je zadnji parametar drukčiji od procedure do procedure jer u njega zapisujemo podatak koji se treba snimiti u INI datoteku.

Zadnja linija kôda vrlo je obvezna, a to je poziv procedure Free. Procedura Free služi za oslobađanje memorije koju zauzima objekt. Ako zaboravimo pozvati proceduru Free, ostavit ćemo smeće u memoriji. Naravno, poziv procedure Free obvezan je samo za objekte koje stvorimo dinamički, pomoću izvornog koda. Ostale objekte (komponente) koje dodamo na formu tijekom dizajna iz memorije će automatski obrisati glavna forma pri zatvaranju aplikacije.

Prije nego što pokrenemo program i testiramo kako u cijelosti funkcionira, <pb n="252"/>obvezno moramo napisati i kôd za učitavanje postavki. Taj je kod vrlo bitan jer inicijalizira varijablu FPostavke koja se koristi unutar OnClose događaja.

Izvorni kôd za učitavanje postavki moramo napisati tako da se izvrši samo jednom, i to odmah prigodom pokretanja aplikacije. Za inicijaliziranje vrijednosti i operacije koje se moraju izvršiti prigodom pokretanja aplikacije najbolje je iskoristiti OnCreate događaj forme. OnCreate događaj forme aktivira se odmah pri pokretanju aplikacije (nakon stvaranja glavne forme) i taj se događaj unutar života aplikacije aktivira, sasvim sigurno, samo jednom.

procedure TMainForm.FormCreate(Sender: TObject);

var

Ini: TIniFile;

begin

FPostavke := ExtractFilePath(Application.ExeName) +

STR_POSTAVKE_DATOTEKA;

if FileExists(FPostavke) then

begin

Ini := TIniFile.Create(FPostavke);

WordWrapItem.Checked := Ini.ReadBool(STR_EDITOR,

STR_EDITOR_WORDWRAP, True);

Self.Top := Ini.ReadInteger(STR_EDITOR,

STR_EDITOR_TOP, 140);

Self.Left := Ini.ReadInteger(STR_EDITOR,

STR_EDITOR_LEFT, 200);

Self.Width := Ini.ReadInteger(STR_EDITOR,

STR_EDITOR_WIDTH, 520);

Self.Height := Ini.ReadInteger(STR_EDITOR,

STR_EDITOR_HEIGHT, 370);

Editor.Font.Name := Ini.ReadString(STR_FONT,

STR_FONT_IME, ‘MS Sans Serif’);

Editor.Font.Size := Ini.ReadInteger(STR_FONT,

STR_FONT_VELICINA, 8);

PostaviWordWrap(WordWrapItem.Checked);

Ini.Free;

end;

EditorChange(Sender);

IspisNaslovnaTraka;

end;

U prvoj liniji procedure FormCreate inicijalizira se varijabla FPostavke. U tu svrhu se koristi ExeName svojstvo globalnog Application objekta. U ExeName svojstvu upisani su puno ime i putanja glavne izvršne datoteke projekta.

Primjenom funkcije ExtractFilePath koja je deklarirana u SysUtils unitu iz stringa možemo izvući samo putanju. Time dobivamo informaciju o mapi u kojoj se nalazi glavna izvršna datoteka i ostale datoteke naše aplikacije. Upravo je ta mapa najbolja za spremanje INI datoteke.

Nakon što i u ovoj proceduri stvorimo lokalni Ini objekt, krenut ćemo s učitavanjem <pb n="253"/>podataka. Svaki tip podataka ima svoju posebnu funkciju za učitavanje: ReadBool, ReadInteger ili ReadString.

Kod svih funkcija za učitavanje postoje tri parametra: prvi je parametar naziv sekcije u kojoj se nalazi snimljena vrijednost, drugi je parametar ime vrijednosti koju želimo učitati. U zadnji parametar unosimo osnovnu vrijednost koja će se iskoristiti ako funkcija za učitavanje ne može pronaći vrijednost unutar INI datoteke (ovo se događa većinom samo pri prvom pokretanju kada INI datoteka i ne postoji na disku).

10.6.13. Dodavanje kratke pomoći korisnicima

Male i jednostavne aplikacije poput DelphiPad editora teksta ne trebaju dodatne datoteke pomoći. Sve što je potrebno jednoj jednostavnoj aplikaciji su kratki tekstovi koji objašnjavaju čemu služi neka opcija na korisničkom sučelju. Takvi su kratki tekstovi poznati pod nazivima Tooltip ili Hint. Svaka Delphi komponenta posjeduje Hint svojstvo string tipa u koji možemo unijeti kratak tekst koji objašnjava tu komponentu.

Pri postavljanju hintova moramo pripaziti na ShowHint svojstvo glavne forme. Da bi se bilo koji hint prikazao na ekranu, ShowHint svojstvo glavne forme mora biti postavljeno na True. Nakon što upišemo tekst u Hint svojstvo neke komponente i postavimo ShowHint na True, DelphiPad aplikacija će bez problema prikazati hint na ekranu (slika 10.28).

Cijeli izvorni kôd DelphiPad aplikacije može se naći na CD-u u mapi “Primjeri\Poglavlje 10\DelphiPad”.

10.7. Sažetak

Ovo je bilo jedno od najdužih, ali i jedno od najzabavnijih poglavlja. U ovom smo poglavlju mogli vidjeti cijelu i potpuno funkcionalnu Delphi aplikaciju — DelphiPad, koja bez ikakvih problema može stati uz bok golemoj većini aplikacija koje se danas koriste na računalima.

Svi detalji koji čine čak i ovako jednostavnu aplikaciju proveli su nas kroz razne događaje glavne forme i razne funkcije koje već postoje unutar Delphija. Sve te <pb n="254"/>funkcije čine osnovu svakodnevnog programiranja u Delphiju, a ovaj bi sažetak trebao provjeriti tko se može prisjetiti svih funkcija koje smo nedavno vidjeli i koristili se njima.

Pitanja i zadaci

Pitanje 1: Pomoću koje komponente se u Delphiju stvara glavni izbornik aplikacije?

Pitanje 2: Pomoću kojeg alata se stvaraju i podešavaju opcije na glavnom izborniku?

Pitanje 3: Nabrojite četiri standardna dijaloška okvira.

Pitanje 4: Kojom se funkcijom prikazuju standardni dijaloški okviri na ekran?

Pitanje 5: Čemu služi procedura Assign u Delphiju?

Pitanje 6: Pomoću kojeg svojstva alatne trake povezujemo alatnu traku s listom slika?

Pitanje 7: Kojom se funkcijom koristimo kada želimo saznati postoji li neka datoteka na disku?

Pitanje 8: Unutar kojeg događaja možemo zaustaviti zatvaranje aplikacije?

Pitanje 9: Kako možemo zaustaviti zatvaranje aplikacije?

Pitanje 10: Pogledajte sljedeći primjer koda i odgovorite na pitanje: Što će se zapisati u varijablu s?

var

s: string;

begin

s := Format(‘%d, %d, %d...’, [1, 2, Trunc(PI)]);

end;

Pitanje 11: Što je to glyph?

<pb n="255"/>

11. Stvaranje baze podataka pomoću zapisa

11.1. Rad s više formi 256

11.2. HomeDVD aplikacija 257

11.2.1. Korisničko sučelje aplikacije 258

11.2.2. Korisničko sučelje dijaloškog okvira 260

11.2.3. Osnovni dijelovi izvornog koda 261

11.2.4. Prikazivanje informacija o odabranom filmu 263

11.2.5. Otvaranje i zatvaranje baze podataka 265

11.2.6. Dodavanje novog filma u bazu podataka 265

11.2.7. Mijenjanje zapisa u bazi podataka 269

11.2.8. Navigacija baze podataka 270

11.2.9. Brisanje podataka 270

11.2.10. Eksportiranje podataka iz baze 272

11.3. Sažetak 274

<pb n="256"/>

11. Stvaranje baze podataka pomoću zapisa

Evo nas u zadnjem poglavlju knjige u kojem ćemo se baviti stvaranjem vlastite baze podataka pomoću zapisa. Pitanje koje možda visi u zraku glasi: Zašto mi treba neka posebna baza podataka koju moram sam/sama isprogramirati? Iako je Delphi vrlo popularan alat baš zbog svoje podrške raznim bazama podataka kao što su BDE ili ADO, kod malih aplikacija takav gotov sustav može biti prevelik i donijeti sa sobom nepotrebne komplikacije. Ako nam treba malena baza podataka, a ne želimo baš najobičniju tekstualnu datoteku, najbolje je rješenje datoteka zapisa.

U ovom ćemo poglavlju vidjeti još podosta novosti vezanih uz razvoj aplikacija u Delphiju, a najkorisniji detalj je rad s većim brojem formi.

11.1. Rad s više formi

Prije nego što se uhvatimo programiranja baze podataka, moramo naučiti kako dodavati nove forme i raditi s više formi. Za ovo će nam trebati jedan novi projekt. U novi projekt koji se već sastoji od jedne forme dodat ćemo još jednu pomoću opcije File -> New -> Form. Time će se u projekt dodati forma Form2. Prije nego što nastavimo s radom bilo bi dobro snimiti cijeli projekt na disk.

Pri radu s većim brojem formi morat ćemo se prebacivati iz jedne u drugu. Ako želimo vidjeti popis svih formi koje postoje u nekom projektu, možemo odabrati gumb na alatnoj traci ili pritisnuti kombinaciju tipaka Shift + F12.

Trenutačno nam treba forma Form1 jer ćemo pomoću nje morati prikazati formu Form2 na ekran. Iako ovaj projekt ima više formi, trenutačno se samo glavna forma (forma Form1) prikazuje na ekranu. Sve ostale forme od kojih se sastoji projekt moramo prikazati na ekran pomoću izvornog koda.

Forma posjeduje dvije procedure kojima se prikazuje na ekran: Show i ShowModal. Procedura Show prikazuje formu na ekran i postavlja je ispred svih ostalih. Procedura ShowModal prikazuje formu u tzv. modalnom modu. Modalna forma je forma koja ne dopušta korištenje ostalih formi. Da bi se koristile ostale forme, modalnu formu najprije moramo zatvoriti. Modalne se forme najčešće koriste za dijaloške okvire.

Na formi Form1 trebat će nam jedan gumb na čiji ćemo OnClick događaj prikazati drugu formu na ekran.

Nakon što napišemo kôd za prikazivanje forme Form2 i pokušamo pokrenuti aplikaciju dočekat će nas poruka o pogrešci, ali kao što ćemo vidjeti — ovo je jedna od pogrešaka koju možemo vrlo jednostavno popraviti.

<pb n="257"/>

Ova se poruka pojavljuje kada želimo iskoristiti formu koju još nismo uključili u uses listu. Svaka forma koju dodamo u projekt ima svoje zasebne PAS i DFM datoteke i, da bismo dodatnu formu mogli iskoristiti, moramo je uključiti u uses listu glavne forme. Ta poruka služi upravo tomu da se dodatna forma uključi u uses listu glavne forme, pa ćemo uvijek na ovoj poruci odabrati Yes.

Nakon što odaberemo opciju Yes, unit Unit2 gdje je deklarirana forma Form2 bit će dodan u uses listu glavne forme, ali ovaj put ta se uses lista nalazi unutar implementation dijela forme, a ne kao do sada, u interface dijelu. Uses lista u interface dijelu popisuje unite koji su globalno potrebni (u interface i u implementation dijelu), a uses lista unutar implementation dijela popisuje unite koji se koriste samo u izvornom kodu. Ako je moguće, dodatne unite poželjno je uključivati u implementation dio jer će se time smanjiti mogućnost dobivanja cirkularne upotrebe formi — što rezultira pogreškom.

Nakon što formu Form2 uključimo u uses listu glavne forme, aplikacija će se ponovnim pokretanjem moći bez problema kompilirati zajedno s drugom formom.

11.2. HomeDVD aplikacija

HomeDVD je aplikacija koja nema kompleksno korisničko sučelje, ali zato ima kompleksnu pozadinu i funkcionalnost. HomeDVD aplikacija koristi se našim vlastitim formatom baze podataka za spremanje informacija o filmovima. HomeDVD omogućuje samo osnovne operacije — dodavanje novog filma, promjenu već postojećeg ili brisanje. Uz te, osnovne operacije na podacima, omogućuje i eksportiranje podataka iz baze u običnom tekstualnom formatu ili u HTML formatu (HTML tablica).

<pb n="258"/>

11.2.1. Korisničko sučelje aplikacije

HomeDVD aplikacija sastoji se od dvije forme: glavne forme na kojoj se prikazuju detalji odabranih filmova i druge forme (dijaloškog okvira) koja se koristi za dodavanje novog ili za promjenu postojećeg filma.

Na glavnoj se formi nalaze četiri TLabel komponente na kojima se prikazuju detalji filma i dva gumba pomoću kojih se može listati baza podataka. Uz te komponente, jedini detalj koji još postoji na glavnoj formi je glavni izbornik. Za razliku od ostalih izbornika koje smo do sada kreirali, ovaj izbornik ima podizbornik koji se može vidjeti na slici 11.4.

Podizbornik se stvara na vrlo jednostavan način. Nakon što se pomoću dizajnera izbornika na File izborniku stvori opcija Export, dovoljan je desni klik na opciju Export i odabir opcije Create Submenu (slika 11.5).

<pb n="259"/>

Na samom dnu glavne forme nalazi se statusna traka koja se koristi u aplikacijama za prikaz raznih informacija tijekom rada. Statusna je traka u Delphiju predstavljena komponentom TStatusBar koja se nalazi na drugoj polovici Win32 kartice.

Jedino svojstvo TStatusBar komponente koje je promijenjeno u HomeDVD aplikaciji je SimplePanel svojstvo koje je postavljeno na True. Postavkom SimplePanel svojstva na True omogućeno nam je korištenje string svojstva SimpleText kojim se koristimo za prikaz jednostavnih tekstualnih poruka na površini statusne trake.

Najviše promjena doživjela je sama forma. Najosnovnija promjena ponašanja forme je nemogućnost promjene veličine, ni vlastoručno ni pomoću opcija na naslovnoj traci. Vlastoručnu promjenu veličine forme možemo promijeniti postavkom svojstva BorderStyle na bsSingle. Vrijednost bsSingle onemogućuje promjenu veličine dok standardna vrijednost bsSizeable to omogućuje.

Promjena veličine forme preko naslovne trake i dalje je omogućena nakon postavke BorderStyle svojstva na bsSingle. Ako želimo onemogućiti ovu opciju, u Object Inspectoru moramo pomoću plus opcije proširiti svojstvo BorderIcons i isključiti vrijednost biMaximize. Ako isključimo vrijednost biMinimize, aplikaciju nećemo moći minimizirati u traku sa zadacima, a ako isključimo vrijednost biSystemMenu, na naslovnoj se traci više neće pojavljivati ni ikona aplikacije, a ni gumb za zatvaranje prozora.

Uz očitu promjenu pozadinske boje glavne forme, promijenjeno je i svojstvo Position pomoću kojeg definiramo osnovnu poziciju forme na ekranu. U svojstvu Position najčešće se koriste dvije vrijednosti: poDefault i poDesktopCenter. Vrijednost poDefault neće raditi nikakve promjene na formi tijekom pokretanja. Ako postavimo vrijednost poDefault, forma će se pri pokretanju postaviti na istu poziciju na kojoj je bila tijekom dizajna aplikacije. Ako postavimo vrijednost poDesktopCenter, forma će se postaviti točno na sredinu ekrana, što je dobro zbog raznih rezolucija koje korisnici mogu imati na svojim ekranima.

<pb n="260"/>

11.2.2. Korisničko sučelje dijaloškog okvira

Dijaloški okvir definiran je isto kao glavna forma: prikazat će se na sredini ekrana i korisnik neće moći promijeniti veličinu dijaloškog okvira.

Na dijaloškom okviru koriste se već prije viđene komponente: TLabel, TEdit, TBevel i TButton. Uz te komponente, na dijaloškom se okviru koristi i TComboBox komponenta (padajuća lista opcija).

TComboBox komponenta je spoj TListBox i TEdit komponenata i koristi se za prikaz velikoga broja opcija, ali tek kada to korisniku zatreba. TComboBox komponenta se koristi na formama na kojima želimo prikazati velik broj opcija, a ne želimo da te opcije zauzmu veliku površinu.

TComboBox komponenta posjeduje nama tri bitna svojstva: Items, Text i ItemIndex. Items svojstvo je lista stringova, lista svih opcija koje nam nudi padajuća lista. U Text svojstvu zapisuje se odabrani podatak iz liste. ItemIndex svojstvo je Integer podatak u kojem je zapisan indeks podatka u listi. To će nam svojstvo dobro doći u izvornom kodu.

Dva svojstva koja su manje vitalna za funkcioniranje aplikacije su svojstva Style i DropDownCount. Ponašanje TComboBox komponente definira se pomoću svojstva Style. Osnovna vrijednost svojstva Style je csDropDown, čime je moguć odabir podatka iz liste opcija, ali i unos podatka u okvir unosa teksta. Vrijednost csDropDownList onemogućuje unos vrijednosti koja se ne nalazi unutar liste. Korištenjem vrijednosti csDropDownList možemo se osigurati da će odabrani podatak uvijek biti točan i u redu. Time si smanjujemo posao oko provjere vrijednosti koju korisnik unese. Svojstvo DropDownCount služi za podešavanje broja opcija koje će se prikazati na ekranu (slika 11.7).

<pb n="261"/>

Dijaloški su okviri u velikoj većini slučajeva definirani tako da u donjem desnom kutu imaju dva gumba: OK i Cancel. Ti gumbi služe za prihvaćanje postavki dijaloškog okvira ili prekid rada. S obzirom na to da svi dijelovi aplikacija moraju biti pristupačni korisniku koji se koristi mišem, ali i korisniku koji koristi tipkovnicu, moramo se osigurati da će korisnik tipkom Enter moći aktivirati gumb OK, a tipkom Escape gumb Cancel.

Na svu sreću, aktiviranje tih gumba ne zahtijeva pisanje izvornog koda. S obzirom na to da se dijaloški okviri koriste u svim aplikacijama, postoje svojstva specifična baš za trenutačni problem. Gumbi posjeduju svojstvo Default kojim se odabire osnovni gumb dijaloškog okvira. Osnovni gumb bit će prikazan nešto drukčije od ostalih, i to je gumb koji reagira na pritisak tipke Enter na dijaloškom okviru. Uz Default svojstvo koje se postavlja na True na gumbu OK, moramo postaviti i Cancel svojstvo, ali na gumbu Cancel. Gumb koji ima svojstvo Cancel postavljeno na True aktivirat će se kada korisnik pritisne tipku Escape na tipkovnici.

Uz tipke Enter i Escape, većina korisnika ima naviku koristiti se tipkom Tab na tipkovnici, kojom mogu navigirati po dijaloškom okviru. Tipka Tab mora pomicati fokus s komponenata koje se nalaze na vrhu prema komponentama koje se nalaze na dnu dijaloškog okvira. Smjer i ponašanje tipke Tab na nekom dijaloškom okviru podešava se pomoću Integer svojstva TabIndex koje imaju sve komponente.

11.2.3. Osnovni dijelovi izvornog koda

Kao što je bio slučaj i kod DelphiPad aplikacije, na CD-u u mapi “Primjeri\Poglavlje 11\HomeDVD — Kostur” postoji osnovni kostur aplikacije s potpuno definiranom glavnom formom i dijaloškim okvirom. Jedini nedostatak HomeDVD aplikacije je izvorni kôd, ali to ćemo vrlo brzo riješiti.

Na samom početku trebamo definirati osnovne tipove podataka kojima ćemo se koristiti u aplikaciji. Ova verzija HomeDVD aplikacije drži samo nekolicinu podataka o filmu: naslov filma, tip filma, godinu izdanja i ocjenu. Ocjena i tip filma definirani su u dva zasebna enumerirana tipa podataka koji se navode odmah na početku unita, iza rezervirane riječi type. Uz te enumerirane podatke, definiran je zapis u kojem se drže sve informacije o filmu: TDVDMovie. Najzanimljiviji od svih novih podataka je TDVDMovieFile tip podataka: novi tip binarne datoteke u koje se mogu zapisivati samo TDVDMovie podaci.

<pb n="262"/>

Za potrebe prikazivanja tekstualnog opisa ocjene i tipa filma trebaju nam dvije funkcije za konverziju: jedna koja konvertira TDVDGenre u string, a druga TDVDRating u string. Deklaraciju obje funkcije treba dodati u private dio forme, a sama implementacija (izvorni kod) funkcija slijedi u primjeru 11.3.

Unutar private dijela forme trebaju nam dvije varijable, FDVD tipa TDVDMovieFile i FCurrent tipa Integer. FDVD varijabla služi za pristup bazi podataka na disku, a FCurrent varijabla identificira trenutačni film koji se prikazuje na glavnoj formi.

private

<pb n="263"/>

{ Private declarations }

FDVD: TDVDMovieFile;

FCurrent: Integer;

Prije nego što krenemo na malo konkretniji izvorni kôd, moramo dodati jednu vrlo često korištenu konstantu.

var

MainForm: TMainForm;

const

STR_EMPTY_DATABASE = ‘The database is empty.’;

11.2.4. Prikazivanje informacija o odabranom filmu

Prva kompleksnija procedura koju ćemo napraviti je procedura DisplayInfo. Procedura DisplayInfo služi prikazivanju trenutačno odabranog filma na formi, a uz informacije o filmu prikazuje još neke detalje na formi. Deklaracija DisplayInfo procedure također ide u private dio forme.

<pb n="264"/>

DisplayInfo procedura koristi velik broj procedura koje su specifične za rad s datotekama zapisa (file of type).

Prva provjera,

if FileSize(FDVD) > 0 then

koristi se funkcijom FileSize za provjeru veličine datoteke. FileSize funkcija ne vraća veličinu datoteke u bajtima, nego u broju zapisa koji postoje u datoteci. Ako FileSize funkcija vrati broj 0, znači da je datoteka prazna. Ako vrati neki broj, to je broj podataka koji su zapisani u datoteci (trenutačno, to je broj filmova koji postoje u bazi podataka).

Ako baza podataka nije prazna, u statusnu traku zapisat će se poruka o trenutačno prikazanom filmu i broj filmova koji postoje u bazi:

StatusBar.SimpleText := Format(‘Movie %d of %d.’,

[FCurrent+1, FileSize(FDVD)])

Pri ispisu trenutačni film (FCurrent) mora biti uvećan za jedan jer indeksi zapisa u datoteci počinju brojem 0, a ne 1.

Nakon što se potrebna poruka ispiše na naslovnoj traci aplikacije, slijedi dio koda vezan uz gumbe za pretraživanje baze podataka. S obzirom na to da ćemo pogrešnim učitavanjem sigurno dobiti vrlo ružnu poruku o pogrešci, moramo se osigurati da korisnik neće moći odabrati gumb za prijašnji podatak ako trenutačno prikazuje prvi ili da neće moći odabrati gumb za sljedeći podatak ako trenutačno prikazuje zadnji.

Prvi dio provjere za gumbe,

hasMovies := FileSize(FDVD) > 0;

BackButton.Enabled := hasMovies;

NextButton.Enabled := hasMovies;

osigurava da će, u slučaju prazne baze, oba gumba biti onemogućena ili obrnuto. Tek ako u bazi postoji neki film, slijedi daljnji dio ove provjere koji provjerava koji je film trenutačno prikazan i može li korisnik odabrati gumb za prikaz prijašnjeg ili sljedećeg filma:

if hasMovies then

<pb n="265"/>

begin

if FCurrent = 0 then

BackButton.Enabled := False;

if FCurrent = FileSize(FDVD)-1 then

NextButton.Enabled := False;

end;

Zadnji dio procedure DisplayInfo prikazuje informacije o filmu. Ako je FileSize veći od 0, procedura DisplayInfo mora ispisati informacije o trenutačno odabranom filmu. To se postiže tako da se unutar datoteke najprije pronađe podatak. Podaci se unutar ovakve baze podataka traže pomoću procedure Seek.

Seek(FDVD, FCurrent);

Seek procedura traži podatak unutar baze pomoću indeksa podatka. U liniji koda prikazanoj prije, Seek procedura traži trenutačni film pomoću njegova indeksa (FCurrent). Nakon pretrage, cijeli se zapis učitava u privremenu lokalnu varijablu curMovie pomoću obične Read procedure.

Read(FDVD, curMovie);

Nakon učitavanja svi se podaci mogu vrlo jednostavno pročitati iz curMovie zapisa i upisati u odgovarajuću TLabel komponentu na formi.

11.2.5. Otvaranje i zatvaranje baze podataka

Ova je aplikacija dosta jednostavna zato što se svi podaci o filmovima drže u samo jednoj bazi podataka koju otvaramo na početku izvršavanja aplikacije, u OnCreate događaju.

Na samom početku procedure FormCreate poziva se procedura AssignFile za pridjeljivanje imena varijabli za pristup datoteci na disku. AssignFile je Delphi naziv za Assign proceduru kojom smo se koristili u Pascalu za pristup tekstualnim datotekama.

Pri pokretanju aplikacije moramo otvoriti bazu podataka jer sve Read i Seek procedure zahtijevaju otvorenu datoteku. Ako baza podataka ne postoji, procedurom Rewrite moramo je stvoriti. Uz otvaranje baze podataka vidimo da se poziva i procedura DisplayInfo koja će prikazati praznu formu ako je baza prazna ili prvi film u bazi ako jedan ili više filmova postoji u bazi.

Sve datoteke koje otvorimo pomoću AssignFile procedure moramo i zatvoriti. U Pascalu su se datoteke zatvarale procedurom Close, a u Delphiju se datoteke zatvaraju procedurom CloseFile. S obzirom na to da baza podataka treba biti otvorena tijekom cijelog života aplikacije, mjesto za zatvaranje datoteke je OnClose događaj.

procedure TMainForm.FormClose(Sender: TObject;

var Action: TCloseAction);

begin

CloseFile(FDVD);

end;

11.2.6. Dodavanje novog filma u bazu podataka

Dodavanje novog filma u bazu podataka ovisi o dizajnu i funkcioniranju dijaloškog okvira. Tek nakon što potpuno definiramo ponašanje dijaloškog okvira možemo krenuti na pisanje kôda koji će informacije s dijaloškog okvira zapisati u bazu podataka.

<pb n="266"/>

Nešto prije navedena su svojstva OK i Cancel gumba koja su promijenjena. Tada su navedena sva svojstva, osim svojstva ModalResult. ModalResult svojstvo bitno je za modalne forme koje se prikazuju pomoću procedure ShowModal. Ako u ModalResult svojstvo gumba postavimo vrijednost različitu od mrNone, klikom na takav gumb modalna će se forma automatski zatvoriti. Usto što se postavkom ModalResult svojstva forma zatvara, programeri nakon zatvaranja imaju mogućnost vrlo jednostavne provjere gumba na koji je korisnik kliknuo.

ModalResult svojstvo gumba OK postavljeno je na mrNone jer prije nego što zatvorimo ovaj dijaloški okvir moramo provjeriti je li korisnik unio ime filma. Za razliku od OK gumba, ModalResult svojstvo gumba Cancel postavljeno je na mrCancel. Time bez ijedne linije koda dobivamo automatsko zatvaranje forme i informaciju o gumbu kojeg je korisnik odabrao.

Unutar OnClick događaja OK gumba moramo provjeriti samo je li korisnik unio neko ime filma. Ostale vrijednosti ne moramo provjeravati jer nam TComboBox komponente automatski nude neku od predefiniranih vrijednosti.

Uz sad već potpuno razumljivu provjeru unesenog imena filma, najzanimljivija linija koda je zadnja u kojoj u ModalResult svojstvo forme upisujemo <pb n="267"/>vrijednost mrOK. Ta će vrijednost automatski zatvoriti formu, kao i mrCancel postavka gumba Cancel.

Izvorni kôd gumba OK provjerava samo ime filma, dok vrijednosti za ocjenu i tip filma već postoje u TComboBox komponentama. U Items svojstvu TComboBox komponenata zapisane su iste string vrijednosti, kao i u funkcijama za konvertiranje TDVDGenre i TDVDRating podataka u string.

Jedina TComboBox komponenta čije su opcije definirane tek tijekom izvršavanja aplikacije je YearCombo komponenta s popisom godina. S obzirom na to da je OnCreate događaj najbolji događaj za inicijaliziranje podataka, u tom ćemo događaju YearCombo komponenti dodati godine od 1900. do 2005. (ako se ovim programom krene koristiti neki kolekcionar filmova).

Sada nam još ostaje da napišemo odgovor na jedan događaj — OnShow događaj forme. OnShow događaj aktivira se nakon OnCreate događaja, svaki put kada se forma prikaže na ekran pomoću Show ili ShowModal procedura. OnShow događaj se koristi za inicijalizaciju vrijednosti koje su vezane uz fokus vizualnih komponenata ili sličnih vizualnih svojstava. Ako takav kôd stavimo u OnCreate, on će izazvati pogrešku.

Unutar OnShow događaja dijaloškog okvira treba nam kôd koji će brisati stare podatke iz dijaloškog okvira prije nego što se dijaloški okvir u potpunosti prikaže na ekran.

<pb n="268"/>

Kao što je navedeno u komentarima na početku FormShow procedure, samo ako je Tag = 1, trebamo obrisati podatke iz komponenata na dijaloškom okviru. Ako je Tag = 0, opcija Update će u komponente na dijaloškom okviru unijeti podatke odabranog filma koje korisnik želi izmijeniti.

Sad kad smo napokon gotovi s izvornim kodom koji osigurava kvalitetno funkcioniranje dijaloškog okvira, možemo krenuti na sam izvorni kôd opcije Movie -> Add za dodavanje novog filma u bazu.

Prva linija koda pomoću Tag svojstva definira o kojoj je opciji riječ. Kao što smo vidjeli prije, ova se vrijednost koristi u OnShow događaju dijaloškog okvira. Caption dijaloškog okvira postavlja se na “Add Movie” kako bi korisnik znao koju je opciju odabrao.

Nakon tih postavki na ekran prikazujemo dijaloški okvir. Dijaloški okvir moramo prikazati pomoću ShowModal procedure kako bi se zaustavilo daljnje izvršavanje te procedure. Daljnje izvršavanje procedure nastavlja se tek kada korisnik zatvori modalnu formu (dijaloški okvir).

Odmah nakon što se dijaloški okvir zatvori provjeravamo njegovu ModalResult vrijednost. Ako u ModalResult svojstvu naiđemo na vrijednost mrOK, onda možemo krenuti na zapisivanje podataka u bazu.

Sve podatke s dijaloškog okvira moramo najprije zapisati u privremenu varijablu newRec tipa TDVDMovie. Nakon što podatke spremimo u privremenu varijablu, moramo se pomaknuti na kraj baze podataka procedurom Seek:

Seek(FDVD, FileSize(FDVD));

Ova će nas pretraga postaviti na kraj baze podataka, što je obveza za zapisivanje novog podatka. Ako se nalazimo na nekoj drugoj poziciji, onda ćemo ili izazvati pogrešku ili slučajno prebrisati neki već postojeći podatak u bazi.

<pb n="269"/>

Nakon što pomoću procedure Write zapišemo zapis u bazu, FCurrent ćemo postaviti na zadnji podatak (zadnji –1) kako bi nam DisplayInfo procedura mogla prikazati novi film koji smo dodali.

11.2.7. Mijenjanje zapisa u bazi podataka

Mijenjanje zapisa omogućeno je korisniku putem opcije Movie -> Update. Opcija Update vrlo je slična opciji za dodavanje novog filma.

Prvo što moramo napraviti prigodom promjene podataka je provjeriti postoji li u bazi uopće podatak koji možemo izmijeniti. Ako ne postoji, dalje ne smijemo ništa raditi s bazom jer će bilo kakav pokušaj učitavanja donijeti sa sobom jednu lijepu malu pogrešku.

Nakon provjere Seek procedurom, trenutačni film možemo locirati i učitati ga iz baze u privremenu varijablu temp. Nakon toga Tag svojstvo dijaloškog okvira <pb n="270"/>postavljamo na 0, čime onemogućujemo brisanje podataka tijekom OnShow događaja okvira.

Kad sve podatke iz privremene varijable temp prebacimo u odgovarajuće komponente na dijaloškom okviru, pozivom ShowModal procedure prikazujemo ih na ekranu i omogućujemo korisniku potrebne izmjene.

Nakon što korisnik zatvori dijaloški okvir i utvrdimo da je odabrao gumb OK, podatke s dijaloškog okvira najprije spremamo natrag u varijablu temp. Nakon toga se pomoću Seek procedure ponovno vraćamo na točnu poziciju u bazi podataka i zapisujemo nove podatke preko starih podataka, čime uspješno dobivamo izmjenu.

11.2.8. Navigacija baze podataka

Navigacija baze podataka omogućena je u ovoj aplikaciji sa samo dva gumba — listanje filmova prema početku i prema kraju baze. Izvorni kôd za obje procedure vrlo je jednostavan jer je sav kôd već prije napisan: inkrementiranje ili dekrementiranje trenutačne pozicije (FCurrent) i prikazivanje filma na formi.

11.2.9. Brisanje podataka

Brisanje podatka iz baze zahtijeva mnogo više posla nego ijedna opcija koju smo do sada isprogramirali. Brisanje podataka moguće je samo tako da se podatak odsiječe s kraja datoteke. Dakle, brisanje zadnjeg filma vrlo je jednostavno. Pomaknemo kursor datoteke ispred zadnjeg podatka i odsiječemo sve do kraja datoteke.

Što ako želimo obrisati podatak koji se nalazi na početku ili u sredini datoteke? Tu dolazimo do malo većega problema. Podatak koji želimo obrisati moramo nekako odgurati na kraj i onda ga odsjeći. E, u tom kodu leži zec..., odnosno problem. Negdje na Internetu našao sam kôd koji sve podatke najprije sprema u privremeno polje od nekoliko tisuća podataka, onda briše sve podatke iz datoteke te ponovno zapisuje sve podatke iz privremenog polja u datoteku (osim onog kojeg je trebalo pobrisati).

Iako sasvim zanimljivo rješenje, zahtijeva malo preveliku količinu izvornoga koda, a ujedno zahtijeva veće iskorištenje radne memorije nego što je potrebno, pogotovo ako uzmemo u obzir da se ovakve baze koriste za smanjenje korištenja radne memorije.

Mnogo je bolje rješenje napraviti jednu kontinuiranu izmjenu zapisa od podatka <pb n="271"/>koji treba brisati pa sve do kraja datoteke. Dakle, ako trebamo pobrisati film broj 2, mnogo je jednostavnije učitati broj 3 i zapisati ga na mjesto filma 2, pa učitati film 4 i zapisati ga na mjesto filma 3 i tako sve do kraja datoteke. Na ovaj način, kada dođemo do kraja datoteke, zadnji će se podatak nalaziti i na predzadnjem i na zadnjem mjestu što ponovno omogućuje jednostavno brisanje samo zadnjeg <pb n="272"/>podatka.

Nakon provjere ima li podataka u bazi i provjere želi li korisnik doista obrisati podatak slijedi brisanje odabranog podatka. Ako provjera

if FCurrent = FileSize(FDVD)-1 then

utvrdi da je trenutačno odabran zadnji podatak, sve je vrlo jednostavno. Najprije moramo doći u poziciju za rad s podatkom i nakon toga pozvati proceduru Truncate koja će odbaciti kraj datoteke, sve što se nalazi u datoteci iza pozicije na koju nas postavi procedura Seek.

Seek(FDVD, FileSize(FDVD)-1);

Truncate(FDVD);

Ako prije navedena provjera utvrdi da je riječ o podatku koji se nalazi na početku ili u sredini datoteke, situacija je malo kompliciranija. Pomoću for petlje

for i := FCurrent+1 to FileSize(FDVD)-1 do

begin

Seek(FDVD, i);

Read(FDVD, temp);

Seek(FDVD, i-1);

Write(FDVD, temp);

end;

učitavat će se svi podaci od trenutačne pozicije do kraja datoteke i zapisati na poziciju podatka koji se nalazi ispred. Nakon for petlje postavljamo se na poziciju za rad sa zadnjim podatkom i pozivom Truncate procedure odbacujemo višak:

Seek(FDVD, FileSize(FDVD)-1);

Truncate(FDVD);

11.2.10. Eksportiranje podataka iz baze

Eksportiranje podataka iz baze zadnji je detalj koji treba dodati u HomeDVD aplikaciju. Iako se obje procedure uz malo posla mogu svesti na jednu malo kompleksniju proceduru, ovdje su, radi jednostavnosti, navedene odvojeno.

Prva procedura koju ćemo napraviti je procedura za eksportiranje imena filmova iz baze podataka u običnu tekstualnu datoteku. S obzirom na to da smo se već prije u dijelu knjige o Pascalu susreli s tekstualnim datotekama, ovaj kôd ne bi trebao biti problematičan.

<pb n="273"/>

Novost u Delphiju je malo izmijenjeno ime tipa podatka za pristup tekstualnim datotekama — umjesto Text, u Delphiju je TextFile. Sve ostalo je isto.

Nakon što korisnik pomoću TSaveDialog komponente odabere ime datoteke u koju želi eksportirati podatke iz baze, pomoću while petlje proći ćemo kroz cijelu bazu i u tekstualnu datoteku zapisati samo redni broj i naslov filma.

Kad se while petlja završi i kad zatvorimo tekstualnu datoteku, ne smijemo zaboraviti pozvati Seek proceduru da nas vrati na poziciju trenutačno prikazanog podatka. Kao što vidimo, samo eksportiranje u tekstualnu datoteku nije preveliki problem.

Malo veći problem, pogotovo ako znanje o HTML-u nije preveliko, može biti opcija za eksportiranje u HTML datoteku. Opcija za eksportiranje podataka iz baze u HTML datoteku gotovo je identična. Jedina je razlika u tome što pri eksportiranju u HTML moramo generirati osnovnu strukturu HTML datoteke. Nakon eksportiranja jedne pokusne baze podataka, generirani HTML dokument izgleda ovako:

<pb n="274"/>

Osnovna struktura html dokumenta koja nam treba je ovakva:

<html><head><title>My DVD Collection</title></head>

<body><h1>My DVD Collection</h1><p>

<table border=”1”>

Nakon tih tagova, slijedi dio koji generiramo i ispunjavamo naslovima filmova iz baze:

<tr><td>1. Lord of the Rings</td></tr>

<tr><td>2. Film broj 2, itd...</td></tr>

Na kraju html datoteke dodajemo još vrlo malo html tagova i završili smo sa svime:

</table>

</html>

Cijela HomeDVD aplikacija nalazi se na CD-u u mapi “Primjeri\Poglavlje 11\HomeDVD”.

11.3. Sažetak

Ovime je završeno i zadnje poglavlje knjige. Sada još slijedi kratki dodatak o programiranju grafike u DOS-u, a nakon dodatka poglavlje s odgovorima na sva pitanja iz prijašnjih poglavlja.

<pb n="275"/>

12. Dodatak A – Osnove DOS grafike

12.1. Inicijaliziranje grafike 276

12.2. Mod 13H 278

<pb n="276"/>

12. Dodatak A – Osnove DOS grafike

U ovom kratkom dodatku pozabavit ćemo se grafičkim programiranjem u DOS-u. Iako je programiranje grafike jedno od najzanimljivijih područja programiranja, ovo će poglavlje zbog nekoliko razloga biti kratko i sažeto. Prvi i glavni razlog je taj što se DOS operativni sustav više ne koristi. Drugi je razlog što se programiranje grafike u Pascalu za DOS temelji na Borlandovu grafičkom sučelju — BGI (Borland Graphics Interface) koje se smatra, a i jest, vrlo stara tehnologija.

12.1. Inicijaliziranje grafike

Osnova bilo kakvoga grafičkog programiranja u DOS-u je inicijalizacija grafike. Inicijaliziranjem se hardver prebacuje u grafički mod rada, a za inicijaliziranje grafike primjenjuje se procedura InitGraph.

Procedura InitGraph prima tri parametra: oznaku grafičkoga pogonskog programa, grafički mod koji želimo inicijalizirati i putanju do BGI pogonskih programa, ako se oni ne nalaze u istoj mapi gdje se nalazi program.

U vrijeme nastanka BGI pogonskih programa, VGA adapter je bio standard, pa su BGI pogonski programi namijenjeni radu s VGA i starijim (EGA, MCGA) adapterima. Korištenjem BGI-a moguće je inicijalizirati VGA grafiku, čime se postavlja rezolucija od 640x480 piksela. U VGA prikazu možemo raditi s vrlo limitiranim brojem boja — 16 boja.

Primjer inicijalizacije grafike prikazan u pomoći Turbo Pascala pokazuje pogrešan način inicijalizacije. Inicijalizacija grafike primjenom autodetekcije postavlja najveću rezoluciju koju podržava grafički adapter, a najveća rezolucija ovisi o sustavu na kojem se program izvršava. Najsigurniji način inicijalizacije je eksplicitno postaviti zahtjev za VGA grafikom.

<pb n="277"/>

Sve grafičke procedure i konstante deklarirane su u graph unitu pa ga stoga moramo navesti u uses listi. Varijable grDriver i grMode potrebne su nam u pozivu procedure InitGraph. Konstante VGA i VGAHi iskoristili smo ovdje za eksplicitno definiranje rezolucije koju želimo: 640x480 piksela i 16 boja.

Poziv procedure InitGraph u ovom će slučaju funkcionirati ako se BGI pogonski programi (datoteke s ekstenzijom .BGI) nalaze u istoj mapi s programom. Ako su na računalu BGI pogonski programi smješteni u drugoj mapi, onda, umjesto praznoga stringa u trećem parametru trebamo navesti putanju mape, na primjer:

InitGraph(grDriver, grMode, ‘C:\TP\BGI’);

Nakon poziva InitGraph procedure, najbolje je provjeriti je li InitGraph procedura uspješno inicijalizirala grafiku. Za tu provjeru služi funkcija GraphResult koja vraća konstantu grOK ako je sve u redu.

Ako funkcija GraphResult vrati vrijednost grOK, to će značiti da je grafika uspješno inicijalizirana i da možemo iskoristiti bilo koju grafičku proceduru za daljnji rad s grafikom. U navedenom primjeru, nakon GraphResult provjere, slijedi jedna zamalo beskonačna repeat-until petlja. Repeat-until petlja koristi se funkcijom KeyPressed koja vraća informaciju o pritisnutoj tipci na tipkovnici.

Dakle, repeat-until petlja u primjeru ponavljat će sve operacije sve dok korisnik ne pritisne neku tipku na tipkovnici. Ako ne iskoristimo tu petlju, sliku koju iscrtamo na ekranu vidjet ćemo vrlo kratko.

Procedura CloseGraph koju vidimo na kraju primjera označuje kraj rada s grafikom i vraća ekran u tekstualni mod prikaza.

Jedina grafička procedura koja je iskorištena u primjeru 12.1. je procedura OutTextXY koja ispisuje string na određenoj poziciji na ekranu. Pozicija teksta, ali i ostale vrijednosti u grafici, definiraju se mjernom jedinicom pod imenom piksel.

Pri iscrtavanju na ekran bitno je znati da se točka (0,0) nalazi u gornjem lijevom kutu ekrana. To znači da će se tekst u primjeru 12.1. ispisati 10 piksela udaljen od gornje i 10 piksela od lijeve strane ekrana. Maksimalna visina i širina ekrana mogu se saznati korištenjem dvije funkcije. Za maksimalnu visinu koristi se funkcija GetMaxY, a za maksimalnu širinu funkcija GetMaxX.

<pb n="278"/>

U primjeru 12.2. moguće je vidjeti da su svi grafički programi u svojoj osnovi istovjetni, barem što se tiče inicijalizacije i završavanja rada s grafikom. Unutar repeat-until petlje koriste se GetMaxX i GetMaxY funkcije kako bi se dobile točke linija koje su unutar okvira odabrane rezolucije.

Program u primjeru 12.2. nasumično iscrtava raznobojne linije na ekranu. Razne boje linija postavljaju se pomoću procedure SetColor. Procedura SetColor ima samo jedan parametar — boju koja će se koristiti za iscrtavanje. Boje su predstavljene brojevima od 0 do GetMaxColor –1. Funkcija GetMaxColor je funkcija koja vraća broj boja koje su podržane u rezoluciji.

Za samo iscrtavanje linije brine se procedura Line koja ima četiri parametra — koordinate početne i završne točke između kojih se crta linija.

Nakon svih iscrtavanja slijedi poziv procedure Delay čiji je jedini parametar broj milisekunda koliko želimo pauzirati izvršavanje sljedeće naredbe.

12.2. Mod 13H

Mod 13H naziv je za grafički mod koji je bio posebno omiljen među programerima grafike jer pruža vrlo jednostavan pristup samim pikselima u memoriji i zato što podržava 256 boja. U modu 13H rezolucija ekrana iznosi 320x200 piksela.

Kad radimo u modu 13H, BGI nam uopće nije potreban (ni iskoristiv) jer do grafičkog sistema dolazimo izravno, bez potrebe za dodatnim pogonskim programima. Da bismo iskoristili mod 13H, potrebno je znati nešto malo assemblera da bismo ga inicijalizirali. Nakon što inicijaliziramo mod 13H, sve što želimo nacrtati na ekranu moramo također napraviti vlastoručno — iscrtavanje piksela, linija, kružnica i slično.

U primjeru 12.3, koji slijedi, bit će prikazan program koji na ekranu iscrtava crveni, plavi i zeleni gradijent. Iscrtavanje na ekranu radi se pomoću posebno isprogramiranih procedura koje ilustriraju samo najosnovniji rad u modu 13H.

Zbog kompleksnosti kvalitetnoga grafičkog rada u DOS-u danas se primjenjuju drugi operativni sustavi, poput Windowsa ili MacOS-a. Na Windows operativnom sustavu postoji veći broj gotovih grafičkih biblioteka koje pružaju mnogo bolju kvalitetu slike i veću jednostavnost korištenja, a to su GDI, GDI+, OpenGL i DirectX.

<pb n="279"/>

<pb n="280"/>

Program prikazan u primjeru 12.3. sastoji se od velikoga broja pojedinosti koje zaslužuju i zahtijevaju dugotrajno i detaljno objašnjenje, ali to izlazi izvan opsega ove knjige. Sada slijedi samo okvirno objašnjenje predstavljenoga programa.

Na početku programa definirana je konstanta VGA s vrijednošću $A000. Vrijednost $A000 adresa je koja označuje početak memorije ekrana i pristupanjem memoriji na toj lokaciji možemo promijeniti piksele koji se prikazuju na ekranu.

Procedura InitMCGA koja je napisana u assembleru služi za prebacivanje u mod 13H i zamjenjuje standardnu proceduru InitGraph, a procedura RestoreText vraća tekstualni mod i zamjenjuje standardnu proceduru CloseGraph.

Procedura PutPixel koristi se posebnim poljem Mem koje ima i poseban način korištenja. Polje Mem posebno je polje koje Pascal programerima omogućuje izravan pristup memoriji. Poljem Mem koristimo se u ovom slučaju jer je svaki piksel u memoriji predstavljen jednim bajtom.

Ekran se u MCGA rezoluciji sastoji od 64 000 piksela (320x200) i svakom pikselu <pb n="281"/>možemo pristupiti jednostavnom formulom:

pozPiksela = Y * 320 + X

Procedura Linija koja iscrtava cijele linije primjenjuje isti princip rada s pikselima kao procedura PutPixel, uz razliku što se Linija koristi procedurom FillChar za iscrtavanje 320 piksela odjednom.

Procedura Boja je najbitnija jer pomoću nje postavljamo nijanse boja koje su nam potrebne. Prvi je parametar indeks boje koju želimo promijeniti, a na raspolaganju su nam brojevi od 0 do 255. Sljedeća su tri parametra R, G i B nijanse boja (Red, Green i Blue). Svaki od navedena tri parametra može primiti vrijednost od 0 do 255. Sve tri vrijednosti postavljene na nulu stvaraju crnu boju, dok sve tri vrijednosti postavljene na 255 stvaraju bijelu boju.

Na kraju, sam program nije pretjerano kompliciran. Nakon inicijaliziranja grafike, prva for petlja inicijalizira paletu boja, a druga petlja koristi se stvorenom paletom boja za iscrtavanje linija na ekranu.

12.3. Sažetak

U ovom su poglavlju predstavljeni najosnovniji dijelovi grafičkoga programiranja u Pascalu, koji su dovoljni za daljnje proučavanje grafičkih procedura. Popis svih grafičkih procedura s primjerima korištenja nalazi se u datotekama pomoći Turbo Pascala.

<pb n="282"/>

<pb n="283"/>

13. Pitanja i odgovori

Poglavlje 1 – Osnove Pascala 284

Poglavlje 4 – Polja i stringovi 292

Poglavlje 5 – Enumeracije, zapisi i tekstualne datoteke 294

Poglavlje 6 – Pokazivači 295

Poglavlje 7 – Osnove Delphi programiranja 296

Poglavlje 8 – Stvaranje korisničkog sučelja 296

Poglavlje 9 – Stvaranje naprednijih aplikacija 297

Poglavlje 10 – Izbornici i alatne trake 298

<pb n="284"/>

13. Pitanja i odgovori

Poglavlje 1 – Osnove Pascala

Pitanje 1: Kojom rezerviranom riječi imenujemo cijeli program?

Cijeli Pascal program imenuje se pomoću rezervirane riječi program.

Pitanje 2: Pripada li dio u kojem deklariramo varijable obveznom ili opcionalnom dijelu programa Pascal?

Dio u kojem deklariramo varijable pripada opcionalnom dijelu programa Pascal.

Pitanje 3: Nabrojite najmanje 5 rezerviranih riječi Pascala.

Pet nasumično odabranih Pascal rezerviranih riječi: begin, end, for, if i while.

Pitanje 4: Kojom se naredbom koristimo za prikaz neke tekstualne informacije na ekranu?

Za prikaz neke tekstualne informacije na ekranu može se iskoristiti naredba Writeln.

Pitanje 5: Kojom kombinacijom tipaka na tipkovnici možemo prikazati rezultat izvršenja programa?

Rezultat izvršenja programa možemo na ekranu prikazati kombinacijom tipaka Alt + F5.

Pitanje 6: Koja naredba ispisuje tekst na ekran bez pomicanja kursora u novi redak?

Naredbom Write ispisujemo tekst na ekran bez pomicanja kursora u novi redak.

Pitanje 7: Nabrojite najmanje tri Pascalova tipa podataka.

Tri nasumično odabrana Pascalova tipa podataka: byte, char, integer.

Pitanje 8: Što je to varijabla?

Varijabla je pojednostavnjeno ime za mjesto u radnoj memoriji računala u koje možemo spremati podatke.

Pitanje 9: Kojom se rezerviranom riječi koristimo za stvaranje varijabli?

Za stvaranje varijabli koristi se rezervirana riječ var.

Pitanje 10: Čemu služi operator pridjeljivanja i kako on izgleda?

Operator pridjeljivanja je :=. Operator pridjeljivanja služi za zapisivanje određene vrijednosti u neku varijablu.

Pitanje 11: Ako na ekran želimo ispisati vrijednost neke varijable, moramo li ime varijable napisati unutar jednostrukih navodnika? Zašto?

Ne, pri ispisu vrijednosti varijable ona ne smije biti navedena unutar jednostrukih navodnika. Sve što napišemo unutar jednostrukih navodnika bit će shvaćeno kao običan tekst, čime će se na ekran umjesto vrijednosti varijable ispisati njezino ime.

Pitanje 12: Koji su identifikatori netočni?

a) krumpir

b) begin

c) 1slovo

d) prvi broj

<pb n="285"/>

e) x!

f) movie

Netočni su identifikatori: b, c, d, e.

Zadatak 1: Napišite program koji ispisuje poruku “Ovo je Pascal program.” na ekran.

program PascalProg;

begin

Writeln(‘Ovo je Pascal program.’);

end.

Zadatak 2: Pronađite pogrešku:

progrem MojPrviProgram

begin.

Writeln(Moj prvi Pascal program.):

end.

Prva linija koda ima dvije pogreške: rezervirana riječ program napisana je pogrešno kao progrem i na kraju linije, iza identifikatora MojPrviProgram nedostaje točka sa zarezom.

program MojPrviProgram;

U drugoj liniji koda, iza rezervirane riječi begin ne smije pisati točka.

begin

Linija koda u kojoj se koristimo naredbom Writeln ima nekoliko pogrešaka. Unutar zagrada nedostaju jednostruki navodnici oko stringa “Moj prvi Pascal program.”. Također, na kraju linije koda, umjesto dvotočja mora pisati točka sa zarezom.

Writeln(‘Moj prvi Pascal program.’);

Zadatak 3: Napišite program koji će ispisivati zbroj dvije Integer varijable na ekran. Varijable se zovu “prvi_broj” i “drugi_broj”. U varijabli “prvi_broj” mora biti zapisan broj 10, a u varijabli “drugi_broj” mora biti zapisan broj 12.

program Zadatak3;

var

prvi_broj: Integer;

drugi_broj: Integer;

begin

prvi_broj := 10;

drugi_broj := 12;

Writeln(‘Zbroj varijabli iznosi: ‘,

prvi_broj + drugi_broj);

end.

Poglavlje 2 – Provjere i petlje

Pitanje 1: Čemu služi rezervirana riječ if?

Rezervirana riječ if služi za provjeru neke vrijednosti.

Pitanje 2: Nabrojite tri relacijska operatora.

Relacijski operatori Pascala: =, >, <, <=, >=.

Pitanje 3: Je li sljedeća provjera varijable “a” u redu?

var

<pb n="286"/>

a: Integer;

begin

if a := 6 then;

Writeln(‘a jednako 6’);

end.

Nije. Pogreška je u operatoru koji se koristi za provjeru vrijednosti, i u istoj liniji s if provjerom imamo viška točku sa zarezom na kraju linije. Točna provjera varijable “a” treba izgledati ovako:

var

a: Integer;

begin

if a = 6 then

Writeln(‘a jednako 6’);

end.

Pitanje 4: Što će ispisati sljedeći program na ekranu?

var

i: Integer;

begin

i := 2;

i := i + 3;

if i = 5 then

Writeln(‘Broj i = 5.’)

else

Writeln(‘Broj i nije jednak 5.’)

end.

Program će na ekran ispisati poruku “Broj i = 5.”.

Pitanje 5: Pogledajte sljedeći program:

var

i: Integer;

begin

i = ?;

if i = 7 then

Writeln(‘Sedam samuraja’)

else if i = 42 then

Writeln(‘Smisao života’)

else if i = 9 then

Writeln(‘Devet krugova pakla’)

else

Writeln(‘Ništa pametno’);

end.

Ako u prvoj liniji koda umjesto upitnika utipkamo broj 9, što će se nakon pokretanja programa ispisati na ekranu? Ako napišemo 101 umjesto upitnika, što će se sve u tom slučaju ispisati na ekranu?

Ako u varijablu “i” unesemo broj 9, na ekran će se ispisati poruka “Devet krugova pakla”. Ako u varijablu “i” unesemo broj 101, na ekranu će se ispisati poruka “Ništa pametno”.

Pitanje 6: Čemu služi operator not?

Operator not služi za invertiranje neke logičke (Boolean) vrijednosti:

True = not False

<pb n="287"/>

False = not True.

Pitanje 7: Što će ispisati ova case provjera?

var

i: Integer;

begin

i := 4;

select case i of

case 1: Writeln(‘Jedan’);

case 2: Writeln(‘Dva’);

case 3: Writeln(‘Tri’);

case 4: Writeln(‘Četiri’);

end select

end.

Ovaj program neće ispisati ništa jer ovo nije način na koji se piše case provjera u Pascalu.

Pitanje 8: Što radi sljedeći dio koda?

var

i: Integer;

const

tekst_poruke = ‘Pascal’;

begin

for i := 1 to 5 do

Writeln(‘tekst_poruke’);

end.

Ovaj će program pet puta na ekran ispisati tekst “tekst_poruke” jer je naveden unutar navodnika. Kad bismo izostavili navodnike, na ekran bi se ispisao tekst definiran u konstanti.

Pitanje 9: Što će napraviti sljedeći program nakon što ga pokrenemo?

var

i: Integer;

begin

i := 10;

while i < 20 do

begin

Writeln(‘Pascal’);

end;

Ovaj će program ispisivati riječ “Pascal” beskonačno mnogo puta, sve dok ne resetiramo računalo jer nigdje unutar while petlje ne mijenjamo njezin uvjet, ne mijenjamo vrijednost varijable i.

Pitanje 10: Što radi sljedeći program?

var

i: Integer;

begin

i := 60;

repeat

i := i + 1;

Writeln(i);

until i >= 60;

end.

Ispisuje broj 61 na ekran i završava s radom.

<pb n="288"/>

Zadatak 1: Napišite program koji će od korisnika tražiti unos broja i provjeravati je li uneseni broj pozitivan, negativan ili je jednak nuli.

program Zadatak1;

var

broj: Integer;

begin

Write(‘Unesite neki broj: ‘);

Readln(broj);

if broj < 0 then

Writeln(‘Broj je negativan.’)

else if broj = 0 then

Writeln(‘Broj je jednak nuli.’)

else if broj > 0 then

Writeln(‘Broj je pozitivan.’);

end.

Zadatak 2: Napišite program koji će od korisnika tražiti unos broja i provjeravati je li uneseni broj paran ili neparan.

program Zadatak2;

var

broj: Integer;

begin

Write(‘Unesite neki broj: ‘);

Readln(broj);

if broj mod 2 = 0 then

Writeln(‘Broj je paran.’)

else

Writeln(‘Broj je neparan.’);

end.

Zadatak 3: Napišite program koji će pomoću for petlje dvadeset puta na ekran ispisati poruku “Turbo Pascal petlja”.

program Zadatak3;

var

i: Integer;

begin

for i := 1 to 20 do

Writeln(‘Turbo Pascal petlja’);

end.

Zadatak 4: Napišite program koji će pomoću repeat-until petlje ispisati na ekran brojeve od 1 do 10, ali obrnutim redoslijedom –10, 9, 8, .., 1.

program Zadatak4;

var

i: Integer;

<pb n="289"/>

begin

i := 10;

repeat

Writeln(i);

Dec(i);

until i < 1;

end.

Zadatak 5: Napišite program koji će iskoristiti beskonačnu while petlju kako bi od korisnika stalno tražio unos nekog imena. Program mora završiti s radom nakon što korisnik utipka riječ “kraj” (sve malim slovima).

program Zadatak5;

var

s: string;

begin

while s <> ‘kraj’ do

begin

Write(‘Unesite ime: ‘);

Readln(s);

if s <> ‘kraj’ then

Writeln(s);

end;

Writeln(‘Kraj programa’);

end.

Poglavlje 3 – Strukturirano programiranje

Pitanje 1: Čemu služi uses lista?

Uses lista služi za uključivanje dodatnih unita u naš program (dodatnih biblioteka funkcija).

Pitanje 2: Kojom procedurom možemo izbrisati cijeli sadržaj ekrana? U kojem se unitu nalazi ta procedura?

Sadržaj cijelog ekrana možemo izbrisati pomoću procedure ClrScr koja se nalazi u Crt unitu.

Pitanje 3: Što je funkcija?

Funkcija je posebna vrsta procedure koja nakon svojeg završetka vraća rezultat onom dijelu programa koji je pozvao funkciju.

Pitanje 4: Nabrojite tri standardne funkcije Pascala.

Neke od standardnih funkcija Pascala su: Abs, Cos, Round, Sin, Sqr, Sqrt, Trunc.

Pitanje 5: Koliko parametara ima sljedeća procedura?

procedure Ispis;

begin

end;

Procedura Ispis nema ni jedan parametar.

Pitanje 6: Ako deklariramo varijablu unutar neke procedure, kako se zove takva varijabla i možemo li tu varijablu koristiti u nekoj drugoj proceduri?

Varijabla deklarirana unutar neke procedure zove se lokalna varijabla i takvom varijablom možemo se koristiti samo unutar procedure u kojoj je deklarirana.

<pb n="290"/>

Pitanje 7: Gdje se deklariraju globalne varijable?

Globalne se varijable deklariraju unutar glavnog var bloka.

Pitanje 8: Kako se vrijednosti prenose u neku proceduru ili funkciju?

Vrijednosti se u neku proceduru mogu prenijeti preko liste parametara.

Pitanje 9: Kojom rezerviranom riječi stvaramo prijevremenu deklaraciju procedure ili funkcije?

Prijevremenu deklaraciju procedure ili funkcije stvaramo pomoću rezervirane riječi forward.

Pitanje 10: Što radi sljedeća funkcija?

function Max(broj: Integer): Integer;

begin

Max := broj;

end;

Funkcija Max uvijek vraća broj koji joj proslijedimo u parametru “broj”.

Zadatak 1: Napišite proceduru koja se zove “Ime” i koja će vaše ime i prezime ispisivati na ekran.

program Zadatak1;

procedure Ime;

begin

Writeln(‘Pascal/Delphi Programer’);

end;

begin

Ime;

Readln;

end.

Zadatak 2: Napišite proceduru koja će preko liste parametara primati jedan broj. Procedura mora na ekran tekstualno ispisati je li riječ o negativnom broju, pozitivnom ili o nuli.

program Zadatak2;

var

broj: Integer;

procedure TestBroja(NekiBroj: Integer);

begin

if NekiBroj < 0 then

Writeln(‘Broj je negativan.’)

else if NekiBroj = 0 then

Writeln(‘Broj je jednak nuli.’)

else if NekiBroj > 0 then

Writeln(‘Broj je pozitivan.’);

end;

begin

Write(‘Unesite neki broj: ‘);

Readln(broj);

TestBroja(broj);

<pb n="291"/>

Readln;

end.

Zadatak 3: Napišite funkciju koja će preko liste parametara primati dva cijela broja. Funkcija mora obvezno provjeriti jesu li oba broja u rasponu Byte vrijednosti (0—255). Ako su oba broja u tom rasponu, funkcija mora provjeriti i vratiti veći od dvaju brojeva. Ako je neki od brojeva izvan Byte raspona, funkcija mora ispisati poruku o pogrešci i završiti s radom.

program Zadatak3;

var

broj: Integer;

broj2: Integer;

max: Integer;

function MaxByte(Broj1, Broj2: Integer): Byte;

begin

MaxByte := 0;

if (Broj1 < 0) or (Broj1 > 255) then

begin

Writeln(‘Pogresna vrijednost’);

Exit;

end;

if (Broj2 < 0) or (Broj2 > 255) then

begin

Writeln(‘Pogresna vrijednost’);

Exit;

end;

if Broj1 > Broj2 then

MaxByte := Broj1

else

MaxByte := Broj2;

end;

begin

Write(‘Unesite prvi broj: ‘);

Readln(broj);

Write(‘Unesite drugi broj: ‘);

Readln(broj2);

max := MaxByte(broj, broj2);

if max <> 0 then

Writeln(‘Veci broj je broj ‘, max, ‘.’);

Readln;

end.

Zadatak 4: Napišite proceduru koja će od korisnika tražiti unos tri imena. Procedura mora spremiti učitana imena u tri različite globalne varijable.

program Zadatak4;

var

ime1: string;

<pb n="292"/>

ime2: string;

ime3: string;

procedure Ucitaj;

begin

Write(‘Unesite neko ime: ‘);

Readln(ime1);

Write(‘Unesite neko ime: ‘);

Readln(ime2);

Write(‘Unesite neko ime: ‘);

Readln(ime3);

end;

begin

Ucitaj;

end.

Zadatak 5: Napišite funkciju koja će preko liste parametara primati dva cijela broja. Funkcija mora vratiti rezultat dijeljenja tih dvaju brojeva. Prije nego ih krene dijeliti, funkcija se mora osigurati da su oba broja veća od nule.

program Zadatak5;

var

broj1: Integer;

broj2: Integer;

function Dijeli(broj1, broj2: Integer): Integer;

begin

if (broj1 > 0) and (broj2 > 0) then

Dijeli := broj1 div broj2

else

Dijeli := 0;

end;

begin

broj1 := 20;

broj2 := 5;

Writeln(Dijeli(broj1, broj2));

Readln;

end.

Poglavlje 4 – Polja i stringovi

Pitanje 1: U kojoj se situaciji obično koristimo poljem?

Kada moramo raditi s većim brojem varijabli istog tipa.

Pitanje 2: Kojom rezerviranom riječi deklariramo polje?

Polje deklariramo pomoću rezervirane riječi array.

Pitanje 3: Sastoji li se sljedeće polje od 6 ili 7 elemenata?

var

mojiPodaci: arrey[1..6] of Integer;

Ovo se polje ne sastoji ni od jednog elementa jer je rezervirana riječ array pogrešno napisana.

<pb n="293"/>

Pitanje 4: Ako deklariramo polje pod imenom “brojevi” od 6 Integer varijabli s rasponom indeksa od 1 do 6, kako ćemo u prvu varijablu polja upisati broj 100?

brojevi[1] := 100;

Pitanje 5: Ako deklariramo polje od 5 Integer varijabli:

var

polje: array[1..5] of Integer;

kako ćemo ispisati zbroj prva tri elementa polja?

Writeln(polje[1] + polje[2] + polje[3]);

Pitanje 6: Kojim se funkcijama možemo koristiti kada želimo dobiti indeks prvog i zadnjeg elementa polja?

Za dobivanje indeksa prvog elementa koristi se funkcija Low. Za dobivanje indeksa zadnjeg elementa koristi se funkcija High.

Pitanje 7: Od koliko se Char elemenata sastoji string u Pascalu?

Pascal string sastoji se od 256 elemenata, 256 znakova.

Pitanje 8: Čemu služi prvi znak Pascal stringa, znak pod indeksom 0?

U tom se znaku čuva informacija o duljini stringa.

Pitanje 9: Na koja dva načina možemo provesti konkatenaciju stringova?

Konkatenaciju stringova možemo provesti pomoću operatora za konkatenaciju (+) ili pomoću funkcije Concat.

Pitanje 10: Na koja dva načina možemo provjeriti duljinu stringa?

Duljinu stringa možemo provjeriti pomoću funkcije Length i pomoću nultog indeksa string varijable: Ord(string[0]).

Zadatak 1: Napišite proceduru koja će sva velika slova “A” u nekom stringu pretvoriti u mala slova “a”.

program Zadatak1;

var

ime: string;

procedure slovoA;

var

i: Integer;

begin

for i := 1 to Length(ime) do

begin

if ime[i] = ‘a’ then

ime[i] := ‘A’;

end;

end;

begin

ime := ‘abrakadabra tra la la’;

slovoA;

Writeln(ime);

Readln;

end.

Zadatak 2: Napišite proceduru koja će na ekran ispisivati samo prvo i zadnje slovo stringa.

<pb n="294"/>

program Zadatak2;

var

ime: string;

procedure prvoZadnje;

begin

Writeln(ime[1], ime[Length(ime)]);

end;

begin

ime := ‘abrakadabra tra la la kraj’;

prvoZadnje;

Readln;

end.

Poglavlje 5 – Enumeracije, zapisi i tekstualne datoteke

Pitanje 1: Kojom rezerviranom riječi stvaramo novi tip podataka u Pascalu?

Novi tip podataka stvaramo pomoću rezervirane riječi type.

Pitanje 2: Što nije u redu sa sljedećom listom vrijednosti?

TMjesec = Sijecanj, Veljaca, Ozujak;

Vrijednosti liste moraju biti navedeni unutar zagrada.

Pitanje 3: Kako stvaramo set podataka?

Najprije stvaramo enumerirani tip podataka, a nakon toga koristimo se rezerviranom riječi set na enumeriranom podatku.

Pitanje 4: Pri korištenju set varijable koju proceduru možemo iskoristiti ako neku vrijednost želimo uključiti u set?

Možemo iskoristiti proceduru Include.

Pitanje 5: Kojom rezerviranom riječi stvaramo novi zapis?

Novi zapis stvaramo pomoću rezervirane riječi record.

Pitanje 6: Što mora obvezno pisati na kraju definicije zapisa?

Obvezno mora pisati oznaka za kraj bloka — “end;”.

Pitanje 7: Kojim se tipom podataka koristimo kada želimo pristupiti tekstualnoj datoteci na disku?

Moramo se koristiti tipom podataka Text.

Pitanje 8: Kojom procedurom odabiremo datoteku kojom se želimo koristiti?

Datoteke se odabiru pomoću procedure Assign.

Pitanje 9: Nakon što otvorimo datoteku, koju proceduru moramo pozvati na kraju rada s datotekom?

Moramo pozvati proceduru Close za zatvaranje datoteke.

Pitanje 10: Što je to {$tekst}?

Naredba unutar vitičastih zagrada zove se kompilatorska direktiva i služi za promjenu rada kompilatora.

Zadatak 1: Napišite program koji će deset puta u datoteku “C:\Lista.txt” upisati tekst “Linija 1”, “Linija 2”, “Linija 3” itd.

program Zadatak1;

<pb n="295"/>

var

f: Text;

i: Integer;

begin

Assign(f, ‘c:\Lista.txt’);

Rewrite(f);

for i := 1 to 10 do

Writeln(f, ‘Linija ‘, i);

Close(f);

end.

Zadatak 2: Napišite program koji će učitavati tekst iz neke datoteke na disku i prikazivati ga na ekranu. No, program ne smije prikazivati samo tekst iz datoteke na ekranu nego ispred svake linije teksta mora navesti redni broj linije, te na kraju učitavanja datoteke mora ispisati poruku “Kraj.”.

program Zadatak2;

var

f: Text;

i: Integer;

s: string;

begin

Assign(f, ‘c:\Lista.txt’);

Reset(f);

i := 0;

while not eof(f) do

begin

Inc(i);

Readln(f, s);

Writeln(i, ‘. ‘, s);

end;

Writeln(‘Kraj’);

Close(f);

end.

Poglavlje 6 – Pokazivači

Pitanje 1: Čemu služi operator @?

Operator @ koristimo za dobivanje memorijske adrese neke varijable.

Pitanje 2: Kada iza imena pokazivača napišemo ^, što dobijemo?

Dobijemo vrijednost iz memorije na koju pokazivač pokazuje.

Pitanje 3: Ako navedemo samo ime pokazivača, što dobijemo?

Ako navedemo samo ime pokazivača, dobit ćemo memorijsku adresu na koju pokazivač pokazuje.

Pitanje 4: Čemu služi procedura New?

Služi za stvaranje nove dinamičke varijable.

Pitanje 5: Čemu služi procedura Dispose?

<pb n="296"/>

Služi za brisanje dinamičke varijable iz memorije.

Pitanje 6: Čemu služi procedura GetMem?

Služi za alociranje dijela dinamičke memorije kojom ćemo se koristiti pomoću generičkog pokazivača.

Pitanje 7: Čemu služi procedura FreeMem?

Procedura FreeMem služi za oslobađanje dijela memorije koju zauzmemo primjenom GetMem procedure.

Poglavlje 7 – Osnove Delphi programiranja

Pitanje 1: Kako se zove dio Delphi razvojne okoline na kojem su popisane komponente kojima se koristimo tijekom dizajna aplikacija?

Paleta komponenata.

Pitanje 2: Koju ekstenziju ima glavna datoteka Delphi projekta?

Glavna datoteka projekta ima ekstenziju *.dpr.

Pitanje 3: Koja je razlika između opcija Compile i Build pri stvaranju izvršne datoteke?

Razlika je u tome što Build kompilira sve datoteke koje čine projekt, dok Compile kompilira samo one koje su promijenjene od zadnje kompilacije.

Pitanje 4: Kojom se tipkom iz razvojne okoline Delphija pokreće aplikacija?

Tipkom F9 (opcija Run -> Run).

Pitanje 5: Koja se Delphi procedura primjenjuje za prikazivanje jednostavne tekstualne poruke na ekranu?

Koristi se procedura ShowMessage.

Zadatak 1: Potrebno je napraviti program koji se zove “Info” i koji na klik gumba pomoću poruke prikazuje na ekranu autorovo ime i prezime.

procedure TForm1.Button1Click(Sender: TObject);

begin

ShowMessage(‘Delphi Programer’);

end;

Poglavlje 8 – Stvaranje korisničkog sučelja

Pitanje 1: Kako najbrže dodati novu komponentu na formu?

Treba dvaput kliknuti na ikonu željene komponente na paleti komponenata.

Pitanje 2: Koje je apsolutno najbitnije svojstvo svake komponente?

Najbitnije svojstvo svake komponente je svojstvo Name, ime komponente.

Pitanje 3: Navedite tri osnovna svojstva komponenata.

Neka od osnovnih svojstava komponenata su svojstva Name, Top, Left, Width, Height, Caption.

Pitanje 4: Za što se obično koristi TLabel komponenta?

TLabel komponenta se obično koristi za opisivanje druge komponente koja to ne može učiniti sama.

Pitanje 5: Za što se koristimo TEdit komponentom?

TEdit komponentom se koristimo kada želimo dobiti neku tekstualnu informaciju od korisnika.

<pb n="297"/>

Pitanje 6: Kako se zove svojstvo TEdit komponente u koje se zapisuje tekst pri unosu?

Svojstvo se zove Text.

Pitanje 7: Kada ćemo Enabled svojstvo neke komponente postaviti na False?

Svojstvo Enabled obično se postavlja na False u situacijama kada korištenje te komponente nema svrhe ili kada može dovesti do pogreške u aplikaciji.

Pitanje 8: Čemu služi TRadioButton komponenta?

TRadioButton komponenta služi da bismo korisniku omogućili odabir jedne od nekoliko opcija.

Pitanje 9: Kojim operatorom možemo jedan tip objekata pretvoriti u drugi?

Delphi operatorom as.

Pitanje 10: Za što možemo iskoristiti svojstvo Tag?

Svojstvo Tag možemo iskoristiti za upis brojčane vrijednosti koja nam naknadno može pomoći u programiranju za ubrzanje aplikacije ili skraćivanje pisanja izvornog koda.

Zadatak 1: Napravite program koji će na glavnoj formi imati četiri gumba. Klikom na gumb njegov se Caption tekst mora preslikati na naslovnu traku aplikacije.

procedure TForm1.Button1Click(Sender: TObject);

begin

Caption := (Sender as TButton).Caption;

end;

Poglavlje 9 – Stvaranje naprednijih aplikacija

Pitanje 1: Koje dvije komponente mogu sadržavati druge komponente, a koristimo ih za grupiranje komponenata?

TGroupBox i TPanel komponente.

Pitanje 2: Kojim prefiksom započinju konstante boja u Delphiju?

Konstante boja u Delphiju započinju prefiksom “cl”.

Pitanje 3: Kako se zove boja koja se koristi u cijelom operativnom sustavu za bojenje površine komponenata?

Boja koja se koristi za bojenje površine komponente zove se clBtnFace.

Pitanje 4: Kako se zove svojstvo u kojemu je zapisana boja forme?

Svojstvo u kojem je zapisana boja forme zove se Color.

Pitanje 5: Što će se dogoditi ako unutar procedure koja pripada formi Form2 napišemo:

Self.Color := clRed;

Promijenit će se boja forme Form2.

Pitanje 6: Ako želimo podesiti ponašanje komponente prigodom promjene veličine forme, kojim ćemo se svojstvom morati koristiti?

Morat ćemo se koristiti svojstvom Anchors.

Pitanje 7: Ako želimo natjerati da se tijekom promjene veličine forme, mijenjaju i visina i širina, koje vrijednosti moramo odabrati u Anchors svojstvu?

Morat ćemo odabrati sve četiri raspoložive vrijednosti.

Pitanje 8: U koja su dva svojstva zapisane širina i visina klijentskog dijela forme?

<pb n="298"/>

U svojstvima ClientWidth i ClientHeight.

Pitanje 9: Ako na TPanel komponentu dodamo gumb, hoće li TPanel komponenta biti Owner ili Parent gumba?

TPanel komponenta bit će Parent gumba.

Pitanje 10: U kojem su svojstvu TListBox komponente zapisani tekstualni podaci koje vidimo na ekranu?

U Items svojstvu.

Pitanje 11: Kojim alatom možemo tijekom dizajniranja aplikacije dodati podatke u listu?

Editorom liste stringova.

Pitanje 12: U kojem su svojstvu zapisane informacije o odabranim podacima liste?

U svojstvu Selected.

Zadatak 1: Ministarstvu za usavršavanje brojenja na prste do 10 potreban je program koji će na klik gumba u jednu listu upisati brojeve od 1 do 10. Uz tu opciju, te vitalne podatke program mora moći spremiti na disk u datoteku “C:\TopSecret.txt”.

procedure TForm1.Button1Click(Sender: TObject);

var

i: Integer;

begin

for i := 1 to 10 do

ListBox1.Items.Add(IntToStr(i));

ListBox1.Items.SaveToFile(‘c:\TopSecret.txt’);

end;

Zadatak 2: Hrvatski institut za istraživanje neparnih brojeva (HIINB) treba prerađenu verziju programa iz zadatka 1. Ta verzija programa mora imati gumb koji će sve neparne brojeve prebaciti u drugu listu i spremiti te podatke na disk u datoteku “C:\Neparni.txt”.

procedure TForm1.Button2Click(Sender: TObject);

var

i: Integer;

begin

for i := 0 to ListBox1.Items.Count - 1 do

begin

if Odd(StrToInt(ListBox1.Items[i])) then

ListBox2.Items.Add(ListBox1.Items[i]);

end;

ListBox2.Items.SaveToFile(‘c:\Neparni.txt’);

end;

Poglavlje 10 – Izbornici i alatne trake

Pitanje 1: Kojom komponentom se u Delphiju stvara glavni izbornik aplikacije?

Glavni izbornik aplikacije stvara se pomoću TMainMenu komponente.

Pitanje 2: Kojim se alatom stvaraju i podešavaju opcije na glavnom izborniku?

Opcije na glavnom izborniku stvaraju se i podešavaju pomoću dizajnera izbornika.

Pitanje 3: Nabrojite četiri standardna dijaloška okvira.

<pb n="299"/>

TOpenDialog (otvaranje), TSaveDialog (snimanje), TColorDialog (odabir boje) i TFontDialog (odabir fonta).

Pitanje 4: Kojom se funkcijom prikazuju standardni dijaloški okviri na ekran?

Standardni dijaloški okviri na ekran se prikazuju pomoću funkcije Execute.

Pitanje 5: Čemu služi procedura Assign u Delphiju?

Procedura Assign služi kopiranju svojstava drugog objekta koji je istog tipa.

Pitanje 6: Kojim svojstvom alatne trake povezujemo alatnu traku s listom slika?

Alatna traka povezuje se s listom slika putem Images svojstva.

Pitanje 7: Kojom se funkcijom koristimo kada želimo saznati postoji li neka datoteka na disku?

Za provjeru postoji li datoteka na disku koristi se funkcija FileExists.

Pitanje 8: Unutar kojeg događaja možemo zaustaviti zatvaranje aplikacije?

Zatvaranje aplikacije možemo zaustaviti unutar OnCloseQuery događaja.

Pitanje 9: Kako možemo zaustaviti zatvaranje aplikacije?

Zatvaranje aplikacije možemo zaustaviti tako da u CanClose parametar događaja OnCloseQuery upišemo vrijednost False.

Pitanje 10: Pogledajte sljedeći primjer koda i odgovorite na pitanje: Što će se zapisati u varijablu "s"?

var

s: string;

begin

s := Format(‘%d, %d, %d...’, [1, 2, Trunc(PI)]);

end;

U varijablu “s” zapisat će se tekst “1, 2, 3...” (bez navodnika).

Pitanje 11: Što je to glyph?

Glyph je slika (bitmapa) malenih dimenzija koja se koristi na izbornicima ili alatnim trakama za prikaz neke opcije.

ŠKOLSKA KNJIGA, d.d.

Zagreb, Masarykova 28

Za izdavača

ANTE ŽUŽUL, prof.

Tisak dovršen u listopadu 2004.



Previous page

Next page


Ivan Hladni [2004], Paskal i Delphi programiranje (Školska knjiga, Zagreb), 299 pp. [word count] [Hladni_Pascal].

© 2006-2009 by the Institute of Croatian Language and Linguistics

Powered by PhiloLogic
with extensions by D. Ćavar