Delphi 在TListView中居中显示子项图像

Delphi 在TListView中居中显示子项图像,delphi,tlistview,subitem,Delphi,Tlistview,Subitem,是否可以将子项图像的绘图固定在t视图中,以便它们不会如图所示在左侧被切断? 好吧,彼得·范·怀克,我举了一个简单的例子,说明了如何让所有者绘制TListView组件,以便在子项中居中显示图像 答案已重写。为了减少答案的大小,我删除了未使用和错误的部分。以前的版本可以在问题编辑历史记录中找到。 下面的图片代表了新代码的工作。 一个橙色行是选定的行。 选定行上的图像周围为白色。这不是一个bug-它是一个带有这种填充的源图像 有一个代码允许执行与图片上相同的操作: procedure TForm1.

是否可以将
子项
图像的绘图固定在
t视图
中,以便它们不会如图所示在左侧被切断?

好吧,彼得·范·怀克,我举了一个简单的例子,说明了如何让所有者绘制
TListView
组件,以便在子项中居中显示图像

答案已重写。为了减少答案的大小,我删除了未使用和错误的部分。以前的版本可以在问题编辑历史记录中找到。

下面的图片代表了新代码的工作。
一个橙色行是选定的行。
选定行上的图像周围为白色。这不是一个bug-它是一个带有这种填充的源图像

有一个代码允许执行与图片上相同的操作:

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;
要应用此代码,必须激活
OwnerDraw
属性

请参阅这篇文章,它将导致
docs.embarcadero
。我还想展示上面一个链接的引用:

将OwnerDraw设置为true,以允许列表视图接收OnDrawItem事件,而不是列表项的默认呈现

p.S.
在调整列的大小后,可能会出现一些
图形瑕疵
——只要尝试以隐藏(列的最小可能大小)和显示图像的方式调整列的大小(列的任何大小将超过关联图像的大小),您就会明白我的意思

p.S.S.

画一个我留给你作为家庭作业的子项目的文本;)

也许,只有
OwnerDraw
属性允许您自己将图标居中。请添加MCVE以复制此图标,好吗?就个人而言,我认为没有定制图纸是不可能的,但我想你的评论是写给我的,所以我必须解释一下我的评论的意义。当我建议使用
OwnerDraw
属性时,我打算将其与OwnerDraw事件一起使用。在我看来,“使用OwnerDraw财产”这句话正是我前面描述的意思。我相信彼得·范怀克有足够的经验来理解这一点;)@迪玛,对不起,不,不,不是对你,我会用那个@thing:)它是对OP的,因为他们会收到关于“问题线程”中任何通信的通知,即使没有那个@thing。好的,但回到主题上来,就个人而言,我不认为有办法在这个控制子项中水平(或者甚至垂直)居中图像,正如你所指出的(对不起,没有投票支持你的评论,但我认为这也是答案)。@Dima,不用担心:)无论如何,答案很好!(投票通过后,将进行回顾:)谢谢您的全面回答!我已经试过了,它可以很好地用于带有图标的列。我现在对包含文本的列有一些问题,无法以不同的字体显示它们。而且,当鼠标移动到包含文本的列上时,这些列看起来会变成黑色。