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.

#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);
}windows

相關文章
相關標籤/搜索