MFC 判断mfc invalidatee(); 刷新画布

6138人阅读
Win32(11)
其中引用了下篇文章:
一:什么时候才会发生重绘窗口的消息?&& & & 当需要更新或重新绘制窗口的外观时,应用程序就会发送WM_PAINT消息。对窗口进行重新绘制。&二:Invalidate() -- RedrawWindow() -- UpdateWindow()三个函数有什么异同?&& & & Invalidate()是强制系统进行重画,但是不一定就马上进行重画。因为Invalidate()只是通知系统,此 时的窗口已经变为无效。强制系统调用WM_PAINT,而这个消息只是Post就是将该消息放入消息队列。当执行到WM_PAINT消息时才会对敞口进行重绘。&& & UpdateWindow只向窗体发送WM_PAINT消息,在发送之前判断GetUpdateRect(hWnd,NULL,TRUE)看有无可绘制的客户区域,如果没有,则不发送WM_PAINT。&& & RedrawWindow()则是具有Invalidate()和UpdateWindow()的双特性。声明窗口的状态为无效,并立即更新窗口,立即调用WM_PAINT消息处理。&
三:刷新组合
InvalidateRect(hctrl,null,true) ;&
UpdateWindow(hctrl);&这两个函数组合起来是什么意思呢?
InvalidateRect是会触发WM_PAINT事件,但是不是立即就触发,一般都会等当前操作的过程结束才触发,&如果需要立即触发,那么配合UpdateWindow()使用就可以了。先执行InvalidateRect,再执行UpdateWindow().
/************************************************************************************/
还有一篇文章也可以,不过好像有些问题。
Invalidate在消息队列中加入一条WM_PAINT消息,其无效区为整个客户区。
UpdateWindow直接发送一个WM_PAINT消息,其无效区范围就是消息队列中WM_PAINT消息(最多只有一条)的无效区。
效果很明显,当调用Invalidate之后,屏幕不一定马上更新,因为WM_PAINT消息不一定在队列头部,而调用UpdateWindow会使WM_PAINT消息马上执行的,绕过了消息队列。
如果调用Invalidate之后想马上更新屏幕,那就加上UpdateWindow()这条语句。&
MSDN的解释&UpdateWindow&The&UpdateWindow&function&updates&the&client&area&of&the&specified&window&by&sending&a&WM_PAINT&
message&to&the&window&if&the&window's&update&region&is&not&empty.&The&function&sends&a&WM_PAINT
&message&directly&to&the&window&procedure&of&the&specified&window,&bypassing&the&application&queue.&
If&the&update&region&is&empty,&no&message&is&sent.&&InvalidateRect&The&system&sends&a&WM_PAINT&message&to&a&window&whenever&its&update&region&is&not&empty&and
&there&are&no&other&messages&in&the&application&queue&for&that&window.&&翻译成中文大概的解释如下:&&&UpdateWindow:如果有无效区,则马上sending&a&WM_PAINT&message到窗口处理过程,不进消息队列进行排队等待,立即刷新窗口,否则,什么都不做。&&InvalidateRect:设置无效区,如果为NULL参数,则设置整个窗口为无效区。当应用程序的那个窗口的消息队列为空时,则sending&a&WM_PAINT&message(即使更新区域为空).在sending&a&WM_PAINT&message的所有InvalidateRect的更新区域会累加。&
&1:设置无效区&&InvalidateRect&&2:立即刷新&&UpdateWindow();&如果不调用&InvalidateRect就调用&UpdateWindow,那么UpdateWindow什么都不做。&??????如果调用&InvalidateRect&后不调用UpdateWindow,则系统会自动在窗口消息队列为空的时候,系统自动发送一WM_PAINT消息。&
调用UpdateWindow()时将会发送一个WM_PAINT消息,而应用程序在接收到WM_PAINT消息后,将自动地调用Invalidate(),所以,在程序代码中,不一定要出现Invalidate()!
UpdateWindow()就是立即发送WM_PAINT消息,只对声明无效的区域起作用,&&&& Invalidate()则是声明无效的方式之一。
Invalidate()表示客户区域无效,在下次WM_PAINT发生时重绘。而WM_PAINT是由系统进行维护的,每当CWnd的更新区域不为空,并且在应用程序的窗口消息队列中没有其它消息时,Windows就发送一条WM_PAINT消息。&&&& Invalidate里面有个bool型的参数,用来标识重绘的时候是否用背景色填充。是不是用SetBkcolor函数?下去继续研究。
&updateWindow则是要求系统对区域进行立即重绘。
&看到有人在网上提出问题,他在Invalidate后面又写了绘图的函数但是没有执行,因为invalidate执行过以后转到PAINT命令了。所以后面的都没有显示。
&也终于想通我绘的图一直在闪啊闪,因为我在PAINT里面用到Invalidate()函数,所以他不停的自嵌套,倒是绘的图不停的闪。
Invalidate让客户区处于可以重画的状态,而UpdateWindow开始重画,但是它先判断客户区是否为空,不空UpdateWindow不执行,为空才执行重画。
Invalidat最后也是调用InvalidatRect,在windows API里只有InvalidatRect的
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:367855次
积分:3898
积分:3898
排名:第6920名
原创:60篇
转载:51篇
评论:112条
(3)(1)(2)(1)(3)(1)(4)(4)(2)(1)(3)(3)(3)(3)(2)(1)(2)(1)(3)(3)(5)(2)(1)(6)(10)(1)(8)(9)(3)(4)(1)(2)(1)(3)(2)(2)(4)VC窗口刷新InvalidateRect和UpdateWindow
首先说说WM_PAINT这个重要的消息:
  The WM_PAINT message is generated by the system
and should not be sent by an application.The system sends this
message when there are no other messages in the application's
message queue
  也就是说WM_PAINT消息是由系统产生,非要等应用程序的消息队列为空时才发送WM_PAINT消息,并且该消息不应该被程序(自己写代码用SendMessage)来发送。
  当调用UpdateWindow函数,或者是Window检测到窗口被覆盖的地方需要恢复的时候,比如,第一次创建窗口,改变了窗口的大小,最大化,最小化等等(其实这些事件发生时会调用UpdateWindow函数,由该函数发送WM_PAINT消息),它会向用户程序发送一个WM_PAINT消息。窗口过程收到WM_PAINT消息后,并不代表整个客户区都需要被刷新,有可能客户区被覆盖的区域只有一小块,这个区域叫做“无效区域”,程序只需要更新这个区域。与WM_TIMER消息类似,WM_PAINT消息也是一个低级别的消息,虽然它不会像WM_TIMER消息一样被丢弃,但Windows总是在消息循环空的时候才把WM_PAINT放入其中。
  无效区域的坐标并不附带在WM_PAINT消息的参数中,在程序中有其他方法可以获取。WM_PAINT消息只是通知程序有个区域需要更新而已,所以Windows也不会同时将两条WM_PAINT消息放入消息循环中。当Windows要放入一条WM_PAINT消息的时候,如果发现已经存在一个无效区域了,那么它只需要把新旧两个无效区域合并计算出一个无效区域就可以了,消息循环中还是只需要一条WM_PAINT消息。
  实际上,Windows为每个窗口维护一个“绘图信息结构”,无效区域的坐标就在其中,每当消息循环空的时候,如果Windows发现存在一个无效区域,就会放入一个WM_PAINT消息。那么“绘图信息结构”怎么获取呢?BeginPaint函数的第二个参数就是一个绘图信息结构的缓冲区地址,windows会在这里返回绘图信息结构,结构中包含了无效区域的位置和大小,绘图信息结构的定义如下:
typedef struct tagPAINTSTRUCT { // ps 
    HDC    
    BOOL fE 
    RECT rcP 
    BOOL fR 
    BOOL fIncU 
    BYTE rgbReserved[32]; 
} PAINTSTRUCT; 
  其中hdc字段是窗口的设备环境句柄,rcPaint字段是一个RECT结构,它指定了无效区域矩形的对角顶点(如果开始有一个((0,0),(40,40)),现在又来一个((20,20),(60,30)),那么拼接后就是((0,0),(60,40))),fErase字段如果为非零值,表示Windows在发送WM_PAINT消息前已经使用背景色擦除了无效区域,后面3个字段是Windows内部使用的,应用程序不必去理会他们。
  在某些情况下,显示区域的一部分被临时覆盖,Windows试图保存一个显示区域,并在以后恢复它,但这不一定能成功。Windows可能发送WM_PAINT消息:Windows擦除覆盖了部分窗口的对话框或消息框;菜单下拉出来,然后被释放;显示工具提示消息。
  在某些情况下,Windows总是一定保存它所覆盖的显示区域,然后恢复它。这些情况是:鼠标光标穿越显示区域;图标拖过显示区域。
  有时候应用也需要能够主动引发窗口中的绘制操作,比如当窗口显示的数据改变的时候,这一般是通过InvalidateRect和
InvalidateRgn函数来完成的。InvalidateRect和InvalidateRgn把指定的区域加到窗口的Update
Region中,当应用的消息队列没有其他消息时,如果窗口的Update
Region不为空时,系统就会自动产生WM_PAINT消息。
  系统为什么不在调用Invalidate时发送WM_PAINT消息呢?又为什么非要等应用消息队列为空时才发送WM_PAINT消息呢?这是因为系统把在窗口中的绘制操作当作一种低优先级的操作,于是尽可能地推后做。不过这样也有利于提高绘制的效率:两个WM_PAINT消息之间通过InvalidateRect和InvaliateRgn使之失效的区域就会被累加起来,然后在一个WM_PAINT消息中一次得到更新,不仅能避免多次重复地更新同一区域,也优化了应用的更新操作。像这种通过InvalidateRect和InvalidateRgn来使窗口区域无效,依赖于系统在合适的时机发送WM_PAINT消息的机制实际上是一种异步工作方式,也就是说,在无效化窗口区域和发送WM_PAINT消息之间是有延迟的;有时候这种延迟并不是我们希望的,这时我们当然可以在无效化窗口区域后利用SendMessage
发送一条WM_PAINT消息来强制立即重画,但不如使用Windows
GDI为我们提供的更方便和强大的函数:UpdateWindow和RedrawWindow。UpdateWindow会检查窗口的Update
Region,当其不为空时才发送WM_PAINT消息;RedrawWindow则给我们更多的控制:是否重画非客户区和背景,是否总是发送WM_PAINT消息而不管Update
Region是否为空等。
  BeginPaint
  在处理消息时,没有使用BeginPaint和EndPaint这对函数,结果导致其余的消息弹不出来,窗口拖动时,不停闪烁(其实那就是重绘)。后来还是在MSDN上找到了答案,现将原话贴出来。(在MSDN的The
WM_PAINT Message标题中)
  BeginPaint sets the update region of a window to
NULL. This clears the region, preventing it fromgenerating
subsequent WM_PAINT messages. If an application processes a
WM_PAINT message but does not call BeginPaint or otherwise clear
the update region, the application continues to receive WM_PAINT
messages as long as the region is not empty. In all cases, an
application must clear the update region before returning from the
WM_PAINT message. 
  BeginPaint函数的作用就是将窗口需要重绘的区域设置为空(也就是Update
Region置空)。在正常情况下,我们接收到了WM_PAINT消息后,窗口的Update
Region都是非空的(如果为空就不需要发送WM_PAINT消息了)。而当你响应这个消息的时候又不调用BeginPaint来清空,窗口的Update
Region就一直是非空的,系统就会一直发送WM_PAINT消息。这样就形成了一个处理WM_PAINT消息的死循环。
  BeginPaint和WM_PAINT消息紧密相关。试一试在WM_PAINT处理函数中不写BeginPaint会怎样?程序会像进入了一个死循环一样达到惊人的CPU占用率,你会发现程序总在处理一个接一个的WM_PAINT消息。这是因为在通常情况下,当应用收到WM_PAINT消息时,窗口的Update
Region都是非空的(如果为空就不需要发送WM_PAINT消息了),BeginPaint的一个作用就是把该Update
Region置为空,这样如果不调用BeginPaint,窗口的Update
Region就一直不为空,如前所述,系统就会一直发送WM_PAINT消息。
  BeginPaint和WM_ERASEBKGND消息也有关系。当窗口的Update
Region被标志为需要擦除背景时,BeginPaint会发送WM_ERASEBKGND消息来重画背景,同时在其返回信息里有一个标志表明窗口背景是否被重画过。当我们用InvalidateRect和InvalidateRgn来把指定区域加到Update
Region中时,可以设置该区域是否需要被擦除背景,这样下一个BeginPaint就知道是否需要发送WM_ERASEBKGND消息了。
  当然关于
WM_PAINT消息还有很多的知识需要学习。另外要注意的一点是,BeginPaint只能在WM_PAINT处理函数中使用,并且在调用了BeginPaint函数后,不要忘记了调用EndPaint函数,他们可是一对的。
  重画函数 InvalidateRect,Invalidate,UpdateWindow,
RedrawWindow
  InvalidateRect(部分区域) 和Invalidate(整个窗口)
仅仅是用来设置无效区域,但是并不重绘窗口。
  UpdateWindow 检查窗口有无无效区域,如果有,则立即发送一个WM_PAINT
消息给窗口并立即重画。 
  RedrawWindow相当于先调用InvalidateRect,紧接着又调用UpdateWindow,此外RedrawWindow还提供了一些前两者没法做到的功能。
如果不调用 InvalidateRect就调用
UpdateWindow,那么UpdateWindow什么都不做,因为没有无效区域。如果调用 InvalidateRect
后不调用UpdateWindow,则系统会自动在窗口消息队列为空的时候,系统自动发送一WM_PAINT消息。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。本帖子已过去太久远了,不再提供回复功能。问题:(javascript)leafletjs的invalidateSize方法在angularJS里不生效?
描述:我用jquery和angualrJS分别做了个demo,地图刚开始的时候是隐藏的,点击一个图片后,该图片消失,地图显示,地图由于在显示的过程中,大小变化了,所以使用map.invalidateSize()方法,让地图很快显示出来;用jQuery写,一点问题都没有,然而,用angularJS写,这个方法却不生效,请大神们指教~&body ng-app="app" ng-c ng-show="!show" ng-class="{'show': !show}"&
&div&&/div&
&span&×&/span&
&img src="fake_map.png" ng-click="fn()" ng-show="show"&
&script type="text/javascript"&
var map = L.map('map').setView([22.27, 113.06], 12);
L.tileLayer('https://api./v4/mapbox.streets-basic/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoiYWJieW1ycyIsImEiOiJjaW9jb3J0ZWEwNGJwdmlsend4M2VoeWp5In0._xG7qbB8euaHzRxbY2DrFw', {
maxZoom: 18
}).addTo(map);
var marker = L.marker([22.27, 113.06]).addTo(map);
var app = angular.module('app',[]);
app.controller('ctrl', function ($scope) {
$scope.show =
$scope.fn = function(){
$scope.show=!$scope.
map.invalidateSize();
console.log('test');
解决方案1:已修复~$scope.fn = function() {$scope.show = !$scope.
var box = document.querySelector('.map-box');
angular.element(box).on('animationend', function(){
map.invalidateSize();
以上介绍了“(javascript)leafletjs的invalidateSize方法在angularJS里不生效?”的问题解答,希望对有需要的网友有所帮助。
本文网址链接:/itwd/1205124.html
上一篇: 下一篇:

我要回帖

更多关于 mfc 画布 的文章

 

随机推荐