Aki először találkozik a Delphivel, vagy még keveset tud róla, talán tanulságosnak találhatja, ha végigcsinálja ezt a tutorialt. Feltételezzük az alapvető programozói tudást, ennek birtokában valószínűleg az új programnyelvvel kapcsolatos kezdeti kérdések közül sokra választ kaphat az olvasó. Nem törekszünk a teljességre, inkább ízelítőt szeretnénk adni a nyelv és a fejlesztői környezet kínálta lehetőségekről.
Válasszuk ki a File menüből a New Applicationt. A fejlesztői környezet indításakor erre nincs is szükség, alapból egy üres formot tartalmazó projectet kapunk. Ezt akár rögtön le is fordíthatjuk és futtathatjuk: működőképes alkalmazásunk van. Próbaképp rakhatunk komponenseket is a formra, futtatáskor mind meg fog jelenni.
A Component menüből a New Component pontot választva egy dialógusablak jelenik meg, itt állítsuk be az alábbiakat: Ancestor: TButton, Name: TButtonKa, Palette page: Samples, Unit file: ButtonKa.pas. Ezután installáljuk az alapértelmezésben felkínált helyre, tipikusan a C:\Program Files\Borland\Delphi5\Lib\dclusr50.dpk-ba. Ha mindent jól csináltunk, a komponenspalettán a Samples fülön megjelent a ButtonKa. Tegyünk egyet a formunkra!
A frissen létrehozott komponensünk forráskódját nyissuk meg. (Tipikusan: C:\Program Files\Borland\Delphi5\Lib\ButtonKa.pas.) Adjunk a komponensünkhöz két új tulajdonságot, egy szám és egy szöveg típusút; nevük legyen szam ill. szoveg.
A hozzájuk tartozó változókat ill. eljárásokat és függvényeket deklaráljuk...
majd implementáljuk.
Próbaképp fordítsuk le a programot, hogy mindent jól csináltunk-e. Valami ilyesmit fogunk látni:
Most az object inspectorban a Form1 events fülét nyissuk meg és az OnCreate-hez rendeljünk egy Kezdet nevű eljárást, és írjuk a törzsébe:
Ha a "ButtonKa1." kiírása után várunk egy kicsit, megjelenik egy lista, amiről kiválaszthatjuk többek között a szam és a szoveg tulajdonságokat. Ebből is látszik, hogy a fejlesztői környezet már felismerte ezeket, és - mivel published-ként deklaráltuk őket - fejlesztési időben már a rendelkezésünkre bocsátotta.
Ha most újra lefordítjuk a programot, ezt látjuk:
Most adjunk a formunkhoz egy soreditort a standard komponens fülről, majd az Object Inspectorban rendeljünk hozzá az editor OnChange eventjéhez egy UjSzoveg nevű eljárást:
Ha most lefordítjuk a programot, már szerkeszthetjük is a gombunk szövegét az editorból. Gyakorlásképp az olvasó megpróbálhatja egyénileg megvalósítani, hogy a gombra klikkelve növekedjen a számláló, a formra klikkelve pedig csökkenjen. Egy egyszerű megoldás, hogy a ButtonKa1 OnClick eseményéhez rendeljük az alábbi eljárást:
A Form1 OnClick eseménye pedig legyen:
Ezen a ponton már ilyet is láthatunk:
Megjegyzés: A form csak akkor kapja meg a klikkelés eseményét, ha az nem a gombon vagy az editoron történt.
Figyeljük meg, hogy pl. az inc eljárást nem tudjuk használni a fenti esetben - ebben pl. különböznek a propertyk a tagváltozóktól. Nyilván nem lenne elvi akadálya, hogy pl. érték szerinti paraméternek átadjunk egy propertyt, de az inc eljárásnál nem is erről lenne szó... Mindenki tudja, milyen paraméterátadások vannak Pascalban?
Tegyünk fel két radio buttont a formunkra, az elsőnek "Button" legyen a Caption-je, a másodiknak "Edit". Rendeljünk hozzájuk OnClick üzenetkezelőket, az elsőhöz a SelBut-ot, a másodikhoz a SelEdit-et. Írjunk az eljárások törzsébe egy-egy pontosvesszőt, ugyanis automatikusan törlődnek, ha üresen hagyjuk őket. A formhoz rendeljünk egy Lenyom nevű eljárást az OnMouseDown eseményhez. (Az OnMouseDown eseményt egy egérgomb lenyomása váltja ki, ellentétben a már ismert OnClickkel, amely a bal egérgombbal történt klikkelést jelenti. Előbbi megkapja paraméterként az egér helyét, utóbbi nem.)
Tegyünk be egy AC: TControlClass típusú private tagot...
...majd inicializáljuk a Kezdet-ben:
Ha nagyon ráérünk, akkor állítsuk a RadioButton1 Checked propertyjét True-ra.
(Egyébként a TControlClass definíciója: type TControlClass = class of TControl; ezt be is írhatjuk, de fölösleges.)
Módosítsuk az UjSzoveg eljárást, majd a SelBut-ot és a SelEdit-et, valamint a Lenyom-ot, hogy a végeredmény az alábbi legyen:
A Lenyom eljárásban érdekesség, hogy bár az "uc" új kontrollnak mindenképp van Caption propertyje, mégis a főablak Captionje változik, ugyanis a TControlnak önmagában nincs. Nem kapunk hibaüzenetet, hisz látszik a Caption tag, csak nem azt látjuk, amelyiket szeretnénk. Kiváló példa arra, hogy hogyan okozhat nehezen felderíthető programozási hibát a with utasítás használata.
Így néz ki a program:
A formunkhoz adjunk egy MainMenu standard komponenst. Mindegy, hogy hova helyezzük az ikont, a menü mindenképp a form tetején fog megjelenni. Az ikonra jobb gombbal kattintva válasszuk a menu designert. Itt szerkeszthetjük a menüt, adjunk hozzá pl. egy "a" és egy "b" menüt, alájuk pedig tetszőlegesen elosztva pl. "aa", "ab", "ac", "ba" menüpontokat. Válasszuk ki az "aa"-t az object inspectorban (pl. helyben klikkeljünk rá) és rendeljük hozzá az OnClick eseményéhez:
Futtassuk a programot és próbáljuk ki.
A File menüből válasszuk ki a New Form menüpontot. Az új formra tegyünk rá egy editort. Menjünk vissza a Form1-hez (pl. használjuk a View menüt), majd a file menü use unit pontját kiválasztva adjuk hozzá a unit2-t. Így a főform látni fogja a második form minden public tagját és eljárását. Hogy megjelenítsük, az "ab" menüponthoz rendeljük az alábbi eljárást:
Így máris kommunikáltunk vele. A ShowModal akkor ér véget, amikor lezárul a Form2. Ha nem modálisan akarjuk megjeleníteni, akkor használjuk a Show-t. Kétirányú kommunikációra példa:
Cseréljük le ez előbbi eljárás törzsét az alábbira:
Tegyünk egy gombot a Form2-re, az OnClick-je legyen:
Ha itt megfeledkezünk a use unit-ról, akkor sincs baj, a Delphi fordításkor rögtön felajánlja, hogy megcsinálja helyettünk.
Tegyünk a Form2-re még két editort, egy címkét és egy gombot, majd a gomb üzenetkezelője legyen az alábbi:
Ha a programot a szerkesztőből indítjuk, akkor alaphelyzetben minden kivétel megállítja a futást és elindítja a debuggert. Ha csak a kész .exe-t futtatjuk, akkor a feldolgozatlan hibák csak üzenetablakot dobnak (ld. osztás nullával), alapértelmezésben a program nem áll le.
Hozzunk létre pl. egy Paradox 7 adatbázist a Database Desktoppal, adjunk hozzá néhány mezőt... lehet próbálkozni. Pl. a mezőnevek legyenek A, B és C, A típusa legyen long int és ez legyen kulcs, B típusa legyen Alpha és hossza 42, C típusa legyen number. Ha kész vagyunk vele, mentsük el és a Delphiben nyissuk meg a form wizardot, és generáltassunk hozzá egy formot. Ilyen egyszerű az egész. Pl. eddigi projectünkhöz hozzáadhatjuk, ha nem engedjük neki, hogy main formot generáljon (az az alapértelmezett); generáljunk formot és data module-t is (ezt mind az utolsó oldalon lehet beállítani a wizard-ban).
A Unit1-be tegyük bele a use unit4-et, majd az "ac" menüponthoz rendeljük hozzá:
Végül a "ba" menüponthoz:
Az új form editoraihoz közvetlenül hozzáférünk; azonban az adatokat inkább a data module-on keresztül érjük el, ha a use unit3-at beraktuk - a DataModule3 ill. annak Table1 tagja rendelkeznek a megfelelő eljárásokkal.
A Delphi-ben talán kissé szokatlan módon, kódolással fogunk elkészíteni egy saját komponenst, mely később a VCL szerves részét képezi, és az alkalmazások formjára felpakolható, azokon látható, használható.
A komponens egy hétszegmenses kijelző lesz, mely egyetlen számjegyet képes ábrázolni, de több ilyen komponens egymás mellé pakolásával előállítható egy például egy digitális óra.
Vágjunk bele. A New menüpontban nyissunk egy új unitot. A komponensünk ebből az egyetlen forrásból fog állni. Legyen a neve LEDSSD (LED Seven Segment Display). Hozzunk létre benne egy osztályt, mely a TLEDSSD nevet viseli és a TGraphicControl osztályból származik (mivel grafikus komponenst kreálunk). Ahhoz, hogy ebből az osztályból származtathassunk fel kell tüntetnünk a Controls unitot a uses kulcsszó után. A TGraphicControl osztály tartalmaz egy Canvas tagot, amire rajzolni fogunk. Valamint van neki Paint metódusa, aminek felüldefiniálásával megjeleníthetjük a saját komponensünket jellemző grafikát.
Az osztály deklarációja alá az interface részbe kell még egy procedure Register; szignatúrát rakni. Ezt ki is fejthetjük az implementation rész legelején. A RegisterComponent végzi el a komponensünk regisztrációját a komponenspalettán. Ennek használatához be kell írni a Classes unitot is a uses részbe. Első paraméter a paletta neve, legyen most "Sajat", második a Típus - amit regisztrálni szeretnénk - szögletes zárójelek között megadott megnevezése.
Írjuk meg az osztályunkhoz a Create konstruktort és a Destroy destruktort is. Az előbbi kapjon egy TComponent típusú COwner paramétert, ez lesz a komponensünk szülőobjektuma, ami adott esetben pl egy Form. A konstruktorban már elérhetjük a TGraphicControl-ban deklarált adattagokat. Hogy milyen mezők vannak, nézzük meg a help-ben. Inicializáljuk komponensünket a szülő konstruktorával, majd állítsunk be a Width és Height mezőknek egy alapértelmezett értéket. Az így elkészített komponens már életképes. Mentsük el a fájlt, majd a Component menü Install Component menüpontjában a forrásfájlunkat kiválasztva telepíthetjük.
Miután installáltuk, nyithatunk egy új Form-ot, és arra fel is rakhatjuk, bár sokat még nem látunk belőle...
Jöjjön az érdemi munka. Tervezzük meg konkrétabban a komponens képességeit. Az előzőekben leírtak egy általános grafikus komponens elkészítésénél is járható út a kezdeteknél. Nyilván előtte át kell gondolni mi az ami már meg van valósítva egy létező komponensben, amit szülőként használhatunk. Nekünk most a nyers grafikus komponens felelt meg a legjobban, mivel csak egy Canvassal bővíti a TComponentet.
Nézzük mit várunk el a kijelzőtől.
Nyilvánvaló, hogy a kijelezni kívánt számjegyet el kell tárolni egy belső adattagban. Vegyük fel a Value: Byte mezőt, és deklaráljuk a setter metódust. Ezután először a színezéseket valósítsuk meg. Ehhez vegyünk fel újabb TColor típusú adattagokat CASegment, CISegment, CBackground néven. Ezekhez deklaráljuk a setter eljárásokat is, valamint published propertyket is létre kell hozni hozzájuk, melyben megadjuk, hogy olvasásnál a mező értékét adja vissza, írásnál pedig a settert hívja meg. A konstruktorban adjunk ezeknek a mezőknek egy alapértelmezett színt: CASegment = clLime; CISegment = clGreen; CBackground = clBlack;. Valamint definiáljuk felül az ősosztály Paint metódusát, ahol egyelőre csak a komponens hátterét rajzoljuk meg.
Természetesen a többi setter-t is meg kell írni a SetValue mintájára. Ha elmentjük majd újra installáljuk a komponenst akkor az ObjectInspectorban megjelennek az új tulajdonságok, valamint fekete hátteret kap a komponensünk.
Lépjünk tovább. A könnyebb programozhatóság kedvéért definiálnunk kell, hogy mely számjegyek megjelenítése esetén mely szegmensek "világítanak". Valamint a könnyebb/egyszerűbb Paint metódus érdekében nyilvántartjuk a szegmensek sarokpontjainak koordinátáit is, ekkor majd minden szegmensen végig kell iterálni és megnézni (a későbbiekben definiált) mátrixban, hogy a szegmens „világít”-e és annak megfelelő színnel meghívni a Canvas Polygon metódusát, ami kirajzolja a kitöltött poligont. Mindezekhez le kell rögzíteni a szegmensek sorrendjét. Legyen például:
--a--
| |
f b
| |
--g--
| |
e c
| |
--d--
Így már létrehozhatjuk a számjegy-szegmens aktivitási mátrixot. Például a tömb első (nulladik) eleme a 0-ás számjegy úgy jeleníthető meg, ha g szegmens kivételével az összes "világít". Ezt definiáljuk az osztályunkon kívül.
A szegmensek sarokpontjai legyenek az óramutató járásával megegyező sorrendben :
0
/ \
5 1
| |
| |
4 2
\ /
3
Definiáljunk egy adattagot mely az összes szegmens minden pontjának koordinátáját tartalmazza SegmentPoints: array[0..6,0..5] of TPoint;. A TPoint típus használatához a Windows unitot is fel kell venni a uses listába. Ezeket a pontokat majd egy privát Geometry nevű tagfüggvény fogja karbantartani/kiszámítani amit minden méretezés után, valamint minden setter függvény végén meghívunk.
Vegyük fel a belső adattagokat és a published propertiket a szegmens vastagsághoz, szegmensköz szélességhez, valamint a szegély vastagsághoz. Írjuk meg a hozzájuk tartozó settereket is.
Most pedig írjuk meg a Geometry eljárást amely minden szegmensre kiszámítja annak pontjait a komponens adattagjai értékének függvényében.
A komponens forráskódja: LEDSSD.zip
Egy demo program forráskódja: LEDSSDDemo.zip