Autor Beitrag
Coder
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1383
Erhaltene Danke: 1

WinXP
D2005 PE
BeitragVerfasst: Mi 20.06.07 19:12 
Hi
Ich würde gern eine Komponente um Prozeduren erweitern, um diese in eine eigene Unit zu schreiben.
Jedoch soll es nicht zu kompliziert werden d.h. ich will die erweiterte Komponente nicht extra in der IDE installieren sondern die Eigenschaften des Vorfahren übernehmen, der bereits auf die Form gesetzt und richtig konfiguriert ist.
Dazu hab ich dieses Testprojekt erstellt.
ausblenden 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:
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

  TMyButton = class(TButton)
    procedure MakeCaption;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TMyButton.MakeCaption;
begin
  Self.Caption := '123';
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyButton(Button1).MakeCaption;
end;

Das funktioniert soweit gut.
Aber kann ich den TButton in ein TMyButton "umwandeln" und dabei die Eigenschaften in einem Rutsch übernehmen, sodass ich mir das TMyButton( sparen kann?

MfG
mkinzler
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 4106
Erhaltene Danke: 13


Delphi 2010 Pro; Delphi.Prism 2011 pro
BeitragVerfasst: Mi 20.06.07 19:14 
Garnicht, da Sender ja vom typ TComponent ist.

_________________
Markus Kinzler.
Coder Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1383
Erhaltene Danke: 1

WinXP
D2005 PE
BeitragVerfasst: Fr 03.08.07 02:33 
Das obere Beispiel funktioniert.

Aber jetzt hab ich mal probiert der Komponente eine weitere Variable anzuhängen:
ausblenden 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:
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

  TMyButton = class(TButton)
  public
    s: String;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyButton(Button1).s := 'Test';
  ShowMessage(TMyButton(Button1).s);
end;

So bekommt man eine Zugriffsverletzung.
Das erscheint mir auch irgendwie logisch, da wohl gar kein Speicher für die Variable reserviert wird, oder?
Wie könnte man das lösen, eine Komponente mit Funktionen, Prozeduren und Variablen einfach zu erweitern?
Ich will vermeiden, dass jemand, der meinen Quellcode kompilieren will, erst noch zig Komponenten in seine IDE installieren muss.

MfG
Logikmensch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: Fr 03.08.07 07:01 
Dass das nicht richtig funzt liegt daran, dass ein Nachkomme auch als solcher Createt werden muss, damit die Instanz richtig initialisiert wird. Mit Deinem TypeCast umgehst Du dies. Da Dein Button1 nur als TButton instantiiert ist, fehlen ihm Deine neuen Eigenschaften, sprich Deine neue Variable und dann gibt's unweigerlich Probleme. Das Prinzip der OOP richtig zu benutzen ist Grundlage für gutes OOP, daher ist mir jetzt nicht klar, was Du eigentlich einsparen willst.

Wenn Du ohne eine neue Kompo zu erstellen, eine Kompo um weitere Fähigkeiten erweitern willst, dann erstelle diese nicht mit dem Formulardesigner, sondern zur Laufzeit. Das Hinzufügen eines Buttons ist doch recht simpel:

innerhalb des private-Abschnitts Deines Forms eintragen:
ausblenden Delphi-Quelltext
1:
2:
3:
...
Fmybutton:Tmybutton;
...


innerhalb des FormCreate-Events einzutragen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
....
Fmybutton:=Tmybutton.Create(Self);
Fmybutton.Parent:=Self; //oder irgendeine andere Kompo, wo der Knopf drauf platziert werden soll
//und dann natürlich die Button-Eigenschaften setzen:
Fmybutton.Caption:='TestKnopf';
Fmybutton.OnClick:=mybuttonclick;
...


innerhalb des FormDestroy-Events einzutragen:
ausblenden Delphi-Quelltext
1:
2:
3:
...
Fmybutton.Free;
...


So, dann kannst Du Dich in Deinem Code mit Deinem Knöpfchen freuen. :-)

_________________
Es gibt keine Probleme - nur Lösungen!
Coder Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1383
Erhaltene Danke: 1

WinXP
D2005 PE
BeitragVerfasst: Fr 03.08.07 15:06 
Jupp. Nur muss ich dann die ganzen Eigenschaften der Komponente auch zur Laufzeit setzen.
Beim VirtualTreeView sind das ne ganze Menge.
Und das ist mir für nur eine zusätzliche Eigenschaft zu viel Aufwand.
Da lass ichs lieber mit OOP.

MfG
Logikmensch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: Fr 03.08.07 18:13 
Stimmt, bei komplexeren Objekten ist es mit dem Designer einfacher. Ich verstand Dich so, dass es Dir "nur" um einen Button geht.

Ich hoffe, ich war nicht zu schroff. Meine ersten Versuche in der Komponentenentwicklung gingen in dieselbe Richtung wie Dein Typecast-Versuch. :-)

_________________
Es gibt keine Probleme - nur Lösungen!
Reinhard Kern
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 591
Erhaltene Danke: 14



BeitragVerfasst: Fr 03.08.07 18:19 
user profile iconCoder hat folgendes geschrieben:
Jupp. Nur muss ich dann die ganzen Eigenschaften der Komponente auch zur Laufzeit setzen.
Beim VirtualTreeView sind das ne ganze Menge.
Und das ist mir für nur eine zusätzliche Eigenschaft zu viel Aufwand.
Da lass ichs lieber mit OOP.

MfG


Hallo,

ich mache mir einfach eine neue Klasse, die die zugrundeliegende Komponente "benutzt" und erweitert:

ausblenden volle Höhe 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:
52:
53:
54:
55:
56:
  TRKStringGrid = class (TComponent)
    private
    FHeader : TLabel;
    public
    FStringGrid : TStringGrid;
    NextRow,NextEntry : integer;
    constructor create (AOwner : TComponent; myGrid : TStringGrid); 
    procedure AssignHeader (H : TLabel);
    procedure SetHeader (txt : string);
    procedure SetHItem (txt : string; cix : integer);
    procedure SetC0Item (txt : string; rix : integer);
    procedure SetC0Number (rn : integer);
    procedure SetColText (txt : string; cix : integer);
    procedure SetColTextDef (deftxt,txt : string; cix : integer);
    procedure SetColInt (v : longint; cix : integer);
    procedure SetColBool (b : boolean; cix : integer);
    procedure Sort (col : integer; num,renumber : boolean);
    procedure Pack;
    procedure AutoAlign (h_only : boolean);
    procedure ClearGrid (irows : integer);
    procedure NewRow;
    procedure NewEntry;
    function  GetSelectedRow : integer;
    function  GetSelectedCode : ShortString;
    function  GetColText (c,r : integer) : ShortString;
    function  GetColInt (c,r : integer) : longint;
    end;


implementation

uses BLMain;

 constructor TRKStringGrid.create (AOwner : TComponent; myGrid : TStringGrid);
 begin
 inherited create (AOwner);
 FStringGrid := myGrid;
 end;

 procedure TRKStringGrid.AssignHeader (H : TLabel);
 begin
 FHeader := H;
 end;

 procedure TRKStringGrid.SetHeader (txt : string);
 begin
 if Assigned (FHeader) then FHeader.Caption := txt;
 end;
 
 procedure TRKStringGrid.SetHItem (txt : string; cix : integer);
 begin
 if Assigned (FStringGrid) then
   FStringGrid.Cells [cix,0] := txt;
 end;

.....


Geht in beliebigem Umfang, ich muss eben nur beim Create mit der Komponente "connecten". Im Beispiel sind es 2, ein Label und ein Stringgrid. Das Label benutze ich nur manchmal.

Gruss Reinhard
dummzeuch
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: So 05.08.07 13:52 
Titel: den Compiler reinlegen
Hi,

es gibt auch die Moeglichkeit, dem Compiler vorzuspiegeln, dass eine Komponente von einem abgeleiteten Typ ist:

ausblenden 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:
unit Unit1;

interface

[...]

type
  TEdit = class(Controls.TEdit)
  public
    procedure doSomething;
  end;

type
  TForm1=class(TForm)
    Edit1: TEdit;
    [...]
  end;
[...]

implementation

[...]
procedure TEdit.doSomething;
[...]
end.


Damit hat ploetzlich jede TEdit-Komponente auf dem Formular eine zusaetzliche Methode doSometing, die man wie folgt aufrufen kann:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure TForm1.Edit1Click(Sender: TObject);
begin
  (Sender as TEdit).doSomething;
end;


Auf diese Weise kann man einer Komponente auch neue Eventhandler, Messagehandler und Properties verpassen. Funktioniert wunderbar, auch ueber Unit-Grenzen hinweg, man muss nur den Gueltigkeitsbereich des Typs beachten.

Im Grunde genommen ist dies nichts anderes als das Erstellen einer abgeleiteten Komponente, nur dass man sie nicht in der IDE installiert und dass sie denselben Namen hat wie eine Standard-Komponente.

twm

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt
Reinhard Kern
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 591
Erhaltene Danke: 14



BeitragVerfasst: So 05.08.07 19:46 
Titel: Re: den Compiler reinlegen
user profile icondummzeuch hat folgendes geschrieben:
Hi,

es gibt auch die Moeglichkeit, dem Compiler vorzuspiegeln, dass eine Komponente von einem abgeleiteten Typ ist:

ausblenden 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:
unit Unit1;

interface

[...]

type
  TEdit = class(Controls.TEdit)
  public
    procedure doSomething;
  end;

type
  TForm1=class(TForm)
    Edit1: TEdit;
    [...]
  end;
[...]

implementation

[...]
procedure TEdit.doSomething;
[...]
end.


Damit hat ploetzlich jede TEdit-Komponente auf dem Formular eine zusaetzliche Methode doSometing, die man wie folgt aufrufen kann:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure TForm1.Edit1Click(Sender: TObject);
begin
  (Sender as TEdit).doSomething;
end;


Auf diese Weise kann man einer Komponente auch neue Eventhandler, Messagehandler und Properties verpassen. Funktioniert wunderbar, auch ueber Unit-Grenzen hinweg, man muss nur den Gueltigkeitsbereich des Typs beachten.

Im Grunde genommen ist dies nichts anderes als das Erstellen einer abgeleiteten Komponente, nur dass man sie nicht in der IDE installiert und dass sie denselben Namen hat wie eine Standard-Komponente.

twm


Hallo,

damit verarschst du nicht den Compiler, der unterscheidet sicher zwischen Unit1.TEdit und Controls.TEdit, sonst würde das ganze ja auch nicht funktionieren. Für dein Unit1.TEdit wird ganz ordentlich eine erweiterte Methodentabelle angelegt mit doSomething.

Vielmehr legst du die kleinen Hilfsprogramme wie den Object-Inspector herein - nehme ich an, sonst wäre das ganze wenig sinnvoll. Wenn ich Unit1.TEdit nicht damit bearbeiten kann, habe ich ja nichts von der ganzen Übung.

Gruss Reinhard
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 05.08.07 20:26 
Ich bezweifle, dass das wirklich stabil laufen wird, da die VCL Komponenten-Klassen allein an ihrem Namen unterscheided, wodurch nicht sicher ist, ob Controls.TEdit oder Unit1.TEdit in der DFM-Resource gemeint ist. Und selbst wenn es korrekt aufgelöst wird, besteht immer noch das Problem, ob er wirklich eine Instanz von Unit1.TEdit angelegt wurde (oder doch nur von Controls.TEdit, was dann ziemlich krachen würde ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
dummzeuch
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: So 05.08.07 21:07 
Hi,

user profile iconBenBE hat folgendes geschrieben:
Ich bezweifle, dass das wirklich stabil laufen wird, da die VCL Komponenten-Klassen allein an ihrem Namen unterscheided, wodurch nicht sicher ist, ob Controls.TEdit oder Unit1.TEdit in der DFM-Resource gemeint ist. Und selbst wenn es korrekt aufgelöst wird, besteht immer noch das Problem, ob er wirklich eine Instanz von Unit1.TEdit angelegt wurde (oder doch nur von Controls.TEdit, was dann ziemlich krachen würde ...


Es funktioniert und ist stabil. Was nicht klappt, sind neue published properties, die wuerden nicht gestreamt.

twm
Coder Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1383
Erhaltene Danke: 1

WinXP
D2005 PE
BeitragVerfasst: Mi 08.08.07 16:08 
Klasse! Dann werd ich das so machen wie dummzeuch.
Danke an alle :zustimm: