
VCL Programmeer technieken in Delphi
Inleiding
In de paper OOP is de theorie van het object georiënteerd programmeren in Delphi
besproken.
In dit paper zetten we deze lijn voort en kijken we hoe OOP binnen Delphi toegepast is.
VCL staat voor Visual Component Library. Deze library bevat een groot aantal klassen.
Hier bevinden zich alle componenten die in Delphi gebruikt worden.
Voordat we met de VCL aan de gang gaan worden eerst nog een aantal OOP technieken besproken welke ook veel binnen de Delphi VCL toegepast worden.
Klassenmethoden en -gegevens
Een klassenmethode wordt, net als een normale methode, binnen de klasse gedeclareerd, ehter deze wordt vooraf gegaan van de sleutel class.
Type
MijnKlasse = Class
Class function TotaalAantal : Integer;
Klassenmethodes en gegevens worden door de gehele klasse gedeeld, dus niet door een
specifieke instantie van die klasse.
M.a.w. bovenstaande functie geldt voor alle objecten die van class MijnKlasse zijn.
Delphi zelf maakt veel gebruik van klassemethoden, bijv. om het aantal objecten van een bepaalde klasse te bepalen.
Methode-pointers
Een methode-pointer, die sterk lijkt op een procedure type, verwijst naar een methode.
(Klinkt logisch)
MijnProcedureType=procedure (Aantal : Integer);
MijnMethodPointerType = procedure(Aantal : Integer) of object;
Een veld in een object kan als volgt gedeclareerd worden :
type
MijnKlasse = Class;
Aktie : MijnMethodPointerType;
Het gave van dit veld is, dat dit veld toegewezen kan worden aan een methode van
hetzelfde soort.(Zelfde soort betekend hier met dezelfde parameters.
Stel dat in een heel andere klasse de volgende methode gedeclareerd is :
Type
NogEenKLasse =Class;
Procedure DoeHet (X : Integer);
Stel dat de volgende instanties van deze klasse bestaan :
MijnObject : MijnKlasse;
NogEenObject : NogEenKlasse;
De volgende toewijzing is nu toegestaan :
MijnObject.Aktie:=NogEenObject.DoeHet;
Als nu de methode Aktie van MijnObject wordt aangeroepen, dan wordt de methode DoeHet
van NogEenObject aangeroepen.
Hier wordt de aanroep van de methode gedelegeerd.
De event-handler van een knop doet precies hetzelfde. Een button heeft een
methode-pointer die OnClick heet.
Aan deze method-pointer kan een methode van het formulier toegewezen worden. Dit is wat er
in Delphi achter de schermen gebeurd.
type
TnotifyEvent = procedure (Sender : TObject ) of Object; //de methode pointer
MijnButton = Class;
OnClick : TNotifyEvent;
End;
TForm1 = Class (TForm)
Procedure OnButton1Click (Sender : TObject);
Button1 : MijnButton;
end;
In de unit van Form1 kan nu de volgende procedure geschreven worden :
MijnButton.OnClick := Form1.OnButton1Click;
Hier wordt de onclick methode gedelegeerd aan het formulier.
De events van het tabblad events in de object inspector zijn eigenlijk een kenmerk van de
methode pointer;
Klasseverwijzingen
Klasseverwijzingen zijn verwijzingen naar klassen. ( ook dat klinkt allemaal weer erg logisch)
type
TmijnClassRef = Class of TMijnClass;
TNieuweClass = class (TMijnClass);
var
EenClassRef : TMijnClassRef;
EenObject : TMijnClass;
Begin
EenClassRef := TMijnClass;
EenObject := TMijnClass.Create;
Deze regels kunnen, in het kader van de klasseverwijzing ook als volgt geschreven worden :
EenClassRef :=TMijnClass;
EenObject := EenClassRef.Create;
Voor klasseverwijzingen gelden dezelfde compatibiliteitsregels als die voor klassen.
EenClassRef := TNieuweClass;
Delphi bevat standaard een groot aantal klasseverwijzingen waarvan hier de belangrijkste :
TClass = class of TObject;
TComponentClass = class of TComponent;
TControlClass = Class of TControl;
De verwijzing TClass kan gebruikt worden voor alle verwijzingen naar een willekeurige
klasse.
Elke klasse is immers afgeleid van TObject;
Klasseverwijzingen kunnen op de vogende manier gebruikt worden :
Stel op een formulier wordt de volgende klasseverwijzing gedeclareerd :
NewControl : TControl;
ClassRef : TControlClass;
We kunnen nu aan classref elk willekeurige control toekennen op de volgende manier :
ClassRef := TRadioButton; of ClassRef := TEdit; etcetera.
De creatie van de control kan als volgt geschieden :
NewControl := ClassRef.Create(Self);
Afhankelijk wat ClassRef wordt toegewezen bepaald wat er gecreëerd wordt.
Dit is feitelijk wat er zich achter de schermen in Delphi afspeelt.
Kenmerken (propertys)
Objecten bezitten kenmerken en methodes. De plaats waar zij gedeclareerd worden bepaald
hun geldigheid.
We hebben toegangsopdrachten public, private en protected reeds
besproken in de OOP paper.
Naast deze drie is er ook nog de toegangsopdracht published.
Kenmerken ofwel propertys die hierbinnen gedeclareerd worden zijn ook in de
ontwerpfase beschikbaar.
Zij kunnen middels de Object inspector ingesteld worden.
De methoden die aan een gebeurtenis worden toegewezen, moeten published methoden zijn.
Een kenmerk wordt gekoppeld aan een aantal read- en write-methoden.
Middels kenmerken krijg je toegang tot een veld. (zowel public als private)
Property Periode : Integer
read FPeriode write SetPeriode;
Om toegang tot het kenmerk Periode te krijgen dient FPeriode (private veld) gelezen
worden.
De methode SetPeriode wijzigt de waarde van FPeriode.
Desgewenst kan FPeriode middels een methode gelezen worden : read GetPeriode
Zonder write methode is het kenmerk alleen lezen.
Gebeurtenissen (events)
Wanneer op een component geklikt wordt (bijv. op een button) dan genereert het
component een gebeurtenis.
Een component is voor het afhandelen van gebeurtenissen afhankelijk van de eigenaar, dit
is meestal het formulier. Dit is, zoals eerder besproken de techniek van het delegeren.
M.a.w. de event-handler van een component is een methode van het formulier waar in het
component is opgenomen.
Gebeurtenissen (events) zijn eigenlijk gewoon kenmerken (propertys).
In de klasse wordt een onchange event als volgt gedeclareerd :
type
TmijnKlass = Class
private
FOnChange : TNotifyEvent;
Protected
Procedure DoChange; Virtual;
Public
Property OnChange : TNotifyevent
Read FOnChange write FOnChange;
end;
procedure TMijnKlass.DoChange;
begin
If Assigned(FOnChange) then
FOnChange(Self)
end;
De methode DoChange wordt aangeroepen als er een wijziging plaats vindt in mijn klass
en zal indien FOnChange juist is toegewezen de betreffende On change methode
uitvoeren.
Een methode die een waarde wijzigt is bijv:
Procedure TMijnKlass.SetWaarde (aTeller : Integer);
begin
aWaarde :=aWaarde + aTeller;
DoChange;
end;
Tip : Kijk op de de componenten page van deze site om te zien hoe e.e.a. toegepast wordt bij het creëren van nieuwe classen .
Nu we (zeer globaal) de werking van Delphi (VCL) hebben bekeken hebben we een indruk
hoe e.e.a. binnen Delphi in elkaar grijpt.
Motto van bovenstaand verhaal is "oefening baart kunst"
We gaan nu verder met het bekijken van de VCL zelf :
De hiëarchie van de Delphi VCL
Elke klasse binnen Delphi is een subklasse van TObject.
Hierdoor kunnen we het type TObject gebruiken als vervanging van voor het type van alle
klassentypen binnen de VCL.
Event-handler hebben de parameter Sender die van het type TObject is.
Populair houdt dat in dat het object Sender van elk type kan zijn.
Zoals gezegd stammen alle klassen af van TObject, maar ze zijn onderling weer
gesubklassed. Er onstaat als het ware een boom waarbij we alleen de laagste klassen, de
uiteinden van de takken gebruiken in onze programmas.
Degene die componenten maken zullen met diepere klassen in aanraking komen.
Het schiet aan het doel van dit paper voorbij om de complete hiëarchie van de VCL te
bespreken.
In de Delphi help, en op de bekende posters, is veel over de VCL terug te vinden.
In dit paper heb ik getracht een beeld te geven van de complexe werking van de Delphi
VCL en hoe we daar zelf op in kunnen haken.
Dit paper is zeker niet volledig en alleen met veel oefenen kunnen we deze technieken
beter gaan beheersen.
Bestuderen van de Delphi VCL source-code is ook een goede manier om meer inzicht in deze
techniek te krijgen.