简体   繁体   中英

How to draw a bmp/icon on a TListView subitem in Delphi?

I would like to draw an icon/bmp into a subitem of a TListView using delphi. But I don't know how to accomplish that. It works fine for the first item on the list, but having problems with the subitems.

You could use the CustomDrawSubItem event.

The example below ignores the text and draws rectangles. Unfortunately it is a bit of a hassle to get the rectangle for the right column, but this approach works:

procedure TForm.ListViewCustomDrawSubItem(Sender: TCustomListView;
  Item: TListItem; SubItem: Integer; State: TCustomDrawState;
  var DefaultDraw: Boolean);
var
  r : TRect;
  i : Integer;
begin
  r := Item.DisplayRect(drBounds);
  for i := 0 to SubItem-1 do begin
    r.Left := r.Left + ListView.Columns.Items[i].Width;
    r.Right := r.Left  + ListView.Columns.Items[i+1].Width;
  end;
  case SubItem of
     1 : ListView.Canvas.Pen.Color := clRed;
  else
    ListView.Canvas.Pen.Color := clBlue;
  end;

  ListView.Canvas.Rectangle(r.Left, r.Top, r.Right, r.Bottom);
  DefaultDraw := False;
end;

使用TImageList组件保存图像,将其分配给listviews的SmallImages属性并设置子项的ImageIndex。

After tried Gamecat proposed solution, there are serious issues handling the redraw event after resizing the component, so at the end I came up with 2 possible workarounds:

  1. Since subitems are Strings I handled to change the Font Family and using Wingdings I used a triangle-like character, then I just changed the font color to make it look like a glyph. (I know, it is not very clean, but it worked for me from a time and effort perspective)

  2. Use a TDataGrid from the beginning, it knows the concept of cells and we can add practically anything and no need to worry with redrawing events. (Useless for me, cause the existing component already had a lot of functionality build on it).

OK, 13 years late, but this is a clean way to get the bounds.

uses Winapi.CommCtrl;

...

procedure TFrmMain.ListView1(
  Sender: TCustomListView;
  Item: TListItem; 
  SubItem: integer; 
  State: TCustomDrawState;
  var DefaultDraw: Boolean);    
var
  lv: TListView absolute Sender;
  SubItemRect: TRect;
begin
  ListView_GetSubItemRect(lv.Handle, Item.Index, SubItem, LVIR_BOUNDS, @SubItemRect);

  // Now you know the boundaries of the sub item...

  // So you could do something like:
  lv.Canvas.Draw(SubItemRect.Left, SubItemRect.Top, MyBitmap);

end;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM