程序中用到Windows通用控件。比如按钮控件,进度条控件等等。但是有时我们需要给控件更多的特色,这就需要做控件的子类化(subclassing).
子类化,通俗来讲就是用自己的窗口处理函数来处理特定消息,并将自己其他消息还给标准(默认)窗口处理函数。在SDK中,通过SetWindowLong来指定一个自定义窗口处理函数:SetWindowLong(hwnd, GWL_WNDPROC, (LONG)UserWndProc);
_editHwnd = _editHtmlBody.GetSafeHwnd();//获得窗口对象(CWnd的派生对象)指针的句柄(HWND)
//_lpEditProc 为内置窗口处理地址
_lpEditProc(WNDPROC)::SetWindowLong(_editHtmlBody.GetSafeHwnd(),GWLP_WNDPROC(LONG)&CTabHtmlBody::SubEditProc);
//该函数用来改变指定窗口的属性 GWLP_WNDPROC 为窗口设定一个新的处理函数。
long CTabHtmlBody::SubEditProc(HWND hWnd,UINT uMsg,WPARAM wparam,LPARAM lparam)
{
PAINTSTRUCT ps;
if(uMsg == WM_PAINT)
{
::CallWindowProc(_lpEditProc,hWnd,uMsg,wparam,lparam);
::BeginPaint(hWnd,&ps);
ShowLineNum(_editHwnd); //该函数设置RichEdit控件左侧40像素显示行号
return ::EndPaint(hWnd,&ps);
}
return ::CallWindowProc(_lpEditProc, hWnd, uMsg, wparam, lparam);
}
void CTabHtmlBody::ShowLineNum(HWND hEdit)
{
RECT ClientRect; //RechEdit客户区大小
HDC hdcEdit; //RechEdit的DC
HDC hdcCpb; //与RechEdit兼容的DC
HBITMAP hdcBmp; //与RechEdit兼容的位图dc
int CharHeigh;
int chHeigh;
int FirstLine; //文本框第一个可见行的行号
int ClientHeigh; //RechEdit的客户去高度
int LineCount;
wchar_t countBuf[10]; //显示行号的缓冲区
CHARFORMAT CharFmt;
hdcEdit = ::GetDC(hEdit);
::GetClientRect(hEdit,&ClientRect);
ClientHeigh = ClientRect.bottom - ClientRect.top;
hdcCpb = ::CreateCompatibleDC(hdcEdit);
hdcBmp = ::CreateCompatibleBitmap(hdcEdit,40,ClientHeigh);
SelectObject(hdcCpb,hdcBmp);
::FillRect(hdcCpb,&ClientRect,::CreateSolidBrush(0x8080ff));
::SetBkMode(hdcCpb,TRANSPARENT);
LineCount = ::SendMessage(hEdit,EM_GETLINECOUNT,0,0);
RtlZeroMemory(&CharFmt,sizeof(CharFmt));
CharFmt.cbSize = sizeof(CharFmt);
::SendMessage(hEdit,EM_GETCHARFORMAT,TRUE,(long)&CharFmt);
CharHeigh = CharFmt.yHeight/15;
chHeigh = CharHeigh;
CharHeigh = 2;
SetTextColor(hdcCpb,0x000000);
FirstLine = ::SendMessage(hEdit,EM_GETFIRSTVISIBLELINE,0,0);
FirstLine++;
while(FirstLine < LineCount)
{
::TextOut(hdcCpb,1, CharHeigh, countBuf,wsprintf(countBuf,L"%4u", FirstLine++));
CharHeigh += chHeigh + 3;
if(CharHeigh > ClientHeigh) break;
}
::BitBlt(hdcEdit,0,0,40,ClientHeigh,hdcCpb,0,0,SRCCOPY);
::DeleteDC(hdcCpb);
::ReleaseDC(hEdit,hdcEdit);
::DeleteObject(hdcBmp);
}