1. 程式人生 > >MFC 給對話方塊新增圖片背景

MFC 給對話方塊新增圖片背景

在windows開發當中做介面的主要技術之一就是使用MFC,通常我們看到的QQ,360,暴風影音這些漂亮的介面都可以用MFC來實現。今天我們來說一下如何用MFC美化對話方塊,預設情況下,對話方塊的背景如下:

那麼,我們如何將它的背景變成如下介面呢,而且還要保留對話方塊的移動功能,漂亮背景如下:

為了實現美化對話方塊背景的效果,我們需要讓我們的對話方塊響應WM_CTLCOLOR訊息,每當我們的對話方塊或者它的子控制元件需要重繪時,我們的對話方塊都會收到這個訊息,

因此,我們需要為對話方塊新增WM_CTLCOLOR的訊息響應函式,完成對訊息的處理,WM_CTLCOLOR的響應函式定義如下:

HBRUSH CMFCDialogUIDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
 
    if (pWnd == this)
    {
        return m_bkBrush;
    }
 
    return hbr;
}
當我們的對話方塊需要重繪的時候,我們的對話方塊就會收到WM_CTLCOLOR訊息,然後我們的對話方塊處理函式會呼叫OnCtlColor函式來處理該訊息,在這個函式中,pDC代表我們要繪製的上下文環境,pWnd代表我們要繪製的視窗指標,nCtlColor代表我們要繪製的視窗型別,在函式的內部我們首先呼叫父類的OnCtlColor,目的是為了對該訊息做預設處理,這是MFC訊息響應函式的慣用寫法,但是在我們這裡,我們不能使用預設處理返回的畫刷,所以我們需要做一個特殊的判斷,如果pWnd指向的視窗地址是當前對話方塊,那麼我們就返回m_bkBrush,這個畫刷是一個影象畫刷,它會在我們的對話方塊客戶區繪製我們想讓它顯示的圖片。下面我們看一下m_bkBrush是如何建立的,首先在我們的對話方塊的標頭檔案中增加一個CBrush變數,變數名是m_bkBrush,然後在對話方塊的OnInitDialog中初始化它,OnInitDialog的定義如下:
BOOL CMFCDialogUIDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
 
    // 將“關於...”選單項新增到系統選單中。
 
    // IDM_ABOUTBOX 必須在系統命令範圍內。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);
 
    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }
 
    // 設定此對話方塊的圖示。  當應用程式主視窗不是對話方塊時,框架將自動
    //  執行此操作
    SetIcon(m_hIcon, TRUE);            // 設定大圖示
    SetIcon(m_hIcon, FALSE);        // 設定小圖示
 
    // TODO:  在此新增額外的初始化程式碼
 
    CString strBmpPath = _T(".\\res\\Background.png");
 
    CImage img;
 
    img.Load(strBmpPath);
 
    //MoveWindow(0, 0, img.GetWidth(), img.GetHeight());
 
    CBitmap bmpTmp;
 
    bmpTmp.Attach(img.Detach());
 
    m_bkBrush.CreatePatternBrush(&bmpTmp);
 
    return TRUE;  // 除非將焦點設定到控制元件,否則返回 TRUE
}
現在我們看一下,在OnInitDialog中,我們都做了什麼,首先,我們建立了一個CString變數strBmpPath,用它指向我們的圖片檔案,然後我們建立了一個CImage變數img,這個變數可以方便的載入各種格式的影象檔案,所以我們使用它的目的是為了方便載入png格式的檔案,MoveWindow的目的是為了調整我們的對話方塊客戶區的大小,使客戶區的大小與圖片的大小一致,然後我們建立了一個CBitmap型別變數bmpTmp,使用它是因為CBrush的成員函式CreatePatternBrush的引數要求輸入這種型別的引數,所以必須將img轉換成CBitmap,轉換的方法是bmpTmp.Attach(img.Detach()),img.Detach會釋放影象的控制代碼,並且返回這個控制代碼,bmpTmp使用Attach繫結img返回的影象控制代碼,從而完成了物件型別的轉換,最後呼叫CreatePatternBrush,這個函式的功能是使用傳遞給它的影象建立一個影象畫刷,然後在OnCtlColor中,使用它填充對話方塊的背景,程式執行效果如下:


現在雖然程式的客戶區已經變成了對話方塊的背景,但是對話方塊原來的標題欄和背景圖片的標題欄重複,看起來很彆扭,通過設定對話方塊的Border屬性可以消除原來的標題欄,設定如下:

Border:None

再次編譯,執行程式,效果如下:

現在的對話方塊背景已經和我們設想的基本一致,還有一點小瑕疵,大家仔細觀察對話方塊的底邊,左下角和右下角有多於的畫素,下面我們通過程式碼消除它。

在OnInitDialog尾部追加如下程式碼:

CRgn rgnTmp;
RECT rc;
GetClientRect(&rc);
rgnTmp.CreateRoundRectRgn(rc.left + 3, rc.top + 3, rc.right - rc.left - 3, rc.bottom-rc.top -3, 6, 6);
SetWindowRgn(rgnTmp, TRUE);


通過以上的程式碼可以讓對話方塊變成一個圓角矩形,這樣就可以去掉邊角的點,程式最終執行效果如下:


現在這個對話方塊的背景已經完全符合我們的要求,但是它現在不能拖動,因為它的標題欄是假的,所以,我們最後一個目標就是讓這個視窗可以拖動,如何才能讓它移動呢?

Windows只允許我們拖動對話方塊的標題欄,當我們的滑鼠在對話方塊上拖動的時候,對話方塊會收到一個WM_NCHITTEST訊息,預設的訊息處理函式會判斷當前的滑鼠是否在對話方塊的標題欄,如果在就返回HTCAPTION標誌,否則就返回其它標誌,當返回HTCAPTION標誌的情況下,系統就會允許對話方塊拖動,所以我們可以欺騙windows系統,讓WM_NCHITTEST的響應函式永遠返回HTCAPTION標誌就可以了,為對話方塊新增WM_NCHITTEST響應函式,程式碼如下:

LRESULT CMFCDialogUIDlg::OnNcHitTest(CPoint point)
{
    // TODO:  在此新增訊息處理程式程式碼和/或呼叫預設值
    LRESULT ret = CDialogEx::OnNcHitTest(point);
    return (ret == HTCLIENT) ? HTCAPTION : ret;
}

 

//模擬標題欄拖動
LRESULT CMainDlg::OnNcHitTest(CPoint point)
{
    // TODO: Add your message handler code here and/or call default
    UINT nHitTest = CDialogEx::OnNcHitTest(point);
    if ((nHitTest == HTCLIENT) && (::GetAsyncKeyState(MK_LBUTTON) < 0))
    {
        CRect rectDlg;
        GetWindowRect(rectDlg);//獲得窗體的大小        
        if (point.y < rectDlg.top + 30)
        {
            nHitTest = HTCAPTION;
        }
        else
        {
            nHitTest = HTNOWHERE;
        }
    }
    return nHitTest;
    //return CDialogEx::OnNcHitTest(point);
}
重新編譯程式碼,現在的對話方塊背景已經美化完成,並且這個對話方塊可以拖動。
下篇文章,我們會為這個對話方塊新增美化的按鈕。