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

设置对话框色彩及背景图片可在OnCtlColor(),OnEraseBkgnd(),OnPaint()里设置,

对话框初始化完毕,显示时调用OnSize()->OnEraseBkgnd(),->OnPaint()->OnCtlColor(),

1、若想改变对话框大小,比如全屏显示ShowWindow(SW_SHOWMAXIMIZED);UpdateWindow();
此中 ShowWindow会调用OnSize()->OnEraseBkgnd(),
        UpdateWindow();调用OnPaint()->OnCtlColor(),
2、若对话框中没有设置消息响应OnEraseBkgnd(),,则系统默认消息响应OnEraseBkgnd()会调用OnCtlColor()设置对话框背景(即调换OnEraseBkgnd())
 对话框的背景设置可在OnCtlColor()中进行,因为OnCtlColor()一般会被多次调用,所以要想设置的CFont,CBrush等应在OnInitDialog中初始化,

3、若要在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轮回络续的刷新窗口,法度也无法响应其他消息(除非应用多线程),看来应用无效区的处理机制还是有其必定性的。


     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)中是参加消息处理队列。


Invalidate和UpdateWindow的差别。

Invalidate在消息队列中参加一条WM_PAINT消息,其无效区为全部客户区。而UpdateWindow直接发送一个WM_PAINT消息,其无效区局限就是消息队列中WM_PAINT消息(最多只有一条)的无效区。结果很明显,调用Invalidate之后,屏幕不必然即速更新,因为WM_PAINT消息不必然在队列头部,而调用UpdateWindow会使WM_PAINT消息即速履行的,绕过了消息队列。若是你调用Invalidate之后想即速更新屏幕,那就加上UpdateWindow()这条语句

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值