Is it possible to fix the drawing of subitem
images in a TListView
so that they are not cut-off on the left hand side as shown in the image?
Well, Pieter van Wyk, I did minimal example of how you can owner-draw your TListView
component in order to center images in sub-items.
Answer has been rewritten. In order to decrease size of answer I had deleted unused and wrong parts. Previous versions may be found in history of question editing.
Picture below represents work of the new code.
One orange row is a selected row.
Images on selected row have white color around it. It is not a bug - it is a source image with such fill.
There is the code that allows to do the same thing as on the picture:
procedure TForm1.ListView1DrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect;
State: TOwnerDrawState);
var
Bmp: TBitmap;
Image: TBitmap;
R: TRect;
CenterH: Integer;
CenterV: Integer;
ImageIndex: Integer;
ItemWidth: Integer;
i: Integer;
begin
// Set initial legth of point at the end of which image will be drawn.
// Column 0 is a "fixed" column
ItemWidth := Sender.Column[0].Width;
R := Rect;
Bmp := TBitmap.Create;
try
Image := TBitmap.Create;
try
Bmp.SetSize(R.Width, R.Height);
// Make fill for item
if Item.Selected then
Bmp.Canvas.Brush.Color := clWebOrange
else
Bmp.Canvas.Brush.Color := clMoneyGreen;
Bmp.Canvas.FillRect(Bmp.Canvas.ClipRect);
// Output image associated with 'fixed' column
TListView(Sender).SmallImages.GetBitmap(Item.ImageIndex, Image);
CenterH := (Sender.Column[0].Width - Image.Width) div 2;
CenterV := (R.Height - Image.Height) div 2;
Bmp.Canvas.Draw(CenterH, CenterV, Image);
// Output text
Bmp.Canvas.TextOut(CenterH + Image.Width + 6, 6, Item.Caption);
// Draw sub-items
for i:=0 to Item.SubItems.Count - 1 do
begin
// Obtain index of image
ImageIndex := Item.SubItemImages[i];
// Get associated image
TListView(Sender).SmallImages.GetBitmap(ImageIndex, Image);
// Center image
CenterH := (Sender.Column[i+1].Width - Image.Width) div 2;
CenterV := (R.Height - Image.Height) div 2;
// Output image
Bmp.Canvas.Draw(ItemWidth + CenterH, CenterV, Image);
// Increase point where image started to be drawn
Inc(ItemWidth, Sender.Column[i+1].Width);
end;
// Draw ready item's image onto sender's canvas
Sender.Canvas.Draw(R.Left, R.Top, Bmp);
finally
Image.Free;
end;
finally
Bmp.Free;
end;
end;
To apply this code you must activate OwnerDraw
property.
See this TListView.OwnerDraw Property that leads to docs.embarcadero
. I also would like to show a quote from a link above:
Set OwnerDraw to true to allow the list view to receive the OnDrawItem event instead of the default rendering of list items.
P.S.
After column has been resized, there could be some graphical artifacts
- just try to resize column in a way to hide (minimal possible size of column) and show image (any size of column that will exceeds size of associated image) and you will see what I meant.
P.S.S.
Drawing a text of sub-items I leave to you as a homework ;)