Delphi-PRAXiS
Seite 1 von 3  1 23      

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 String in Listview Data ? (https://www.delphipraxis.net/149791-string-listview-data.html)

Blamaster 30. Mär 2010 10:07


String in Listview Data ?
 
Hi,

ich möchte einen String im .Data eines Listviewitems hinterlegen.

Wie genau macht man das ?

Ich habe es gerade mal so versucht:

Delphi-Quellcode:
var
 test: string;
 item: TListItem;
begin
 test := 'Ich liege in der Listview.Items.Item.data'
 
 item := Listview.Items.Add;
 item.Caption := 'Irgendwas';
 item.Data := Pointer(test);
end;
Und dann zum auslesen:

Delphi-Quellcode:
ShowMessage(String(ListView.Items.Item[x].Data));
Dabei entstehen aber große Unregelmäßigkeiten. Mal steht der string im Data so wie er soll, mal nur merkwürdige Zeichen, mal garnichts, mal gibt es eine exception. Wo liegt mein Fehler ?

Mfg Yannic

IceBube 30. Mär 2010 10:15

Re: String in Listview Data ?
 
Hallo!

Also bei mir funktioniert das einwandfrei. Fehler sind bei mir nicht aufgetreten, auch wenn man nichts in die Data schreibt..kommt keine Exception...

lg

Neutral General 30. Mär 2010 10:17

Re: String in Listview Data ?
 
Der String darf nicht in einer lokalen Variable gespeichert sein. Dann sollte es gehen.

himitsu 30. Mär 2010 10:18

Re: String in Listview Data ?
 
Eventuell schlägt hier die Referenzzählung des Strings zu, wenn du den String über Pointer(...) zuweißt, wird da die Referenzzählung nicht behandelt.
Wird dann der übergebene String mal freigegeben, dann ist er weg und in .Data steht nur ein Zeiger zu einem nicht mehr existierendem String.

versuch es mal so:
Delphi-Quellcode:
//zuweisen
String(item.Data) := test;

// auslesen
test := String(item.Data);

Blamaster 30. Mär 2010 10:30

Re: String in Listview Data ?
 
@ himitsu

Delphi-Quellcode:
String(item.Data) := test;
Dabei bekomme ich einen Error "Left side cannot be assigned to"

Kann evtl. meine for schleife das Problem sein ?

Delphi-Quellcode:
for i := 0 to x do
begin
test := 'Ich liege in der Listview.Items.Item.data an der Stelle + ' ' + IntToStr(i);

item := Listview.Items.Add;
item.Caption := 'Irgendwas';
item.Data := Pointer(test);
end;
Ein Pointer ist ja ein Zeiger zeigt dieser nur zum zuweisen auf test, so dass der String danach fest im item.Data liegt ?

himitsu 30. Mär 2010 10:40

Re: String in Listview Data ?
 
tja, entweder zu sorgst dafür, daß "test" nie freigegeben/verändert wird, solange die Referenz in item.Data liegt,

oder du mußt eben doch die Referenzzählung beachten

Delphi-Quellcode:
var P: Pointer;

// zuweisen
String(P) := test;
item.Data := P;

// auslesen
test := String(item.Data);

// freigeben
P := item.Data;
String(P) := '';

oder du legst doch einen Record, mit deinem String, in item.Data ab


oder du gehst über einen PChar (natürlich mußt du dafür selber den Speicher reservieren und den Stringinhalt dareinkopieren), welchen du dann an item.Data übergibst.
(und freigeben nicht vergessen)

Blamaster 30. Mär 2010 11:40

Re: String in Listview Data ?
 
Hi,

sprich dein Beispielcode müsste in meinem Fall so aussehen ?

Delphi-Quellcode:
var
  P: Pointer;
  test: string;
  i: integer;
  item: TListItem;
begin
 for i := 0 to 10 do
 begin
  item := TListItem.Items.Add;
  item.caption := 'Test ' + IntToStr(i);
  test := 'Ich liege in der Listview.Items.Item.data an der Stelle ' + IntToStr(i);
  String(P) := test;
  item.Data := P;
 end;
end;
Wenn ja, dann geht es so auch nicht selbe Probleme wie in Post 1.

Mfg Yannic

hoika 30. Mär 2010 11:58

Re: String in Listview Data ?
 
Hallo,

ich nehme für meine TListItem.Data immer eine Klasse
die in einer Liste steckt.
Nat. darf die Liste nicht lokal sen, sondern gehört ins Form.

In deinem Fall würde auch eine TStringList reichen.

Wie schon weiter vorn gesagt, darf die String-Variable
nicht lokal sein.

Data ist ja nur ein Zeiger auf das Original.
wenn das Original weg ist, zeigt Data irgendwohin.


Heiko

Blamaster 30. Mär 2010 13:03

Re: String in Listview Data ?
 
Hi,

schade das Data so umständlich zu verwenden ist.

also nochmal zum verständnis. Data enthält einen pointer der auf die richtigen Daten zeigt. Wenn die Variable auf die Pointer zeigt nun so nicht mehr existiert gibt es Probleme logisch.

Was ändert sich dann aber durch eine globale Variable ? Diese existiert dann zwar immernoch nur wenn ich eine einfache Stringvariable habe und sich alle Datafelder auf diese beziehen, dann müssten doch alle den aktuellen Wert der Stringvariableenthalten oder nicht ?

So wie ich es verstehe:

- Data -> Enthält pointer auf Objekt -> Pointer verweist auf globale Variable test

Jetzt lese ich Data aus:

- Data liest seinen Pointer der ihm sagt wo er nachsehen muss sucht dann nach der variable test und liest sie aus.

Sprich wenn am Schluss wo es um die Ausgabe geht in der globalen Variable 'blub' steht, dann würde jedes durch die for schleife definierte Datafeld nun auf 'blub' zeigen oder nicht ?

Mit einer Progressbar geht das ganze recht einfach ind verständlich:

Delphi-Quellcode:
var
 pb: TProgessBar
 item: TListItem;
 i: integer;
begin
 for i := 0 to 10 do
 begin
  item := Listview.Items.Add
  item.Caption := 'Progressbar ' + IntToStr(i);
  pb := TProgressbat.Create(nil);
  item.Data := pb;
 end;
end;
Wieso lässt sich das mit einem string nicht auch so einfach erledigen ?

Wie genau war das mit mir würde auch eine Strnglist reichen gemeint ?

Mfg Yannic

himitsu 30. Mär 2010 13:24

Re: String in Listview Data ?
 
.Data ist nicht wirklich umständlich nutzbar ... es ist wie mit jedem anderen Zeiger/Pointer auch.
Und hier war nunmal die eigentlich gute Referenzzählung schuld, welche man durch solch einen Cast absichtlich umgeht.

Einziges Problem bei Properties ist, daß sie keinen gleichzeitigen Schreib- und Lesezugriff erlauben, weswegen String(item.Data):=irgendwas; nicht ging.



Die hoika schon sagte, wenn man auf was zeigen will, dann muß man dafür sorgen, daß dieses nicht in der Zwischenzeit freigegeben wird.
Wobei Objekte keine referenzzählung haben und man sie daher auch direkt, in einen Pointer gekastet, in Data eintragen könnte.

Delphi-Quellcode:
item.Data := Pointer(Test);
//auslesen
Test := PChar(item.Data);
//oder
Test := String(item.Data); // wenn Test ein String ist
ist praktisch das Selbe wie
Delphi-Quellcode:
item.Data := PChar(Test);
//auslesen
Test := PChar(item.Data);
außer daß bei PChar für einen Leerstring (nil) nicht nil, sondern ein Zeiger auf einen mit #0 gefüllten Speicherplatz übergeben wird.

Wird jetzt Test verändert, freigegeben oder verschoben, dann zeigt .Data natürlich immernoch auf die Stelle des "alten" Strings und somit teigt String(item.Data) nicht mehr auf einen String und es knallt oder es kommt im günstigsten Falle nur Schrott raus.

Delphi-Quellcode:
var
  P: Pointer;
  i: integer;
  item: TListItem;
begin
  for i := 0 to 10 do
  begin
    item := TListItem.Items.Add;
    item.caption := 'Test ' + IntToStr(i);
    String(P) := 'Ich liege in der Listview.Items.Item.data an der Stelle ' + IntToStr(i);
    item.Data := P;
  end;
end;
Delphi-Quellcode:
test := 'Ich liege in der Listview.Items.Item.data an der Stelle ' + IntToStr(i);
String(P) := test;
item.Data := P;
test := '';
Hier wird P wie eine Stringvariable behandelt, es wird also bei Zuweisung auch der Referenzzähler des String erhöht.
Gibt man nun test wieder frei, dann wird der Referenzzähler erniedrigt, aber da ja noch die Referenz für String(P) existiert, wird der String nicht freigegeben, sondern existiert weiterhin in P.
Die Folge ist nun, daß man beim löschen des Items auch den String in item.Data mit freigeben muß, da ja sonst ein Speicherleck entsteht.


Fazit:
Wird etwas direkt in .Data abgelegt, dann muß man es dort auch wieder freigeben,
auch wenn man ein Objekt nur da reinlegt.

Wärend bei hoikas Vorschlag das Objekt in einer externen Liste liegt und in P nur eine Kopie des Instanzzeigers.
Bei ihm muß/darf man das Objekt in .Data also nicht freigeben, da hierfür die Liste verantwortlich ist, welche ja quasi das Original besitzt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:52 Uhr.
Seite 1 von 3  1 23      

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