Listview 的自绘

开发的过程中,经常要使用到 TListview,为了界面美观,需要自绘 TListview,下面就 TListview 自绘的三个方面,总结一下。
  1、显示千万条数据记录;   
  2、表格自绘;              
  3、表头自绘;  
         

  1、显示千万条数据记录;
 
     A:OwnerData 设为 True, OwnerDraw 暂时设为 False, 不进行自绘,由系统来完成绘制。
            我们的重点放在显示千万条记录上面;
     
     B:数据来源,数据库查询:

 ADOQuery1.SQL.Clear; 
 ADOQuery1.Close;
 ADOQuery1.SQL.Text := 'select ROW_NUMBER() over(order by ID) as RowNum, * from TableName';
 ADOQuery1.Open;

        这里:
        ID                :数据库表中自增长字段(换成你要查询的数据库表中的自增长字段);
        TableName :数据库表名;
        *                  :数据库中所有字段名称;
                               实际使用中,最好不要用 * ,需要显示哪些字段就填入字段名称 ,效率会大大提高。
         注:                        
          ID 是必须的,为最后一列,不显示的一列,用于记录标识;当选中/双击时,根据此列值,可找到数据库对应记录。

          无论你的查询语句如何写,select ROW_NUMBER() over(order by ID) as RowNum 是必不可少的
      
      ADOQuery1 查询结束后,添加代码:

lvData.Items.Count := ADOQuery1.RecordCount; 

     将触发 OnData 事件:

     C:双击 OnData 事件,进入代码界面:
        假设 ADOQuery1 查询结果中包含千万条记录
        显示数据前,列名先准备好。动态创建也可以。
        注:
         列名一般使用字段名,但字段名一般为英文。实际使用肯定是需要中文的。
         我们可以使用字段的说明属性,来当作列名。
         建立字段时,顺手给字段的列属性中的说明属性加个中文说明,
         程序中获取字段对应的说明属性来当作列名,就OK了。

      procedure TfrmListViewData.lvDataData(Sender: TObject; Item: TListItem);
      var
        I: Integer;
      begin
        ADOQuery1.RecNo := Item.Index + 1;
        Item.Caption    := ADOQuery1.Fields[1].AsString;
        for I           := 2 to ADOQuery1.Fields.Count - 1 do
        begin
          if ADOQuery1.Fields[I].DataType = ftBlob then
            Item.SubItems.Add('')
          else
            Item.SubItems.Add(ADOQuery1.Fields[I].AsString);
        end;
      end;

        OK,大功告成。上面代码只是示例,细节根据自己需要,自己把控。
      
  2、表格自绘; 
       
这一步比较容易;
        A:设置 OwnerDraw 为 True ,就会触发自绘事件;
        B:双击 OnCustomDrawItem 事件,在事件中输入自绘代码。
              有画布 Canvas,TListview(Sender).Canvas,有 Item ,想绘制成啥样,就绘制成啥样。
              划过/选中/动态,等等效果都可以在这里实现。
    
  3、表头自绘;        
      想绘制表头,就需要知道表头句柄。
      想得到表头句柄,就需要拦截 ListView 的 WMParentNotify 消息,因为表头的创建是由它完成的。     
      类定义:

type
        TListView = Class(ComCtrls.TListView)
        private
            FHeaderHandle: Integer;
            { 表头的回调过程 }
            FOldHeaderProc, FHeaderInstance: Pointer;
        protected
          procedure WMParentNotify(var Message: TWMParentNotify); message WM_PARENTNOTIFY;
          procedure HeaderWndProc(var Message: TMessage);
      end;

        实现:

procedure TListView.WMParentNotify(var Message: TWMParentNotify);
begin
  if (Message.Event = WM_CREATE) then
  begin
    FHeaderHandle  := message.ChildWnd;                                       // 获取到表头句柄
    FOldHeaderProc := Pointer(GetWindowLong(FHeaderHandle, GWL_WNDPROC));     // 保存好表头原有的回调过程
    SetWindowLong(FHeaderHandle, GWL_WNDPROC, Integer(FHeaderInstance));      // 指向表头新的回调过程,用于自绘
  end;
  inherited;
end;

     注:
         这里还有一些细节,比如:
         WINXP、WIN7、WIN10下创建表头句柄是有点差别的;
         创建时,需要经过几次才会真正得到句柄;
        上面的代码只是核心代码,细化没有写出,自己动手试试,也就能理解了。

     

     事前要设置一下表头新的回调过程: 

FHeaderInstance := MakeObjectInstance(HeaderWndProc);
 { 自绘表头 }
 procedure TListView.HeaderWndProc(var Message: TMessage);
 begin
   with Message do
   begin
   { 自绘表头 }
     if msg = WM_PAINT then
     begin
       { 有句柄 FHeaderHandle,就可以得到画布 Canvas ,有画布就可以自绘了 }
     end;
   end;
 end;

注:
  还有其它消息可以处理:
  WM_SETCURSOR  :当鼠标移动到表头分割线时;
  WM_NCHITTEST   :调整表头宽度;
  HDM_LAYOUT       :调整表头高度;
  等等,绘制表头悉数掌控。


OK,绘制完毕。

效果图:
效果图
 

滚动条的绘制比较好玩。以后在写吧。不在 TListview 的自绘范围内。
它是一个通用的绘制类,可以给任意控件来用(除了IE控件)。
滚动条自绘

如果您要在C#中创建自绘ListView控件,可以使用以下步骤: 1. 创建一个新的Windows窗体应用程序项目。 2. 在工具箱中找到ListView控件并将其拖放到窗体上。 3. 在窗体的代码文件中添加以下命名空间: ```csharp using System.Runtime.InteropServices; ``` 4. 在窗体的代码文件中添加以下常量和结构体: ```csharp private const int LVM_FIRST = 0x1000; private const int LVM_SETBKCOLOR = LVM_FIRST + 1; private const int LVM_SETTEXTBKCOLOR = LVM_FIRST + 38; private const int LVM_SETTEXTCOLOR = LVM_FIRST + 36; [StructLayout(LayoutKind.Sequential)] public struct LVITEM { public int mask; public int iItem; public int iSubItem; public int state; public int stateMask; public IntPtr pszText; public int cchTextMax; public int iImage; public IntPtr lParam; public int iIndent; public int iGroupId; public int cColumns; public IntPtr puColumns; } [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); ``` 5. 在窗体的代码文件中添加以下方法: ```csharp private void SetListViewProperties() { // 设置背景颜色 SendMessage(listView1.Handle, LVM_SETBKCOLOR, 0, SystemColors.Window.ToArgb()); // 设置文本背景颜色 SendMessage(listView1.Handle, LVM_SETTEXTBKCOLOR, 0, SystemColors.Window.ToArgb()); // 设置文本颜色 SendMessage(listView1.Handle, LVM_SETTEXTCOLOR, 0, SystemColors.ControlText.ToArgb()); } private void DrawListViewItem(DrawListViewItemEventArgs e) { // 自定义项的绘制方式 // ... } ``` 6. 在窗体的代码文件中添加以下事件处理程序: ```csharp private void Form1_Load(object sender, EventArgs e) { SetListViewProperties(); } private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e) { DrawListViewItem(e); } ``` 7. 在DrawListViewItem方法中实现您自己的绘制逻辑。在这个方法中,您可以使用GDI+绘制ListView控件的项。 以上就是创建自绘ListView控件的基本步骤。请注意,您需要在DrawListViewItem方法中实现自定义的绘制逻辑以达到您想要的外观效果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dbyoung

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值