程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 圖形界面上的任意形狀圖形按鈕

圖形界面上的任意形狀圖形按鈕

編輯:關於VC++

一、實現原理

我們知道windows窗口默認都是矩形,要實現任意形狀的窗口就需要自繪。為此從CBUTTON派生一個按鈕類CControlButton,重載DrawItem消息處理進行自繪。圖片的背景是矩形的,假如我們的按鈕圖片是圓形的,當把圖片繪制上去之後,我們發現多出了背景部分。如何消除背景呢?

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

圖1    圖2

圖1的背景為白色,圖2是將圖1中需要顯示部分填充黑色而得。實現去除背景貼圖關鍵代碼如下:

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);
    }
MaskDC是圖2的DC,MemDC為圖1的DC。

效果如下圖所示:

可能這時你就納悶了,為什麼背景色還是白色呢,是不是代碼沒有去掉圖片的背景色呢?答案是貼圖的時候已經去掉了背景色。請看分析

按鈕是一個子窗口,默認情況下主窗口和按鈕子窗口背景都是白色,但是往往我們需要在主窗口上繪制一張圖片,這樣窗口看起來就比較美觀。這樣子做之後,按鈕子窗口和主窗口的背景就不一樣了。在進行按鈕自繪的時候,那就是把按鈕背景作為目的地進行OR、AND運算,因為按鈕背景就是白色的,所以效果看起來也就是白色的。

要解決這個問題也很簡單,我們獲取按鈕所在主窗口中的矩形區域,把這個區域的主窗口背景繪制到按鈕中,再進行繪制按鈕圖片的操作就可以了。

通過這樣做之後,效果如下圖:

為此,我們已經得到一個圖片按鈕了。但僅僅這樣還不行,這按鈕的響應區域還是矩形區域,也就是說除了按鈕圖片之外的區域也響應鼠標點擊。那我們就需要構造一個按鈕圖片區域,使用庫函數SetWindowRgn就可以確定響應區域了。SetWindowRgn有個參數為HRGN類型,因此我們需要獲得一個HRGN。

Jean-Edouard Lachand-Robert 寫了一個 BitmapToRegion 函數,函數的功能為把一張位圖根據一種顏色轉化為一個區域,這個我們就可以得到一個HRGN。有關BitmapToRegion詳情請看代碼說明。我們用圖2中的黑色區域去轉化成區域,為此我們就得了一個圖片按鈕的響應區域了。

另外,CControlButton類還提供了通常的四態按鈕的支持,即鼠標劃過、點擊、正常、獲得焦點四種情況對應加載四張不同的位圖。

二、成員函數介紹

① void CControlButton::SetMaskBitmapId(int mask, bool action)

功能:設置圖2資源圖片

返回值:無

參數:mask ,圖2的資源ID

action,值為TRUE則有效,FALSE為無效

② void CControlButton::SetBackBmp(int nBgdBmpId,CRect rect);

功能:設置按鈕背景圖片

返回值:無

參數:nBgdBmpId ,主窗口背景圖片資源ID

rect , 按鈕在主窗口中的客戶區矩形, 使用GetWindowRect, ScreenToClient這兩個函數即可以輕松獲得。

③ void CControlButton::SetRgnMask(int nMaskBmpId, bool nAction)

功能:設置有效區域函數:

返回值:無

參數:nMaskBmpId ,圖2的資源ID

nAction ,值為TRUE則設置有效,FALSE則無效,通過這樣可以使用或禁止構造響應區域

④void CControlButton::SetBitmapId(int nOver,int nNormal,int nPressed,int nFocus)

功能:設置按鈕動態加載的四幅圖片 :

返回值:無

參數:nOver,鼠標劃過對應按鈕圖片資源ID。

nNormal ,正常狀態下 對應按鈕圖片資源ID

nPressed ,按下按鈕對應圖片資源ID

nFocus ,獲得焦點情況下圖片資源ID

三、使用說明

CControlButton類從CButton類派生,使用時,只需在界面上放置一個按鈕控件,添加CControlButton類,關聯一個CControlButton的控件變量,然後進行初始化即可:

CRect btnRect; //定義按鈕矩形變量
m_demoBtn.GetWindowRect(btnRect); //獲取按鈕窗口矩形區域
ScreenToClient(btnRect); //轉換成客戶區域
//設置按鈕的背景圖片,跟主窗口的背景圖片一樣
m_demoBtn.SetBackBmp(IDB_BACKGROUND,btnRect);
m_demoBtn.SetRgnMask(IDB_OKmask,TRUE);//設置響應區域,TRUE設置構造區域有效
m_demoBtn.SetMaskBitmapId(IDB_OKmask,TRUE);  //設置掩碼圖片
//設置按鈕的四種狀態圖
m_demoBtn.SetBitmapId(IDB_btn_ok_b,IDB_btn_ok_a,IDB_btn_ok_c,IDB_btn_ok_a);

四、結束語

本類是在我朋友hurryboylqs四態圖片按鈕類的基礎上完成,衷心感謝hurryboylqs的幫助,希望本文對大家有一點點幫助。本人深知本類還有一些不足之處,如若大家對本類有修改完善,也請連修改說明給我發送一份,萬分感謝!

Email:[email protected]

本文配套源碼

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