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

QC#101189

我试图自定义在Delphi TListView中绘制一个进度条,如NGLN’s answer to another SO question所示.除了使用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.

表单文件

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

解决方法

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

解决办法是在进行自定义绘图之后,将项目绘画的公共控件分配给设备上下文的背景模式设置为透明:

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,R.Bottom-1);

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

在[子]项目绘画循环中,绘画始终以自顶向下的方式完成,具有较低索引的项目在具有较高索引的项目之前发送NM_CUSTOMDRAW通知.当鼠标从一行移动到另一行时,需要重新绘制两行 – 一个放弃热状态,一个获取它.当自定义绘图有效时,绘制掉热状态的行会使DC处于不良状态.当向上移动鼠标时,这不是问题,因为该项目最后被绘制.

自定义绘图ListView和TreeView控件与自定义绘制其他控件不同,有些复杂(参见:Custom Draw With List-View and Tree-View Controls).但是你可以完全控制整个过程. VCL的“comctrls.pas”中的TC_CANOMDRAW案例TCustomListView.CNNotify中的代码同样复杂.但是尽管提供了一堆自定义绘图处理程序(其中一半是高级的),但是您无法控制VCL的工作.例如,您不能返回您想要的CDRF_xxx,或者您无法设置所需的clrTextBk.我有偏见的是,Delphi列表视图控件中存在一个错误/设计问题,但是我没有比找到解决方法更直观的直觉.

相关文章

ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c++ 调用, 抽空研究了一下该库的最新版 ,把...
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和EDX)2个变址和指针寄存器(ESI和EDI) 2个指针寄...
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的功能是:将源操作数送到目的操作数中,即:...
有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。 1.CreateProcess因为使用复杂...
API原型: Declare Function MoveFileEx& Lib "kernel32" Alias "MoveFileExA" (By...