vc++ 建立異性窗體(1)

weixin_33816946發表於2011-01-13

隨著Microsoft憑藉Windows在作業系統上取得的巨大成績,Windows使用者介面也日益成為業界標準。統一的介面給廣大使用者對應用軟體的學習與使用帶來了很大方便。但每天都面對同一副面孔,日久天長難免會產生一些厭倦,開發一些“離經叛道”,一改Windows應用程式千篇一律的“標準”介面,一定會給你帶來一種清新的感覺。標準Windows應用程式視窗一般為帶有標題欄的淺灰色矩形外觀,因而“異形”對話方塊/視窗也主要是顏色與外形上動手腳。

1:改變背景顏色

改變對話方塊(視窗)的背景顏色是最簡單的改變Windows應用程式外觀的方法,根據Windows建立與管理機理,一般有兩種方法。一種是處理WM_CTLCOLOR訊息,首先建立所選背景顏色的刷子,然後呼叫SetBkColor()SetDialogBkColor()以所建立的刷子來繪製視窗或對話方塊的背景。需要重畫視窗或對話(或對話的子控制元件)時,Windows向對話傳送訊息WM_CTLCOLOR,應用程式處理WM_CTLCOLOR訊息並返回一個用來繪畫對話背景的刷子控制程式碼。另外一種是響應WindowsWM_ERASEBKGND訊息,Windows向視窗傳送一個WM_ERASEBKGND訊息通知該視窗擦除背景,可以使用VC++ClassWizard過載該訊息的預設處理程式來擦除背景(實際是用刷子畫),並返回TRUE以防止Windows擦除視窗。

2.改變視窗外形

通過使用新的SDK函式SetWindowRgn(),可以將繪畫和滑鼠訊息限定在視窗的一個指定的區域,因此實際上是使視窗成為指定的不規則形狀(區域形狀)。“區域”是Windows GDI中一種強有力的機制,區域是裝置上的一塊空間,可以是任意形狀,複雜的區域可以由各個小區域組合而成。Windows內含的區域建立函式有CreateRectRgn()CreatePolyRgn()CreatePolygonRgn()CreateRoundRectRgn()CreateEllipticRgn(),再通過CombineRgn()來組合區域,即可得到複雜形狀的區域,獲得複雜形狀的視窗外形。

通過上面的方法雖然可以得到“異形”視窗,但感覺顏色單調,外形也不夠“COOL”,能否獲得更酷的“異形”對話方塊/視窗呢?回答是肯定的。下面就介紹利用點陣圖和蒙板建立“異形”對話方塊/視窗的方法。

3.利用點陣圖建立異形對話方塊視窗

利用點陣圖建立異形對話方塊原理是根據象素的顏色來進行“扣像”處理,對所有非指定顏色象素區域進行區域組合。利用這一技術,實際上就是實現對話方塊/視窗的點陣圖背景,並且對指定的顏色區域進行透明處理。下面就以透明點陣圖為背景的對話方塊為例來說明:

首先用繪圖軟體如PhotoShop繪製編輯一幅擬做對話方塊背景用的圖片,用BMP格式儲存,假設存為Back.Bmp。需要說明的是,雖然Visual C++整合開發環境的資源編輯器只能編輯不超過16色的點陣圖,但完全我們可以以真彩色方式儲存,不必理會Visual C++的警告。

下一步是用Visual C++AppWizard建立一個基於對話方塊的應用程式假定命名為Trans。用資源編輯器引入背景圖片Back.Bmp,如果是高彩色,不必理會出現的警告資訊,點選OK確認即可。為了明確,修改預設的資源ID標識IDB_BITMAP1IDB_BACKBMP。然後修改對話方塊的StylePopupBorderNone

CTransDlg類新增區域處理功能模組void CTransDlg::SetupRegion(CDC *pDC /*對話方塊視窗DC*/, UINT BackBitmapID /*背景點陣圖資源ID*/, UINT MaskBitmapID /*區域處理點陣圖資源ID*/, COLORREF TransColor = 0x00000000 /*透明顏色值,預設為黑色*/)。到目前為止,我們暫時認為MaskBitmapID等同於BackBitmapID。其核心工作是根據MaskBitmapID指示點陣圖的象素顏色進行區域組合。完整的程式碼如下:

void CTransDlg::SetupRegion(CDC *pDC /*對話方塊視窗DC*/,

UINT BackBitmapID /*背景點陣圖資源ID*/,

UINT MaskBitmapID /*區域處理點陣圖資源ID*/,

COLORREF TransColor /*透明顏色值*/)

{

CDC memDC;

CBitmap cBitmap;

CBitmap* pOldMemBmp = NULL;

COLORREF cl;

CRect cRect;

UINT x, y;

CRgn wndRgn, rgnTemp;

//取得視窗大小

GetWindowRect(&cRect);

//背景點陣圖資源ID

m_BackBitmapID = BackBitmapID

//裝載點陣圖

cBitmap.LoadBitmap(MaskBitmapID);

memDC.CreateCompatibleDC(pDC);

pOldMemBmp = memDC.SelectObject(&cBitmap);

//首先建立預設的完整區域為完整的視窗區域

wndRgn.CreateRectRgn(0, 0, cRect.Width(), cRect.Height());

//下面的兩層迴圈為檢查背景點陣圖象素顏色,進行透明區域處理;

//當象素顏色為指定的透明值時,即將該點從區域中剪裁掉。

//其中用到的幾個成員變數m_MaskLeftOffm_MaskTopOff

//m_MaskRightOffm_MaskBottomOffm_FrameWidth

//m_CaptionHeight,其作用後面再作說明,此時可全部當作0來處理。

for(x= m_FrameWidth+m_MaskLeftOff;x<=cRect.Width() - m_FrameWidth-m_MaskRightOff; x++){

for(y = m_CaptionHeight+m_MaskTopOff;
y<=cRect.Height() - m_FrameWidth-m_MaskBottomOff; y++){

//取得座標處象素的顏色值

cl = memDC.GetPixel(x - m_FrameWidth-m_MaskLeftOff,y - m_CaptionHeight-m_MaskTopOff);

if(col == TransColor)

{//象素顏色為指定的透明色,建立透明“微區域”

rgnTemp.CreateRectRgn(x, y, x+1, y+1);

//“扣像”,從完整的區域中“扣除”透明的“微區域”

wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_XOR);

//刪除剛建立的透明“微區域”,釋放系統資源

rgnTemp.DeleteObject();

}

}

}

if (pOldMemBmp) memDC.SelectObject(pOldMemBmp);

//用設定視窗為指定的區域

SetWindowRgn((HRGN)wndRgn, TRUE);

}

重置系統預設的背景擦除操作,即新增WM_ERASEBKGND訊息處理過程,這一步可以藉助ClassWizard來簡化操作。

BOOL CTransDlg::OnEraseBkgnd(CDC* pDC)

{// TODO: Add your message handler code here and/or call default

CRect rect;

CDC memDC;

CBitmap cBitmap;

CBitmap* pOldMemBmp = NULL;

GetWindowRect(&rect);

//裝載背景點陣圖

cBitmap.LoadBitmap(m_BackBitmapID);

memDC.CreateCompatibleDC(pDC);

pOldMemBmp = memDC.SelectObject(&cBitmap);

//將背景點陣圖複製到視窗客戶區

pDC->BitBlt(0, 0, rect.Width(), rect.Height(),

&memDC, 0, 0, SRCCOPY);

if (pOldMemBmp) memDC.SelectObject( pOldMemBmp );

//刪除系統卻省的OnEraseBkgnd功能

相關文章