Entwickler-Ecke

Sonstiges (Delphi) - Objekte dynamisch erzeugen


Arakis - Do 13.06.02 21:52
Titel: Objekte dynamisch erzeugen
Hi,
zur Zeit programmiere ich einen Tabsheet-Browser so wie bei Natcaptor. Zu jedem dynamisch erstellten Browser muss ich jede Menge Infos zusätzlich speichern, wie z.B. die History usw.
Dazu habe ich einfach mal ein Object TBrowserDataen erstellt. Darin enthalten sich Stringlisten, Prozeduren, usw.
Das Problem jetzt ist nur, dass halt für jeden Browser so ein Datan-Objekt haben muss. Fast ohne Probleme geht es, wenn ich global ein ein Array of TBrowserdaten erstelle, nur bekomme ich dann Probleme beim Löschen und mit dem "Aufrücken". Ich habe mir sagen lassen, TList und TObjectslist wären da die bessere Möglichkeit. Aber mit denen bekomme ich nichts auf die Reihe. Denn so bald ich die Funkion verlasse, die das Object deklariert hat, wird das Objekt freigegeben, und der Zeiger in der TList zeigt ins Leere. Also suche ich nach einer Create-Methode. Gibt es anscheinend aber nicht. Wie kann ich jetzt ein Object dynamisch erstllen, dass auch nach verlassen der Funkion weiter im Speicher bleibt? Ist das nur mit Klassen möglich? Und wenn, wie?
user defined image

Bin für jede Hilfe dankbar :P

Bis dann,
Arakis
user defined image


Thunderman - Do 13.06.02 22:22

Hallo!

Also Variablen von einfachen Typen wie Integer oder auch records kannst du dynamisch mit New(); erzeugen und mit Dispatch wieder freigeben.
Klassen kannst du so erzeugen:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
type
  TMeineKlasse class(TComponent)
    x : Integer;
  end;
...
var
  MeineKlasse : TMeineKlasse;
begin
...
  MeineKlasse := TMeineKlasse.Create(nil);
...
end;

Die so erzeugte Variable MeineKlasse kannst du als Pointer in einer TList speichern. Und über diese Liste jederzeit auf die Variable zugreifen. Du musst nur bei beiden Fällen darauf achten, die Variablen auch wieder am Ende deines Programms auf jeden Fall wieder freizugeben. Entweder mit Dispatch(); oder halt im 2. Fall mit MeineKlasse.Free;

New und Dispatch sind eigentlich recht gut in der Delphi-Hilfe erklärt.
Falls Du noch Fragen zu TList hast, einfach raus damit.


Arakis - Do 13.06.02 22:32
Titel: Bitte ein kleines Beispiel
Jo, hätt ich :D

Du meinst, mein Objekt dürfte dann keine weiteren Unterobjekte enthalten, weil die ja nicht einfache Integer/String-Variablen sind? Was ist denn der Unterschied von Klassen und Objekten? Dann werde ich wahrscheinlich aber Klassen nehemen. Könnest du mir den Gefallen tun und ein ganz kleines Beispiel posten, wie man zur Laufzeit eine Klasse Erstellt, in einer TList (oder TObjectList/TClasslist) abspeichert, in einer anderen Funkion wieder anspricht? Dann wäre da noch das wieder freigeben mit free.
Wäre nett :wink:

Bis dann
user defined image


Tino - Do 13.06.02 23:25

Hi,

ich hab mir mal ein Beispiel zusammen gecodet:

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:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
Type
  tBrowser = Class
      Private
        fHistory: tStringList;    
      Public
        Constructor Create;
        Destructor Destroy;  override;

        Property History: tStringList read fHistory write fHistory;
    End;
    
  tBrowserList = Class
      Private
        fList: tList;
        
        Function GetCount: Integer;
        Function GetItems (Index: Integer): tBrowser;
        Procedure SetItems (Index: Integer; aBroswer: tBrowser);
      Public
        Constructor Create;
        Destructor Destroy;  override;
        
        Function Add (aBrowser: tBrowser): Integer;
        Procedure Delete (aIdx: Integer);
        Procedure Clear;
        
        Property Count: Integer read GetCount;
        Property Items [Index: Integer]: tBrowser read GetItems write SetItems;
    End;
    
{ tBrowser }    
    
Constructor tBrowser.Create;
Begin
  fHistory := tStringList.Create;
End;

Destructor tBrowser.Destroy;  
Begin
  fHistory.Free;
  
  Inherited;
End;

{ tBrowserList }

Constructor tBrowserList.Create;
Begin
  fList := tList.Create;  
End;

Destructor tBrowserList.Destroy;  override;
Begin
  Clear;
  fList.Free;
  
  Inherited;  
End;

Function tBrowserList.GetCount: Integer;
Begin
  GetCount := fList.Count;  
End;

Function tBrowserList.GetItems (Index: Integer): tBrowser;
Begin
  GetItems := tBrowser (fList [Index]);  
End;

Procedure tBrowserList.SetItems (Index: Integer; aBroswer: tBrowser);
Begin
  fList [Index] := aBrowser];  
End;
        
Function tBrowserList.Add (aBrowser: tBrowser): Integer;
Begin
  Add := fList.Add (aBrowser);  
End;

Procedure tBrowserList.Delete (aIdx: Integer);
Begin
  fList.Delete (aIdx);  
End;

Procedure tBrowserList.Clear;
Var
  Idx: Integer;
Begin
  For Idx := Count -1 DownTo 0 Do
    Delete (Idx);  
End;

Die Benutzung ist relativ einfach: Auf deinem Mainform erstellst Du eine Variable vom Type tBrowserList (am besten im OnCreate):BrowserList := tBrowserList.Createdieses Objekt musst Du natürlich wieder freigeben (im OnDestroy):BrowserList.FreeWenn Du jetzt ein neues Browserfenster erstellst musst du auch ein neues tBrowser-Objekte erstellen und der BrowserList hinzufügen:

Quelltext
1:
2:
3:
4:
  MDIForm := tMDIForm.Create (MainForm);
  BrowserInfo := tBrowser.Create;

  BrowserList.Add (BrowserInfo);
So mit hast Du zu jedem Browserfenster auch ein Info-Objekt (z. B. mit der Historyliste). Was Du jetzt noch machen musst ist das tBrowser-Objekt mit dem MDI-Form "verbinden". Am besten im Constructor des tBrowser-Objekt das MDI-Form mit angeben.

Gruß


Arakis - Do 13.06.02 23:28

Besten Dank Tino, werde ich dir nie vergessen 8)

Bis dann
user defined image


Tino - Do 13.06.02 23:33

Gerne! Aber keine Garantie das das sofort funktioniert da ich es nicht getestet habe.


Arakis - Fr 14.06.02 00:05
Titel: Programmierhilfe im Editor funzt nicht
Die Garantie sei dir gegeben :wink:
So wende ich das jetzt an:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TForm1.Button1Click(Sender: TObject);
var
  b : TBrowser;
begin
  b:=TBrowser.Create;
  b.fHistory.Add('test');
  BrowserList.Add(b);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  showmessage(BrowserList.Items[0].fHistory.text);
end;

Funzt ganz prima! Aber hier ist eine Sache, die ich schon öfters mal bei Objekten beobachtet habe: ich schreibe:
BrowserList.Items[0].fHistory
setzte dann einen Punkt, aber es kommt keine Programmierhilfe vom Editor! Woran liegt das eigentlich? Er konnte mir ja schließlich auch fHistory ohne zu überlegen anbieten.
user defined image

Bis dann
user defined image


Tino - Fr 14.06.02 09:37

Hab natürlich etwas vergessen: Hab meinen Beitrag von oben erweitert. Hinzugekommen ist die 9. Zeile:Property History: tStringList read fHistory write fHistory;Zu Deiner Frage warum fHistory nicht in der Codevervollständigung angezeigt wird: fHistory ist in der Private-Section definiert und gehört somit NUR dem Objekt selbst. Nach außen hin kann man es nicht benutzen! Deshalb habe ich jetzt auch in der Public-Section das Property History hinzugefügt damit Du sauber an das History-Objekte ran kommst!

Gruß


Phoenix - Di 25.06.02 16:21
Titel: Re: Programmierhilfe im Editor funzt nicht
Huhu,

Arakis hat folgendes geschrieben:
Funzt ganz prima! Aber hier ist eine Sache, die ich schon öfters
mal bei Objekten beobachtet habe: ich schreibe:
BrowserList.Items[0].fHistory
setzte dann einen Punkt, aber es kommt keine Programmierhilfe vom
Editor! Woran liegt das eigentlich?


Das liegt daran, das er ab dem Index in dem Array das Objekt nicht
mehr eineindeutig Identifizieren kann, selbst wenn das Array
ausschliesslich diesen einen Objekttyp beinhaltet. Das ist ein Bug(?),
oder ein fehlendes Feature der IDE.

Grüßle,

Sebastian