TListView 的 Header 部分默認 BtnFace 顏色,高度也不能改變。咱們能夠經過編寫一些代碼來實現這些功能;windows
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;spa
Header的高度,是在一個處理一個叫 HDM_LAYOUT 的消息的時候進行設置。code
msdn的原話以下:orm
那麼咱們就用SetWindowLong 來改變 Header的 消息過程。blog
//--------------------------------------------------------------------------- #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的窗口過程當中編寫WM_PAINT 消息處理函數。可是這樣寫,你會發現沒法在Header上輸出文字。準確的說,你繪製上去的文字it
會莫名其妙的不見,好比,拉寬一下Header 中的某一列,文字就會消失邊檢。使得這種重繪很差控制;ast
正確的作法是這樣form
下面是實現的代碼
//--------------------------------------------------------------------------- #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(); } //---------------------------------------------------------------------------
---2016年6月15日更新
上個版本雖然實現了效果,可是有一個bug,雙擊列頭中間的分割區域,會致使背景色丟失;
解決辦法是,
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); } LRESULT result = oldListViewProc(hwnd,uMsg,wParam,lParam); //--雙擊列的分隔區事件 if (uMsg == WM_NOTIFY) { NMHDR* nmhdr = (NMHDR*)lParam; if (nmhdr != NULL && nmhdr->hwndFrom == hListViewHeader && nmhdr->code == HDN_DIVIDERDBLCLICK) { //將HDF_STRING 從新設置爲 HDF_OWNERDRAW SetHDItem(); } } return result; }
以後雙擊分隔區的效果