設置對話框背景顏色及背景圖片可在OnCtlColor(),OnEraseBkgnd(),OnPaint()里設置,對話框初始化完畢,顯示窗口時按順序調用OnSize()>OnEraseBkgnd()>OnPaint()>OnCtlColor()。
OnEraseBkgnd()中默認調用基類(CFrameWnd)的OnEraseBkgnd(), 用窗口類中注冊的Brush繪制背景。因此,繪制窗口背景時最好重寫OnEraseBkgnd(),但后面不能調用基類的OnEraseBkgnd()。
同時,MSDN關 WM_ERASEBKGND消息的說明中有寫道,DefWindowProc使用窗口類注冊的背景Brush繪制背景,如果背景Brush是NULL,則需處理處理WM_ERASEBKGND消息。言外之意,處理WM_ERASEBKGND消息但不傳給DefWindowProc就可以自己繪制背景,系統又不會重復繪制一遍。
When this member(背景畫刷) is NULL, an application must paint its own background whenever it is requested to paint in its client area. To determine whether the background must be painted, an application can either process the WM_ERASEBKGND message or test the fErase member of the PAINTSTRUCT structure filled by the BeginPaint function.
方法如下:
- BOOL CMainWindow::OnEraseBkgnd(CDC* pDC)
- {
- // TODO: 在此添加消息處理程序代碼和/或調用默認值
- CRect rc;
- GetClientRect(&rc);
- pDC->FillSolidRect(&rc , RGB(0,0,255) );
- //return CFrameWnd::OnEraseBkgnd(pDC);
- return TRUE;
- }
當然,也可以重寫OnEraseBkgnd()直接返回TRUE,然后在OnPaint()中改變背景。
更直接的方法是修改窗口類,實現更改背景顏色
- BOOL CMainWindow::PreCreateWindow(CREATESTRUCT& cs)
- {
- // TODO: 在此添加專用代碼和/或調用基類
- if( CFrameWnd::PreCreateWindow(cs))
- {
- //改變窗口類
- WNDCLASS wndclass;
- ::GetClassInfo(AfxGetInstanceHandle(),cs.lpszClass,&wndclass);
- //wndclass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
- //wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
- wndclass.hbrBackground=CreateSolidBrush(RGB(0,100,100));
- wndclass.hbrBackground=m_BKBrush;//m_BKBrush不能為函數局部變量
- wndclass.hbrBackground=*(new CBrush(RGB(25,25,0)));//最方便的方法
- //wndclass.hCursor = AfxGetApp()-> LoadCursor(IDC_CURSOR1);
- wndclass.lpszClassName = _T("newViewClassName ");
- VERIFY(AfxRegisterClass(&wndclass));
- cs.lpszClass=wndclass.lpszClassName;
- return TRUE;
- }
- return FALSE;
- }
若改變對話框大小,比如全屏顯示ShowWindow(SW_SHOWMAXIMIZED);UpdateWindow();
其中 ShowWindow會調用OnSize()->OnEraseBkgnd(),
UpdateWindow();調用OnPaint()->OnCtlColor(),
若對話框中沒有設置消息響應OnEraseBkgnd(),,則系統默認消息響應OnEraseBkgnd()會調用OnCtlColor()設置對話框背景(即替代OnEraseBkgnd())
對話框的背景設置可在OnCtlColor()中進行,因為OnCtlColor()一般會被多次調用,所以要想設置的CFont,CBrush等應在OnInitDialog中初始化,若要在OnCtlColor()中設置,在設置前先調用Detach就可以了,如下示例
- HBRUSH CDb3Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
- {
- if(pWnd->GetDlgCtrlID()==IDC_STATIC5)
- {
- m_font.CreatePointFont(300,"宋體");
- pDC->SelectObject(&m_font);
- m_font.Detach();
- pDC->SetBkMode(TRANSPARENT);
- return (HBRUSH)::GetStockObject(NULL_BRUSH);
- }
- }
但是如果在OnCtlColor()在設置背景圖片,則圖片不會隨對話框大小按比例縮放
所以可調用StretchBlt()函數設置,如下示例:
- void CDb3Dlg::OnPaint()
- {
- CClientDC cdc(this); CDC comdc;
- comdc.CreateCompatibleDC(&cdc);
- CBitmap bitmap;
- bitmap.LoadBitmap(IDB_BITMAP2);
- comdc.SelectObject(&bitmap);
- CRect rect;
- GetClientRect(rect);
- BITMAP bit;
- bitmap.GetBitmap(&bit);
- cdc.StretchBlt(0,0,rect.Width(),rect.Height(),&comdc,0,0,bit.bmWidth,bit.bmHeight,SRCCOPY);
- }//全屏顯示對話框背景圖片(限bmp格式)
對於窗口程序,一般有個特點:窗口大部分的區域保持不變,只有不分區域需要重新繪制。如果將整個窗口全部刷新的畫,就做了許多不必要的工作,因而,MFC采用了一套基於無效區的處理機制。在分析無效區處理之前,我們要明白一個現實,現在的機器還不夠牛,如果夠牛的話,我們干脆將整個窗口不斷的重新繪制好了。事實上即使夠牛也不行,對於一個單線程程序,通過一個while循環不斷的刷新窗口,程序也無法相應其他消息(除非使用多線程),看來使用無效區的處理機制還是有其必然性的。
