日期:2014-05-17  浏览次数:21006 次

问个重绘的问题
1、窗体的重绘是怎么运作的,当屏幕发生改变时才调用重绘还是每隔固定的时间就刷新一次屏幕呢?指的是Windows自己处理的重绘,比如最小化一个窗体后,再还原,还可以照常显示在屏幕上(不大懂这个,可能问的方式不对)

2、C#里控件的Paint事件和系统自己完成的重绘(可能这说法有问题)有什么区别和先后顺序?
  比如我想在控件的Paint事件里对控件进行重绘

 private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
   //Graphics pics = pictureBox1.CreateGraphics();//采用这种方法绘图,被遮住再移开后,遮住部分无法恢复,疑问在这
   Graphics pics = e.Graphics ;
//画图部分
}


发现当控件仅被其他窗体遮住的时候不会触发Paint事件,但是当被遮住的部分露出来的时候就会触发Paint事件。
当pictureBox1被窗体X遮住一部分,移开窗体X后,触发Paint事件,如果此时用CreateGraphics画图的话,被遮住的部分并没有图像,只在未遮住的部分显示出画出的图像。是不是用CreateGraphics画的图被遮住后就无法被恢复?(即使不是用Paint事件画图,在Click事件里用CreateGraphics画图,被遮住后,再移开,画出的部分就没了)
用PaintEventArgs获取的Graphics就可以被Windows保存并恢复吗?
触发了Paint事件后,是不是先执行这个事件里的代码,然后再执行系统自身的重绘呢(就是由Windows系统控制的,可能说法又有问题),只重绘由遮住到露出来的部分吧?

请帮忙解答下,谢谢
C# 重绘 GDI

------解决方案--------------------
不是定时刷新,底层是收到Windows的Paint消息就刷新
------解决方案--------------------
1、是屏幕改变(位置,大小,被覆盖再露出等)都会引起重绘
   比如最小化一个窗体后,再还原,这个就会触发重绘
2、在Click事件里...
   你只有在点击时才会重绘,而Paint事件是自动触发重绘
------解决方案--------------------
一.Windows程序中的绘制和更新
与DOS环境比较,Windows中的应用程序在处理文字和图形绘制时有以下区别:
1.只能在窗口的客户区域绘制文字和图形
2.在窗口上绘制的内容不一定能够保留到程序下一次有意地改写时。
比如,当您的窗口被其他窗口覆盖,Windows不会保存您的窗口,当其他窗口移开时,Windows会要求你自己重新绘制窗口。

二.WM_PAINT消息
Windows通过发送WM_PAINT消息通知窗口其部分显示区域需要绘制。Windows给窗口发送WM_PAINT的时机也就是窗口需要进行绘制

的时机:
1.大多数程序在进入消息循环之前,通过调用UpdateWindow来给窗口过程发送一个WM_PAINT消息。
2.在以下几种情况,Windows给窗口过程发送WM_PAINT消息:
·窗口中先前被隐藏的部分变得可见
·使用者改变窗口大小(设置了CS_HREDRAW和CS_VREDRAW)
·使用ScrollWindow或ScrollDC滚动显示区的一部分
·使用InvalidateRect或InvalidateRgn可以产生WM_PATIN
在以下情况,Windows尝试保留窗口内容,在以后需要的时候恢复。如果失败,则产生WM_PAINT消息:
·Windows擦除了覆盖部分窗口的对话框或消息框
·菜单弹出,然后释放
·显示工具提示消息
3.在下列情况,Windows总是保存被覆盖的显示区域,然后恢复他们:
·鼠标穿越显示区域
·图标拖过显示区域

三.程序组织形式
程序应当仅在处理WM_PAINT消息时在显示区域进行绘制。如果程序需要在其他时间更新显示区域,可以强制Windows产生一个

WM_PAINT消息。

四.有效区域和无效区域
(一)概述
显示区中需要重新绘制的区域叫做“无效区域”,包含“无效区域”所需的最小矩形叫做“无效矩形”。Windows内部为每个窗口

保存一个“绘图信息结构”,用来保存窗口的无效区域、无效矩形以及一些其他信息。
当窗口存在“无效区域”时,Windows就会给窗体发送WM_PAINT消息。当一个WM_PAINT在消息队列中还未处理,又有新的无效区域

增加时,Windows只是修改窗口的“绘图信息结构”,把新的无效区域合并进去,并不给窗口发送新的WM_PAINT;同样,如果一个

消息队列中的WM_PAINT消息还未处理,窗口中不存在无效区域了(比如调用了ValidateRect删除了所有无效区域),那么

WM_PAINT消息将会被移出消息队列。
总之,消息队列中至多有一个WM_PAINT消息。这样设计的目的是尽量减少重绘的次数。

(二)增加和删除无效区域
1.增加无效区域
·Windows会自动管理窗口的无效区域。
·可以通过调用InvalidateRect来将某个区域合并到窗体的无效区域中
·调用函数UpdateWindow会使整个客户区无效
2.删除无效区域
无效区域不会自动消失,除非调用某些可以删除无效区域的函数
·处理WM_PAINT时,BeginPaint函数会使整个客户区有效(删除所有无效区域)
·ValidateRect函数可以使指定区域变得有效
3.获取无效区域信息
·在处理WM_PAINT时
·调用GetUpdateRect来获取无效区域
------解决方案--------------------
你可以先建立一个画布,然后画到这个画布上,最后设置picturebo1.backgroundimage=画布,这样就没paint什么的影响,更没有多余额外的重复绘制.
------解决方案--------------------
引用:
1、窗体的重绘是怎么运作的,当屏幕发生改变时才调用重绘还是每隔固定的时间就刷新一次屏幕呢?

怎么可能“每隔固定的时间刷新一次”呢?

比如你说0.2秒钟刷新一次,那么屏幕没有任何改变、无需刷新时为什么闲着没事去刷新呢?而如果屏幕改变了,你不是即刻显示,而是间隔这么长时间才“一卡一卡”地显示,这种程序给用户的体验就显得档次太低、太没有专业概念了。

这个方面不需要犹豫,不需要去想什么“固定的时间刷新”那样的东西。