Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Allgemeine Frage zu Zuweisungen von Instanzen (https://www.delphipraxis.net/93994-allgemeine-frage-zu-zuweisungen-von-instanzen.html)

guidobrose 14. Jun 2007 13:29


Allgemeine Frage zu Zuweisungen von Instanzen
 
Hallo, ich habe zwar grad ein Tutorial durchgelesen, aber es werfen sich doch noch Fragen auf.

Ich habe zwei Instanzen z.B.
Delphi-Quellcode:
var Liste1, Liste2: TStringlist;

Liste1:=TStringlist.Create;
Liste2:=TStringlist.Create;
Durch diese Zuweisungen wird jetzt der notwendige Speicher für die Listen reserviert und der Zeiger darauf in "Liste1" und "Liste2" gespeichert, oder?
Delphi-Quellcode:
Liste2:=Liste1;
Dies bewirkt nun das der Zeiger auf den Speicher von Liste1 auf Liste2 kopiert wird. Damit greifen beide Variablen nun auf den selben Speicherbereich (auf die gleiche Liste) zu. Der vorher zugewiesene Speicherbereich von Liste2 ist damit zwar noch im Speicher vorhanden, aber nicht mehr erreichbar (und damit verwaist), oder?

Delphi-Quellcode:
var Liste1, Liste2: TStringlist;

Liste1:=TStringlist.Create;
Liste2:=Liste1;
Das sollte demnach auch funktionieren, da ja durch die Variablendeklaration der Speicher für den Zeiger auf eine Liste erzeugt wurde und nun der Inhalt von Liste1 auch über Liste2 erreichbar ist, oder?

Jetzt noch eine etwas spezieller auf mein eigentliches Problem zugeschnittene Frage:
Ich möchte eine Klasse von TEdit ableiten und dieser eine Funktion Autocomplete verpassen. Für diese Funktion benötige ich natürlich auch eine Liste, die die Strings enthält, in denen gesucht wird. Also ungefähr so:
Delphi-Quellcode:
  TXTEdit = class(TEdit)
  private
    FAutocomplete: Boolean;
    FSearchList: TStringlist;
  protected
    procedure DoAutocomplete;
    procedure CMChanged(var Message: TMessage); message CM_CHANGED;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Autocomplete: Boolean read FAutocomplete write FAutocomplete default False;
    property Searchlist: TStringlist read FSearchlist write FSearchlist;
  end;
Meine Idee ist, irgendwo im aufrufenden Programm zu schreiben:
Delphi-Quellcode:
  MyEdit.Searchlist:=EineStringliste;
  MyEdit.Autocomplete:=True;
wobei EineStringliste einiges sein kann, z.B. EinStringGrid.Cols[0] oder EineListbox.Items

Leider funktioniert das nicht so ganz wie ich will, sondern führt noch zu einer Zugriffsverletzung. Eigentlich sollte es doch nicht notwendig sein eine Instanz von FSearchlist im constructor zu erzeugen, mir reicht es ja, den Zeiger auf die zugewiesenen Liste zu haben, oder? Ich habe zwar beide Varianten bereits ohne Erfolg ausprobiert, aber mir gehts darum grundsätzlich zu verstehen, ob das so gehen müsste.

Ich hoffe, jemand kann mir auf meine Anfängerfragen eine Antwort geben. Es ist echt tragisch, man glaubt, jetzt kann ich genug, um ohne Hilfe weiter zu kommen und schon stößt man auf das nächste Problem.

Guido

shmia 14. Jun 2007 13:33

Re: Allgemeine Frage zu Zuweisungen von Instanzen
 
Delphi-Quellcode:
property Searchlist: TStringlist read FSearchlist write FSearchlist; // Falsch
property Searchlist: TStrings read FSearchlist write FSearchlist; // Besser

Phoenix 14. Jun 2007 13:36

Re: Allgemeine Frage zu Zuweisungen von Instanzen
 
Also beide Annahmen oben stimmen.
Die 'verwaiste' TStringList aus der ersten Annahme nennt man übrigens ein Speicherleck. -> Speicher der angefordert wird aber nie freigegeben wird.

Delphi-Quellcode:
property Searchlist: TStringlist read FSearchlist write FSearchlist;
Pfui. :zwinker:

Delphi-Quellcode:
[...]
function getSearchList:TStringlist;
[...]
property Searchlist: TStringlist read getSearchList write FSearchlist;
Und dann weiter:
Delphi-Quellcode:
function TXTEdit.getSearchList: TStringList;
begin
  if not Assigned(FSearchList) then
    FSearchList := TStringList.Create();

  result := FSearchList;
end;

destructor TXtEdit.Destory;
begin
  if Assigned(FSearchList) then
    FreeAndNil(FSearchList);

  inherited;
end;
Somit bekommst Du die Instanz der Searchlist genau dann, wenn Du das erste mal drauf zugreifst und räumst sie wieder auf, wenn Dein Edit zerstört wird.

guidobrose 14. Jun 2007 13:51

Re: Allgemeine Frage zu Zuweisungen von Instanzen
 
Delphi-Quellcode:
property Searchlist: TStringlist read FSearchlist write FSearchlist; // Falsch
property Searchlist: TStrings read FSearchlist write FSearchlist; // Besser
Mit TStringlist und TStrings bin ich mir im Gebrauch nicht immer sicher, aber da TListbox.Items auch vom Typ TStrings ist, wird es wohl so sein.

Delphi-Quellcode:
[...]
function getSearchList:TStrings;
[...]
property Searchlist: TStrings read FSearchList write SetSearchlist;
Sollte es nicht so herum sein. Ich erzeuge doch die Liste, wenn ich an Searchlist etwas zuweise, oder?

ABER Warum muss ich diese Liste überhaupt erzeugen? Der Speicher für die Liste ist doch bereits durch die Liste vorhanden, die ich an das XTEdit zuweisen möchte. Mir würde ja ein Zeiger darauf ausreichen (Annahme 2) UND erzeuge ich da nicht ein Speicherleck, wenn ich für FSearchlist Speicher reserviere und dieser dann meine "externe" Liste zuweise? Oder bin ich voll daneben?

Hawkeye219 14. Jun 2007 14:05

Re: Allgemeine Frage zu Zuweisungen von Instanzen
 
Hallo Guido,

Zitat:

Ich möchte eine Klasse von TEdit ableiten und dieser eine Funktion Autocomplete verpassen.
hast du schon einmal daran gedacht, eine TComboBox mit Delphi-Referenz durchsuchenTComboBox.Style = csSimple zu verwenden?

Gruß Hawkeye

Phoenix 14. Jun 2007 14:13

Re: Allgemeine Frage zu Zuweisungen von Instanzen
 
Zitat:

Zitat von guidobrose
Oder bin ich voll daneben?

Ja, denn Du willst einem Control für die interne Verwendung externe Objekte zuweisen.

Sorry, aber als Entwickler erwarte ich von einem Control, das es alles mitbring was es braucht.

Wäre ja noch schöner, wenn ich eine ComboBox auf mein Formular ziehe, dass ich dem dann die StringListe in denen die Items stecken auch noch selber ezeugen und zuweisen müsste. Nein, so Dinger hat das Control mitzubringen, und ich muss mich nur noch drum kümmern, dass das richtige da drin steht.

Ghostwalker 14. Jun 2007 14:13

Re: Allgemeine Frage zu Zuweisungen von Instanzen
 
Eine Gegenfrage...warum willst du die Liste außerhalb der Componente erzeugen, wenn sie eh nur von der Componente benutzt wird ? :)

Das mit dem direkten Zuweisen der Zeiger funktioniert deshalb nicht, weil es eben Objekt sind und die nicht nur Daten enthalten. Hinzu kommt, das deine Liste in der Komponente eine Property ist, d.h. da spielt dann noch das Streaming-System für VCL-Komponenten mit rein (wichtig um das z.B. in DFM-Dateien zu speichern) sowie die RTTI.

Ich gehe mal davon aus das du später diese Liste im Objektinspektor editieren willst, dir aber ggf. mehrfach laden bei mehreren XEdit's sparen möchtest. Dann hier mal ein Beispiel wie es funktioniert:


Die Componente (also..der entscheidende Teil davon):

Delphi-Quellcode:
   TXEdit = class(TEdit)
   PRIVATE
      fsearchlist:TStrings;
   PUBLIC
      Constructor Create(AOwner:TComponent);
      Destructor Destroy;Override;
   PUBLISHED
       property Searchlist : TStrings read fsearchlist write fsearchlist;
   END;

   IMPLEMENTATION

   Constructor TXEdit.Create(AOwner:Tcomponent);
   begin
     inherited create(AOwner);
     fsearchlist := TStringlist.create;
   end;
   
   Destructor TXEdit.Destroy;
   begin
    fsearchlist.free;
    inherited;
   end;
Get und Set-Methoden sind nicht unbedingt notwendig, das die Liste beim erzeugen der Komponente gleich mit erzeugt wird und beim zerstören der Komponente freigegeben wird. Das ist wichtig, damit die Liste später auch in der DFM-Datei landet.

Nun zum Programm, das gerne eine Liste an mehrere XEdits verteilen will:

Delphi-Quellcode:
    Procedure TForm1.Button1Click(Sender:TObject);
    var
     iList : TStrings;
    begin
      iList := TStringlist.create;
      iList.loadfromfile('C:\Searchlist.txt');
      XEdit1.Searchlist.assign(iList);
      XEdit2.Searchlist.assign(iList);
      XEdit3.Searchlist.assign(ilist);
      ilist.free;
    end;
Feddich..alle 3 Edits enthalten nun ein kopie der daten aus ilist. :)

Hoffe das hilft.

guidobrose 14. Jun 2007 14:45

Re: Allgemeine Frage zu Zuweisungen von Instanzen
 
Danke für die Infos bisher :-D

@Hawkeye: Nein, da verschwende ich keinen Gedanken daran, weil mir die Combobox nicht gefällt. Die Daten, mit denen mein Autovervollständigen arbeiten soll werden aus einem StringGrid kommen, das aus einer Datenbank gefüllt wird.

Ich habe jetzt mal was probiert, was sogar (weitgehend) funktioniert, aber noch Fragen bei mir aufwirft.

Delphi-Quellcode:
type

  TXTEdit = class(TEdit)
  private
    FAutocomplete: Boolean;
    FBAutocomplete: Boolean;
    FSearchList: TStrings;
    //FOnAutocomplete: TXTAutocompleteEvent;
  protected
    procedure DoAutocomplete;
    procedure CMChanged(var Message: TMessage); message CM_CHANGED;
  public
    constructor Create(AOwner: TComponent);Override;
    destructor Destroy; override;
    property Autocomplete: Boolean read FAutocomplete write FAutocomplete default False;
    //property OnAutocomplete: TXTAutocompleteEvent read FOnAutocomplete write FOnAutocomplete;
    property Searchlist: TStrings read FSearchlist write FSearchlist;
  end;

  TForm3 = class(TForm)
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private-Deklarationen }
    Edit: TXTEdit;
  public
    { Public-Deklarationen }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

constructor TXTEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FSearchlist:=TStrings.Create;
end;

destructor TXTEdit.Destroy;
begin
  FSearchlist.Free;
  inherited Destroy;
end;

procedure TXTEdit.DoAutocomplete;
var I, StartPos: Integer;
begin
  if assigned(FSearchlist) then
  begin
    for I:=0 to FSearchlist.Count-1 do
    begin
      if (Text='') or (LowerCase(FSearchlist.Strings[I])=LowerCase(Text)) then
      begin
//        if assigned(FOnAutocomplete) then
//          OnAutocomplete(I);
        Exit;
      end;
      if StrLComp(PChar(LowerCase(FSearchlist.Strings[I])), PChar(LowerCase(Text)),
        Length(Text)) = 0 then
      begin
        StartPos := Length(Text);
        Text := Text + Copy(FSearchlist.Strings[I], StartPos + 1, Length(FSearchlist.Strings[I]));
        SelStart := StartPos;
        SelLength := Length(Text) - StartPos;
//        if assigned(FOnAutocomplete) then
//          OnAutocomplete(I);
        Exit;
      end;
    end;
  end;
end;

procedure TXTEdit.CMChanged(var Message: TMessage);
begin
  if FAutocomplete then
    DoAutocomplete;
  inherited;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  Edit:=TXTEdit.Create(self);
  Edit.Parent:=Form3;
  Edit.Searchlist:=Listbox1.Items;
end;

procedure TForm3.FormDestroy(Sender: TObject);
begin
  Edit.Searchlist:=nil; //Warum brauche ich das???
end;

end.
Wenn ich die Zeile in FormDestroy nicht einfüge, dann kommt es zu einer ungültigen Zeigeroperation. Warum?

Phoenix 14. Jun 2007 14:54

Re: Allgemeine Frage zu Zuweisungen von Instanzen
 
Delphi-Quellcode:
procedure TForm3.FormCreate(Sender: TObject);
begin
  Edit:=TXTEdit.Create(self);
  Edit.Parent:=Form3;
  Edit.Searchlist:=Listbox1.Items; // <-- hier überschreibst Du die Instanz
end;
Das Formular will dann die ListBox aufräumen, die Items der Listbox, die die Listbox selber aufräumen will, wurde aber schon vom Edit aufgeräumt (ode rumgekehrt).

Bei den Items musst Du die per Assign von der Listbox auf das Edit kopieren.

DP-Maintenance 14. Jun 2007 15:00

DP-Maintenance
 
Dieses Thema wurde von "Phoenix" von "Object-Pascal / Delphi-Language" nach "VCL / WinForms / Controls" verschoben.
Eigentlich gehts hier ja auch eher um Controls ;-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:04 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz