Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Klasse als Eigenschaft einer Komponente verwenden...?


Ares - Di 02.10.07 13:51
Titel: Klasse als Eigenschaft einer Komponente verwenden...?
Hallo!

Ich bastel gerade an einer eigenen Komponente für einen Dialog. Der Dialog verfügt über mehrere Buttons (OK, Abbrechen, etc.). Unter anderem soll es die Komponente erlauben, dass der Benutzer den Typ der Buttons frei wählen kann. Es soll also möglich sein TButton, TBitBtn, TSpeedButton oder irgendeine beliebige Komponente die von TWinControl abgeleitet ist als Button zu verwenden. Alle Buttons sollen dann vom ausgewählten Typ sein.

Wie kann ich sowas machen? Wie füge ich also eine Eigenschaft zu einer Komponente hinzu, die vom Typ "Typ" bzw. "Klasse" ist? Es müsste ja etwas sein wie:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
property ButtonType: "Typ" read FButtonType write SetButtonType;
...
procedure MyComponent.SetButtonType(buttonType: "Typ");
begin
   if (buttonType is TWinControl) then FButtonType := "Typ" else
      raise Exception.Create('Button-Typ von TWinControl abgeleitet sein');
   ...
   NextBtn := FButtonType.Create;  // geht das?
end;
...


Kann das funktionieren?

Vielen Dank für Ihre Hilfe
Ares


Reinhard Kern - Di 02.10.07 18:17
Titel: Re: Klasse als Eigenschaft einer Komponente verwenden...?
user profile iconAres hat folgendes geschrieben:
Hallo!

Ich bastel gerade an einer eigenen Komponente für einen Dialog. Der Dialog verfügt über mehrere Buttons (OK, Abbrechen, etc.). Unter anderem soll es die Komponente erlauben, dass der Benutzer den Typ der Buttons frei wählen kann. Es soll also möglich sein TButton, TBitBtn, TSpeedButton oder irgendeine beliebige Komponente die von TWinControl abgeleitet ist als Button zu verwenden. Alle Buttons sollen dann vom ausgewählten Typ sein.

Wie kann ich sowas machen? Wie füge ich also eine Eigenschaft zu einer Komponente hinzu, die vom Typ "Typ" bzw. "Klasse" ist? Es müsste ja etwas sein wie:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
property ButtonType: "Typ" read FButtonType write SetButtonType;
...
procedure MyComponent.SetButtonType(buttonType: "Typ");
begin
   if (buttonType is TWinControl) then FButtonType := "Typ" else
      raise Exception.Create('Button-Typ von TWinControl abgeleitet sein');
   ...
   NextBtn := FButtonType.Create;  // geht das?
end;
...


Kann das funktionieren?

Vielen Dank für Ihre Hilfe
Ares


Mit Bordmitteln sicher nicht. Typ oder Klasse kennt nur der Compiler, normalerweise geht das beim Compilieren unter und die exe enthält keine Informationen mehr darüber. Ausnahmen wie bei "is" oder "as" werden intern abgehandelt.

Die Felder eines Objekts sind Adressen (von Variablen oder Prozeduren) - ein Typ hat keine Adresse, eine Klasse auch nicht, zumindest solange es kein entsprechndes Objekt gibt.

Du kannst dir natürlich eine eigene Enumeration definieren (tInvalid,tInteger,tReal,...) und mit "is" arbeiten, ist aber recht umständlich. Ich verwende sowas für meine Ini-Dateien mit verschiedenen Konstruktoren:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
   TRKiniSettingRecord = record
     SetupControl : TControl;
     BackLink : TRKiniSettingValue;
     dirty : boolean;
     removed : boolean;
     FieldIndex : word;  { 1..FieldLength }
       case TRKiniSettingVariant of
         sv_Undef   : (vUndef : longint);
         sv_String  : (VString : string[6]);
         sv_Bool    : (vBool : boolean);
         sv_Integer : (vInteger : longint);
         sv_Real    : (vReal : double);
         sv_Color   : (vColor : TColor);
         sv_Pen     : (vPen : longint);
     end;

{...}

constructor TRKiniSettingValue.Create_String (imax : integer; IG,II : TRKiniSettingName;
                Def : ShortString; EC : array of TEdit; OwnerTable : TRKIniSettingTable);
var i : integer;
begin
sType := sv_String;
for i := 0 to High (EC) do OwnerTable.SetupControlArray[i] := EC[i];
Create_General (imax,IG,II,Def,OwnerTable);
end;

constructor TRKiniSettingValue.Create_Bool   (imax : integer; IG,II : TRKiniSettingName;
                    Def : Boolean; BC : array of TButtonControl; OwnerTable : TRKIniSettingTable);
var i : integer;
begin
sType := sv_Bool;
for i := 0 to High (BC) do OwnerTable.SetupControlArray[i] := BC[i];
Create_General (imax,IG,II,Def,OwnerTable);
end;

{...}

constructor TBPMLogSettings.CreateTable (IC : TRKIniClass);
begin
inherited Create (IC);
SetLength (SetupControlArray,70);
with BLMainForm do
  begin
  Station_Node       := TRKiniSettingValue.Create_Integer (-maxStationNo,'Station',
        'Node',0, [nil] ,self);
  Station_Description  := TRKiniSettingValue.Create_String (-maxStationNo,'Station',
        'Description','', [nil] ,self);
  Station_CommPort   := TRKiniSettingValue.Create_Integer (-maxStationNo,'Station',
        'CommPortNumber',0, [nil] ,self);
{...}


Ich lege dabei im Konstruktor der Settings-Klasse fest, welcher Typ, indem der entsprechende Konstruktor für den Eintrag aufgerufen wird.

Gruss Reinhard


SvenAbeln - Di 02.10.07 19:31

Hallo,

versuch es mal so:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
property ButtonType: TWinControlClass read FButtonType write SetButtonType;
...
procedure MyComponent.SetButtonType(buttonType: TWinControlClass);
begin
   FButtonType := buttonType
   ...
   NextBtn := FButtonType.Create;  // geht das?   // Ja geht, wenn FButtontype eine Klasse ist
end;
...



dann kannst du den Typ wie folgt setzen:

Delphi-Quelltext
1:
  MyComponent.ButtonType := TButton;  // oder TBitBtn usw