AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TDictionary Zugriff über property

Ein Thema von Kratos · begonnen am 20. Dez 2023 · letzter Beitrag vom 20. Dez 2023
Antwort Antwort
Kratos

Registriert seit: 15. Okt 2019
51 Beiträge
 
Delphi 10.3 Rio
 
#1

TDictionary Zugriff über property

  Alt 20. Dez 2023, 10:43
Delphi-Version: 10.3 Rio
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:
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;
Alle Keys des Dictionary erscheinen in einer ListBox. Desweiteren existiert ein TMemo und ein TImage.
Ein Eintrag in der ListBox soll ausgewählt werden. SomeText soll im TMemo und SomeBitmap im TImage angezeigt werden.
Delphi-Quellcode:
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;
SomeText wird richtig aus dem Dictionary geladen und angezeigt.
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
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

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

AW: TDictionary Zugriff über property

  Alt 20. Dez 2023, 11:03
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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Kratos

Registriert seit: 15. Okt 2019
51 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: TDictionary Zugriff über property

  Alt 20. Dez 2023, 11:22
Direkt danach soll es im TImage angezeigt werden.
TImage.Picture.Bitmap.Assign(MyBitmap); Wenn das Bitmap gefüllt ist, dann wird ein schwarzes Viereck im TImage angezeigt, welches 16x16 Pixel groß ist.
Das ist aber nicht das Bild, welches in der DB gespeichert ist.

Anmerkung: Schon im GetSomeBitmap kommen die falschen Abmessungen heraus.

War das die Information, die du haben wolltest oder habe ich dich falsch verstanden?
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

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

AW: TDictionary Zugriff über property

  Alt 20. Dez 2023, 11:32
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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Kratos

Registriert seit: 15. Okt 2019
51 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: TDictionary Zugriff über property

  Alt 20. Dez 2023, 12:04
Zitat:
Was geschieht im weiteren Verlauf mit MyBitmap? Wird es irgendwie manipuliert oder freigegeben?
MyBitmap wird ganz zum Schluss in der ListBoxOnclick-Methode freigegeben.

Zitat:
Es wäre auch interessant zu wissen was in LoadFromDB mit MyBitmap passiert, was uns aktuell noch verborgen wird.
NACHDEM in LoadFromDB die Methode SaveToDictionary aufgerufen wird, wird auch hier MyBitmap freigegeben.

Ich hab jetzt mal BEIDE MyBitmap.Free auskommentiert.
Jetzt wird alles korrekt angezeigt!
So ein einfacher Fehler... das kann echt nicht sein.

Vielen Dank, wirklich!!!

[EDIT]: Ich hab MyBitmap.Free in ListBoxOnClick() mal wieder mit reingenommen.
Es funktioniert weiterhin.

Aber dann hab ich dennoch einen Denkfehler.
Denn ich nahm an, wenn ich eine extra Bitmap in SaveToDictionary anlege und diese neue Bitmap befülle und anschließend in das TDictionary wegspeichere, dass ich dann die alte Bitmap aus LoadFromDB freigeben darf. Während die neue Bitmap NICHT freigegeben wird.
Das erschließt sich mir gerade nicht.

Geändert von Kratos (20. Dez 2023 um 12:11 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

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

AW: TDictionary Zugriff über property

  Alt 20. Dez 2023, 12:53
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:
function GetSomeText(AMyKey: string): string;
var
  Test: TTest;
begin
  Test := TTest.Create;
  FDD.TryGetValue(AMyKey, Test);
  Result := Test.SomeText;
end;
Das TryGetValue gibt die gefundene TTest-Instanz im Parameter Test zurück. Die vorher erzeugte Instanz verbleibt somit als Speicherleck. Besser wäre:
Delphi-Quellcode:
function GetSomeText(AMyKey: string): string;
var
  Test: TTest;
begin
  Result := ''; // Wert bei not found
  if FDD.TryGetValue(AMyKey, Test) then
    Result := Test.SomeText;
end;
Analog hier:
Delphi-Quellcode:
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;
Und hier wäre eventuell das besser:
Delphi-Quellcode:
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;
Damit die Bitmaps auch am Ende freigegeben werden, sollte in einem TTest.Destroy noch ein SomeBitmap.Free erfolgen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Kratos

Registriert seit: 15. Okt 2019
51 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: TDictionary Zugriff über property

  Alt 20. Dez 2023, 13:27
@Uwe Raabe

Vielen Dank für deine zusätzlichen Erklärungen und Tipps!
  Mit Zitat antworten Zitat
Antwort Antwort

 

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 06:19 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