![]() |
Komponente mit TStrings Property erstellen
Hallo,
wie der Titel schon aussagt, habe ich ein kleines Problem beim Erstellen einer Komponente, welche ein TStrings Objekt als Property im OI anbieten soll. Ich habe mich beim Erstellen, an diverse Tutorials gehalten (zumindest versucht) aber jedesmal, wenn ich die Komponente dann auf ein Formular ziehe, der Property SQL (das ist die TStrings Property) einen String zuweise und das ganze dann noch ein zweites mal versuche, bekomme ich Zugriffsverletzungen, so, dass nur noch das Beenden von Delphi hilft. Ich verwende Delphi 7 Professional.
Delphi-Quellcode:
Was mache ich da nur falsch?
unit GSQuery;
interface uses SysUtils, Classes; type TGSQuery = class(TComponent) private FSQL: TStringList; procedure setSQL(const Value: TStringList); { Private-Deklarationen } protected { Protected-Deklarationen } public { Public-Deklarationen } constructor Create(aOwner: TComponent); override; destructor Destroy; override; published { Published-Deklarationen } property SQL: TStringList read FSQL write setSQL; end; procedure Register; implementation procedure Register; begin RegisterComponents('GS', [TGSQuery]); end; { TGSQuery } constructor TGSQuery.Create(aOwner: TComponent); begin inherited; FSQL := TStringList.Create; end; destructor TGSQuery.Destroy; begin FSQL.Free; inherited; end; procedure TGSQuery.setSQL(const Value: TStringList); begin FSQL := Value; end; end. |
Re: Komponente mit TStrings Property erstellen
Hallo Günter,
der Fehler steckt in der Setter-Methode. Durch die direkte Zuweisung überschreibst du die im Constructor initialisierte Referenz auf das TStringList-Objekt mit einem neuen Zeiger, was zunächst nur zu einem Speicherleck führt. Gleichzeitig übernimmt aber nun das Query-Objekt die Verantwortung für die übergebene Liste, die du vermutlich nach der Zuweisung zur SQL-Eigenschaft freigibst. Damit ist dann der Zeiger innerhalb des Query-Objekts ungültig! Besser ist es, im Setter den Inhalt der Liste zu kopieren:
Delphi-Quellcode:
Noch ein Vorschlag: ändere den Datentyp von FSQL ab in TStrings. Dadurch kannst du später beliebige TStrings-Nachfolger (z.B. TMemo.Lines) zuweisen. Im Constructor von TGSQuery muß natürlich weiterhin ein TStringList-Objekt instanziiert werden, da TStrings abstrakte Methoden enthält.
FSQL.Assign(Value);
Gruß Hawkeye |
Re: Komponente mit TStrings Property erstellen
Danke :)
Wenn ich Assign verwende klappt es, ein Query Objekt kommt aber nicht wirklich vor, das ist wirklich der komplette Quelltext der Komponente ... die Query kommt erst später dazu :) Das mit TStrings habe ich aber nicht hinbekommen, da meckert der Compiler immer über inkompatible Typen.
Delphi-Quellcode:
unit GSQuery;
interface uses SysUtils, Classes; type TGSQuery = class(TComponent) private FSQL: TStringList; procedure setSQL(const Value: TStrings); { Private-Deklarationen } protected { Protected-Deklarationen } public { Public-Deklarationen } constructor Create(aOwner: TComponent); override; destructor Destroy; override; published { Published-Deklarationen } property SQL: TStrings read FSQL write setSQL; end; procedure Register; implementation procedure Register; begin RegisterComponents('GS', [TGSQuery]); end; { TGSQuery } constructor TGSQuery.Create(aOwner: TComponent); begin inherited; FSQL := TStringList.Create; end; destructor TGSQuery.Destroy; begin FSQL.Free; inherited; end; procedure TGSQuery.setSQL(const Value: TStrings); begin FSQL.Assign(Value); end; end. |
Re: Komponente mit TStrings Property erstellen
Du mußt die Deklaration im private-Abschnitt ebenfalls ändern:
Delphi-Quellcode:
Falls du innerhalb der Komponente einmal auf die TStringList-Eigenschaften zugreifen mußt, benötigst du einen TypeCast:
private
FSQL: TStrings;
Delphi-Quellcode:
Bei der SQL-Eigenschaft sehe ich diese Notwendigkeit aber nicht.
TStringList(FSQL).Sorted := True;
PS: mit "Query-Objekt" meinte ich eine Instanz deiner TGSQuery-Klasse. Gruß Hawkeye |
Re: Komponente mit TStrings Property erstellen
Dankeschön, jetzt funktioniert das mal soweit wie ich es wollte.
|
AW: Komponente mit TStrings Property erstellen
Hallo zusammen,
das Thema ist zwar schon älter - ich habe aber bei gleichem Source-Code folgendes Problem: Im OI kann ich schön Strings in die Stringliste eintragen (mit dem automatisch öffnenden String-Listen-Editor). Soweit so gut. Wenn ich das Programm aber starte, dann sind die eingetragenen Werte nicht mehr vorhanden --> gibt es da einen Trick? Wo sollen die auch her kommen?:shock:
Code:
Im Konstruktor wird FSQL erzeugt --> ist also LEER.:?
constructor TGSQuery.Create(aOwner: TComponent);
begin inherited; FSQL := TStringList.Create; end; WIE komme ich nun an die zur Designzeit eingetragenen Werte?:cyclops: Wäre schön, wenn jemand eine Antwort für mich hätte. Viele Grüße, Poolspieler |
AW: Komponente mit TStrings Property erstellen
Hallo,
ich bin ein bisschen weiter: In FSQL sind die Werte schon vorhanden. Allerdings erst nach einem noch unbekannten Zeitpunkt. Problem ist, dass ich versuche, diese Werte im CONSTRUCTOR einer Combobox zuzuweisen. Und zum Zeitpunkt des Konstruktors ist FSQL tatsächlich noch LEER!
Code:
Frage:
constructor TGSQuery.Create(aOwner: TComponent);
begin inherited; FSQL := TStringList.Create; end; combobox.Items.Assign(FSQL); WANN werden die Werte nach FSQL geladen? Ich habe schon das Ereignis AfterConstruction probiert --> da ist FSQL noch LEER! Mit dem Debugger konnte ich den Zeitpunkt auch noch nicht finden. :( Hat jemand eine Idee? Viele Grüße, Poolspieler |
AW: Komponente mit TStrings Property erstellen
Hallo,
hast Du denn einen Setter für FSQL in Deiner Klasse TGSQuery? Schau Dir mal den Quellcode in ![]() Gruß |
AW: Komponente mit TStrings Property erstellen
Hallo Volker,
danke für Deine Antwort! Ja, habe ich schon. Allerdings stand ich auch gerade ganz schön auf der Leitung: Im Konstruktor muss es natürlich heißen:
Code:
Was will ich denn mit ZWEI Listen???????? :stupid:
constructor TGSQuery.Create(aOwner: TComponent);
begin inherited; ... combobox := TComboBox.Create(Self); ... FSQL := combobox.Items; // und NICHT: //FSQL := TStringList.Create; end; Es ist halt doch schon spät... Viele Grüße, Poolspieler |
AW: Komponente mit TStrings Property erstellen
Noch eine weiterfuehrende Frage,
ich habe auch eine TStrings Liste in den Properties einer eigenen Komponente. Zur Designzeit werden die eingetragenen Werte in der Liste durch eine Setter procedure uebernommen. Nun werden die eigentragenen Werte in der Stringliste dazu verwendet ein Array zu fuellen (wird ebenfalls in der Setter procedure erledigt). Das funktioniert waehrend des Designs prima, allerdings ist das Array zur Laufzeit wieder leer. Die Komponente ist von TPaintBox abegeleitet. Da das Array vom Typ record ist und einige werte zur Laufzeit geaendert werden kann ich das Erstellen des Arrays nicht einfach in die paint procedure packen, da sonst jedesmal standardwerte im Array stehen. Gibt es eine procedure die nur einmal nach dem constructor ausgefuehrt wird? Gutelo Edit: Habs jetzt so geloest in der paint procedure auch wenns nich ganz optimal ist: if Length(Arr) = 0 then FillArr(SList, Arr); Arr ist das Array, SList ist TStrings mit Werten und FillArr eine Prozedur die die Werte aus SList in Arr eintraegt. |
AW: Komponente mit TStrings Property erstellen
|
AW: Komponente mit TStrings Property erstellen
hmm, wenn ich ein override bei AfterConstruction durchfuehre und meinen Code eintrage dann passiert leider garnichts :(
Edit: hmm, ein showmessage zeigt mir dass er AfterConstruction abarbeitet, aber das Array wird nicht gefuellt |
AW: Komponente mit TStrings Property erstellen
Zitat:
Delphi-Quellcode:
kann aus nicht funktionierendem Code auch keinen funktionierenden zaubern ;)
AfterConstruction
Zeig doch mal den Code und mindestens den interface Teil deiner Komponente |
AW: Komponente mit TStrings Property erstellen
Hallo Rufo,
ich stell das Problem mal kurz dar mit Auszug aus meiner Komponente
Code:
Wie vorher schon gesagt reicht das "ReadButtons(VButtonList, AllButtons);" in SetButtonList nicht aus. Das AllButtons Array, welches zur Designzeit gefuellt wird, ist zur Laufzeit wieder leer. Auch wenn ich "ReadButtons(VButtonList, AllButtons);" in AfterConstruction packe bleibt das Array leer.unit MyComponent; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Dialogs, ExtCtrls, Math, StrUtils; type TPanelButton = record Left : integer; Top : integer; Width : integer; Height : integer; Caption : String; BorderColor : TColor; FillColor : TColor; FillCheckColor : TColor; UnCheckedFont : TFont; CheckedFont : TFont; Checked : boolean; end; Type TPanelButtons = Array of TPanelButton; ... MyComponent = class(TPaintBox) private VButtonList : TStringList; ... procedure SetButtonList(Value: TStringList); AllButtons : TPanelButtons; published ... property ButtonList : TStringList read VButtonList write SetButtonList; public procedure ReadButtons(List : TStrings; var BTNArr : TPanelButtons); ... implementation ... constructor MyComponent.Create(AOwner: TComponent); begin inherited Create(AOwner); VButtonList := TStringList.create; ... end; procedure MyComponent.SetButtonList(Value: TStringList); begin VButtonList.Assign(Value); ReadButtons(VButtonList, AllButtons); refresh; end; procedure MyComponent.ReadButtons(List : TStrings; var BTNArr : TPanelButtons); var i: Integer; PosKomma : integer; PosStart : integer; begin // Format of Button Strings: Caption,Left,Width,Top,Height SetLength(BTNArr, List.count); for i := 0 to List.Count - 1 do begin // Caption PosStart := 1; PosKomma := Pos(',', List[i]); BTNArr[i].Caption := Copy(List[i],PosStart,PosKomma-PosStart); // Left PosStart := PosKomma+1; PosKomma := PosEx(',', List[i], PosStart); BTNArr[i].Left := StrToInt(Copy(List[i],PosStart,PosKomma-PosStart)); // Top PosStart := PosKomma+1; PosKomma := PosEx(',', List[i], PosStart); BTNArr[i].Width := StrToInt(Copy(List[i],PosStart,PosKomma-PosStart)); // Width PosStart := PosKomma+1; PosKomma := PosEx(',', List[i], PosStart); BTNArr[i].Top := StrToInt(Copy(List[i],PosStart,PosKomma-PosStart)); // Height PosStart := PosKomma+1; PosKomma := Length(List[i])+1; BTNArr[i].Height := StrToInt(Copy(List[i],PosStart,PosKomma-PosStart)); // Other Button Options BTNArr[i].UnCheckedFont := TFont.Create; BTNArr[i].UnCheckedFont.Color := clBlue; BTNArr[i].CheckedFont := TFont.Create; BTNArr[i].CheckedFont.Color := clWhite; BTNArr[i].BorderColor := clBlue; BTNArr[i].FillColor := clWhite; BTNArr[i].FillCheckColor := clBlue; BTNArr[i].Checked := false; end; end; ... procedure MyComponent.paint(); begin ... hier werden die buttons aus dem Array gezeichnet end; Ich vermute, dass es am "Array of record" liegt. Bei anderen Strukturen bleiben die Werte zwischen Designzeit und Laufzeit erhalten. |
AW: Komponente mit TStrings Property erstellen
Aha, zur DesignTime und zur RunTime.
Wo sagst du denn, dass das ButtonArray auch gespeichert werden soll? Oder wie denkst du, dass zur RunTime noch was aus der DesignTime bekannt ist? Nachschauen, ja aber wo denn? Diese Informationen müssen in der .dfm stehen Und idR werden solche Unterkomponenten in variabler Anzahl als Collection gespeichert (die werden dann auch automatisch in der .dfm abgelegt und wieder ausgelesen, wenn published) Schau dir dazu mal ein paar Komponenten an, die solche Unterkomponenten haben (z.B. ![]() |
AW: Komponente mit TStrings Property erstellen
Naja, die Eintraege der TStringList bleiben ja auch zur Runtime erhalten. Und ich habe eine weitere Stringlist die nicht in einem Array gespeichert wird sondern nur in einem Record:
type TPanelGraph = record Left : integer; Top : integer; Width : integer; Height : integer; Gap : integer; BorderColor : TColor; FillColor : TColor; FillCheckColor : TColor; Values : Array of integer; end; Und in diesem Fall sind die Designzeit Eintraege ebenfalls noch zur Runtime vorhanden. |
AW: Komponente mit TStrings Property erstellen
Aaargs, nun reicht es doch die Werte mit der Setter prozedur zur Designzeit zu setzen und die Array werte sind zur Laufzeit noch da. Kann leider nicht sagen warum es jetzt geht.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:03 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz