当前位置:编程问答 > C/C++ >

实现不规则窗体------基于MFC based DLG

实现界面如下所示:(文末有源码下载地址,初写技术博客,写的不好还请大家多多批评指正)

 

实现过程:

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为起点的,在这个

补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,