设置对话框背景颜色及背景图片可在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循环不断的刷新窗口,程序也无法相应其他消息(除非使用多线程),看来使用无效区的处理机制还是有其必然性的。