![]() |
Delphi-Version: 10.3 Rio
TDictionary Zugriff über property
Hallo Leute,
aus Gründen des Betriebsgeheimnisses hab ich vorsichtshalber den gesamten Code anonymisiert. Ich möchte keine Probleme bekommen. Programmaufbau: - 1 zentrale Daten-Unit - mehrere VCL-Units Die Informationen, die ich brauche und in das Dictionary geschrieben werden sollen, kommen aus einer MSSQL-DB.
Delphi-Quellcode:
Alle Keys des Dictionary erscheinen in einer ListBox. Desweiteren existiert ein TMemo und ein TImage.
unit Data;
... type TTest = class SomeText: string; ... // weitere Einträge SomeBitmap: TBitmap; end; TAnother = class private FDD: TDictionary<string,TTest>; GetSomeText(AMyKey: string): string; GetSomeBitmap(AMyKey: string): TBitmap; ... public property pSomeText[AMyKey: string]: string read GetSomeText; property pSomeBitmap[AMyKey: string]: TBitmap read GetSomeBitmap; end; procedure LoadFromDB; var MyKey: string; MyStringStream: TStringStream; MyBlobStream: TStream; begin ... qry.SQL.Text := 'select MyKey, SomeText, Image from table'; qry.Open(); ... MyKey := qry.FieldByName('MyKey').AsString; // MyKey ist eineindeutig ... MyStringStream := StringStream.Create; TBlobField(qry.FieldByName('SomeText')).SaveToStream(MyStringStream); MyStringStream.Position := 0; ... MyBitmap := TBitmap.Create; MyBlobStream := qry.CreateBlobStream(qry.FieldByName('Image'), bmRead); MyBlobStream.Position := 0; MyBitmap.LoadFromStream(MyBlobStream); ... SaveToDictionary(MyKey, MyStringStream.ReadString(MyStringStream.Size), MyBitmap); end; procedure SaveToDictionary(AMyKey, ASomeText: string; AMyBitmap: TBitmap); var Test: TTest; begin Test := TTest.Create; Test.SomeText := ASomeText; // Test.SomeBitmap := TBitmap.Create -> keine Veränderung festgestellt, egal ob auskommentiert oder nicht Test.SomeBitmap := AMyBitmap; FDD.Add(AMyKey, Test); and; // funktioniert function GetSomeText(AMyKey: string): string; var Test: TTest; begin Test := TTest.Create; FDD.TryGetValue(AMyKey, Test); Result := Test.SomeText; end; // funktioniert nicht function GetSomeBitmap(AMyKey: string): TBitmap; var Test: TTest; begin Test := TTest.Create; FDD.TryGetValue(AMyKey, Test); Result := Test.SomeBitmap; end; Ein Eintrag in der ListBox soll ausgewählt werden. SomeText soll im TMemo und SomeBitmap im TImage angezeigt werden.
Delphi-Quellcode:
SomeText wird richtig aus dem Dictionary geladen und angezeigt.
unit VCL_1;
... procedure ListBoxOnClick; var MyBitmap: TBitmap; begin if MyListBox.ItemIndex > -1 then begin MyMemo.Text := pSomeText[MyListBox.Items[MyListBox.ItemIndex]]; // funktioniert ... MyBitmap := TBitmap.Create; MyBitmap := pSomeBitmap[MyListBox.Items[MyListBox.ItemIndex]]; // funktioniert nicht end; end; SomeBitmap nicht. Im TImage ist nur ein 16x16 Pixel großes schwarzes Viereck zu sehen, egal welche Größe das Bild in der DB hat. Ich hab Ewigkeiten rumgesucht, auch hier im Forum. Eventuell hab ich auch einfach nicht die richtigen Suchbegriffe gewählt. ChatGPT hat auch keine hilfreichen Antworten. Direkt nachdem ich einen Eintrag zum Dictionary hinzugefügt habe, habe ich mir testweise die Abmessungen der Bitmap des letzten Eintrags des Dictionary ausgeben lassen. Die Höhe und Breite der Bitmap stimmen mit denen in der DB überein. Erst wenn ich an einer späteren Stelle im Programm über die property das Bitmap holen will, tritt das Fehlverhalten auf und die Abmessungen betragen 16x16. Vielleicht hab ich einen grundlegenden Denkfehler. Ich weiß jedenfalls nicht mehr weiter. Hat eventuell von euch jemand eine Idee? Gruß Kratos |
AW: TDictionary Zugriff über property
Im ListBoxOnClick wird MyBitmap ein leeres per TMyBitmap.Create zugewiesen, direkt darauf aber durch das Bitmap aus dem Dictionary überschrieben. Damit zeigt MyBitmap direkt auf die Instanz in dem Direktory. Es ist also von entscheidender Bedeutung, was darauf mit MyBitmap geschieht.
|
AW: TDictionary Zugriff über property
Direkt danach soll es im TImage angezeigt werden.
Delphi-Quellcode:
Wenn das Bitmap gefüllt ist, dann wird ein schwarzes Viereck im TImage angezeigt, welches 16x16 Pixel groß ist.
TImage.Picture.Bitmap.Assign(MyBitmap);
Das ist aber nicht das Bild, welches in der DB gespeichert ist. Anmerkung: Schon im
Delphi-Quellcode:
kommen die falschen Abmessungen heraus.
GetSomeBitmap
War das die Information, die du haben wolltest oder habe ich dich falsch verstanden? |
AW: TDictionary Zugriff über property
Was geschieht im weiteren Verlauf mit MyBitmap? Wird es irgendwie manipuliert oder freigegeben?
Es wäre auch interessant zu wissen was in LoadFromDB mit MyBitmap passiert, was uns aktuell noch verborgen wird. |
AW: TDictionary Zugriff über property
Zitat:
Zitat:
Delphi-Quellcode:
die Methode
LoadFromDB
Delphi-Quellcode:
aufgerufen wird, wird auch hier MyBitmap freigegeben.
SaveToDictionary
Ich hab jetzt mal BEIDE
Delphi-Quellcode:
auskommentiert.
MyBitmap.Free
Jetzt wird alles korrekt angezeigt! So ein einfacher Fehler... das kann echt nicht sein. Vielen Dank, wirklich!!! [EDIT]: Ich hab
Delphi-Quellcode:
in
MyBitmap.Free
Delphi-Quellcode:
mal wieder mit reingenommen.
ListBoxOnClick()
Es funktioniert weiterhin. Aber dann hab ich dennoch einen Denkfehler. Denn ich nahm an, wenn ich eine extra Bitmap in
Delphi-Quellcode:
anlege und diese neue Bitmap befülle und anschließend in das TDictionary wegspeichere, dass ich dann die alte Bitmap aus
SaveToDictionary
Delphi-Quellcode:
freigeben darf. Während die neue Bitmap NICHT freigegeben wird.
LoadFromDB
Das erschließt sich mir gerade nicht. |
AW: TDictionary Zugriff über property
TBitmap ist ja eine Klasse und in der TTest-Instanz wird nur ein Zeiger auf die TBitmap-Instanz gespeichert. Ebenso enthält das Directory nur Zeiger auf TTest-Instanzen.
Folgendes ist also problematisch:
Delphi-Quellcode:
Das TryGetValue gibt die gefundene TTest-Instanz im Parameter Test zurück. Die vorher erzeugte Instanz verbleibt somit als Speicherleck. Besser wäre:
function GetSomeText(AMyKey: string): string;
var Test: TTest; begin Test := TTest.Create; FDD.TryGetValue(AMyKey, Test); Result := Test.SomeText; end;
Delphi-Quellcode:
Analog hier:
function GetSomeText(AMyKey: string): string;
var Test: TTest; begin Result := ''; // Wert bei not found if FDD.TryGetValue(AMyKey, Test) then Result := Test.SomeText; end;
Delphi-Quellcode:
Und hier wäre eventuell das besser:
function GetSomeBitmap(AMyKey: string): TBitmap;
var Test: TTest; begin Result := nil; // Wert bei not found if FDD.TryGetValue(AMyKey, Test) then Result := Test.SomeBitmap; end;
Delphi-Quellcode:
Damit die Bitmaps auch am Ende freigegeben werden, sollte in einem
procedure ListBoxOnClick;
var MyBitmap: TBitmap; begin if MyListBox.ItemIndex > -1 then begin MyMemo.Text := pSomeText[MyListBox.Items[MyListBox.ItemIndex]]; ... MyBitmap := pSomeBitmap[MyListBox.Items[MyListBox.ItemIndex]]; Image.Picture.Graphic := MyBitmap; // kein MyBitmap.Free, da uns die Instanz hier nicht gehört. Andernfalls klappt es beim zweiten Mal vermutlich nicht mehr. end; end;
Delphi-Quellcode:
noch ein
TTest.Destroy
Delphi-Quellcode:
erfolgen.
SomeBitmap.Free
|
AW: TDictionary Zugriff über property
@Uwe Raabe
Vielen Dank für deine zusätzlichen Erklärungen und Tipps! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:22 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-2025 by Thomas Breitkreuz