MFC中改变对话框背景的几个消息函数OnEraseBkgnd、 OnPaint、 OnCtlColor的调用顺序

设置对话框背景颜色及背景图片可在OnCtlColor(),OnEraseBkgnd(),OnPaint()里设置,对话框初始化完毕,显示时调用OnSize()->OnEraseBkgnd(),->OnPaint()->OnCtlColor(),

若想改变对话框大小,比如全屏显示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格式)

    用了两年的VC,其实对OnPaint的工作原理一直都是一知半解。这两天心血来潮,到BBS上到处发帖询问,总算搞清楚了,现在总结一下。

     对于窗口程序,一般有个特点:窗口大部分的区域保持不变,只有不分区域需要重新绘制。如果将整个窗口全部刷新的画,就做了许多不必要的工作,因而,MFC采用了一套基于无效区的处理机制。在分析无效区处理之前,我们要明白一个现实,现在的机器还不够牛,如果够牛的话,我们干脆将整个窗口不断的重新绘制好了。事实上即使够牛也不行,对于一个单线程程序,通过一个while循环不断的刷新窗口,程序也无法相应其他消息(除非使用多线程),看来使用无效区的处理机制还是有其必然性的。

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

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

1)  直接发送WM_PAINT消息,用PostMessage(),SendMessage()函数发送WM_PAINT消息。使用以上两函数发送WM_PAINT消息,能将WM_PAINT消息发送到WINDOWS程序消息队列中,当WINDOWS将WM_PAINT消息发送给具体的消息处理函数时,如果窗口的无效区域为空则WINDOWS将不理睬该消息。若存在无效区域,则调用窗口处理函数处理。要注意的这里需要存在无效区域,因此要调用2)中的函数使得窗体(或者部分)无效,其处理过程与2)相同,将WM_PAINT消息送入消息处理队列。与3)不同的是WM_PAINT并不立即处理;

2)  调用相应的API实现WM_PAINT消息的发送:Invalidate(),InvalidateRect(), InvalidateRgn():以上函数将窗口的特定区域标定为无效,当WINDOWS检测到窗口中存在无效区域时将向消息队列发送WM_PAINT 消息。我当时用的就是Invalidate()函数;

3)  UpdateWindow():该函数调用后WINDOWS将向窗口发送一个非队列化的WM_PAINT消息,它不经过消息循环而直接发送给了窗口消息处理函数。如果窗口无效区域不存在,WINDOWS将不理睬该消息。注意这里因为要使得窗口无效区不存在,因此还是调用Invalidate(),InvalidateRect(), InvalidateRgn()函数,和2)中不同的是这里的WM_PAINT消息会被立即处理,而2)中是加入消息处理队列。

简单起见,你可以使用2)中方案进行问题解决。

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

时间: 2024-09-26 22:51:49

MFC中改变对话框背景的几个消息函数OnEraseBkgnd、 OnPaint、 OnCtlColor的调用顺序的相关文章

vc中改变对话框的背景色

---- 笔者曾在<软件报>2000年第5期中讨论过如何改变控件的颜色,但还有相当一部分的读者来信提问:一个基于对话框的MFC AppWizard应用程序中,如何改变对话框的背景颜色呢?对于这个问题,其实可以由几种不同的方法来实现,具体如下(粗斜体代码为增添的):  ---- 方法一:调用CWinApp类的成员函数SetDialogBkColor来实现.  ---- 其中函数的第一个参数指定了背景颜色,第二个参数指定了文本颜色.下面的例子是将应用程序对话框设置为蓝色背景和红色文本,步骤如下: 

VC/MFC如何设置对话框背景颜色

VC/MFC如何设置对话框背景颜色 2007-06-19 19:57 1. 重载OnCtlColor    (CDC*    pDC,    CWnd*    pWnd,    UINT    nCtlColor),即WM_CTLCOLOR消息.      ----    ①在CExampleDlgDlg的头文件中,添加一CBrush的成员变量:        class    CExampleDlgDlg    :    public    CDialog      {...      pro

mfc对话框-MFC中向导对话框中单选按钮的问题

问题描述 MFC中向导对话框中单选按钮的问题 我给单选按钮RADIO1建立类向导之后,BN_CLICKED函数里面应该怎么定义才能使单选按钮选择之后再次选择之后还是可以选择的,我现在的是点了单选按钮就不能再次点击了,,.另外怎么设置是只有选择单选按钮之后才能点击下一步?求解 解决方案 MFC单选按钮的分组问题MFC单选按钮MFC单选按钮 解决方案二: http://blog.csdn.net/zssureqh/article/details/7604018 解决方案三: 一个Group组中. 你

总结:MFC中一个对话框的关闭过程 .

说起来挺简单的,一个对话框关闭时要依次调用该类的DestroyWindow-OnDestroy-PostNcDestroy,根据关闭的方法不同,在这些函数之前会调用OnOK.OnCancle或者OnClose.         这里要说的是,模态对话框的消息循环要到调用了PostNcDestroy之后才真正的结束,即ContinueModal循环在这里才结束,然后类的析构函数将被调用,这个对话框才真正的被销毁了.         如果一个模态对话框还有一个模态的子对话框,那就更要注意了.如果子对

设置背景颜色-MFC中在View类中改变ClientDC的背景颜色

问题描述 MFC中在View类中改变ClientDC的背景颜色 我在MFC中建立了一个工程,用来在CView类中通过ClientDC来进行画图操作,现在想将ClientDC的默认背景颜色从白色改成黑色或者其他的颜色,求各位C大神指点,谢啦! PS:我试过在PreCreateWindow()和OnEraseBkgnd()函数中进行设置,但是没有成功,代码如下,请各位大神改正. BOOL CTestView::PreCreateWindow(CREATESTRUCT& cs) { cs.lpszCl

背景图片-MFC中对话框中图片适应窗口的问题

问题描述 MFC中对话框中图片适应窗口的问题 我自己建的窗口,当从文件加载背景图片时消失在对话框中的图片太大没有显示完全?这个该如何解决呢!? 解决方案 什么意思,能说清除一点吗

MFC CDockablePane改变窗口大小时,pane中的对话框大小也改变

问题描述 MFC CDockablePane改变窗口大小时,pane中的对话框大小也改变 解决方案 解决方案二: 解决方案三: mfc中控件随着窗口的大小改变而改变大小 解决方案四: 给cmainframe映射wm_size消息或者重写onsize,在里面通过movewindow调整你里面的控件大小. 解决方案五: 不行,哪个是对话框随pane移动

MFC VS2012对话框背景填图

这是使用VS 2012编写MFC对话框程序的教程,主要是关于图片处理方面的操作,这些在MFC游戏.图片处理.软件编写中是经常要用到的知识. 一.创建项目 文件-新建项目-MFC应用程序-该页面使用"基于对话框"-完成即可. 注意:取消"使用Unicode库",否则在使用AfxMessageBox会报错,没有一个可以转换的参数类型,要加AfxMessageBox(_T("..")).运行结果: 二.添加背景Bitmap资源 在"资源视图&

MFC 基础知识:对话框背景添加图片和按钮Button添加图片

        很长时间没有接触MFC相关的知识了,我大概是在大二时候学习的MFC相关知识及图像处理,现在由于要帮个朋友完成个基于C++的程序,所以又回顾了下相关知识.的确,任何知识一段时间过后都比较容易忘记,但回顾起来还是很有印象的.        这篇文章主要是回顾以前的MFC基础知识,给对话框添加背景图片和给按钮button添加背景图片:希望此篇基础性文章对大家有所帮助!同时为下次做MFC相关知识提供点此时所想所感吧.内容比较简单,高手飘过~ 一. 对话框背景添加图片         首先