Hi DP-ler,
jetzt geht es endlich richtig los, der erste echte Schritt in Richtung Komponentenerstellung. Ich habe mich entschieden, vor dem Debug Manager noch eine kleine Runde
Komponenten-Basics einzuschieben. Sonst wäre es wahrscheinlich doch ein wenig schwer mitzukommen, wenn man noch nie Komponenten entwickelt hat. Und schließlich ist das ja auch das gewollte Publikum des Artikels.
Estellen einer Komponente
Fangen wir mal ganz vorne an und das auch praktisch. Delphi starten und/oder eventuell geöffnete Projekte schließen.
Nochmal: ich nutze die englische Delphi Version, es sollte aber nicht schwer sein, entsprechende Schritte nachzuvollziehen.
Im Menü Datei|Neu wählen wir jetzt das Item
Komponente aus und klicken den OK Schalter.
http://www.gatenetwork.com/delphi-sa...ourse03_01.gif
Anschließend präsentiert Delphi uns einen Dialog, der uns die Möglichkeit gibt, den "Rahmen" der Komponente zu erstellen. Dort füllen wir die Startdaten der Komponente ein.
http://www.gatenetwork.com/delphi-sa...ourse03_02.gif
Delphi erstellt uns jetzt eine kleine
Unit, welche wie folgt aussieht.
Code:
unit SenselessSample;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TSenselessSample = class(TComponent)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('gate(n)etwork', [TSenselessSample]);
end;
end.
Damit ist der erste Schritt schon geschafft, wir haben eine Komponente, die, in ihrer jetzigen Form, völlig unnütz ist, aber bereits funktioniert. Aber den Test sparen wir uns noch ein paar Minuten. Etwas sinnvolles wäre doch ganz nett, oder?
Der Aufbau unserer Unit
Was sehen wir jetzt eigentlich? Die
Unit für unsere Komponente ist genau wie jede andere
Unit aufgebaut.
- unit - Der Name der Unit, der gleich dem Namen des PAS Datei ist.
- uses - Die am häufigsten genutzten Units werden automatisch eingebunden. Editieren dieser Liste ist, wie sonst auch, möglich.
- type - Die Typen Deklarationen starten hier.
- TSenselessSample = class(TComponent)An dieser Stelle deklarieren wir unsere Komponente. Abgeleitet von TComponent, ist es eine non-visual Komponente, welche der Anwender unseres Programmes nicht direkt zu sehen bekommt (Siehe 2. Posting).
Folgende Bereiche gehören zu der Komponente.- private - In diesem Bereich werden alle Variablen und Methoden deklariert, welche nur innerhalb dieser Klasse für die direkte Verwendung zur Verfügung stehen.
- protected - In diesem Bereich werden alle Eigenschaften, Variablen und Methoden deklariert, welche nur innerhalb dieser Klasse und aller davon abgeleiteten Klassen zur Verfügung stehen.
- public - In diesem Bereich werden alle Eigenschaften und Methoden deklariert, welche auch ausserhalb der Klasse zur Verfügung stehen. Diese Eigenschaften und Methoden können somit überall im Projekt (in Verbindung mit einem Objekt der entsprechenden Klasse) verwendet werden. Es wird i.A. als schlechte Programmierpraktik angesehen, wenn in diesem Bereich Variablen deklariert werden, da die Klasse keine Kontrolle über diese haben würde.
- published - In diesem Bereich werden alle Eigenschaften, welche auch im Design-Modus im Object Inspektor manipuliert werden können. (z.B: TLabel.Caption, TEdit.Text; TForm.Icon, ...)
- procedure Register; - Es wird die Prozedure deklariert, welche Delphi später aufruft, um unsere Komponente in die Palette zu laden.
- implementation - Hier fängt der eigentliche Teil unserer Unit an - der ganze ausgeführte Code.
- procedure Register; - Schon wieder. Na gut, hier melden wir die Komponente wirklich an. In diesem Fall wird eine Palette mit dem Namen "gate(n)etwork" eingerichtet.
- end. - Alles hat mal ein Ende, auch unsere unit

Hinweis: Ein Hinweis sei mir noch gestattet. In den jeweiligen Abschnitten (private, protected, ...) müssen alle Variablen stets vor den Methoden (procedure, function) und Eigenschaften (property) deklariert werden.
"Filling in the meat"
Wollen wir dieser sinnlosen Komponente mal noch ein wenig Inhalt geben. Dazu deklarieren wir insgesamt sechs Eigenschaften. Zwei geben uns die Möglichkeit Fließkommazahlen entgegenzunehmen, vier weitere zeigen jeweils auf eine TLabel Komponente.
Dazu füllen wir den Bereich zwischen
private und
end; wie folgt aus.
Code:
published
{ Published declarations }
property X: Double;
property Y: Double;
property Result_Add: TLabel;
property Result_Sub: TLabel;
property Result_Mul: TLabel;
property Result_Div: TLabel;
end;
Der Bezeichner
property teilt Delphi mit, das es sich um eine Eigenschaft der Klasse handelt. In diesem Fall habe ich die Eigenschaften
X, Y, Result_Add, Result_Sub, Result_Mul und
Result_Div deklariert. Noch sind wir aber nicht fertig. Jetzt positionieren wir den Cursor innerhalb des gerade eingefügten Bereiches und lassen Delphi ein bisschen für uns arbeiten. Einfach mal die Tasten [STRG]+[SHIFT]+[C] drücken und Delphi "
completes" unsere Klasse und die ganze
Unit.
Code:
unit SenselessSample;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TSenselessSample = class(TComponent)
private
FX: Double;
FY: Double;
FResult_Add: TLabel;
FResult_Sub: TLabel;
FResult_Mul: TLabel;
FResult_Div: TLabel;
procedure SetResult_Add(const Value: TLabel);
procedure SetResult_Div(const Value: TLabel);
procedure SetResult_Mul(const Value: TLabel);
procedure SetResult_Sub(const Value: TLabel);
procedure SetX(const Value: Double);
procedure SetY(const Value: Double);
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
property X: Double read FX write SetX;
property Y: Double read FY write SetY;
property Result_Add: TLabel read FResult_Add write SetResult_Add;
property Result_Sub: TLabel read FResult_Sub write SetResult_Sub;
property Result_Mul: TLabel read FResult_Mul write SetResult_Mul;
property Result_Div: TLabel read FResult_Div write SetResult_Div;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('gate(n)etwork', [TSenselessSample]);
end;
{ TSenselessSample }
procedure TSenselessSample.SetResult_Add(const Value: TLabel);
begin
FResult_Add := Value;
end;
procedure TSenselessSample.SetResult_Div(const Value: TLabel);
begin
FResult_Div := Value;
end;
procedure TSenselessSample.SetResult_Mul(const Value: TLabel);
begin
FResult_Mul := Value;
end;
procedure TSenselessSample.SetResult_Sub(const Value: TLabel);
begin
FResult_Sub := Value;
end;
procedure TSenselessSample.SetX(const Value: Double);
begin
FX := Value;
end;
procedure TSenselessSample.SetY(const Value: Double);
begin
FY := Value;
end;
end.
Da wir uns entschieden haben, TLabel zu nutzen müssen wir die uses Klausel ein wenig erweitern.
Code:
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
wird zu
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
Was ist alles geschehen?
Schauen wir uns einfach mal die aufgefüllte Zeile einer
property an.
Code:
property X: Double;
wird zu
property X: Double read FX write SetX;
Delphi hat für uns die üblichste Behandlungsart einer Eigenschaft eingetragen. Das heisst, wenn jemand die Eigenschaft
X ermitteln will, so wird der Wert der Variablen
FX direkt zurückgegeben. Delphi hat auch gleich die Variable
FX für uns im
private Bereich deklariert.
Danke Borland. Ausserdem hat Delphi auch gleich definiert, wie Änderungen der Eigenschaft übernommen werden. Damit wir bei eventuellen Änderungen reagieren können, hat Delphi das Setzen der Variable nicht direkt erledigt, sondern eine "Wrapper" Methode
SetX erstellt. Diese Methode übernimmt das Speichern der Änderungen.
Code:
procedure TSenselessSample.SetX(const Value: Double);
begin
FX := Value;
end;
Diese Art der Variablenbehandlung kommt uns jetzt noch sehr zu gute.
"And Action!"
Jetzt fügen wir noch eine Methode zum
private Bereich hinzu, damit wir die die Hauptfunktionalität noch angenehm verpacken können.
Code:
private
...
procedure UpdateLabels;
{ Private declarations }
protected
Und noch einmal [STRG]+[SHIFT]+[C] für die automatische Code-[b]C[/c]ompletion drücken!
Code:
procedure TSenselessSample.UpdateLabels;
begin
end;
Jetzt haben wir unsere Hauptmethode fast fertig. Es müssen nur noch ein paar Zeilen Code hinein und das Ergebnis sieht wie folgt aus.
Code:
procedure TSenselessSample.UpdateLabels;
begin
// summe ermitteln und darstellen
if Assigned(FResult_Add) then
try
// label für summe wurde zugewiesen
FResult_Add.Caption := FloatToStr(FX + FY);
except
on E:
Exception do
// oops
FResult_Add.Caption := E.Message;
end;
// differenz ermitteln und darstellen
if Assigned(FResult_Sub) then
try
// label für differenz wurde zugewiesen
FResult_Sub.Caption := FloatToStr(FX - FY);
except
on E:
Exception do
// oops
FResult_Sub.Caption := E.Message;
end;
// produkt ermitteln und darstellen
if Assigned(FResult_Mul) then
try
// label für produkt wurde zugewiesen
FResult_Mul.Caption := FloatToStr(FX * FY);
except
on E:
Exception do
// oops
FResult_Mul.Caption := E.Message;
end;
// quotient ermitteln und darstellen
if Assigned(FResult_Div) then
try
// label für quotient wurde zugewiesen
FResult_Div.Caption := FloatToStr(FX / FY);
except
on E:
Exception do
// oops
FResult_Div.Caption := E.Message;
end;
end;
Für jedes Ergebnis überprüfen wir zuerst, ob ein entsprechendes Label vorhanden ist und anschließend versuchen wir das Ergebnis zu ermitteln und darzustellen. Wenn das fehlschlagen sollte, liefern wir eine entsprechende Fehlermeldung zurück.
Jetzt tragen wir in alle
Set Methoden noch als letzten den Aufruf zu unserer
UpdateLabels; Methode ein und sind soweit fertig. Einen Schönheitsfehler müssen wir noch beseitigen. Da es geschehen kann, dass eines der zugewiesenen Labels vom Form entfernt wird, müssen wir abschliessend noch dieses Ereignis abfangen und die entsprechden FResult_XXX Variabel auf nil setzen! Dazu überlaufen wir die Standard Notification Methode.
Code:
protected
{ Protected declarations }
procedure Notification(
aComponent: TComponent; Operation: TOperation
); override;
Den kompletten Code könnt Ihr jetzt lesen.
Code:
unit SenselessSample;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TSenselessSample = class(TComponent)
private
FX: Double;
FY: Double;
FResult_Add: TLabel;
FResult_Sub: TLabel;
FResult_Mul: TLabel;
FResult_Div: TLabel;
procedure SetResult_Add(const Value: TLabel);
procedure SetResult_Div(const Value: TLabel);
procedure SetResult_Mul(const Value: TLabel);
procedure SetResult_Sub(const Value: TLabel);
procedure SetX(const Value: Double);
procedure SetY(const Value: Double);
procedure UpdateLabels;
{ Private declarations }
protected
{ Protected declarations }
procedure Notification(
aComponent: TComponent; Operation: TOperation
); override;
public
{ Public declarations }
published
{ Published declarations }
property X: Double read FX write SetX;
property Y: Double read FY write SetY;
property Result_Add: TLabel read FResult_Add write SetResult_Add;
property Result_Sub: TLabel read FResult_Sub write SetResult_Sub;
property Result_Mul: TLabel read FResult_Mul write SetResult_Mul;
property Result_Div: TLabel read FResult_Div write SetResult_Div;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('gate(n)etwork', [TSenselessSample]);
end;
{ TSenselessSample }
procedure TSenselessSample.Notification(
aComponent: TComponent; Operation: TOperation
);
begin
inherited Notification(aComponent, Operation);
if (Operation = opRemove) then
begin
if aComponent = FResult_Add then
FResult_Add := nil;
if aComponent = FResult_Sub then
FResult_Sub := nil;
if aComponent = FResult_Mul then
FResult_Mul := nil;
if aComponent = FResult_Div then
FResult_Div := nil;
end;
end;
procedure TSenselessSample.SetResult_Add(const Value: TLabel);
begin
FResult_Add := Value;
UpdateLabels;
end;
procedure TSenselessSample.SetResult_Div(const Value: TLabel);
begin
FResult_Div := Value;
UpdateLabels;
end;
procedure TSenselessSample.SetResult_Mul(const Value: TLabel);
begin
FResult_Mul := Value;
UpdateLabels;
end;
procedure TSenselessSample.SetResult_Sub(const Value: TLabel);
begin
FResult_Sub := Value;
UpdateLabels;
end;
procedure TSenselessSample.SetX(const Value: Double);
begin
FX := Value;
UpdateLabels;
end;
procedure TSenselessSample.SetY(const Value: Double);
begin
FY := Value;
UpdateLabels;
end;
procedure TSenselessSample.UpdateLabels;
begin
// summe ermitteln und darstellen
if Assigned(FResult_Add) then
try
// label für summe wurde zugewiesen
FResult_Add.Caption := FloatToStr(FX + FY);
except
on E:
Exception do
// oops
FResult_Add.Caption := E.Message;
end;
// differenz ermitteln und darstellen
if Assigned(FResult_Sub) then
try
// label für differenz wurde zugewiesen
FResult_Sub.Caption := FloatToStr(FX - FY);
except
on E:
Exception do
// oops
FResult_Sub.Caption := E.Message;
end;
// produkt ermitteln und darstellen
if Assigned(FResult_Mul) then
try
// label für produkt wurde zugewiesen
FResult_Mul.Caption := FloatToStr(FX * FY);
except
on E:
Exception do
// oops
FResult_Mul.Caption := E.Message;
end;
// quotient ermitteln und darstellen
if Assigned(FResult_Div) then
try
// label für quotient wurde zugewiesen
FResult_Div.Caption := FloatToStr(FX / FY);
except
on E:
Exception do
// oops
FResult_Div.Caption := E.Message;
end;
end;
end.
Installieren der Komponente
Der letzte wichtige Schritt ist die Installation der Komponente in der Delphi Palette. Ausserdem könnte man jetzt noch ein Icon für die Komponente erstellen, aber dazu kommen wir ein anderes Mal, wenn es nicht gerade diese sinnlose Komponente ist.
Um die Komponente zu installieren, wählt im Menü
Komponenten|Komponente installieren. Delphi trägt automatisch alles ein und schlägt Euch das Standard User-Komponenten Packet vor. Das ist auch in Ordnung. Mit OK bestätigen.
http://www.gatenetwork.com/delphi-sa...ourse03_03.gif
Anschliessend seht Ihr das Fenster zum kompilieren und installieren des Packages.
http://www.gatenetwork.com/delphi-sa...ourse03_04.gif
"Kompilieren" und anschließend "Installieren" drücken. Fertig.
Der Test des Sinnlosen
Alle offenen Projekte schließen und eine neue Anwendung anlegen. 4 Labels auf das Form packen und von der "gate(n)etwork" Seite unsere Komponente auswählen und auf das Form packen. Jetzt nur noch die vier Labels den entsprechenden Eigenschaften zuordnen und ein wenig im Objekt Inspektor rumspielen.
Viel Spass,
hier gibt es alles noch zum Download