程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 實現不規則窗體------基於MFC based DLG

實現不規則窗體------基於MFC based DLG

編輯:C++入門知識

實現界面如下所示:(文末有源碼下載地址,初寫技術博客,寫的不好還請大家多多批評指正)

 

實現過程:

1、首先創建基於DLG的MFC應用程序,命名為:tryBGDlg,並將DLG的屬性設置為:Title Bar :False ,其它設置不變
2、制作兩幅圖像,其中的一幅黑白圖像,是根據播放器外觀來制作的,其中白色區域是要保留的最終在桌面上顯示的區域。將這兩幅圖像添加到工程中,第一個ID號設置為IDB_INTERFACE,第二個ID號設置為:IDB_MASK


3、在CtryBGDlg類中添加一個在函數:

//函數說明:cBitmap是要傳入的掩碼位置變量,這裡是指IDB_MASK創建的對象,TransColor是指要設為透明相素的RGB值
[cpp] 
void CtryBGDlg::SetupRegion(  CDC *pDC, CBitmap &cBitmap, COLORREF TransColor ) 

    CDC memDC; 
    memDC.CreateCompatibleDC(pDC); 
 
    CBitmap *pOldMemBmp=NULL; 
    pOldMemBmp=memDC.SelectObject(&cBitmap); 
 
    BITMAP bit;  
    cBitmap.GetBitmap (&bit); 
 
    CRgn crRgn, crRgnTmp; 
    crRgn.CreateRectRgn(0, 0, 0, 0);//創建一個空區域 
 
    int iX = 0;int iY = 0; 
    for (iY = 0; iY < bit.bmHeight; iY++) 
    { 
        do 
        { 
            //skip over transparent pixels at start of lines. 
            while (iX <= bit.bmWidth && memDC.GetPixel(iX, iY) == TransColor) 
                iX++; 
            //remember this pixel 
            int iLeftX = iX; 
            //now find first non transparent pixel 
            while (iX <= bit.bmWidth && memDC.GetPixel(iX, iY) != TransColor) 
                ++iX; 
            //create a temp region on this info 
            crRgnTmp.CreateRectRgn(iLeftX, iY, iX, iY+1); 
            //combine into main region. 
            crRgn.CombineRgn(&crRgn, &crRgnTmp, RGN_XOR); 
            //delete the temp region for next pass (otherwise you'll get an ASSERT) 
            crRgnTmp.DeleteObject(); 
        }while(iX < bit.bmWidth); 
        iX = 0; 
    } 
 
    SetWindowRgn(crRgn, TRUE); 
 
    iX = (GetSystemMetrics(SM_CXSCREEN))-700; 
    iY = (GetSystemMetrics(SM_CYSCREEN)) / 2 - (bit.bmHeight / 2); 
    SetWindowPos(&wndTop, iX, iY, bit.bmWidth, bit.bmHeight, NULL);    
     
    // Free resources. 
    memDC.SelectObject(pOldMemBmp); // Put the original bitmap back (prevents memory leaks) 
    memDC.DeleteDC(); 
    crRgn.DeleteObject(); 

4、在BOOL CtryBGDlg::OnInitDialog()函數中添加如下代碼:

[cpp]
CBitmap bmp; 
    bmp.LoadBitmapW(IDB_MASK); 
    this->SetupRegion(this->GetWindowDC(),bmp,RGB(0,0,0)); 
5、添加對WM_ERASEBKGND消息響應,並在BOOL CtryBGDlg::OnEraseBkgnd(CDC* pDC)函數中添加如下代碼

[cpp] 
BOOL CtryBGDlg::OnEraseBkgnd(CDC* pDC) 

    // TODO: 在此添加消息處理程序代碼和/或調用默認值 
    CRect rect; 
    this->GetWindowRect(&rect); 
 
    CDC memDC; 
    CBitmap bmp; 
    CBitmap *pOldBmp=NULL; 
 
    bmp.LoadBitmapW(IDB_INTERFACE); 
    memDC.CreateCompatibleDC(pDC); 
    pOldBmp=memDC.SelectObject(&bmp); 
 
    pDC->BitBlt(0,0,rect.Width(),rect.Height(),&memDC,0,0,SRCCOPY); 
 
 
    if(pOldBmp) 
    { 
        memDC.SelectObject(pOldBmp); 
    } 
    return true; 
 
//  return CDialog::OnEraseBkgnd(pDC); 

到此就實現了不規則窗體的創建,創建後的視圖如開頭所示。

6、一般我們還要實現對窗體的托動操作,實現方法如下:

添加對WM_NCHITTEST消息的響應,並在生成的LRESULT CtryBGDlg::OnNcHitTest(CPoint point)函數中添加如下代碼:
 
LRESULT CtryBGDlg::OnNcHitTest(CPoint point) 

    // TODO: 在此添加消息處理程序代碼和/或調用默認值 
    CRect rc; 
    GetClientRect(&rc); 
    ClientToScreen(&rc); 
    return rc.PtInRect(point) ? HTCAPTION : CDialog::OnNcHitTest(point); 
//  return CDialog::OnNcHitTest(point); 

至此就完全實現了,不規則窗體的創建和對窗體托動消息的響應部分。


下面將細致的講解具體實現原理及部分的代碼的解析:
總原理:這個程序的原理主要是先用IDB_MASK圖像計算出要設定的窗體的輪廓,然後利用SetWindowRgn()函數來對其進行更改。最後在窗體重繪的時候響應WM_ERASEBKGND消息,將窗體背景圖片IDB_INTERFACE貼到窗體上。

 

利用IDB_MASK圖像計算窗體輪廓的原理:

計算窗體輪廓的代碼主要靠SetupRegion()函數來實現,考慮到窗體的不規則,應采取掩模位圖的方式來對其進行描述,對於本例,其白色區域為要保留的不規則窗體的輪廓區域。這段代碼首先是用crRgn.CreateRectRgn(0, 0, 0, 0)創建一個空的區域,然後對IDB_MASK圖像的像素信息進行一列一列的枚舉,計算出每列中不設為透明的區域,然後跟crRgn合並,所以最後的crRgn就是所要設定的區域。

核心代碼為:

[cpp]
CRgn crRgn, crRgnTmp; 
    //創建一個空區域 
    crRgn.CreateRectRgn(0, 0, 0, 0); 
 
    int iX = 0;int iY = 0; 
    for (iY = 0; iY < bit.bmHeight; iY++) 
    { 
        do 
        { 
            //skip over transparent pixels at start of lines. 
            //以一個相素列為單位,找到在這一個相素列中,第一個不是要設為透明相素的點iX。 
            //然後再找到以這個iX為起點的,在這個一個相素列中最後跟他臨近的最後一個不是透明的點。 
            //然後將他們一起合並到crRgn中。 
            while (iX <= bit.bmWidth && memDC.GetPixel(iX, iY) == TransColor) 
                iX++;//在iY和iY+1這個相索列中,第一個不設為透明的點的X坐標 
            int iLeftX = iX;//保存這個點的坐標 
            while (iX <= bit.bmWidth && memDC.GetPixel(iX, iY) != TransColor) 
                ++iX;//這是找到在iX最臨近的不透明的X坐標 
            crRgnTmp.CreateRectRgn(iLeftX, iY, iX, iY+1);//這四個點連在一起就是現在剛找到的不透明的區域 
            //合並區域 
            crRgn.CombineRgn(&crRgn, &crRgnTmp, RGN_OR); 
            //記得最終要手動刪除crRgnTmp對象 
            crRgnTmp.DeleteObject(); 
        }while(iX < bit.bmWidth);//如果iX沒有達到圖片的末尾,說明還沒有枚舉完這一行,則在iY和iY+1這個行上,進行下一輪的//枚舉 
        iX = 0; 
    } 

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