Question

I have a listbox of images that normally works fine, but today it throws a access violation for no apparent reason.

Here is my code:

procedure TfrmSelectIcon.ListBox1DrawItem(Control: TWinControl; Index: integer;
  Rect: TRect; State: TOwnerDrawState);
var
  icone: TImageItem; // Ticone;
  png1: TPngImage;
  ImageIcone: TPngImage;
  TextPosition: integer;
  nomearquivo: string;
  Images: TImageList;
begin

  icone := TImageItem(listaIcone.Items[StrToInt(TListBox(Control).Items.Strings
    [Index])]);
  // Ticone(listaIcone.Items[strtoint(TListBox(Control).Items.Strings[Index])]);
  nomearquivo := Diretorio + icone.arquivo;

  // ShowMessage(nomearquivo);

  TListBox(Control).Canvas.FillRect(Rect);
  if FileExists(nomearquivo) then
  begin
    png1 := TPngImage.Create;
    png1.LoadFromFile(nomearquivo);  //here happen the problem.
    png1.Draw(TListBox(Control).Canvas, Rect);
  end;

end;

The file exists and it's a .png.

The bug happens just on the fifth image.

Was it helpful?

Solution

You have a memory leak, as you are not freeing the TPngImage objects you create. But worse, you should NOT be loading image files during a drawing operation to begin with. You should instead load the images once beforehand and then reuse them each time an item need to be drawn.

Try something more like this:

private
  Images: array of TPngImage; // or any other container you want to use

...

procedure TfrmSelectIcon.FormDestroy(Sener: TObject);
var
  I: Integer;
begin
  for I := 0 to High(Images) do
    Images[I].Free;
end;

procedure TfrmSelectIcon.ListBox1DrawItem(Control: TWinControl; Index: integer; Rect: TRect; State: TOwnerDrawState);
var
  png: TPngImage;
begin
  png := Images[Index];
  if (png <> nil) and (not png.Empty) then
    png1.Draw(TListBox(Control).Canvas, Rect);
end;

var
  icone: TImageItem; // Ticone;
  nomearquivo: string;
  I: Integer;
begin
  SetLength(Images, ListBox1.Items.Count);
  for I := 0 to High(Images) do
    Images[I] := nil;
  for I := 0 to High(Images) do
  begin
    // personally, I would suggest storing the TImageItem pointers
    // in the TListBox.Items.Objects[] property for easier access:
    //
    // icone := TImageItem(ListBox1.Items.Objects[I]);
    //
    icone := TImageItem(listaIcone.Items[StrToInt(ListBox1.Items.Strings[I])]);

    nomearquivo := Diretorio + icone.arquivo;
    if FileExists(nomearquivo) then
    begin
      try
        Images[I] := TPngImage.Create;
        Images[I].LoadFromFile(nomearquivo);
      except
      end;
    end;
  end;
end;

OTHER TIPS

Problem solved:

TListBox(Control).Canvas.FillRect(Rect);
  if FileExists(nomearquivo) then
  begin
    png1 := TPngImage.Create;
    png1.LoadFromFile(nomearquivo);
    png1.Draw(TListBox(Control).Canvas, Rect);
    **FreeAndNil(png1);** //i put this line and works fine!
  end;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top