AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Delphi Freigeben vom Propertys aus Generics..Tlist<tcontrol> gelingt nicht

Freigeben vom Propertys aus Generics..Tlist<tcontrol> gelingt nicht

Ein Thema von DrUArn · begonnen am 13. Mär 2018 · letzter Beitrag vom 14. Mär 2018
Antwort Antwort
DrUArn

Registriert seit: 20. Mär 2003
130 Beiträge
 
Delphi 10.3 Rio
 
#1

Freigeben vom Propertys aus Generics..Tlist<tcontrol> gelingt nicht

  Alt 13. Mär 2018, 18:24
Hi Comm,

habe ein Problem beim "Nachempfinden" von Components oder controls.
Propertys sollen in eine Generics.collections.tlist<tcontrol> eingeschrieben und verwaltet werden

Die Propertys werden unter bestimmten umständen nicht "gelöscht".

Funktionierendes Beispiel:
Delphi-Quellcode:
type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    FormRiched: TRichEdit;
    Formmemo: TMemo;
    DelformRiched: TButton;
    DelFormMemo: TButton;
    RichEdit2: TRichEdit;//zum Anzeigen
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure DelformRichedClick(Sender: TObject);
    procedure DelFormMemoClick(Sender: TObject);
  private
    FList: Tlist<tcontrol>;
    { Private-Deklarationen }
    property List: Tlist<tcontrol> read FList write FList;
  public
    { Public-Deklarationen }
  procedure showListinfos;
  end;

//erzeugen der Liste
procedure TForm1.FormCreate(Sender: TObject);
begin
list:=tlist<tcontrol>.Create;
list.Add(FormRiched);
list.Add(FormMemo);
end;

//freigeben der Liste
procedure TForm1.FormDestroy(Sender: TObject);
begin
freeandnil(flist);
end;

procedure TForm1.DelformRichedClick(Sender: TObject);
begin
if assigned(list.items[0]) then
begin
  list.items[0].free; //freeandnil(list.items[0]) geht nicht
  list.items[0]:=nil; //sonst zeigt der Listeneintrag noch auf "Etwas" ?, beim Erneuten aufrufen dieser Procedure Fehler
end;
showListinfos;
end;

procedure TForm1.DelFormMemoClick(Sender: TObject);
begin
if assigned(list.items[1]) then
begin
 list.items[1].free; //freeandnil(list.items[0]) geht nicht
 list.items[1]:=nil;
end;
showlistinfos;
end;

// zeigt, was noch assigned ist
procedure TForm1.showListinfos;
var
  I: Integer;
begin
RichEdit2.Clear;
for I := 0 to list.count-1 do
begin
if Assigned(list.items[i]) then
 richedit2.Lines.add('Eintrag '+inttostr(i)+' is ASSIGNEd' ) else
 richedit2.Lines.add('Eintrag '+inttostr(i)+' is NOT ASSIGNEd' )
end;
if assigned(FormRiched) then
 richedit2.Lines.add('FormRiched '+' is ASSIGNEd' ) else
  richedit2.Lines.add('FormRiched '+' is NOT ASSIGNEd' );

  if assigned(Formmemo) then
 richedit2.Lines.add('FormMemo is ASSIGNEd' ) else
  richedit2.Lines.add('FormeMemo is NOT ASSIGNEd' )
end;
Ich schreibe FormRichEd und FormMemo ein eine Liste und lösche sie dann per Button. Wenn ich beide Buttons betätigt habe, zeigt procedure TForm1.showListinfos folgendes:

Eintrag 0 is NOT ASSIGNEd
Eintrag 1 is NOT ASSIGNEd
FormRiched is NOT ASSIGNEd
FormeMemo is NOT ASSIGNEd

würde ich in der liste die Einträge nicht =NIL setzen, sieht es so aus:
Eintrag 0 is ASSIGNEd
Eintrag 1 is ASSIGNEd
FormRiched is NOT ASSIGNEd
FormeMemo is NOT ASSIGNEd

also die Liste zeigt noch auf etwas. (wenn man über die Liste auf die Propertys versuchen würde, zu zugreifen - ist ja assigned - gibt's Fehler) Aber die Propertays FormRichEd und Formmemo wurden ordnungsgemäß freigegeben und von wem auch immer auf nil gesetzt.



Nun Der PROBLEMFALL als verkürztes Beispiel: Ein z.b. tRichedit soll als Propertys einen tRichedit und ein tmemo verwalten. Und diese sollen auch über eine eigenen Liste verwaltet werden

Delphi-Quellcode:
type

tShowOpt_UA =(ShowOwnRichEd_UA, ShowOwnMemo_UA,ShowOwnHeadContr_UA,ShowOwnstatBar_UA, ShowDeleteOwnComps_UA);
tShowOpts_UA = set of tShowOpt_UA;


TTestRich_UA = class(TRichedit)
private
  { private declarations }
    FOwnRichEd: trichedit;
    FOwnMemo: tmemo;
    FOwnControlList: tlist<TControl>;// geht so nicht zum löschen?
protected
  { protected declarations }
    procedure SetParent(AParent: TWinControl); override;//hier wird Parent Von testrich gesetzt und und man kann z.b. Top und left von den Own-Komponenten setzen
public
  { public declarations }
  property OwnControlList: tlist<TControl> read FOwnControlList write FOwnControlList;//die Verwaltungsliste
published
  { published declarations }
  property OwnRichEd: trichedit read FOwnRichEd write FOwnRichEd;
  property OwnMemo: tmemo read FOwnMemo write FOwnMemo;

  constructor Create(AOwner:TComponent);override;
  procedure CreateOwnComps(SO: tshowopt_UA);virtual;//hier wird je nach Anforderung OwnRiched und OwnMemo erzeugt

  procedure CreateOwnRichEd;virtual;// Routine für OwnRiched
  procedure CreateOwnMemo;virtual;// Routine für OwnMemo

  destructor destroy;override;//die Liste wieder löschen
  procedure expresscontrols;virtual;//Onwriched und OwnMemo Parent zuteilen - Darstellung auf der Form

  procedure SetParentDepOwnProps(SO: tshowopt_UA);virtual;//das Berechnen, was vor dem Setzen von Riched.parent nicht mgl. war
end;

{ TTestRich_UA }
constructor TTestRich_UA.Create(AOwner: TComponent);
 var so:tshowopt_UA;
     I: Integer;
 begin
  inherited;
  OwnControlList:=tlist<TControl>.create;
  OwnRichEd:=nil;
  OwnMemo:=nil;
  for so := Low(tshowopt_UA) to High(tshowopt_UA) do
      CreateOwnComps(so);

for I := 0 to componentcount-1 do
if components[i] is tcontrol then
OwnControlList.add(tcontrol(components[i]));
{
  entspricht oben
  with OwnControlList do
  begin
  add(FOwnRichEd);
  add(FOwnMemo);
  end;
}

end;

procedure TTestRich_UA.CreateOwnComps(SO: tshowopt_UA);
begin
case so of
  ShowOwnRichEd_UA: CreateOwnRichEd;
  ShowOwnMemo_UA: CreateOwnMemo;
end;

end;

procedure TTestRich_UA.CreateOwnMemo;
begin
  if not Assigned(OwnMemo) then
  begin
  OwnMemo:=tmemo.create(self);
  with OwnMemo do
  begin
  name:='OwnMemo';
  SetSubComponent(true);
  width:=Width div 2;
  Height:=height;
  if self.parent=nil then parent:=self else
  begin
  parent:=self.parent; //zur laufzeit erzeugt
   SetParentDepOwnProps(ShowOwnMemo_UA);//dann auch top und left berechnen
  end;
  Show;
  end;
  end else OwnMemo.show;

end;

procedure TTestRich_UA.CreateOwnRichEd;
begin
  if not Assigned(OwnRichEd) then
  begin
  OwnRichEd:=trichedit.create(self);
  with OwnRichEd do
  begin
  name:='OwnRiched';
  SetSubComponent(true);
  width:=Width div 2;
  Height:=height;
  if self.parent=nil then parent:=self else
  begin
  parent:=self.parent; //zur laufzeit erzeugt
   SetParentDepOwnProps(ShowOwnRichEd_UA);//dann auch top und left berechnen
  end;
  Show;
  end;
  end else ownriched.show;

end;

destructor TTestRich_UA.destroy;
begin
  freeandnil(fOwnControlList);
  inherited;
end;

procedure TTestRich_UA.expresscontrols;
 var i:integer;
begin
for I := 0 to componentcount-1 do
begin
  if components[i] is tcontrol then
  begin
   tcontrol(components[i]).parent:=self.parent;
   SetParentDepOwnProps(tshowopt_UA(i));
  end;
end;

end;

procedure TTestRich_UA.SetParent(AParent: TWinControl);
begin
  inherited;//parent wird gestzt
   if not (csDestroying in ComponentState) then // wenn nicht gerade in in auflösung
    expresscontrols;
end;

procedure TTestRich_UA.SetParentDepOwnProps(SO: tshowopt_UA);
  Procedure CalcOwnrichEd;
  begin
      if assigned(OwnRichEd) then
      with OwnRichEd do
      begin
        top:=self.top;
        left:=self.left+self.Width;
  end;
  end;

  Procedure CalcOwnMemo;
  begin
  if assigned(OwnMemo) then
  with Ownmemo do
  begin
  top:=self.top;
  left:=self.left-Width;
  end;
  end;


begin
case so of
  ShowOwnRichEd_UA: CalcOwnrichEd;
  ShowOwnMemo_UA: CalcOwnMemo;
end;

Wenn ich nun wie im funktionierenden Beispiel OwnRiched und OwnMemo via FOwnControlLis lösche und Nil setze,

Delphi-Quellcode:
procedure TForm1.Button3Click(Sender: TObject);
begin
if assigned(TestRich_UA1.OwnControlList.items[0]) then
begin
TestRich_UA1.OwnControlList.items[0].free;
TestRich_UA1.OwnControlList.items[0]:=nil;// ohne Nil setzen zeigt der Listeneintrag noch auf etwas
end;
showOwnListinfos;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
if assigned(TestRich_UA1.OwnControlList.items[1]) then
begin
TestRich_UA1.OwnControlList.items[1].free;
TestRich_UA1.OwnControlList.items[1]:=nil;// ohne Nil setzen zeigt der Listeneintrag noch auf etwas
end;
showOwnListinfos;
end;

ergibt die Prüfung auf Assigned folgendes:

Eintrag 0 is NOT ASSIGNEd
Eintrag 1 is NOT ASSIGNEd
ownRiched is ASSIGNEd
ownMemo is ASSIGNEd


D. h, die Propertys werden nicht gelöscht (?) oder zumindestens nicht Nil gesetzt.
Wenn ich z. B. dann auf die
procedure CreateOwnRichEd;virtual;
procedure CreateOwnMemo;virtual;
zugreife, gelten die propertys als assigned, und es wird .show angewendet. Allerdings zeigen sich die beiden nicht wieder, aber es wird auch kein Fehler ausgelöst.


Woran liegt das - unterschiedliche Owner und Parent - Parent als Tform verhindert irgendwas?

Bin gespannt

Grüße Uwe
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
971 Beiträge
 
Delphi 6 Professional
 
#2

AW: Freigeben vom Propertys aus Generics..Tlist<tcontrol> gelingt nicht

  Alt 13. Mär 2018, 21:00
Hmm..

Dir ist (hoffe ich) wohl bekannt, das eine Variable, die auf ein Object 'zeigt' nicht auf 'nil' gesetzt wird, wenn das Object zerstört wird?
Sie behält die Adresse, wo das Object mal war!
Dies ist bei jeder Objectvariable so...
Egal ob dies ein ListItem oder direkt eine Variable ist.

Bei einfachen Variablen gibt es dafür FreeAndNil()...
  Mit Zitat antworten Zitat
DrUArn

Registriert seit: 20. Mär 2003
130 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: Freigeben vom Propertys aus Generics..Tlist<tcontrol> gelingt nicht

  Alt 13. Mär 2018, 23:50
@HolgerX

Hallo, danke für die Antwort.

hmm ... im Prinzip weiß ich daß, aber im Trial and Error habe ich gesehen, daß beim Löschen der Listen-Variablen
im FUNKTIONIERENDEN BEISPIEL (Propertys direkt in tform gelegt) die Properties zum Schluß auch Nil waren:

Delphi-Quellcode:
if assigned(list.items[0]) then
begin
  list.items[0].free; //freeandnil(list.items[0]) geht nicht Es wird hier FormRiched.free gerufen

{list.items[0]:=nil;} //auch wenn ich den Listen-Eintrag nicht Nil setze
end;
ist FormRiched (oder FormMemo) hier schon NIL!
ICH WEISS NICHT; WER DAS MACHT!
Auch wenn ich den Listeneintrag NICHT Nil setze.

Den Listeneintrag muß ich Nil setzen, um bei einer erneuten Listen-Nutzung dort dann nicht in einen nur scheinbar assigned Listeneintrag zu greifen.


Im PROBLEMFALL wird ja ein ähnliches Konstrukt angewendet, nur das OwnRichEd und OwnMemo nicht das tForm als Eigentümer haben, sondern z.b. ein anderes Trichedit. Parent von den beiden Own-Komponenten wird erst gesetzt, damit sie sichbar werden im tForm.

Beim Löschen über die Liste
Delphi-Quellcode:
if assigned(TestRich_UA1.OwnControlList.items[0]) then
begin
TestRich_UA1.OwnControlList.items[0].free;
TestRich_UA1.OwnControlList.items[0]:=nil;
end;
wird zwar hier wohl z.B. Ownriched.free, damit Ownriched zerstört, aber eben nicht Nil gesetzt.

Heißt für mich leider, daß es wohl nichts wird, aus einer Liste heraus Properties zu löschen (GEHT) und Nil zu setzen (GEHT NICHT).

Die Hoffnung war, dies mit einer eleganten for-to-Schleife über die Listeneinträge zu schaffen statt z.B. so

Delphi-Quellcode:
case so of
  ShowOwnRichEd_UA: if free then FreeAndNil(FOwnRichEd) else if assigned(ownriched) then ownriched.hide;
  ShowOwnMemo_UA: if free then FreeAndNil(FOwnMemo) else if assigned(OwnMemo)then OwnMemo.Hide;
end;
hat sich da wohl erledigt.

Und dennoch - warum geht das bei Properties auf der Form?

Guß Uwe
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.474 Beiträge
 
Delphi 12 Athens
 
#4

AW: Freigeben vom Propertys aus Generics..Tlist<tcontrol> gelingt nicht

  Alt 14. Mär 2018, 00:30
ist FormRiched (oder FormMemo) hier schon NIL!
ICH WEISS NICHT; WER DAS MACHT!
Aber ich

Das funktioniert nur bei Feldern im published Bereich, so wie sie vom Form-Designer angelegt werden. Beim TComponent.Create wird AOwner.InsertComponent aufgerufen, was wiederum ein SetReference(True) aufruft. Darin wird im Owner nach einem (published) Field gesucht, daß den gleichen Namen hat wie die Komponente, und falls gefunden auf die Instanz der Komponente gesetzt. Nur durch diesen Mechanismus kann man die Form-Komponenten über ihren Variablennamen ansprechen.

Beim Destroy der TComponent geht es dann den umgekehrten Weg über RemoveComponent und SetReference(False) , was dann die Feld-Variable auf nil setzt.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:03 Uhr.
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