使用自定义绘图时,Delphi列表视图控件中是否存在错误?

Dav*_*nan 14 delphi delphi-xe2

QC#101189

我正在尝试TListView根据NGLN对另一个SO问题的答案在Delphi中自定义绘制进度条.除了使用Vista中引入的新资源管理器主题绘制时与热跟踪的交互之外,此工作正常.

热跟踪绘画和Delphi自定义绘图事件似乎互相干扰.例如,我看到的那种输出看起来像这样:

在此输入图像描述

第1列中的文字应为第3项,但已删除.它看起来像列表视图控件的Delphi包装中的一个错误,但同样可能是我做错了!

虽然我一直在XE2中开发这个,但是在2010年也发生了同样的行为,大概是XE.

这是重现此行为的代码:

Pascal文件

unit Unit1;

interface

uses
  Windows, Classes, Controls, Forms, CommCtrl, ComCtrls;

type
  TForm1 = class(TForm)
    ListView: TListView;
    procedure FormCreate(Sender: TObject);
    procedure ListViewCustomDrawSubItem(Sender: TCustomListView;
      Item: TListItem; SubItem: Integer; State: TCustomDrawState;
      var DefaultDraw: Boolean);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  ListView.RowSelect := True;
  ListView.Items.Add.Caption := 'Item 1';
  ListView.Items.Add.Caption := 'Item 2';
  ListView.Items.Add.Caption := 'Item 3';
end;

procedure TForm1.ListViewCustomDrawSubItem(Sender: TCustomListView;
  Item: TListItem; SubItem: Integer; State: TCustomDrawState;
  var DefaultDraw: Boolean);
var
  R: TRect;
begin
  DefaultDraw := False;
  ListView_GetSubItemRect(Sender.Handle, Item.Index, SubItem, LVIR_BOUNDS, @R);
  Sender.Canvas.MoveTo(R.Left, R.Top);
  Sender.Canvas.LineTo(R.Right-1, R.Bottom-1);
end;

end.
Run Code Online (Sandbox Code Playgroud)

表格文件

object Form1: TForm1
  Caption = 'Custom Draw List View Bug'
  ClientHeight = 290
  ClientWidth = 554
  OnCreate = FormCreate
  object ListView: TListView
    Align = alClient
    Columns = <
      item
        Caption = 'Column 1'
        Width = 250
      end
      item
        Caption = 'Column 2'
        Width = 250
      end>
    ViewStyle = vsReport
    OnCustomDrawSubItem = ListViewCustomDrawSubItem
  end
end
Run Code Online (Sandbox Code Playgroud)

Ser*_*yuz 13

这是针对有缺陷行为的解决方法,而不是如果VCL中存在错误以及一些想法而回答问题.

解决方法是在执行自定义绘图后,将项目绘制cyle的公共控件指定的设备上下文的背景模式设置为透明:

procedure TForm1.ListViewCustomDrawSubItem(Sender: TCustomListView;
  Item: TListItem; SubItem: Integer; State: TCustomDrawState;
  var DefaultDraw: Boolean);
var
  R: TRect;
begin
  if not [CustomDrawing] then  // <- If we're not gonna do anything do not
    Exit;                      //    fiddle with the DC in any way

  DefaultDraw := False;
  ListView_GetSubItemRect(Sender.Handle, Item.Index, SubItem, LVIR_BOUNDS, @R);
  Sender.Canvas.MoveTo(R.Left, R.Top);
  Sender.Canvas.LineTo(R.Right-1, R.Bottom-1);

  SetBkMode(Sender.Canvas.Handle, TRANSPARENT); // <- will effect the next [sub]item
end; 
Run Code Online (Sandbox Code Playgroud)



在[子]项目绘制周期中,绘画总是以自上而下的方式完成,具有较低索引的项目在具有较高索引的项目NM_CUSTOMDRAW之前被发送通知.当鼠标从一行移动到另一行时,需要重新绘制两行 - 一行失去状态,另一行获得它.看起来,当自定义绘图生效时,绘制失去热状态的行会使DC处于不合需要的状态.向上移动鼠标时不会出现问题,因为该项目最后被绘制.

自定义绘图ListView和TreeView控件与自定义绘制其他控件不同,有些复杂(请参阅:使用列表视图和树视图控件自定义绘制).但是你可以完全控制整个过程.在该代码NM_CUSTOMDRAW的情况下,TCustomListView.CNNotify在VCL的"comctrls.pas"是同样复杂.但是,尽管提供了一堆自定义绘图处理程序(其中一半是高级的),但您无法控制VCL的功能.例如,你无法返回CDRF_xxx你想要的,或者你无法设置clrTextBk你想要的.我的偏见是,在Delphi列表视图控件中存在一个错误/设计问题,但在找到解决方法时,我没有比直觉更具体的内容.

  • @David - 欢迎你!尽管我认为,当新版本的comctl32.dll到来时,测试解决方法可能是个好主意. (2认同)