Autor Beitrag
j0hnny Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: So 31.10.10 14:05 
Cool, danke. Funktioniert super. Bei mir macht der allerdings mit Strg+Shift+C noch zusätzlich eine Set-Funktion "property ColorError: TColor read FColorError write SetColorError;". Aber von Hand eingetragen klappts.

Jetzt bin ich schon fast fertig mit der Komponente. Allerdings würde ich gerne noch eine Liste von Strings mit dazugehörigen Floats definieren. Also jeweils Variablenname und Wert. Für die Liste der Strings kann ich ja eine StringList als property definieren, die über das IDE definiert werden kann. Aber wie mache ich das mit dem array of Double? Ohne property würde ich einfach einen dynamischen array definieren. Aber wie mache ich eine Liste von Zahlen, die per IDE eingetragen werden kann? Gibt es eine Art StringList für Zahlen oder die Möglichkeit auch dynamische Arrays als property zu benutzen? Oder fällt euch noch ne andere Möglichkeit ein?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 31.10.10 14:10 
user profile iconj0hnny hat folgendes geschrieben Zum zitierten Posting springen:
Bei mir macht der allerdings mit Strg+Shift+C noch zusätzlich eine Set-Funktion "property ColorError: TColor read FColorError write SetColorError;". Aber von Hand eingetragen klappts.
Ich mache das so:
Ich schreibe "property XY", drücke dann Strg + Left, kopiere den Namen, schreibe "read F", Strg + V, "write F", Strg + V, dann Strg + Shift + C. Schon ist alles fertig. ;-)

Und für die zweite Frage: Das müsste mit einer eigenen Klasse gehen, aber da müsste ich auch mal schauen welche Methoden du implementieren musst.

// EDIT:
Auf den ersten Blick würde ich sagen du musst ReadData und WriteData implementieren.
j0hnny Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: Mo 01.11.10 16:08 
Dank eurer Hilfe bin ich nun soweit Fertig mit meiner Komponente. Allerdings gibts noch eine Sache, die ich nicht hinbekomme. Und zwar habe ich zwei Komponenten miteinander verknüpft. Also in Comp1 ist Comp2 eingebunden als:

ausblenden Delphi-Quelltext
1:
2:
published
  property Comp2: TComp2 read FComp2 write FComp2;


Wie teile ich Comp1 mit, dass sich bei Comp2 eine Variable geändert hat? Muss ich das irgendwie ein procedure von Comp1 in Comp2 überschreiben oder so?

Ein weiteres Problem ist, dass ich wenn ich bei Load von Comp1 auf Comp2 zugreifen will, ist Comp2 noch NIL. Wie kriege ich hin, dass Comp2 vor Comp1 geladen wird?

Grüße
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 01.11.10 16:23 
Du kannst z.B. einen Setter für deine Eigenschaft benutzen. Dann kannst du beim zuweisen von comp2 ein Event dort setzen, das dir dann eine Änderung mitteilt.

Ja, und wegen nil: wenn du das im Konstruktor erzeugst, klappt das. Wenn das erst später zugewiesen wird, kannst du auch keine Eigenschaften der Unterklasse im OI zuweisen.
j0hnny Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: Mo 01.11.10 17:02 
Comp2 ist ja quasi schon der Comp1 zugewiesen. Die Änderung einer Eigenschaft von Comp2 soll der Comp1 mitgeteilt werden. Hier weiß ich jetzt nicht, wie ich zwischen Comp1 und Comp2 kommunizieren kann, wenn Comp2 schon zugewiesen wurde.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 01.11.10 17:33 
Das kannst du wie gesagt beim Zuweisen einrichten. Indem du einen Setter benutzt, der dafür ein Event bei der untergeordneten Komponente setzt.
Dann wird die entsprechende Methode in deiner äußeren Komponente ausgelöst, wenn die innere das Event feuert.
j0hnny Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: Mo 01.11.10 22:15 
Sorry, aber irgendwie raff ich das nicht so ganz. Also die untergeordnete Comp2 soll der übergeordneten Comp1 sagen, dass es bei ihr was neues gibt^^ Also hab ich irgendwie das Problem wie ich aus Comp2 auf Comp1 zugreifen, weil ja Comp1 in Comp2 integriert ist und nicht umgekehrt.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 02.11.10 00:08 
ok, mal so im Browser runtergetippselt, Tippfehler kannst du behalten: :D
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:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
type
  TChangedValue = (chvFirst, chvSecond);

  TOnValueChanged = procedure(Sender: TObject; ChangedValue: TChangedValue) of object;

  TComp2 = class
  private
    FOnValueChanged: TOnValueChanged;
    FValue1, FValue2: Integer;
    procedure DoValueChanged(ChangedValue: TChangedValue);
    procedure SetValue1(const Value: Integer);
    procedure SetValue2(const Value: Integer);
  public
    property OnValueChanged: TOnValueChanged read FOnValueChanged write FOnValueChanged;
    property Value1: Integer read FValue1 write SetValue1;
    property Value2: Integer read FValue2 write SetValue2;
  end;

  TComp1 = class
  private
    FComp2: TComp2;
    procedure Comp2ValueChanged(Sender: TObject; ChangedValue: TChangedValue);
  public
    constructor Create();
    destructor Destroy(); override;
    property Comp2: TComp2 read FComp2;
  end;

implementation

procedure TComp2.DoValueChanged(ChangedValue: TChangedValue);
begin
  if Assigned(FOnValueChanged) then
    FOnValueChanged(Self, ChangedValue);
end;

procedure TComp2.SetValue1(const Value: Integer);
begin
  FValue1 := Value;
  DoValueChanged(chvFirst);
end;

procedure TComp2.SetValue2(const Value: Integer);
begin
  FValue2 := Value;
  DoValueChanged(chvSecond);
end;

procedure TComp1.Comp2ValueChanged(Sender: TObject; ChangedValue: TChangedValue);
begin
  if ChangedValue = chvFirst then
    ShowMessage('Erster Wert geändert')
  else
    ShowMessage('Anderer Wert geändert');
end;

constructor TComp1.Create();
begin
  FComp2 := TComp2.Create();
  FComp2.OnValueChanged := Comp2ValueChanged;
end;

destructor Destroy(); override;
begin
  FComp2.Free();
end;
j0hnny Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: Mi 03.11.10 12:32 
Vielen Dank! Wusste ich garnicht, dass man das so mit den Events machen kann. Sehr schön.

Jetzt habe ich aber schonwieder ein Problem. Irgendwie komme ich mit der Reihenfolge der Funktionsaufrufe bei Erzeugung mehrerer Komponenten absolut nicht klar.

Also ich verknüpfe zwei Komponenten miteinander. Comp2 ist quasi ne Unterkomposition von Comp1. In Comp2 gibts eine StringList als published property, die man in der IDE verändern kann. Nun gibt es einen Setter für diese Stringlist, der mir aus den Strings einen array von Zahlen macht. Das klappt soweit ganz gut. Allerdings ist dieser array nach ausführen des Programms wieder gelöscht, obwohl er zur Designtime noch gefüllt existiert.
Naja jetzt will ich über Comp1 auf diesen array von Comp2 zugreifen. Habe jetzt verschiedene Dinge ausprobiert. Beispielsweise den Setter der Stringlist auch beim Laden von Comp2 zu aktivieren um den array zu füllen.
Dieser array ist aber noch nicht gefüllt, wenn ich ihn in Comp1 aufrufen will.
Wenn ich jetzt einen Getter für den array nutze, existiert zu den Zeitpunkt des Aufrufs in Comp1 aber noch nicht die Stringlist.
Wenn ich beim Create von Comp2 auf die Stringlist zugreifen will ist diese noch leer. Wenn ich in Comp2 beim Loaded auf die Stringlist zugreife um den array zu füllen klappt dies zwar, aber das Loaded von Comp2 wird erst nach dem Loaded von Comp1 ausgeführt.

Gibt es nicht irgendeine Möglichkeit auf die generierten Daten aus der Designtime in der Runtime zuzugreifen? Bzw. wie kriege ich es hin, dass Loaded von Comp2 vor Comp1 ausgeführt wird? Oder gibt es vielleicht auch noch eine weiter Funktion die ich überschreiben kann, die nach Loaded ausgeführt wird?
j0hnny Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: Mi 03.11.10 16:55 
Hat sich erledigt. Habe es jetzt anders gelöst. Aber vielen Dank nochmal für eure Hilfe.

Jetzt habe ich aber immer noch eine Frage. Ich habe zwei fast identische Komponenten. Die einen leitet sich von TEdit (TComp1) ab und die andere von TLabeledEdit (TComp2). Beide haben die selbe property Prop1. Jetzt möchte ich beide miteinander kompatibel machen. Die Komponenten kommunizieren unter sich über:

ausblenden Delphi-Quelltext
1:
2:
if Owner.Components[i].ClassType=TComp1 then
 temp:=TComp1(Owner.Components[i]).Prop1;


Jetzt möchte ich aber, dass diese Abfrage für Comp1 und Comp2 funktioniert:

ausblenden Delphi-Quelltext
1:
2:
3:
Comp:=Owner.Components[i];
if (Comp.ClassType=TComp1) or (Comp.ClassType=TComp2) then
 temp:=TComp1(Owner.Components[i]).Prop1;


Das liefert mir aber leider ne Zugriffsverletzung. Kann man irgendwie auf Prop1 zugreifen, ohne vorher abzufragen, ob es sich um TComp1 oder TComp2 handelt?

EDIT: Habe ein weiteres Problem. Und zwar benutze ich einen Setter für TStrings. Wenn die Strings über die Designumgebung geändert werden, wird die Setter Prozedur ausgelöst. Wenn ich aber zur Runtime Strings editieren, wird die Setter Prozedur nicht ausgelöst. Gibts da eine einfache Methode auf Änderungen zu reagieren?

Grüße
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 03.11.10 17:48 
user profile iconj0hnny hat folgendes geschrieben Zum zitierten Posting springen:
Kann man irgendwie auf Prop1 zugreifen, ohne vorher abzufragen, ob es sich um TComp1 oder TComp2 handelt?
Packe die gemeinsamen Eigenschaften in ein interface und lasse das beide implementieren. ;-)
j0hnny Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: Mi 03.11.10 18:00 
Wie kann man denn beide in ein Interface packen?^^
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 03.11.10 18:08 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
type
  IMyInterface = interface
    property XY read Get...
  end;

  TComp1 = class(T..., IMyInterface)
    property XY read Get...
  end;

  TComp2 = class(T..., IMyInterface)
    property XY read Get...
  end;

var
  a: IMyInterface;
begin
  a := MyComp1;
  a.XY ...
  a := MyComp2;
  a.XY ...
  // usw.
Casten geht natürlich auch.
j0hnny Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: Mi 03.11.10 18:37 
Danke! Habs jetzt in ein Interface gepackt. Nur leider will er jetzt nicht

ausblenden Delphi-Quelltext
1:
2:
Comp:=Owner.Components[i];
IMyInterface(Comp).Prop1;


fressen :(
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 03.11.10 20:02 
Das geht nicht so einfach. Hier musst du erst nachfragen ob das Objekt das Interface implementiert. Beispiel (sehr zusammengedrängt und ungetestet^^):
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  MyInterface: IMyInterface;
  MyObject: TComponent;
begin
  MyObject := TComp1.Create(nil);
  TComp1(MyObject).XY := 100;
  if Succeeded(IInterface(MyObject).QueryInterface(IMyInterface, MyInterface)) then
    ShowMessage(IntToStr(MyInterface.XY));
j0hnny Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 30



BeitragVerfasst: Mi 03.11.10 23:28 
Wenn ich eh eine Abfrage brauche, dann mache ich es einfach ähnlich wie oben beschrieben. Aber die Sache mit dem Interface ist schonmal gut um das Ganze besser zu ordnen. Wieder was dazu gelernt ;)

Hast du vielleicht auch noch eine Antwort auf meine andere Frage :) Hatte die nur via Edit hinzugefügt.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 04.11.10 06:00 
Der Unterschied ist, dass zur Designzeit das TStrings Objekt neu zugewiesen wird, während du dir das vermutlich holst und darin etwas änderst. Und das löst den Setter nicht aus.

Du kannst aber eine eigene Klasse von TStringList ableiten und dort Changed überschreiben. Oder eine normale TStringList nehmen und OnChanged zuweisen.

Dann bekommst du darüber die Änderungen mit.