|
1.4 公共模块设计
为了使程序的界面更美观,在本系统中使用钩子函数对按钮控件进行了修改,首先创建一个按钮类CDrawButton类。CDrawButton类的代码如下:
//定义按钮状态 enum ButtonState {bsNormal,bsHot,bsDown}; //按钮包装类 class CDrawButton { public: ButtonState m_State; //按钮当前状态 WNDPROC m_OldProc; //记录按钮的窗口函数 int m_Flag; //是否释放关联按钮的CDrawButton对象 static int m_Style; //按钮风格 public: CDrawButton( ) //构造函数 { m_State = bsNormal; //设置按钮状态 m_OldProc = NULL; //设置窗口函数 m_Flag = 0; //设置按钮风格 } virtual ~CDrawButton() //析构函数 { m_State = bsNormal; //设置按钮状态 m_OldProc = NULL; //设置窗口函数 }; LRESULT OnPaint( HWND hWnd ) //绘制窗口时处理函数 { CWnd* pWnd = CWnd::FromHandle(hWnd); CPaintDC dc(pWnd); CString Text; //标题 CRect RC; //区域 CFont Font; //字体 CFont *pOldFont; //原字体 CBrush Brush; //画笔 CBrush *pOldBrush; //原画笔 CPoint PT(2,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_State == bsNormal) //判断按钮状态 {
if (m_Style==2) { CBitmap bmp; bmp.LoadBitmap(IDB_BKBUTTON); //加载图片资源 Brush.CreatePatternBrush(&bmp); //根据图片资源创建画笔 } else Brush.CreateSolidBrush( RGB( 200, 200, 200 ) ); //用颜色创建画笔 dc.SetTextColor( RGB( 80, 80, 80) ); //设置文本颜色 } else if( m_State == bsDown ) //判断按钮是否按下 { Brush.CreateSolidBrush( RGB( 160, 160, 160 ) ); //用颜色创建画笔 dc.SetTextColor( RGB( 50, 50, 250 ) ); //设置文本颜色 } else if( m_State == bsHot ) //判断按钮是否热点 { Brush.CreateSolidBrush( RGB( 100, 100, 180 ) ); //用颜色创建画笔 dc.SetTextColor( RGB( 250, 250, 0 ) ); //设置文本颜色 }
pOldBrush = dc.SelectObject( &Brush ); //将画刷选入设备环境中 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(Text ); //获得窗口显示文本 dc.DrawText( Text, &RC, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); //绘制文本
dc.SelectObject( pOldFont ); dc.SelectObject( pOldBrush );
return TRUE; } LRESULT OnLButtonDown( HWND hWnd, UINT nFlags, CPoint point ) //鼠标左键按下时处理函数 { m_State = bsDown; //设置按钮状态 SetCapture(hWnd); //捕获鼠标 SetFocus(hWnd); //设置焦点 InvalidateRect(hWnd,NULL,TRUE); //重绘窗口区域 return TRUE; }
LRESULT OnLButtonUp( HWND hWnd, UINT nFlags, CPoint point ) //鼠标左键抬起时处理函数 { if( m_State != bsNormal ) //判断按钮状态 { m_State = bsNormal; //设置按钮状态 ReleaseCapture(); //释放鼠标 InvalidateRect(hWnd,NULL,TRUE); //重绘窗口区域 //发送WM_COMMAND消息 SendMessage( GetParent(hWnd), WM_COMMAND, GetDlgCtrlID(hWnd), (LPARAM) (hWnd) ); } return TRUE; } LRESULT LoseFocus(HWND hWnd) //失去焦点时处理函数 { m_State = bsNormal; //设置按钮状态 InvalidateRect(hWnd,NULL,TRUE); //重绘窗口区域 SendMessage( hWnd, WM_KILLFOCUS, (long)hWnd, 0); // 发送WM_KILLFOCUS消息 return TRUE; } LRESULT OnMouseMove(HWND hWnd, UINT nFlags, CPoint point ) //鼠标移动时处理函数 { HRGN hRgn = CreateRectRgn( 0, 0, 0, 0 ); //创建矩形区域 GetWindowRgn( hWnd,hRgn ); //获得窗口区域 BOOL ret = PtInRegion( hRgn, point.x, point.y ); //判断鼠标是否在窗口区域中 if( ret ) { if( m_State == bsDown) //判断按钮是否按下 return TRUE; if( m_State != bsHot ) //判断按钮是否热点 { m_State = bsHot; //设置按钮状态 InvalidateRect(hWnd,NULL,TRUE); //重绘窗口区域 UpdateWindow(hWnd); //更新显示窗口 SetCap tare(hWnd); //捕获鼠标 } } else { m_State = bsNormal; //设置按钮状态 InvalidateRect(hWnd,NULL,TRUE); //重绘按钮区域 ReleaseCapture(); //释放鼠标 } DeleteObject( hRgn ); return TRUE; } }; |
代码贴士 SetBkMode:设置背景模式,值为TRANSPARENT时进行透明处理。 CreateFont:初始化用指定特性定义的CFont对象。 InvalidateRect:屏蔽一个窗口客户区的全部或部分区域,会导致窗口在事件期间部分重画。 SendMessage:将指定的消息发送到一个或多个窗口,此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。
然后,定义一个新的定义按钮窗口函数,以取代按钮默认的窗口函数,对一些消息进行特殊处理。代码如下:
LRESULT __stdcall DefWindowProc1(HWND hWnd,UINT Msg, WPARAM wParam, LPARAM lParam ) { CPoint pt; CDrawButton *pButton=(CDrawButton*)GetWindowLong(hWnd, GWL_USERDATA); //获得窗口信息 switch (Msg) { case WM_LBUTTONDBLCLK: //屏蔽双击事件 { return TRUE; break; } case WM_PAINT: //绘制窗口事件 { if (pButton->m_Style>0) return pButton->OnPaint( hWnd); else return CallWindowProc(pButton->m_OldProc, hWnd,Msg,wParam,lParam); break; } case WM_LBUTTONDOWN: //鼠标左键按下事件 { pt.x = LOWORD(lParam); //鼠标按下的横坐标 pt.y = HIWORD(lParam); //鼠标按下的纵坐标 if (pButton->m_Style>0) return pButton->OnLButtonDown( hWnd, 0, pt ); else return CallWindowProc(pButton->m_OldProc, hWnd,Msg,wParam,lParam); break; } case WM_LBUTTONUP: //鼠标左键抬起事件 { pt.x = LOWORD(lParam); //鼠标按下的横坐标 pt.y = HIWORD(lParam); //鼠标按下的纵坐标 if (pButton->m_Style>0) return pButton->OnLButtonUp( hWnd, 0,pt ); else return CallWindowProc(pButton->m_OldProc, hWnd,Msg,wParam,lParam); break; } case WM_MOUSEMOVE: //鼠标移动事件 { pt.x = LOWORD(lParam); //鼠标按下的横坐标 pt.y = HIWORD(lParam); //鼠标按下的纵坐标 if (pButton->m_Style>0) return pButton->OnMouseMove(hWnd,0, pt); else return CallWindowProc(pButton->m_OldProc, hWnd,Msg,wParam,lParam); break; } case WM_DESTROY: //销毁窗口 { WNDPROC procOld=pButton->m_OldProc; SetWindowLong(hWnd,GWL_WNDPROC,(long)procOld); //恢复原来的窗口函数 CWnd* pWnd = ::CWnd::FromHandle(hWnd); //将按钮对象与控制块分离 if (pWnd) { pWnd->Detach(); } pButton->m_Flag = 1; return 1; } default : { break; } } return CallWindowProc(pButton->m_OldProc, hWnd, Msg, wParam, lParam ); }
| 定义钩子函数,对按钮类控件进行子类化。代码如下:
LRESULT CALLBACK HOOKProc( int nCode, WPARAM wParam, LPARAM lParam ) { PCWPSTRUCT wc = (PCWPSTRUCT) lParam; HWND hWnd = wc->hwnd; if( hWnd ) { char ClassName[MAX_PATH] = ""; GetClassName( hWnd, ClassName, MAX_PATH ); //去掉窗口类名 if( strcmp( ClassName, "Button" ) == 0 ) { CWnd *pWnd = CWnd::FromHandle( hWnd ); if ( pWnd->GetStyle() & BS_RADIOBUTTON ) //判断单选按钮 { return 1; } if ( pWnd->GetStyle() & BS_CHECKBOX ) //判断复选框 { return 1; } WNDPROC WndProc; WndProc = (WNDPROC) GetWindowLong( hWnd, GWL_WNDPROC ); CDrawButton *pButton=(CDrawButton*)GetWindowLong(hWnd,GWL_USERDATA); if (pButton != NULL&& pButton->m_Flag==1 ) { SetWindowLong(hWnd,GWL_USERDATA,0); //设置窗口信息 //设置窗口对话框函数地址 SetWindowLong( hWnd, GWL_WNDPROC, (LONG)pButton->m_OldProc ); pButton->m_OldProc = NULL; delete pButton; } else if (pButton == NULL ) { if( WndProc !=DefWindowProc1 ) { pButton = new CDrawButton; pButton->m_OldProc = WndProc; SetWindowLong(hWnd,GWL_USERDATA,(long)pButton); //设置窗口信息 WndProc = (WNDPROC) SetWindowLong( hWnd, GWL_WNDPROC, (LONG) DefWindowProc1); //设置窗口函数地址 } } } } return CallNextHookEx( hWndHook, nCode, wParam, lParam ); }
| 定义一个安装钩子的函数RunHook,代码如下:
BOOL RunHook( HMODULE hModule, DWORD dwThreadID) { hWndHook = SetWindowsHookEx( WH_CALLWNDPROC, (HOOKPROC) HOOKProc, hModule, dwThreadID ); //安装钩子 return TRUE; } | 定义一个卸载钩子的函数StopHook,代码如下:
BOOL StopHook() { UnhookWindowsHookEx(hWndHook); //卸载钩子 return TRUE; }
|
【责任编辑: 夏书 TEL:(010)68476606】
|