MFC学习对话框及窗口背景色 .

摘要:
对话框的背景颜色和图片可以在OnCtlColor()、OnEraseBkgnd()和OnPaint()中设置。对话框初始化后,按显示窗口时的顺序调用OnSize()˃OnEraseBkgnd()˃OnPaint()˃OnCtlColor()。默认情况下,OnEraseBkgnd()调用基类的OnEraseBugnd(),并使用窗口类中注册的笔刷绘制背景。同时,MSDN关闭了WM_ ERASEBKGND消息的描述说明DefWindowProc使用窗口类注册的背景画笔绘制背景。如果背景画笔为NULL,则需要处理WM_ERASEBKGND消息。隐含的意思是,处理WM_ ERASEBKGND消息可以由系统绘制,而无需将其发送到DefWindowProc。更直接的方法是修改窗口类以更改背景颜色[cpp]viewplaincopyprint?

设置对话框背景颜色及背景图片可在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.

方法如下:

  1. BOOLCMainWindow::OnEraseBkgnd(CDC*pDC)
  2. {
  3. //TODO:在此添加消息处理程序代码和/或调用默认值
  4. CRectrc;
  5. GetClientRect(&rc);
  6. pDC->FillSolidRect(&rc,RGB(0,0,255));
  7. //returnCFrameWnd::OnEraseBkgnd(pDC);
  8. returnTRUE;
  9. }
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()中改变背景。

更直接的方法是修改窗口类,实现更改背景颜色

  1. BOOLCMainWindow::PreCreateWindow(CREATESTRUCT&cs)
  2. {
  3. //TODO:在此添加专用代码和/或调用基类
  4. if(CFrameWnd::PreCreateWindow(cs))
  5. {
  6. //改变窗口类
  7. WNDCLASSwndclass;
  8. ::GetClassInfo(AfxGetInstanceHandle(),cs.lpszClass,&wndclass);
  9. //wndclass.hbrBackground=(HBRUSH)(COLOR_3DFACE+1);
  10. //wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
  11. wndclass.hbrBackground=CreateSolidBrush(RGB(0,100,100));
  12. wndclass.hbrBackground=m_BKBrush;//m_BKBrush不能为函数局部变量
  13. wndclass.hbrBackground=*(newCBrush(RGB(25,25,0)));//最方便的方法
  14. //wndclass.hCursor=AfxGetApp()->LoadCursor(IDC_CURSOR1);
  15. wndclass.lpszClassName=_T("newViewClassName");
  16. VERIFY(AfxRegisterClass(&wndclass));
  17. cs.lpszClass=wndclass.lpszClassName;
  18. returnTRUE;
  19. }
  20. returnFALSE;
  21. }
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就可以了,如下示例

  1. HBRUSHCDb3Dlg::OnCtlColor(CDC*pDC,CWnd*pWnd,UINTnCtlColor)
  2. {
  3. if(pWnd->GetDlgCtrlID()==IDC_STATIC5)
  4. {
  5. m_font.CreatePointFont(300,"宋体");
  6. pDC->SelectObject(&m_font);
  7. m_font.Detach();
  8. pDC->SetBkMode(TRANSPARENT);
  9. return(HBRUSH)::GetStockObject(NULL_BRUSH);
  10. }
  11. }
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()函数设置,如下示例:

  1. voidCDb3Dlg::OnPaint()
  2. {
  3. CClientDCcdc(this);CDCcomdc;
  4. comdc.CreateCompatibleDC(&cdc);
  5. CBitmapbitmap;
  6. bitmap.LoadBitmap(IDB_BITMAP2);
  7. comdc.SelectObject(&bitmap);
  8. CRectrect;
  9. GetClientRect(rect);
  10. BITMAPbit;
  11. bitmap.GetBitmap(&bit);
  12. cdc.StretchBlt(0,0,rect.Width(),rect.Height(),&comdc,0,0,bit.bmWidth,bit.bmHeight,SRCCOPY);
  13. }//全屏显示对话框背景图片(限bmp格式)
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循环不断的刷新窗口,程序也无法相应其他消息(除非使用多线程),看来使用无效区的处理机制还是有其必然性的。

VC程序是基于消息机制的,你所做的任何操作,比如点击鼠标,拖动窗口,首先进入系统的消息队列。这里的系统消息队列包括多个程序的消息,系统再将消息发送给相应的程序。既然是队列,这就有一个先进先出的问题,屏幕上的无效区更新消息出现的频率就会特别高。比如当左上角更新的消息还没有处理,右下角更新的消息已经过来了。为了避免多次处理WM_PAINT消息,系统就将这些窗口更新消息合并到一条,只是将无效区范围变成包括这两次更新无效区范围在内的矩形区域。这样就减少了WM_PAINT消息的处理次数,提高了效率。

那么,在OnPaint消息处理函数中,又是怎样实现更新无效区的呢?首先,要明白MFC中所有绘图操作都是基于设备描述表(Device Context,简称DC)的,具体信息可参看任何一本VC教材。DC中包含了绘图设备的各种信息,对于屏幕绘图,其实就是有一块内存(显存),专门用来存放要显示到屏幕上的信息,显示器以85HZ的频率(我以前的显示器)将其内容刷新的屏幕上。这里就到了关键点,显示器的刷新是将显存中的内容完全更新到显示器上,不存在无效区处理的问题,那么,无效区的处理一定发生在DC的绘图处理上。事实确实如此,当程序调用OnPaint消息时,首先将无效区范围传递给DC,DC在进行绘图操作时,就只更新无效区范围内的信息,其他地方的不管,这就提高了效率。

现在你明白OnPaint的处理是怎么一回事了吧?这里还想说一下Invalidate和UpdateWindow的区别。Invalidate在消息队列中加入一条WM_PAINT消息,其无效区为整个客户区。而UpdateWindow直接发送一个WM_PAINT消息,其无效区范围就是消息队列中WM_PAINT消息(最多只有一条)的无效区。效果很明显,调用Invalidate之后,屏幕不一定马上更新,因为WM_PAINT消息不一定在队列头部,而调用UpdateWindow会使WM_PAINT消息马上执行的,绕过了消息队列。如果你调用Invalidate之后想马上更新屏幕,那就加上UpdateWindow()这条语句。

免责声明:文章转载自《MFC学习对话框及窗口背景色 .》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇[转载]nc命令详解SAP BRIM计费与收入创新解决方案-融合开票下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

MFC的简单加法器(二)

   创建对话框主要分两大步,第一,创建对话框资源,主要包括创建新的对话框模板、设置对话框属性和为对话框添加各种控件;第二,生成对话框类,主要包括新建对话框类、添加控件变量和控件的消息处理函数等。鸡啄米在本节中先讲讲怎样创建对话框模板和设置对话框属性。        创建基于对话框的应用程序框架        之前鸡啄米创建的HelloWorld程序是单文...

HOOK自绘原理

做“HOOK文件打开/保存对话框”的过程中,我首先研究了界面库的相关知识。界面库一般都是由C/C++这种中低级语言编码,这是因为在Windows下的界面库实现技术大都以直接操作控制Windows的消息和调用Windows的API为主,这就是这种中低级语言的优势了。无论何种界面库,最为根本的原理就是获得或者截获窗口的某些消息,按照自己的需要处理这些消息,画出...

MFC 消息类型

---恢复内容开始--- 1、命令消息(WM_COMMAND) 所有派生自 CCmdTarget 的类都有资格接受WM_COMMAND。 2、Window消息(WM_xxx) 所有派生自 CWnd 的类都有资格接受 WM_xxx。 3、控件消息(WM_NOTIFY) 控件向其父窗口通知消息。 消息处理 1、WM_xxx 消息处理 窗口类(自身)处理→基类处...

VC项目配置基础 (VC6.0 和VC2005)

一.预处理宏 1. 通用宏 VC6.0中: Project Settingà C/C++à Preprocessor definitions VC2005中: 项目属性à 配置属性à C/C++à 预处理器定义 WIN32:指明是Window 32位系统的编译器,一般用作平台识别。 _MBCS/_UNICODE:指明该工程使用的字符集(多字节字符集/UN...

Windows消息机制详解

消息是指什么? 消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉。一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向 Windows发出一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。 消息本身是作为一个记录传递给应用程序的,这个记录中包含...

MFC对话框和控件

对话框和控件 对话框是Windows应用程序中一种常用的资源,其主要功能是输出信息和接收用户的输入数据。控件是嵌入在对话框中或其它父窗口中的一个特殊的小窗口,它用于完成不同的输入、输出功能。对话框与控件关系密切,在每个对话框上一般都有一些控件,对话框依靠这些控件与用户进行信息的交互。 在MFC中,对话框的功能被封装在CDialog类中,而CDialog类是...