Autor |
Beitrag |
j0hnny 
      
Beiträge: 30
|
Verfasst: 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 31.10.10 14:10
j0hnny hat folgendes geschrieben : | 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 
      
Beiträge: 30
|
Verfasst: 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:
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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
      
Beiträge: 30
|
Verfasst: 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
      
Beiträge: 30
|
Verfasst: 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 02.11.10 00:08
ok, mal so im Browser runtergetippselt, Tippfehler kannst du behalten:  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 
      
Beiträge: 30
|
Verfasst: 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 
      
Beiträge: 30
|
Verfasst: 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:
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:
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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 03.11.10 17:48
|
|
j0hnny 
      
Beiträge: 30
|
Verfasst: Mi 03.11.10 18:00
Wie kann man denn beide in ein Interface packen?^^
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 03.11.10 18:08
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 ... | Casten geht natürlich auch.
|
|
j0hnny 
      
Beiträge: 30
|
Verfasst: Mi 03.11.10 18:37
Danke! Habs jetzt in ein Interface gepackt. Nur leider will er jetzt nicht
Delphi-Quelltext 1: 2:
| Comp:=Owner.Components[i]; IMyInterface(Comp).Prop1; |
fressen 
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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^^): 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 
      
Beiträge: 30
|
Verfasst: 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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.
|
|
|