程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> VC用Win API實現自繪按鈕類

VC用Win API實現自繪按鈕類

編輯:關於VC++

俗話說佛要金裝、人要衣裝,作軟件的當然得要個好界面啦^_^。網上提供的控件自繪基本上是MFC或WTL封裝好的類,對於不想用MFC的人來說是一無是處的,我可是WIN32API的堅決擁護者。因為MFC等也是用WIN32API封裝起來的,學好了WIN32API,可以深入的了解WINDOWS內部的機制,編寫出來的程序才能得到更好的優化。

下面分析一下自繪按鈕的原理,用過MFC自繪按鈕的人都知道,是通過重載了父窗口WM_DRAWITEM的響應消息實現的。同時也要子類化按鈕來得到按鈕的其他有用的消息,比如WM_MOUSEMOVE、WM_KEYDOWN等消息。因為MFC的消息循環都是封裝好的,所以只要派生一下基本控件類就可以了。當是用WIN32API做的話就需要自己來子類化按鈕窗口的消息循環了,相信經常編程的朋友都知道,子類化控件要用到SetWindowLong來改變窗口的回調過程,然後在回調窗口內添上自己需要處理的消息即可。因為我們要實現自繪按鈕所以最好把子類化的過程做成一個類,然後傳給它要自繪的按鈕句柄就行了。因為要在類裡面實現消息回調函數,但是類裡面的消息回調函數只能是靜態的,所以不能對應每個實例的消息回調。在我實現的按鈕子類化類裡,我用到Thunk技術或SetProp函數來實現的,具體請網上查找。

下面我來談談自繪按鈕裡最重要的部分,就是響應按鈕消息函數裡的WM_PAINT消息,我們所有的自繪動作都在這裡進行的。WM_PAINT裡的繪圖操作與普通窗口的操作一樣,但是為了跟蹤按鈕的當前狀態,我們還要響應按鈕窗口的WM_MOUSEMOVE、WM_SETFOCUS、WM_KILLFOCUS、WM_LBUTTONDOWN、WM_ENABLE等消息來得到當前按鈕的狀態。從而在WM_PAINT裡面繪出不同的狀態,能實現的東西很多可以說你想多少基本就能實現多少^_^,看個人喜好了,我提供源代碼大家可以自行修改。我也是參看了ButtonST裡面自繪的代碼,我自己添加了右鍵拖動功能,鼠標掠過發生功能大家有興趣可以自己添加,鍛煉一下自己的編程能力^_^。

下面我說一下我做的這個類的一個問題,我把按鈕類做成了一個動態庫,調用時只要加上我的頭文件和連接的lib庫就可以了。我的動態庫在WIN32的程序加載是沒有問題的,但是在MFC裡面,必需要響應父窗口的WM_DRAWITEM消息,在裡面直接返回,而不要調用MFC默認的處理就OK了。這是因為我沒有截獲父窗口的WM_DRAWITEM消息,否則在關閉程序時會出現非法操作!主要代碼分析如下:

自繪按鈕類聲明:class DLLPORT CWINButton
{
public:
   //初始化按鈕(這是第一步!)
   BOOL GetItemhWnd(HWND hWnd);
   //還原按鈕區域設置
   BOOL Restore();
   //設置按鈕是否可以拖動
   BOOL SetDrag(BOOL Enable);
   //設置按鈕圖標
   BOOL SetIcon(HICON icon);
   //設置按鈕文字
   BOOL SetText(char *text, HFONT font);
   BOOL SetText(char *text);
   BOOL SetText(char *text, COLORREF color);
   //設置按鈕有效區域
   BOOL SetupRegion(COLORREF TransColor);
   LRESULT OnPaint(HDC hdc);
   //設置按鈕無效時的圖片
   BOOL SetDisablePic(HBITMAP bmp);
   //設置按鈕按下時的圖片
   BOOL SetPressPic(HBITMAP bmp);
   //設置懸停按鈕時的圖片
   BOOL SetHoverPic(HBITMAP bmp);
   //設置按鈕背景圖片,第二個參數是是否根據圖片調整按鈕大小
   BOOL SetBackPic(HBITMAP bmp, BOOL bReSize);
   //設置按鈕的提示消息
   BOOL SetToolTip(char *text);
   CWINButton();
   virtual ~CWINButton();
  
private:
   static LRESULT WINAPI stdProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam);
   WNDPROC GetThunk();
   WNDPROC CreateThunk();
   LRESULT CALLBACK WINProc(UINT message, WPARAM wParam, LPARAM lParam);
   BOOL DrawInsideBorder(HDC dc, RECT *rect);
   BOOL DrawFlat(HDC dc, RECT *rect);
   BOOL DrawDefault(HDC dc);
   HWND m_ToolTip;
   HWND m_hWnd;
   HWND m_hWndParent;
   LONG m_OldProc;
   WNDPROC m_thunk;
   TOOLINFO ti;
   HICON m_icon;
   HBITMAP m_Back; //按鈕背景圖片
   HBITMAP m_Hove; //鼠標懸停時按鈕背景圖片
   HBITMAP m_Press; //鼠標按下時按鈕背景圖片
   HBITMAP m_Disable; //按鈕無效時背景圖片
   BITMAP bm;
   COLORREF m_textcolor; //按鈕文字的顏色
   BOOL m_bMouseTracking; //判斷鼠標是否在窗口內
   BOOL m_bPress; //判斷鼠標是否按下
   BOOL m_Enable; //控件是否有效
   BOOL m_bFocus; //按鈕是否處於輸入焦點
   BOOL m_bOwnerDraw; //判斷是否用戶自己貼圖
   BOOL m_bDrag; //是否處於拖動狀態
   BOOL m_bDragEnable; //是否允許拖動
   char m_text[MAX_TEXTLEN]; //按鈕文字
   char m_tiptext[MAX_TEXTLEN]; //按鈕提示文字
   HFONT m_font; //按鈕文字字體
   HCURSOR m_OldCursor;
   RECT m_ParentRt;
   RECT m_BeginRt;
   RECT m_CurrentRt;
   POINT m_BeginPt;
   POINT m_CurrentPt;
   int m_CaptionHeight;
   int m_BorderWidth;
   int m_EdgeWidth;
  
protected:
   //按鈕的外邊框
   HPEN m_BoundryPen;
  
   //鼠標指針置於按鈕之上時按鈕的內邊框
   HPEN m_InsideBoundryPenLeft;
   HPEN m_InsideBoundryPenRight;
   HPEN m_InsideBoundryPenTop;
   HPEN m_InsideBoundryPenBottom;
  
   //按鈕獲得焦點時按鈕的內邊框
   HPEN m_InsideBoundryPenLeftSel;
   HPEN m_InsideBoundryPenRightSel;
   HPEN m_InsideBoundryPenTopSel;
   HPEN m_InsideBoundryPenBottomSel;
  
   //按鈕的底色,包括有效和無效兩種狀態
   HBRUSH m_FillActive;
   HBRUSH m_FillInactive;
};
消息回調類裡的實現代碼:CWINButton::GetItemhWnd()裡面
if(SetProp(m_hWnd, "CWINBUTTON", (HANDLE)this) == 0)
{
   OutputDebugString("SetProp ERROR");
   return FALSE;
}
m_OldProc = SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)stdProc);
CWINButton::stdProc()裡面
{
   CWINButton* w = (CWINButton*)GetProp(hWnd, "CWINBUTTON");
   return w->WINProc(uMsg,wParam,lParam);
}

Thunk 代碼可看我的代碼或者去網上查詢。

以上是我提供給大家的一點淺見,歡迎大家跟我討論有關的技術。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved