四川 曾 志
Microsoft Windows以其豐富一致的圖形用戶界面,簡單靈便的操 作,被廣大用戶所接受。對話框就是其中一個非常重要的界面形式, 并且Windows為其應用程序的開發者提供了相當豐富的界面資源,許多 控制可以方便地加入對話框中。但當我們需要編寫一個商業應用,需 要一個更友好的圖形用戶界面時,就會發現資源的貧乏。 Visual C++提供了一個CBitmap Button類在一定程序上緩解了 增加新資源的要求。但當我們要求在程序中能動態地改變圖形時,我 們就不得不考慮放棄CBitmapButton類,而坐下來自己做一點工作了。 一個可行的辦法就是重載CButton類(即按鈕控制)。這樣對這塊區域 的大小、位置和ID號都可以通過AppStadio方便地制作。當然這樣作最 大的好處還是在于充分利用C++的特性把繪制控制的代碼封裝了起來 ,既避免了重復性開發,又使程序變得更簡潔,增強了代碼的可讀性 。 現在我們就通過創建一個名叫CColorButton的類來學習這種方法 。雖然這是一個功能非常簡單的類,通過調用成員函數ChangeColor可 改變其顏色,鼠標點中時則高亮邊框表示選中。但利用這種思路我們 只需添加幾個數據成員和重載一個函數就可以方便地實現你所需要的 功能。 在創建這個類之前,我們必須先了解WM_DRAWITEM消息。當按鈕 、組合框、列表框或菜單的某一視覺狀況發生變化時,系統就會發送 一條WM_DRAWITEM消息給這些控制的擁有者窗口。這個消息的wParam 指出這個控制的 id 號,而IParam則是一個指向DRAWITEMSTRUCT結構 的指針,該結構存放有關要繪制的項的信息以及繪制所需的類型。DR AWITEMSTRUCT結構具有如下格式。 typedef struct tagDRAWITEMSTRUCT{ UINT CtlType; // 控制類型 UINT CtlID;// 控制的ID號 UNIT itemID;//菜單項的索引 UINT itemAction;// 說明需要的繪圖操作 UINT itemState; // 指明繪圖后的可見狀態 HWND hwndItem; // 控制的窗口句柄 HDC hDC; // 相關的設備環境 RECT rcItem;//被畫控制的邊框 DWORD itemData;// 指定與菜單項相聯系的應用程序定義的 32位值 }DRAWITEMSTRUCT; 其中itemAction 和 itemState決定了需要的繪圖操作。itemAct ion 說明需要的繪圖操作,可為下列值中的一個或多個; 值 含 義 ODA_DRAWENTIRE 需要重來全部控制時 ODA_FOCUS 獲得或失去輸入焦點 ODA_SELECT 選擇狀態改變 itemState指明當前繪圖動作發生之后,項的可見狀態。下面是狀 態標志: 值 含 義 ODS_CHECKD 只用于菜單中 ODS_DISABLE 該項被屏蔽 ODS_FOCUS 該項具有輸入焦點 ODS_GRAYED 只用于菜單中 ODS_SELECT 該項處于被選中狀態 (上) □成都 曾志 用VC++實現自繪按鈕控制 利用VC++編程會發現,當按鈕控制接收到WM-DRMAWITEM消息時 會調用Cbotton類的DrawItem函數。因此我們要做的就是利用C++的 多態性通過重載CButton類的Drawitem函數來響應MW-DRAWITEM消息。 下面我們就實際構造一個CColorButton類。 class ccolorButton:public CButton { private: COLORREF m-color: public: CColorButton():CButton(),m-color(0){}; //構 造函數 void ChangeColor(COLORREF color); //改變顏色 virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct );//重載的函數 }; //重載的虛函數 void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawIt emtruct) { CDC dc; dc.Attach(lpDrawItemStruct->hDC); //得到繪制的設 備環境CDC VERIFY( lpDrawItemStruct->CtlType==ODT-BUTTON); if (lpDrawItemStruct->itemAction & ODA-DRAWENTIRE) { //重繪整個控制 CBrush brush(m-Color); dc.FillRect(&(lpDrawItemstruct->reItem),&brush) ; } if ((lpDrawItemStruct->itemstate & ODS-SELECTED ) && (lpDrawItemStruct->itemAction & (ODA-SELECT | ODA-DRAWENTIRE))) { //選中了本控 制===>高亮邊框 COLORREF fc=RGB(255-GetRvalue(m-color), 255-GetG Value(m-color), 255-GetBValue(m-color)); CBrush brush(fc); dc.FrameRect(&(lpDrawItemStruct->rcItem),&brush ); } if (!(lpDrawItemStruct->itemState & ODS-SELECT ED) && (lpDrawItemStruct->itemAction & ODA-SELECT)){ //控制的選中狀態結束===>去掉邊框 CBrush brush(m-color); dc.FrameRect(&lpDrawItemStruct->rcItem,&brush); } dc.Detach(); } //用于改變顏色的成員函數 void CColorButton::ChangeColor(COLORREF color) { CR ect rect; m-color=color; GetClientRect(&rect); } m-colorChangeColor(COLORREF color)color,WM-DRAWITEM 上面代碼中數據成員m-color和來保存按鈕的顏色。ChangeColo r(COLORREF color)函數負責改變按鈕顏色值為color,然后通過使 控制的客戶區無效而激發WM-DRAWITEM消息。現在這個按鈕控制類就 算搭好了。下面我們把它加入到對話框中來試驗一下(中) 用VC++實現自繪按鈕控制 1.首先通過AppWizard創建一個單文檔的應用。 2.緊接著啟動AppStadio創建一個對話框。添加一個按鈕控制, 并將其ID設置為 IDC-COLORBUTTON。最后一定要記住將push Button Properties對話框中的Owner Draw檢查框置上檢查標志。 3.在AppStadio內運行ClassWizzand來產生CTestDialog類。然 后在CTestdialog類中加入數據成員,在CTestDialog類說明加入如下 的private型數據成員: private: ccolorButton m-ColorButton; 4.現在剩下的問題是到底要怎樣才能使m-ColorButton的DrawI tem函數能響應系統發往ID值為IDC-COLORBUTTON的按鈕控制的WM-D RAWITEM消息。這時就要用到CWnd類的成員函數BOOL CWnd::Subcla ssDlgItem(UINT nID,CWnd *pParent)。通過調用這個函數,我們 可以動態地接管從對話框模板產生的控制,并把它隸屬于CWnd對象。 即用當前的CWnd對象接管發向隸屬于pParent的ID號為nID的控制的一 切消息。對于按鈕控制而言,它把當前的按鈕控制的位置和大小也清 成和nID對應的按鈕控制一樣。于是我們對CTestDialog的源文件進行 如下的編輯: BOOL CTestDialog::OnInitDialog() { CDialog::OnInitDialog(); //TODO:Add extra initialization here m-ColorButton.SubclassDlgtem(IDC-COLORBUTTON,this) ;//接管消息 m-ColorButton.ChangeColor(RGB(255,0,0);//設置為 紅色(可設為任何顏色) return(TRUE); } 接著通過ClassWizzard在CTestDialog中加入一個響應鼠標點擊I DC-COLORBUTTON按鈕的消息的函數: void CTestDialog::OnColerbutton() { //TODO:Add your control notification handler code here int r=int(((float)rand()/RAND-MAX)*255 int g=int(((float)rand()/RAND-MAX)*255 int b=int(((float)rand()/RAND-MAX)*255 m-ColorButton.ChangeColor(RGB(r,g,b)); } 5.最后,利用ClassWizzard為View加入一個響應WM-LBUTTONDO WN的函數,以便激活對話框。請按如下代碼對其進行編輯。 void CTestView::OnLButtonDown(UINT nflags,POINT po int) { CTestDialog dlg; dlg.Domodal(); } 6.編譯并測試該程序。當鼠標在落視窗中時,按下鼠標左鍵應能 彈出一個對話框。在對話框中的紅色矩形區域內按下鼠標左鍵就會使 其邊框變成高亮狀態,若在這塊區域內釋放左鍵則這城區域就會改變 顏色且顏色是隨機的。 只需更改DrawItem函數中的重繪代碼,就可以得到自己的需要圖 形按鈕。
|