Center subitem images in a TListView

和自甴很熟 提交于 2019-12-24 00:43:20

问题


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?


回答1:


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 ;)



来源:https://stackoverflow.com/questions/52116742/center-subitem-images-in-a-tlistview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!