【问题标题】:Center subitem images in a TListView在 TListView 中居中子项图像
【发布时间】:2018-08-31 13:39:58
【问题描述】:

是否可以在TListView 中修复subitem 图像的绘制,使其不会如图所示在左侧被截断?

【问题讨论】:

  • 也许,只有OwnerDraw 属性可以让你自己居中图标。
  • 你能添加一个 MCVE 来重现这个吗?就个人而言,我认为没有自定义绘图是不可能的,但仍然......
  • @Victoria 我想你的评论是写给我的,所以我必须阐明我的评论的意义。当我推荐使用OwnerDraw 属性时,我意味着 将它与所有者绘制事件一起使用。在我看来,“使用 OwnerDraw 属性”这句话的意思正是我之前描述的。我相信 Pieter van Wyk 有足够的经验来理解这一点;)
  • @Dima,对不起,不,不,不是你,我会用那个@东西 :) 这是给 OP 的,因为即使没有那个,他们也会收到关于“问题线程”中任何通信的通知@ 事物。好吧,但回到主题,就我个人而言,我认为没有办法在这个控制子项中水平(甚至垂直)居中图像,正如你所指出的那样(对不起,错过了为你的评论投票,但我认为这也是答案)。
  • @Dima,不用担心 :) 无论如何,答案很好! (已投票,将在之后进行审核:)

标签: delphi tlistview subitem


【解决方案1】:

好吧,Pieter van Wyk,我做了一个最小的例子来说明如何拥有自己的 TListView 组件以使图像在子项中居中。

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

下图代表新代码的工作。
一个橙色行是选定的行。
所选行上的图像周围有白色。这不是错误 - 它是具有此类填充的源图像。

有代码可以做和图片上一样的事情:

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 属性

看到这个TListView.OwnerDraw Property 导致docs.embarcadero。我还想从上面的链接中引用一段话:

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

附言
调整列大小后,可能会有一些graphical artifacts - 只需尝试以隐藏(列的最小可能大小)和显示图像(将超过相关图像大小的任何列大小)的方式调整列大小,您将明白我的意思。

附言
绘制子项目的文本我留给你作为家庭作业;)

【讨论】:

  • 感谢您的全面解答!我已经尝试过了,它适用于带有图标的列。我现在对包含文本的列有一些问题,以不同的字体显示它们。当鼠标移过它们时,包含文本的列看起来也会变黑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-13
  • 2013-06-26
相关资源
最近更新 更多