Search code examples
delphidelphi-11-alexandria

How to draw image from TImage into TListbox?


I'm trying to create a listbox with images. The images will be fetched from a TImage component ; i don't want to use a TImageList because TImage can handle a lot of image types (png, gif, jpg) and i don't have to convert it to populate the Imagelist.

So i've set my listbox style to lbOwnerDrawVariable and i'm trying to paint the image from TImage into the listbox. I've set Image1 width and height to 50 because this is the size i want the images to have on the listbox.

Here is my code :

procedure TForm2.listbox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
var
  CenterText: Integer;
begin
  listbox1.Canvas.FillRect(Rect);
  listbox1.Canvas.draw(rect.Left+4,rect.Top+4,image1.Picture.graphic);
  CenterText := (Rect.Bottom - Rect.top - listbox1.Canvas.TextHeight(text)) div 2;
  listbox1.Canvas.TextOut(Rect.left + 58, Rect.top + CenterText, listbox1.Items.Strings[index]);
end;

But instead of putting the image in each listbox item, it's drawing a lot of images inside thel listbox itself, with its original size instead of 50... what's wrong with my code ?

enter image description here


Solution

  • Image1.Width and Image1.Height are the dimensions of the TImage control. They have nothing to do with the dimensions of the Image1.Picture.

    You need to stretch-draw the image or pre-scale it.

    Just a very quick and dirty example:

    procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    begin
    
      if Control <> ListBox1 then
        Exit;
    
      if Index = -1 then
        Exit;
    
      var C := ListBox1.Canvas;
    
      C.Brush.Color := clWindow;
      C.Font.Color := clWindowText;
      C.FillRect(Rect);
    
      var R := Rect;
      var S := ListBox1.Items[Index];
    
      var G := Image1.Picture.Graphic;
    
      var scale := 1.0;
    
      if (G.Width > 0) and (G.Height > 0) then
      begin
    
        var xscale := R.Width / G.Width;
        var yscale := R.Height / G.Height;
        scale := Min(xscale, yscale);
    
        R.Width := Round(G.Width * scale);
        R.Height := Round(G.Height * scale);
    
        C.StretchDraw(R, G);
    
      end;
    
      R := Rect;
      R.Left := R.Left + Round(G.Width * scale) + C.TextWidth('0');
      C.TextRect(R, S, [tfSingleLine, tfVerticalCenter, tfEndEllipsis]);
    
    end;
    

    Screenshot of a form with a TImage and an owner-drawn list box using the TImage's graphic as an icon for each item.