如何自绘ListView表头

TlistView 控件是vcl 对windows公用控件库的一个封装.用户TlistView控件并未提供自绘表头的事件, 一般情况下, 要想自绘表头比较困难. 但是windows 所有控件的绘制都是由于消息WM_PAINT的产生,而由窗口过程来绘制的, 这样我们似乎就有可能通过WM_PAINT消息能够绘制TlistView表头. 经过分析发现TlistView 的组成实际上包括了两部分, 一部分是TlistView本省, 另外一部分就是TlistView的表头, 该表头实际上是一个嵌入TlistView里面的独立的窗口, 该窗口的类名为”SysHeader32”.(可以使用ccrun写的窗口探测工具spy4win观察的到). 综合上述依据, 实现TlistView表头的自绘可以分为一下几个步骤:

1. 查找TlistView的表头窗口句柄.
2. 替换表头窗口的窗口过程
3. 表头的WM_PAINT消息
4. 在窗口过程中编写绘制代码

这样就能绘制TlistView 的表头了.具体实现方式如下 :
1. 查找表头有三种方式 
一. 使用FindWindowEx :
以类名”SysHeader32”来查找TlistView的子窗口, 由于TlistView只有一个名为”SysHeader32”的子窗口(就是表头), 所以一定能够获取到表头窗口的句柄
二. 使用windows提供的帮助宏ListView_GetHeader
这种方式实际上是通过发送消息来获取表头句柄, 返回值即表头句柄
2. 替换表头的窗口过程
使用SetWindowLong这个API 就可以替换掉一个窗口的窗口过程.(详细步骤请参看MSDN)
3. 请参看示例代码
4. 请参看示例代码

示例代码 :
开发者 : 死牛之祭(A-Few)
2009-08-25
说明 :
该代码可以自由引用, 包括商业应用. 希望转载时尊重作者的署名权利.
学习交流请来信a-few@netease.com.


.h文件
// ---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
// ---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>

// ---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
    TListView *ListView1;

private: // User declarations
public: // User declarations
    __fastcall TForm1(TComponent* Owner);
    __fastcall~TForm1();
};

// ---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
// ---------------------------------------------------------------------------
#endif
.cpp文件
// ---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
// ---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
typedef LRESULT(CALLBACK * TCallBack)(HWND, UINT, WPARAM, LPARAM);

TCallBack g_oldListViewWndProc;
HWND g_hListViewHeader;

LRESULT CALLBACK ListViewWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
    LPARAM lParam)
{
    PAINTSTRUCT ps ={ 0 };
    RECT rect = { 0 };
    HDC hPen = NULL;
    HDC hBrush = NULL;
    int iCount = 0;
    int i1 = 0;
    BYTE red0 = 115, green0 = 154, blue0 = 206;
    BYTE red1 = 255, green1 = 255, blue1 = 255;
    BYTE red, green, blue;
    int j, m, n;

    switch(uMsg)
    {
    case WM_PAINT:
        BeginPaint(g_hListViewHeader, &ps);
        hPen = SelectObject(ps.hdc, GetStockObject(DC_PEN));
        iCount = Header_GetItemCount(g_hListViewHeader); // 获取表头数目
// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=1069&d=uq3568
        SetDCPenColor(ps.hdc, ColorToRGB((TColor)(0x00EFDBCE)));
        red = GetRValue((TColor)(0x00EFDBCE));
        green = GetGValue((TColor)(0x00EFDBCE));
        blue = GetBValue((TColor)(0x00EFDBCE));
        for (int i = 0; i < iCount; i++)
        {
            Header_GetItemRect(g_hListViewHeader, i, &rect); // 获取Item的高度

            m = rect.bottom - rect.top;
            n = m / 2 + 1;
            for (j = 0; j < n; j++)
            {
                red = red0 * (j + 1) / n + red1 * (n - j - 1) / n;
                green = green0 * (j + 1) / n + green1 * (n - j - 1) / n;
                blue = blue0 * (j + 1) / n + blue1 * (n - j - 1) / n;

                SetDCPenColor(ps.hdc, RGB(red, green, blue));
                MoveToEx(ps.hdc, rect.left + 1, rect.top + j, NULL);
                LineTo(ps.hdc, rect.right, rect.top + j);
                MoveToEx(ps.hdc, rect.left + 1, rect.bottom - j - 1, NULL);
                LineTo(ps.hdc, rect.right, rect.bottom - j - 1);
            }
            SetDCPenColor(ps.hdc, ColorToRGB(clBtnFace));
            MoveToEx(ps.hdc, rect.right, rect.top + 1, NULL);
            LineTo(ps.hdc, rect.right, rect.bottom - 1);
            SelectObject(ps.hdc, Form1->Font->Handle);
            i1 = ((rect.bottom - rect.top) - abs(Form1->Font->Height)) / 2;
            hBrush = SelectObject(ps.hdc, GetStockObject(NULL_BRUSH));
            SetBkMode(ps.hdc, TRANSPARENT); // 这是设置背景为透明的
            TextOut(ps.hdc, rect.left + 10, rect.top + i1,
                Form1->ListView1->Columns->Items[i]->Caption.c_str(),
                Form1->ListView1->Columns->Items[i]->Caption.Length());
            SelectObject(ps.hdc, hBrush);
        }
        hPen = SelectObject(ps.hdc, hPen);
        EndPaint(g_hListViewHeader, &ps);
        break;
    default:
        return CallWindowProc((FARPROC)g_oldListViewWndProc, g_hListViewHeader,
            uMsg, wParam, lParam);
    }

    return 0;
}

// ---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
    g_hListViewHeader = FindWindowEx(ListView1->Handle, NULL, "SysHeader32",
        NULL);
    g_oldListViewWndProc = (TCallBack)GetWindowLong
        (g_hListViewHeader, GWL_WNDPROC);
    SetWindowLong(g_hListViewHeader, GWL_WNDPROC, long(ListViewWindowProc));
}

// ---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
    SetWindowLong(g_hListViewHeader, GWL_WNDPROC, (long)g_oldListViewWndProc);
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
如果您要在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方法中实现自定义的绘制逻辑以达到您想要的外观效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值