Erre a gyors áttekintésre azért volt szükség, hogy átlássuk, valójában mikor mit is csinál a program.
Az Init konstruktorban szokás beállítani a változók kezdeti értékét is. Célszerű használni az Inherited Init-et mivel enek paraméterei az objektum méretei - amit beállít - és kinullázza a TOldObject-ben is létező mezőket.
Figyelem! Az INIT konstruktorban még nem szabad hivatkozni az objektum azon mezőire, melyek a képernyőelem rendszerbe illesztését szolgálják (Owner, Next, Prev) hiszen ilyenkor az objektum még nincs rendszerben (majd az AddObject-tel kerül bele) következésképp ezek a mezők NIL-re mutatnak)
Procedure TTextBox.HandleEvent; Var TX: String[1]; Begin Case Event.What OfLátható, hogy az első Case szerkezetbe tettük a beérkező esemény típusát (célszerű akkor is létrehozni ezt a szerkezetet, ha csak egy féle eseményt szokott kapni az objektum)
EvKeyDown: Begin Case Event.KeyCode OfA Case szerkezetbe is lehet Case szerkezetet tenni, de ez általában csak billentyűkódok értelmezésére jó. Egér események értelmezésénél általában marad a jó öreg IF-THEN
32..255: Begin TX:=Event.CharCode; If Cursor<Length(Text) Then Text:=Copy(Text,1,Cursor-1)+TX+Copy(Text,Cursor,255) Else Text:=Text+TX; Inc(cursor); End; 8: Begin If Cursor>1 Then Text:=Copy(Text,1,Cursor-2)+Copy(Text,Cursor,255); Dec(cursor); End; 256*75 : Dec(cursor); 256*77 : Inc(cursor); End; DrawIt; End; End; Inherited HandleEvent(Event); End;
Lássunk egy példát! A következő forráskód a TGomb objektum HandleEvent metódusának részlete:
EvMouseDown: BeginEz a programrész csak akkor hajtódik végre, ha a gomb felett megnyomták az egér valamelyik gombját.
Status:=True; OS:=False;A gombnál ha a Status True akkor a Draw benyomódott gombot rajzol, egyébként kiengedettet.
Repeat If Event.What=EvMouseMove Then Status:=IsInArea(Event.WhereX,Event.WhereY,X,Y,W,H); If Status<>OS Then DrawIt;Az egér megmozdításának figyelése. Ha az egeret elviszik a gomb felől, akkor gomb visszaugrik alapállapotba, ha az egér ismét a gomb fölé kerül a gomb ismét benyomódik. Fontos megjegyezni, hogy más módon nem lehetne megoldani a gomb ijen viselkedését (gondojuk bele: tegyük fel, hogy a gombot feljogosítjuk arra, hogy fogadja az EvMouseMove eseményt is. Ekkor a HandleEvent mindig meghívódik, amikor a gomb felett megmozdul az egér. DE mi van akkor, ha levisszük az egeret a gombról? Akkor már nem fog meghívódni, vagyis a gomb "bennragad".
OS:=Status; GetEvent(Event);Az eseményszerző rutin meghívása. Ez azért jó, mert így ugyanolyan formában kapjuk meg az eseményeket, mintha azokhoz a gomb normális módon juott volna.
Until Event.What=EvMouseUp;A HandleEvent a fenti ciklusban várakozik az egérgomb felengedése esemény beérkezésére.
Status:=False; DrawIt;A gomb eredeti paramétereinek visszaállítása és kirajzolása.
If OS Then BeginHa gomb be volt nyomva, amikor felengedték az egeret, akkor átadódik egy parancs a processznek.
Event.What:=EvCommand; Event.Command:=Command; Owner^.Process(Event); End; End;
Procedure TOldObject.DrawIt; Begin Mouse_Hide; Draw; Mouse_Show; End;Jól látható, hogy a DrawIt először kikapcsolja az egeret, majd meghívja a Draw metódust, majd visszakapcsolja az egeret. Ezzel az egyszerű metódussal elértük, hogy a Draw metódusban nem kell foglalkoznunk azzal, hogy kapcsolgassuk az egeret. A mostani DrawIt itt még nagyon egyszerű, de egy többszíntű felületnél sokkal nagyobb tartalmat fog kapni.
Fontos: Mindig a DrawIt metódust hívjuk meg, ha ki akarunk rajzoltatni egy objektumot!
Első pillantásra elég bonyolultnak tűnik ez a sok kikötés, de valójában az objektumok képei nem szoktak olyan bonyolultak lenni, hogy különösebb fejtörést okozzanak a Draw rutinok írójának. Annyit azért célszerű szemelőtt tartani, hogy mivel sokféle objektum létezhet, mindig állítsunk be újra minden rajzolási paramétert (színek, szöveg típusok, kitöltés típusa stb.) különben kellemetlen meglepetések érhetnek bennünket. (Tulajdonképpen ezeket a rajzolási paramétereket állító rutinokat is beleírhatnánk a DrawIt metódusba így ezzel sem kellene foglalkoznunk).
Most már tudjuk, hogy hogyan rajzoljunk, de még nem tudjuk, hogy pontosan mit is szeretnénk. Azt, hogy egy objektumon belül a képernyőelem pontosan melyik megjelenési formáját szeretnénk megrajzolni (a benyomott vagy a kiengedett gombot), általában objektum-mezőkön keresztül célszerű átadni a Draw-nak.
Fent említettem, hogy a Draw lehetőleg csak annyit rajzoljon, amennyi feltétlenül szükséges. Ennek a kikötésnek a betartása azonban néha furcsa eredményhez vezet: képzeljük el, hogy egy objektum valamilyen okból újrarajzoltatja az egész képernyőt. Ha az általunk írt képernyőelem csak a fontos dolgokat rajzolja ki, akkor az újrarajzolás után bizonyos részek hiányozni fognak. Ennek a problémának az áthidalására célszerű a rendszerobjektumban bevezetni egy új mezőt amely Boolean típusú és ha az értéke True, akkor az objektumok Draw metódusainak a teljes objektumot ki kell rajzolnia. A mezőt hívják mondjuk DrawAll-nak. A DrawAll-t a rendszer Init konstruktora False-ra állítja, de a DrawScreen (amely minden objektumot kirajzol) ezt True-ra állítja majd lefutása után visszaállítja False-ra. Ezzel a módszerrel elértük, hogy az objektumok "tudják", hogy mikor kell teljes képet és mikjor kell csak részleteket rajzolni.
Az objektumok (a gombokat kivéve) általában EvMessage típusú üzeneteket küldenek a processznek, melynek command mez?jében küldik az esemény típusát és az InfoPtr mez? tartalmazza a küldő objektum címét. Az eseményeket úgy célszerű definiálni, hogy az esemény típusából kiderüljön, hogy az milyen képernyőelem küldte. Ez sok objektumnál sokféle eseménytípust jelent, de egyszerűvé teszi a vezérlést.
Tulajdonképpen kb. ennyi volt az, amit a képernyőelemek írásáról első
körben érdemesnek láttam elmondani. És különben is már baromira elálmosodtam.