分类: C/C++
2008-08-01 16:58:31
BOOL IRStartup( HINSTANCE hModule, DWORD dwThreadID ) { globalWndHookEx = SetWindowsHookEx( WH_CALLWNDPROC, (HOOKPROC) IRCallWndProc, hModule, dwThreadID ); return TRUE; }这也是像SkinMagic一类工具的初始化函数。当然在退出时也要释放钩子的。
BOOL IRComplete( void ) { UnhookWindowsHookEx( globalWndHookEx ); return TRUE; }接下来,就是IRCallWndProc这个回调函数的编写,这是至关重要的一个环节,这个函数就是对所要换肤的类对象进行了监视,并改变其消息处理函数,实现换肤的目的。
LRESULT CALLBACK IRCallWndProc( int nCode, WPARAM wParam, LPARAM lParam ) { PCWPSTRUCT pcs = (PCWPSTRUCT) lParam; HWND hWnd = pcs->hwnd; if( hWnd ) { char sClassName[201] = "\0"; GetClassName( hWnd, sClassName, 200 ); if( strcmp( sClassName, "Button" ) == 0 ) { CWnd *pWnd = CWnd::FromHandle( hWnd ); DWORD dwStyle = pWnd->GetStyle(); if( dwStyle == 0x50010000 ) { WNDPROC WndProc; WndProc = (WNDPROC) GetWindowLong( hWnd, GWL_WNDPROC ); if( CButtonExt::m_cWndProc != NULL && \ WndProc != CButtonExt::m_cWndProc ) { return CallNextHookEx( globalWndHookEx, nCode, wParam, lParam ); } if( WndProc != (WNDPROC) CButtonExt::DefWindowProc ) { WndProc = (WNDPROC) SetWindowLong( hWnd, GWL_WNDPROC, (LONG) CButtonExt::DefWindowProc ); CButtonExt::m_cWndProc = WndProc; } } } } return CallNextHookEx( globalWndHookEx, nCode, wParam, lParam ); }这样就对按钮的消息进行了挂钩处理了,就可以重新来绘制按钮了。紧接着就是给出按钮控件的绘制方法,我是用一个类来实现的,都是使用的静态函数直接调用的。
#define STATUS_BUTTON_NORMAL 0x00000000 #define STATUS_BUTTON_HOVER 0x00000001 #define STATUS_BUTTON_DOWN 0x00000002 class CButtonExt { public: CButtonExt() {} ~CButtonExt() {} static UINT m_nStatus; static WNDPROC m_cWndProc; static LRESULT DefWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { CWnd *pWnd = NULL; CPoint point; pWnd = CWnd::FromHandle( hWnd ); switch( message ) { case WM_PAINT: return OnPaint( pWnd ); break; case WM_LBUTTONDOWN: point.x = LOWORD(lParam); point.y = HIWORD(lParam); return OnLButtonDown( pWnd, 0, point ); break; case WM_LBUTTONUP: point.x = LOWORD(lParam); point.y = HIWORD(lParam); return OnLButtonUp( pWnd, 0, point ); break; case WM_LBUTTONDBLCLK: point.x = LOWORD(lParam); point.y = HIWORD(lParam); return OnLButtonDblClk( pWnd, 0, point ); break; case WM_MOUSEMOVE: point.x = LOWORD(lParam); point.y = HIWORD(lParam); return OnMouseMove( pWnd, 0, point ); break; default: break; } return CallWindowProc( m_cWndProc, hWnd, message, wParam, lParam ); } static LRESULT OnLButtonDown( CWnd *pWnd, UINT nFlags, CPoint point ) { m_nStatus = STATUS_BUTTON_DOWN; pWnd->Invalidate(); pWnd->UpdateWindow(); return TRUE; } static LRESULT OnLButtonUp( CWnd *pWnd, UINT nFlags, CPoint point ) { if( m_nStatus != STATUS_BUTTON_NORMAL ) { m_nStatus = STATUS_BUTTON_NORMAL; pWnd->Invalidate(); pWnd->UpdateWindow(); SendMessage( pWnd->GetParent()->m_hWnd, WM_COMMAND, pWnd->GetDlgCtrlID(), (LPARAM) (pWnd->m_hWnd) ); } return TRUE; } static LRESULT OnLButtonDblClk( CWnd *pWnd, UINT nFlags, CPoint point ) { return TRUE; } static LRESULT OnMouseMove( CWnd *pWnd, UINT nFlags, CPoint point ) { HRGN hRgn = CreateRectRgn( 0, 0, 0, 0 ); pWnd->GetWindowRgn( hRgn ); BOOL bIn = PtInRegion( hRgn, point.x, point.y ); if( bIn ) { if( m_nStatus == STATUS_BUTTON_DOWN ) return TRUE; if( m_nStatus != STATUS_BUTTON_HOVER ) { m_nStatus = STATUS_BUTTON_HOVER; pWnd->Invalidate(); pWnd->UpdateWindow(); pWnd->SetCapture(); } } else { if ( m_nStatus == STATUS_BUTTON_HOVER ) { m_nStatus = STATUS_BUTTON_NORMAL; pWnd->Invalidate(); pWnd->UpdateWindow(); ReleaseCapture(); } } DeleteObject( hRgn ); return TRUE; } static LRESULT OnPaint( CWnd *pWnd ) { CPaintDC dc(pWnd); CString cs; RECT rc; CFont Font; CFont *pOldFont; CBrush Brush; CBrush *pOldBrush; CPen Pen; CPen *pOldPen; POINT pt; pt.x = 2; pt.y = 2; dc.SetBkMode( TRANSPARENT ); Font.CreateFont( 12, 0, 0, 0, FW_HEAVY, 0, 0, 0, ANSI_CHARSET, \ OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, \ VARIABLE_PITCH | FF_SWISS, "MS Sans Serif" ); pOldFont = dc.SelectObject( &Font ); if( m_nStatus == STATUS_BUTTON_DOWN ) { Brush.CreateSolidBrush( RGB( 160, 160, 160 ) ); Pen.CreatePen( PS_SOLID, 1, RGB( 100, 100, 100 ) ); dc.SetTextColor( RGB( 50, 50, 250 ) ); } else if( m_nStatus == STATUS_BUTTON_HOVER ) { Brush.CreateSolidBrush( RGB( 60, 60, 180 ) ); Pen.CreatePen( PS_SOLID, 1, RGB( 0, 0, 0 ) ); dc.SetTextColor( RGB( 250, 250, 50 ) ); } else if( m_nStatus == STATUS_BUTTON_NORMAL ) { Brush.CreateSolidBrush( RGB( 240, 240, 240 ) ); Pen.CreatePen( PS_SOLID, 1, RGB( 120, 120, 120 ) ); dc.SetTextColor( RGB( 50, 50, 50 ) ); } pOldBrush = dc.SelectObject( &Brush ); pOldPen = dc.SelectObject( &Pen ); pWnd->GetClientRect( &rc ); dc.RoundRect( &rc, pt ); HRGN hRgn = CreateRectRgn( rc.left, rc.top, rc.right, rc.bottom ); pWnd->SetWindowRgn( hRgn, TRUE ); DeleteObject( hRgn ); pWnd->GetWindowText( cs ); dc.DrawText( cs, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); dc.SelectObject( pOldFont ); dc.SelectObject( pOldBrush ); dc.SelectObject( pOldPen ); return TRUE; } static LRESULT OnEraseBkgnd( CWnd *pWnd, CDC *pDC ) { return TRUE; } }; UINT CButtonExt::m_nStatus = STATUS_BUTTON_NORMAL; WNDPROC CButtonExt::m_cWndProc = NULL程序结构还是很清楚的,这时做一些简单的说明。m_nStatus用来标志按钮的状态,m_cWndProc用来保存系统的消息处理函数地址。其他就不用说了吧。 最后,就是如何在程序中使用的问题了。调用方法其实很简单,在CSkinApp类的InitInstance()函数中加入这样的一句话:
IRStartup( GetModuleHandle( NULL ), GetCurrentThreadId() );在CSkinApp类的ExitInstance()中加入这样的一句话:
IRComplete();这样就实现了对按钮的换肤,是不是很简单啊,我只是做了一个简单的实现,还有很多工作需要大家一起来做,希望有兴趣的朋友一起来做,有什么问题请到 上发问,同时也希望大家把你们的作品公布出来,SkinDemo的开发网站就在,发布你的后继开发,贴出你的心得。 下载本文示例代码