![]() |
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:
Und dann zum auslesen:
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;
Delphi-Quellcode:
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 ?
ShowMessage(String(ListView.Items.Item[x].Data));
Mfg Yannic |
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 |
Re: String in Listview Data ?
Der String darf nicht in einer lokalen Variable gespeichert sein. Dann sollte es gehen.
|
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); |
Re: String in Listview Data ?
@ himitsu
Delphi-Quellcode:
Dabei bekomme ich einen Error "Left side cannot be assigned to"
String(item.Data) := test;
Kann evtl. meine for schleife das Problem sein ?
Delphi-Quellcode:
Ein Pointer ist ja ein Zeiger zeigt dieser nur zum zuweisen auf test, so dass der String danach fest im item.Data liegt ?
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; |
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) |
Re: String in Listview Data ?
Hi,
sprich dein Beispielcode müsste in meinem Fall so aussehen ?
Delphi-Quellcode:
Wenn ja, dann geht es so auch nicht selbe Probleme wie in Post 1.
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; Mfg Yannic |
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 |
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:
Wieso lässt sich das mit einem string nicht auch so einfach erledigen ?
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; Wie genau war das mit mir würde auch eine Strnglist reichen gemeint ? Mfg Yannic |
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:
ist praktisch das Selbe wie
item.Data := Pointer(Test);
//auslesen Test := PChar(item.Data); //oder Test := String(item.Data); // wenn Test ein String ist
Delphi-Quellcode:
außer daß bei PChar für einen Leerstring (nil) nicht nil, sondern ein Zeiger auf einen mit #0 gefüllten Speicherplatz übergeben wird.
item.Data := PChar(Test);
//auslesen Test := PChar(item.Data); 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:
Hier wird P wie eine Stringvariable behandelt, es wird also bei Zuweisung auch der Referenzzähler des String erhöht.
test := 'Ich liege in der Listview.Items.Item.data an der Stelle ' + IntToStr(i);
String(P) := test; item.Data := P; test := ''; 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 20:02 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 by Thomas Breitkreuz