TListView 的 Header 部分默认 BtnFace 颜色,高度也不能改变。我们可以通过编写一些代码来实现这些功能;
- 获得TListView 的Header 的句柄;
TListView的Header其实是一个 HeaderContorl 控件。要获得他的句柄需要调用下面的代码
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- static HWND hListViewHeader = NULL; __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { //获得ListView Header的句柄 hListViewHeader = ListView_GetHeader(ListView1->Handle); } //---------------------------------------------------------------------------
其实还有许多ListView_XXXX 这样的windows API ,需要查看MSDN;
- 改变Header的高度
Header的高度,是在一个处理一个叫 HDM_LAYOUT 的消息的时候进行设置。
msdn的原话如下:
那么我们就用SetWindowLong 来改变 Header的 消息过程。
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- static HWND hListViewHeader = NULL; //Header原来的窗口过程 static WNDPROC oldHeaderWindowProc = NULL; //Header的新窗口过程 LRESULT CALLBACK NewHeaderWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { //先要用原来的窗口过程处理 LRESULT result = oldHeaderWindowProc(hwnd,uMsg,wParam,lParam); //再处理HDM_LAYOUT消息 if (HDM_LAYOUT == uMsg) { LPHDLAYOUT phdmlayout = (LPHDLAYOUT)lParam; //改变header的高度 phdmlayout->pwpos->cy = 27; //改变listview表格部分的高度 phdmlayout->prc->top = phdmlayout->pwpos->cy; } return result; } __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { hListViewHeader = ListView_GetHeader(ListView1->Handle); oldHeaderWindowProc = (WNDPROC)SetWindowLong( hListViewHeader,GWL_WNDPROC,(LONG)NewHeaderWindowProc); ListView1->Invalidate(); } //---------------------------------------------------------------------------
我们会看到这样的效果
- 处理Header的背景色
可以在Header的窗口过程中编写WM_PAINT 消息处理函数。但是这样写,你会发现无法在Header上输出文字。准确的说,你绘制上去的文字
会莫名其妙的不见,比如,拉宽一下Header 中的某一列,文字就会消失边检。使得这种重绘不好控制;
正确的做法是这样
- 调用 Header_SetItem 函数(其实是一个macro) 将ListView的Header 的 format 属性,设置为 HDF_OWNERDRAW (默认是 HDF_STRING).
- 重写ListView 的消息过程。(不是Header的消息过程);
- 在ListView的消息过程中处理 WM_DRAWITEM 消息;(WM_DRAWITEM消息会包含要重绘的 区域,hdc,index,状态等等)
- 在Header 的 HDM_LAYOUT 消息处理过程,也要调用 Header_SetItem,将format消息设置为 HDF_OWERDRAW (否则,每次改变列宽,format属性就又变成HDF_STRING,导致无法重绘)
下面是实现的代码
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- static HWND hListViewHeader = NULL; //Header原来的窗口过程 static WNDPROC oldHeaderWindowProc = NULL; //listView 原来的窗口过程 static WNDPROC oldListViewProc = NULL; //Header的新窗口过程 LRESULT CALLBACK NewHeaderWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { //先要用原来的窗口过程处理 LRESULT result = oldHeaderWindowProc(hwnd,uMsg,wParam,lParam); //再处理HDM_LAYOUT消息 if (HDM_LAYOUT == uMsg) { LPHDLAYOUT phdmlayout = (LPHDLAYOUT)lParam; //改变header的高度 phdmlayout->pwpos->cy = 27; //改变listview表格部分的高度 phdmlayout->prc->top = phdmlayout->pwpos->cy; } return result; } LRESULT CALLBACK NewListViewWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_DRAWITEM) { DRAWITEMSTRUCT* drawItemStruct = (DRAWITEMSTRUCT*)lParam; HDC hdc = drawItemStruct->hDC; int index = drawItemStruct->itemID; RECT rect = drawItemStruct->rcItem; TBrush* brush = new TBrush(); TColor fontColor = clBlack; if (index == 0) { brush->Color = clRed; fontColor = clWhite; } if (index == 1) { brush->Color = clYellow; fontColor = clBlue; } if (index == 2) { brush->Color = clBlue; fontColor = clWhite; } if (index == 3) { brush->Color = clLime; fontColor = clBlue; } FillRect(hdc,&rect,brush->Handle); delete brush; SetTextColor(hdc,fontColor); SetBkMode(hdc,TRANSPARENT); //获取文本 HDITEM hditem= {0}; char buf[100] = {0}; hditem.mask = HDI_TEXT; hditem.pszText = buf; hditem.cchTextMax = 100; Header_GetItem(hListViewHeader,index,&hditem); DrawText(hdc,hditem.pszText,strlen(hditem.pszText),&rect, DT_CENTER |DT_VCENTER |DT_SINGLELINE); } return oldListViewProc(hwnd,uMsg,wParam,lParam); } __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void SetHDItem() { if (hListViewHeader == NULL) { return; } HDITEM hditem; hditem.mask = HDI_FORMAT; hditem.fmt = HDF_OWNERDRAW; //默认是 HDF_STRING int count = Header_GetItemCount(hListViewHeader); for (int i = 0; i < count ;i++) { Header_SetItem(hListViewHeader,i,&hditem); } } void __fastcall TForm1::FormCreate(TObject *Sender) { hListViewHeader = ListView_GetHeader(ListView1->Handle); oldHeaderWindowProc = (WNDPROC)SetWindowLong( hListViewHeader,GWL_WNDPROC,(LONG)NewHeaderWindowProc); oldListViewProc = (WNDPROC)SetWindowLong( ListView1->Handle,GWL_WNDPROC,(LONG)NewListViewWindowProc); SetHDItem(); ListView1->Invalidate(); } //---------------------------------------------------------------------------
显示效果如下
但是,一旦拖动列头会变成这样
所以需要有上述步骤中第4步,在HDM_LAYOUT消息中加入SetHDItem 函数调用
最终代码
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- static HWND hListViewHeader = NULL; //Header原来的窗口过程 static WNDPROC oldHeaderWindowProc = NULL; //listView 原来的窗口过程 static WNDPROC oldListViewProc = NULL; void SetHDItem() { if (hListViewHeader == NULL) { return; } HDITEM hditem; hditem.mask = HDI_FORMAT; hditem.fmt = HDF_OWNERDRAW; //默认是 HDF_STRING int count = Header_GetItemCount(hListViewHeader); for (int i = 0; i < count ;i++) { Header_SetItem(hListViewHeader,i,&hditem); } } //Header的新窗口过程 LRESULT CALLBACK NewHeaderWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { //先要用原来的窗口过程处理 LRESULT result = oldHeaderWindowProc(hwnd,uMsg,wParam,lParam); //再处理HDM_LAYOUT消息 if (HDM_LAYOUT == uMsg) { LPHDLAYOUT phdmlayout = (LPHDLAYOUT)lParam; //改变header的高度 phdmlayout->pwpos->cy = 27; //改变listview表格部分的高度 phdmlayout->prc->top = phdmlayout->pwpos->cy; //将HDF_STRING 重新设置为 HDF_OWNERDRAW SetHDItem(); } return result; } LRESULT CALLBACK NewListViewWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_DRAWITEM) { DRAWITEMSTRUCT* drawItemStruct = (DRAWITEMSTRUCT*)lParam; HDC hdc = drawItemStruct->hDC; int index = drawItemStruct->itemID; RECT rect = drawItemStruct->rcItem; TBrush* brush = new TBrush(); TColor fontColor = clBlack; if (index == 0) { brush->Color = clRed; fontColor = clWhite; } if (index == 1) { brush->Color = clYellow; fontColor = clBlue; } if (index == 2) { brush->Color = clBlue; fontColor = clWhite; } if (index == 3) { brush->Color = clLime; fontColor = clBlue; } FillRect(hdc,&rect,brush->Handle); delete brush; SetTextColor(hdc,fontColor); SetBkMode(hdc,TRANSPARENT); //获取文本 HDITEM hditem= {0}; char buf[100] = {0}; hditem.mask = HDI_TEXT; hditem.pszText = buf; hditem.cchTextMax = 100; Header_GetItem(hListViewHeader,index,&hditem); DrawText(hdc,hditem.pszText,strlen(hditem.pszText),&rect, DT_CENTER |DT_VCENTER |DT_SINGLELINE); } return oldListViewProc(hwnd,uMsg,wParam,lParam); } __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { hListViewHeader = ListView_GetHeader(ListView1->Handle); oldHeaderWindowProc = (WNDPROC)SetWindowLong( hListViewHeader,GWL_WNDPROC,(LONG)NewHeaderWindowProc); oldListViewProc = (WNDPROC)SetWindowLong( ListView1->Handle,GWL_WNDPROC,(LONG)NewListViewWindowProc); SetHDItem(); ListView1->Invalidate(); } //---------------------------------------------------------------------------
时间: 2024-10-25 19:49:58