VCLHome

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 instantie’s 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.

Delegeren is de technologie waarop de Delphi VCL gebaseerd is.

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 (property’s)

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 property’s 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 (property’s).

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 programma’s.

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.

arrows.gif (215 bytes)Top