更新有两种情况引起,A.是承载图形的控件容器在被损毁时触发,称为系统重绘;
B.二是图形系统由于绘制需要在内部调用更新,称为程序重绘。
情况A:
1、它是AWT在操作系统事件作用下要求重绘的,表现为主动,因为它是图形系统承载体,皮之不存毛之焉附?
所以重绘是必须的。
2、重绘时要取得控件损毁区域作为剪裁区绘画所有图形,这样在剪裁区之外的图形部分将不被绘制,
GRAPHICS已优化了剪裁绘画的功能,graphics在绘画前会计算所有要被绘画的图形是否在剪裁区内,
如果不在则不绘制,如果完全在其内则绘制,如果相交就绘被包容的部分。
3、由于剪裁区已优化了性能,如果再把剪裁区作为缓冲图片,性能会更好,所以不需要再计算与剪裁区
相交的图形,而特别针对这些相交图形重绘了,可以重绘所有图形,这样的计算损耗其实跟前者差不多,
不然draw2d一定会采用前者,但实际上draw2d是在剪裁区内重绘所有图形。
4、DRAW2D系统重绘过程:
a.系统事件paint触发LWS.paint方法,该方法调用updateManager.paint方法
b.系统事件resize触发LWS.controlResize方法,该方法调用updateManager.performValidate方法。
c.系统事件resize的调用必定触发事件paint,以上a和b是不是执行了两次重绘呢?
答案肯定不是,但现在还没看懂。但controlResize除了重绘之外,还要调整根图形的客户区及座标。
情况B:
1、由程序指定要更新的图形或区域,对于系统来说是被动晌应。
2、程序重绘是窗口区没有破坏,但在下列因素下却必须重绘:某图形移动、删除、绘画过程、缩放等,
由于它的改变,会牵涉一系统图形改变,那么就需要重绘,特别是图形的移动,辅助图形每步都要擦旧绘新,
重绘频率很高。
3、程序重绘也采用剪裁区,该剪裁区由增量计算脏区域而得,脏区域可由调用产生也可由无效图形区域而得。
这点跟情况A一样,在剪裁区内重绘所有图形,并使用缓冲重绘。
4、DRAW2D程序重绘过程:
a.图形调用重绘方法:validate、invalidate,revalidate,repaint,repaint方法是直接报告脏区域
revalidate先使图形到父级无效并报告诉无效图形;validate设图形有效并调用排版;invalidate
使图形无效并使排版也无效。
b.向updatemanager报告脏区域或无效图形最终均导致performUpdate方法的调用(在之前使用了线程池),
performUpdate方法先firevalidating,这个事件只有figurecanvas视口感兴趣并导致内容对象重新排版,
所有图形有效化,图形有效化导致要重新排版,排版会导致报告脏区域。
接着就是调用repaireDemage修补损毁区。该方法过程如下:
1.合并脏区域得剪裁区;2.用缓冲笔在剪裁区内画所有图形;3.在releaseGraphics方法内调用
griphicsSource的flush方法,在控件内画出缓冲图片。
graphicsSource作缓冲绘制,getGraphics分配缓冲图片并获取缓冲图片大小的graphics对象,rander是将缓冲图片输出并释放。
在绘画时,必须调用一次getGraphics,rander一次,分配一次缓冲不能用多次,因为rander在调用后会释放缓冲
更新的无效图形被重绘的过程分析:
前面谈的是脏区域的更新,有两个方法均可增加脏区域,一个是updateManage#addDirtyRegion一个是IFigure#repaint而后者是调用了前者,现在有个问题,无效图形列表是如何变成脏区域而被更新的呢?为什么在updateManager内不直接将无效图形列表转为脏区域从而实现更新呢?答案是要考虑排版的问题,排版会使图形变形和移位,给用户呈现自动合理的自动布局观感 ,所以这个转换是间接的,而且和前面这两个方法相关,下面的过程描述看过既可明白。
1、 界面晌应,在调用IFigure#setborder, setContstraint()、setLayoutManager()、add()、remove()等,会自动调用revalidate()方法
2、 Revalidate方法使上链图形和布局的persize无效并将根图形增加到无效图形列表
3、 在向无效图形列表增加无效图形时,触发updateManager线程执行performUpdate
4、 performUpdate执行图形有效化和修补图形。在有效化过程中,执行无效列表内图形的validate方法。
5、 IFigure#validate调用本图形的布局对象
6、 布局对象的layout先使所包含的所有图形无效,并根椐现有图形的合适大小为图形分配合适大小(persize)并调用每个图形的setBounds方法重新给图形定位和大小。
7、 IFigure#setBounds调用repaint方法从而完成整个链条。
JAVA窗体坐标是相对于桌面的,即win.getLocation得窗体在桌面位置,而窗体控件是相对于窗体的。
所以必须在graphicsSource获取graphics前平移到正确位置
缓冲使用效果:界面不保持显示状态不变,图形在迅速绘画到缓冲位图中,只在画完后执行对缓冲位图的绘画,画缓冲位图才会导致屏幕更新,
而画一个位图速度很快,何况这个位图缩小到只是被损损坏的区域,一般几百K而已,用户也就感觉不出来了。
鼠标捕获概念:鼠标移到图形上并不是捕获,捕获是指鼠标在图形上被按下后(一定在按下后,也就是说按下鼠标的事件
通知仍是捕标进入时捕获到的mouseTarget图形),其意即为用鼠标捕获了该图形,此概念用于选择图形。
mouseTarget鼠标目标概念:没被捕获并且光标落其上
cursorTarget光标目标:光标在落在其上的图形。
图形的MinimumSize,MaximumSize,PreferredSize,Size,bounds区别:
基本上来说,validate是对于尺寸的调整,而repaint()是对颜色的调整。当我们把一个图形C作为子图形拖到
另一个图形P里的时候(想象P为UML类图里表示类的矩形,C为表示属性或方法的矩形),因为调用了P的add()方法,
所以P及P的所有“祖先”图形都将通过revalidate()被置为invalid状态。UpdateManager随后在performUpdate()
里对这些图形进行validate(),在validate()的过程中,每个图形将通过自己的LayoutManager重新计算自己的尺寸。
这样就实现了P随子图形的多少自动改变大小。由上总结,布局为了控件的包容,自动让控件挪位(排挤),改变大小(
如父控件装不下),以使界面外观作出调整,这些要用到PreferredSize及其它属性。
MinimumSize指一个图形元素最小不能比它小
MaximumSize指图形元素最大不能比它大
PreferredSize的值一定介于MinimumSize和MaximumSize之间,如果小于MinimumSize就用MinimumSize,如果大于MaximumSize就用MaximumSize。PreferredSize可以被布局调整。
size是bounds的宽度和高度
bounds指图形元素的具体位置,包括左上角定点坐标、宽度和高度
layout计算的就是PreferredSize
******更新管理器,图形的repaint,invalidate,validate,revalidate,布局之间关系:*********
LayoutManager(布局管理器)
布局管理器通过Figure#setBounds()改变子图形的位置和大小。
根据布局算法和子图形决定当前图形的preferredSize。
布局的过程是先确定图形的大小,再计算每个子图形的新位置和大小。
Figure#invalidate()
若valid属性已经是false则直接返回。
如果图形拥有LayoutManager,则调用LayoutManager的invalidate()方法,在XYLayout里作用是将preferredSize重置为null值,在FlowLayout里还要把minimumSize置为null值。
将图形的valid属性置为false。
Figure#revalidate()
我觉得它实际代表"recursive invalidate"的意思。这个方法的功能是首先将图形自己invalidate(),然后递归的将图形的父图形invalidate(),一直到根图形为止,这个根图形会被加入到UpdateManager的一个列表中。
在Figure的很多方法里,如setBorder()、setContstraint()、setLayoutManager()、add()、remove()等,会自动调用revalidate()方法。因此,大部分情况下我们不需要手动调用这个方法。
Figure#validate()
若valid属性已经是true则直接返回。
将图形的valid属性置为true。
如果图形拥有LayoutManager,则调用LayoutManager的layout()方法。
对图形的每个子图形,调用validate()方法。
Figure#repaint()
在图形的UpdateManager里,将图形所处的区域标记为“脏”区域,这个区域将由UpdateManager(定期)重画。
在图形的setVisible()、setOpaque()、setForegroundColor()、setBounds()、setBackgroundColor()等方法里会自动调用repaint()方法。
Figure#paint()
虽然名称相似,但这个方法和repaint()关系不大。在Figure里这个方法按顺序调用paintFigure()、paintClientArea()和paintBorder()这三个方法,当实现自己的Figure时,绝大多数情况下应该只覆盖paintFigure()而不是paint()本身。
Figure#getPreferredSize()
对于Label这样的图形,它的preferredSize由它所显示的文本和图标所占空间决定;如果一个图形包含子图形,则它的preferredSize要考虑子图形的排列方式,所以要由LayoutManager来决定。
LayoutManager的getPreferredSize()方法还有两个参数:wHint和hHint,它们分别代表图形的已知长(宽)度,如果其中一个值是大于零的,则在另一个方向上子图形将换行(列)排列,以保证长(宽)度不大于这个已知值。
Figure#invalidate()
1、若valid属性已经是false则直接返回。
2、如果图形拥有LayoutManager,则调用LayoutManager的invalidate()方法,在XYLayout里作用是将preferredSize重置为null值,在FlowLayout里还要把minimumSize置为null值。
3、将图形的valid属性置为false。
IFigure#revalidate()
1、向上递归使包括本图形上源图形无效即调用invalidate()方法
2、递归寻到图形根并调用将根图形updateManager#addInvalidFigure(this)增加到无效图形列表,而该调用将用背后线程执行performUpdate从而执行有效化图形。
3、在Figure的很多方法里,如setBorder()、setContstraint()、setLayoutManager()、add()、remove()等,会自动调用revalidate()方法。因此,大部分情况下我们不需要手动调用这个方法。
Figure#validate()
1、若valid属性已经是true则直接返回。
2、将图形的valid属性置为true。
3、如果图形拥有LayoutManager,则调用LayoutManager的layout()方法。
4、对图形的每个子图形,调用validate()方法。
Figure#repaint()
1、在图形的UpdateManager里,将图形所处的区域标记为“脏”区域,这个区域将由
2、UpdateManager(定期)重画。
3、在图形的setVisible()、setOpaque()、setForegroundColor()、setBounds()、4、setBackgroundColor()等方法里会自动调用repaint()方法。
Figure#paint()
1、虽然名称相似,但这个方法和repaint()关系不大。在Figure里这个方法按顺序调用
2、paintFigure()、paintClientArea()和paintBorder()这三个方法,当实现自己的
3、Figure时,绝大多数情况下应该只覆盖paintFigure()而不是paint()本身。
Figure#getPreferredSize()
1、对于Label这样的图形,它的preferredSize由它所显示的文本和图标所占空间决定;
2、如果一个图形包含子图形,则它的preferredSize要考虑子图形的排列方式,所以要由LayoutManager来决定。
3、LayoutManager的getPreferredSize()方法还有两个参数:wHint和hHint,它们分别代表图形的已知长(宽)度,如果其中一个值是大于零的,则在另一个方向上子图形将换行(列)排列,以保证长(宽)度不大于这个已知值。
4、如果图形的perfsize为空则返回图形size,如果有布局则返回布局计算的perfsize
基本上来说,validate是对于尺寸的调整,而repaint()是对颜色的调整。当我们把一个图形C作为子图形拖到另一个图形P里的时候(想象P为UML类图里表示类的矩形,C为表示属性或方法的矩形),因为调用了P的add()方法,所以P及P的所有“祖先”图形都将通过revalidate()被置为invalid状态。UpdateManager随后在performUpdate()里对这些图形进行validate(),在validate()的过程中,每个图形将通过自己的LayoutManager重新计算自己的尺寸。这样就实现了P随子图形的多少自动改变大小。
上面左图是在子图形上发生改变时,自动调用了Fig4的invalidate()方法,导致到根图形之间的所有图形的invalidate()方法被触发。右图则是UpdateManager对这些invalid图形进行validate(),并且是自上而下进行的(几乎可以认为validate()方法就是对layout()方法的调用)。注意到由于对Fig2进行了layout(),Fig5的尺寸也可能因此发生改变,如果发生了这种情况,则Fig5的invalidate()方法也会被调用。
http://www.cnblogs.com/bjzhanghao/archive/ 2005/09/17 /237923.html
Figure#getPreferredSize()
LayoutManager#getPreferredSize(IFigure, int, int)