為了解決這個(gè)問(wèn)題,我們可以用BitBlt 中的MERGEPAINT和SRCAND的方式進(jìn)行繪制。 MERGEPAINT是把圖形反色后再同貼圖目的地進(jìn)行OR操作,而SRCAND是把圖形和貼圖目的地進(jìn)行AND操作。在計算機中,使用的是數字圖像處理,每一種顏色都是由RGB表示的,RGB是指紅、綠、藍三原色,只要有這3種顏色和對應的顏色強度就可以合成各種顏色了。比如,黑色的RGB值為(0,0,0),白色的RGB值為(255,255,255),括號內對應的是紅綠藍3種顏色的強度。在數字圖像處理中可以實(shí)現OR、AND等邏輯運算。任何顏色同白色進(jìn)行OR運算結果都為白色,進(jìn)行AND運算結果都是該顏色本身;任何顏色跟黑色進(jìn)行OR運算結果都為該顏色本身;進(jìn)行AND運算結果都是黑色。為此,我們準備兩張圖片,如下圖所示:


圖1 圖2
圖1的背景為白色,圖2是將圖1中需要顯示部分填充黑色而得。實(shí)現去除背景貼圖關(guān)鍵代碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | if (IsMask==TRUE) //值為真則去除圖片背景{ CDC MaskDC; MaskDC.CreateCompatibleDC(pDC); if (IsBackBmp==TRUE)//使用和主窗口相同的背景圖片 { CBitmap *pOldBmp; CDC BackDC; BackDC.CreateCompatibleDC(pDC); pOldBmp = MaskDC.SelectObject(&m_MaskBitmap); BackDC.SelectObject(&m_BackBitmap); pDC->BitBlt(0,0,rect.Width(),rect.Height(),&BackDC,BackRect.left,BackRect.top,SRCCOPY); } pDC->BitBlt(0,0,rect.Width(),rect.Height(),&MaskDC,0,0,MERGEPAINT); pDC->BitBlt(0,0,rect.Width(),rect.Height(),&MemDC,0,0,SRCAND); ReleaseDC(&MaskDC); } else { pDC->BitBlt(0,0,rect.Width(),rect.Height(),&MemDC,0,0,SRCCOPY); } |
效果如下圖所示:

可能這時(shí)你就納悶了,為什么背景色還是白色呢,是不是代碼沒(méi)有去掉圖片的背景色呢?答案是貼圖的時(shí)候已經(jīng)去掉了背景色。請看分析
按鈕是一個(gè)子窗口,默認情況下主窗口和按鈕子窗口背景都是白色,但是往往我們需要在主窗口上繪制一張圖片,這樣窗口看起來(lái)就比較美觀(guān)。這樣子做之后,按鈕子窗口和主窗口的背景就不一樣了。在進(jìn)行按鈕自繪的時(shí)候,那就是把按鈕背景作為目的地進(jìn)行OR、AND運算,因為按鈕背景就是白色的,所以效果看起來(lái)也就是白色的。
要解決這個(gè)問(wèn)題也很簡(jiǎn)單,我們獲取按鈕所在主窗口中的矩形區域,把這個(gè)區域的主窗口背景繪制到按鈕中,再進(jìn)行繪制按鈕圖片的操作就可以了。
通過(guò)這樣做之后,效果如下圖:

為此,我們已經(jīng)得到一個(gè)圖片按鈕了。但僅僅這樣還不行,這按鈕的響應區域還是矩形區域,也就是說(shuō)除了按鈕圖片之外的區域也響應鼠標點(diǎn)擊。那我們就需要構造一個(gè)按鈕圖片區域,使用庫函數SetWindowRgn就可以確定響應區域了。SetWindowRgn有個(gè)參數為HRGN類(lèi)型,因此我們需要獲得一個(gè)HRGN。
Jean-Edouard Lachand-Robert 寫(xiě)了一個(gè) BitmapToRegion 函數,函數的功能為把一張位圖根據一種顏色轉化為一個(gè)區域,這個(gè)我們就可以得到一個(gè)HRGN。有關(guān)BitmapToRegion詳情請看代碼說(shuō)明。我們用圖2中的黑色區域去轉化成區域,為此我們就得了一個(gè)圖片按鈕的響應區域了。
另外,CControlButton類(lèi)還提供了通常的四態(tài)按鈕的支持,即鼠標劃過(guò)、點(diǎn)擊、正常、獲得焦點(diǎn)四種情況對應加載四張不同的位圖。
二、成員函數介紹
?、?void CControlButton::SetMaskBitmapId(int mask, bool action)
功能:設置圖2資源圖片
返回值:無(wú)
參數:mask ,圖2的資源ID
action,值為T(mén)RUE則有效,FALSE為無(wú)效
?、?void CControlButton::SetBackBmp(int nBgdBmpId,CRect rect);
功能:設置按鈕背景圖片
返回值:無(wú)
參數:nBgdBmpId ,主窗口背景圖片資源ID
rect , 按鈕在主窗口中的客戶(hù)區矩形, 使用GetWindowRect, ScreenToClient這兩個(gè)函數即可以輕松獲得。
?、?void CControlButton::SetRgnMask(int nMaskBmpId, bool nAction)
功能:設置有效區域函數:
返回值:無(wú)
參數:nMaskBmpId ,圖2的資源ID
nAction ,值為T(mén)RUE則設置有效,FALSE則無(wú)效,通過(guò)這樣可以使用或禁止構造響應區域
?、躹oid CControlButton::SetBitmapId(int nOver,int nNormal,int nPressed,int nFocus)
功能:設置按鈕動(dòng)態(tài)加載的四幅圖片 :
返回值:無(wú)
參數:nOver,鼠標劃過(guò)對應按鈕圖片資源ID。
nNormal ,正常狀態(tài)下 對應按鈕圖片資源ID
nPressed ,按下按鈕對應圖片資源ID
nFocus ,獲得焦點(diǎn)情況下圖片資源ID
三、使用說(shuō)明
CControlButton類(lèi)從CButton類(lèi)派生,使用時(shí),只需在界面上放置一個(gè)按鈕控件,添加CControlButton類(lèi),關(guān)聯(lián)一個(gè)CControlButton的控件變量,然后進(jìn)行初始化即可:
1 2 3 4 5 6 7 8 9 | CRect btnRect; //定義按鈕矩形變量m_demoBtn.GetWindowRect(btnRect); //獲取按鈕窗口矩形區域ScreenToClient(btnRect); //轉換成客戶(hù)區域//設置按鈕的背景圖片,跟主窗口的背景圖片一樣m_demoBtn.SetBackBmp(IDB_BACKGROUND,btnRect);m_demoBtn.SetRgnMask(IDB_OKmask,TRUE);//設置響應區域,TRUE設置構造區域有效m_demoBtn.SetMaskBitmapId(IDB_OKmask,TRUE); //設置掩碼圖片//設置按鈕的四種狀態(tài)圖m_demoBtn.SetBitmapId(IDB_btn_ok_b,IDB_btn_ok_a,IDB_btn_ok_c,IDB_btn_ok_a); |
四、結束語(yǔ)
本類(lèi)是在我朋友hurryboylqs四態(tài)圖片按鈕類(lèi)的基礎上完成,衷心感謝hurryboylqs的幫助,希望本文對大家有一點(diǎn)點(diǎn)幫助。本人深知本類(lèi)還有一些不足之處,如若大家對本類(lèi)有修改完善,也請連修改說(shuō)明給我發(fā)送一份,萬(wàn)分感謝!
聯(lián)系客服