Allemaal mooi, tot de dag dat je graag wil afwijken van die standaarden, en je ÔÇÿeigenÔÇÖ manier wil opleggen. Wat kun je doen?
Hier al een begin van Business Objects, en hoe je die in jouw geval kunt gebruiken.
Delphi heeft het grandioze voordeel dat je er in RAD-mode (Rapid Application Development) kunt werken. Eigenlijk werken de meesten van ons zo. Snel componenten droppen op forms, wat code in button-events steken, en je applicatie werkt. Dit werkt heel goed. Het is een plezier om zo met Delphi te werken.
Wens je af te wijken van de standaard manier waarop de componenten werken, dan dien je andere componenten te zoeken, kopen of je moet zélf klassen of componenten maken.
Eén van de belangrijke redenen om zelf klassen te schrijven, is dat je hetgeen in je database zit, niet eenvoudigweg via zogenaamde ÔÇÿdata-awareÔÇÖ componenten op je scherm te toveren is. Je wil je data omvormen, je wil je data tussentijds in je applicatie gebruiken, je dient berekeningen en controleÔÇÖs uit te voeren. Of omgekeerd, je wil je editvelden ook voor andere dingen gebruiken dan voor het afbeelden van data: het zoeken van data bijvoorbeeld.
Een eerste manier om in te grijpen volgt hier.
Je kunt een aantal omvormingen en ÔÇÿtruukenÔÇÖ toepassen in de OnGetText en OnSetText-events van fields.Wil je het klantnummer bijvoorbeeld afbeelden in een TPanel, dan selecteer je eerst het TField waarin het klantnummer staat, en dan zeg je in zijn OnGetText dat je de waarde in Panel1 zet.
- Klik met je rechter muisknop op je TTable-component, en je krijgt een context-menu.
- Selecteer Fields Editor
- Klik met de rechter muisknop in het witte vak, en selecteer All Fields
- Nu zie je alle velden van je TTable.
- Klik op het veld waarin je klantnummer staat (vb. KlantNummer)
- In de Object Inspector zie je nu een TNumberField voor je klantnummer.
- Maak een handler voor het OnGetText-event, door het tabblad Events te kiezen, en naast OnGetText te dubbelklikken.
In deze handler zeg je wat je met de waarde van het veld gaat doen als het TField vanuit de database opgevuld wordt:
procedure TFormF.MijnFieldGetText(Sender: TField; var Text: string; DisplayText: Boolean); begin Panel1.Caption := sender.asstring end ;
Op deze manier beeld je je gegevens anders af dan gewoon rechtstreeks in TDBEdits.
Je kunt natuurlijk de waarden in een TEdit afbeelden in plaats van in een TPanel, zoals hierboven.
Omgekeerd kun je hetgeen je in TEdits steekt, copiëren naar TDBEdits.
In de OnExit-event copieer je hetgeen ingetikt hebt, naar de overeekomstige TDBEdit. Dus je maakt een TEdit voor je klantnummer, en in de OnExit schrijf je het volgende:
procedure TForm1.Edit1Exit(Sender: TObject); begin Table1Klantnummer.AsString := (Sender as TEdit).Text end;
if StrToInt ((Sender as TEdit).Text) > 0 then Table1Klantnummer.AsString := (Sender as TEdit).Text
if not InZoekMode then if StrToInt ((Sender as TEdit).Text) > 0 then Table1Klantnummer.AsString := (Sender as TEdit).Text
Query1.Params[0].AsString := (Sender as TEdit).Text ; Query1.ExecSQL ;
Als we nu eens alle data en logica van een klant eens in een klasse zouden zetten? Is dit niet de bedoeling van klassen? Dan maak je in die klasse alle ÔÇÿlogicaÔÇÖ die je kent van een klant. Verder maak je een method om een klant te zoeken, en één om een klant weg te schrijven, en je hebt je eerste ÔÇ£Business ObjectÔÇØ. Je mag van die klant een component maken, maar dat hoeft helemaal niet. Je klasse zou er zo kunnen uitzien:
unit KlantUnit ; interface type TKlant = class (TObject) private FNummer : integer ; FFirmanaam: string ; FTable: Ttable ; procedure SetNummer ( value: integer ) ; public constructor Create ; destructor Destroy ; function Post : Boolean ; function Zoek: Boolean ; property Nummer : integer read FNummer write SetNummer ; property Firmanaam: string read FFirmanaam write FFirmanaam ; property Table: TTable read FTable write FTable; end ; implementation procedure TKlant.SetNummer ( value: integer ) ; begin if value > 0 then { hier zit mijn ÔÇ£business logicaÔÇØ; enkel en alleen hier} FNummer := value end ; function TKlant.Post : Boolean ; begin if assigned (FTable) then {wellicht zul je hier wat meer testen willen toevoegen om na te gaan of je de dataset wel kunt gebruiken} result := FTable.InsertRecord ( [FNummer, FFirmanaam] ) end ; function TKlant.Zoek: Boolean ; begin if assigned (FTable) then result := FTable.FindKey([FNummmer]) end ;
In je pogramma kun je nu een (of meerdere) klant-object maken en gebruiken. Dit noemt men het koppelen van de GUI aan de business objecten. Bijvoorbeeld:
uses KlantUnit; var SchermKlant : TKlant ; procedure TForm1.FormCreate(Sender: TObject); begin SchermKlant := TKlant.Create ; SchermKlant.Table := Table1 end ; procedure Form1.ZoekButtonClick (Sender: TObject); begin SchermKlant.Nummer := Edit1.Text ; if SchermKlant.Zoek then Edit2.Text := SchermKlant.FirmaNaam end ;
Maar je mist iets: Alle mooie DataControls, zoals TDBEdit, TDBGrid en zo meer, kun je niet meer gebruiken. Deze link je namelijk aan een TDataSource, die op zijn beurt aan een TTable (of andere) gelinkt is. En een TDataSource kun je niet aan een TKlant linken.
Dus, een TKlant gebruiken met je datacontrols? Vergeet het maar!
Een andere manier om een ÔÇÿdata-awareÔÇÖ business klasse te maken, is ze rechtstreeks af te leiden (inheriten) van TTable of TDBDataSet.Bijvoorbeeld:
TKlant = class (TTable) ;
Ik heb dit ooit, met vallen en opstaan, maar uiteindelijk met succes gedaan. Ik zal eens diep in mijn archieven moeten zoeken om terug uit te pluizen wat je hiervoor allemaal moet doen. En dit toetsen aan de kennis die ik ondertussen bijgekregen heb. Daarna zal ik een vervolg breien op dit artikel.
Of mocht iemand anders met dit artikel ÔÇ£Het LichtÔÇØ gezien hebben, en dit willen neerschrijven in een vervolgartikel, hou je vooral niet in!
Sam Witse.