Search code examples
delphilistviewdelphi-7

Draw the icons to the listview from imagelist?


How to draw the icons to the listview from imagelist? I'm using this code to change the selection color in my listview, but it doesn't have the icons from the imagelist.

procedure TForm2.ListView1DrawItem(Sender: TCustomListView;
  Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var
x, y, i, w, h: integer;
begin
  with ListView1, Canvas do
  begin

    if odSelected in State then
    begin
      Brush.Color := clRed;
      Pen.Color := clWhite;
    end else
    begin
      Brush.Color := Color;
      Pen.Color := Font.Color;
    end;
    Brush.Style := bsSolid;
    FillRect(rect);
    h := Rect.Bottom - Rect.Top + 1;
    x := Rect.Left + 1;
    y := Rect.Top + (h - TextHeight('Hg')) div 2;
    TextOut(x, y, Item.Caption);
    inc(x, Columns[0].Width);
    for i := 0 to Item.Subitems.Count - 1 do begin
      TextOut(x, y, Item.SubItems[i]);
      w := Columns[i + 1].Width;
      inc(x, w);
    end;
  end;
end;

Solution

  • You have to draw images yourself, too.

    procedure DrawListViewItem(ListView: TListView; Item: TListItem; Rect: TRect; 
      State: TOwnerDrawState; SelectedBrushColor, SelectedFontColor, BrushColor, FontColor: TColor);
    var
      x, y, i, w, h, iw, ih: integer;
    begin
      with ListView do
      begin
        if odSelected in State then
        begin
          Canvas.Brush.Color := SelectedBrushColor;
          Canvas.Font.Color := SelectedFontColor;
        end else
        begin
          Canvas.Brush.Color := BrushColor;
          Canvas.Font.Color := FontColor;
        end;
        Canvas.Brush.Style := bsSolid;
        Canvas.FillRect(rect);
    
        h := Rect.Bottom - Rect.Top + 1;
    
        if Assigned(SmallImages) then
          begin
            iw := SmallImages.Width;
            ih := SmallImages.Height;
            x := Rect.Left + 1;
            if Item.ImageIndex >= 0 then 
              SmallImages.Draw(Canvas, Rect.Left + x, Rect.Top +(h - ih) div 2, Item.ImageIndex);
            x := x + iw + 2;
          end
        else
          begin
            iw := 0;
            ih := 0;
            x := Rect.Left + 1;
          end;
    
        y := Rect.Top + (h - Canvas.TextHeight('Hg')) div 2;
        Canvas.TextOut(x, y, Item.Caption);
        inc(x, Columns[0].Width - iw);
        for i := 0 to Item.Subitems.Count - 1 do begin
          Canvas.TextOut(x, y, Item.SubItems[i]);
          w := Columns[i + 1].Width;
          inc(x, w);
        end;
      end;
    end;
    
    procedure TForm1.ListView1DrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState);
    begin
      DrawListViewItem(ListView1, Item, Rect, State, clRed, clWhite, ListView1.Color, ListView1.Font.Color);
    end;
    

    I have moved drawing code into separate function. That makes it reusable and a bit cleaner. Using with directly inside form method can have unwanted side effects. Same goes for double with clause, so I used only one (although I tend to avoid with completely in my code).

    I have noticed that you used Pen.Color, but I changed that to Font.Color, because setting Pen has no effect whatsoever in your code, and I assume that you actually wanted to change color of the text.