其实java里设置属性后会导致重绘的,只不过由于这个重绘事件也被放在事件派发线程里的,因此就导致了事件派发线程被Idle了,要避免这种情况,将这个堵塞动作放到另外的线程里面完成。
repaint是出发重绘动作,当调用repaint后,会通知repaintManager增加一个重绘区域,repaintManager在一定条件下会合并一些重绘区域,然后派发一个绘制动作到事件派发线程(EventQueue)。
事件派发线程执行到这个绘制事件时,就会调用组件的paint,在paint方法里会先调用update来将重绘区域清空(默认情况下是填充白色),然后再调用paintComponent来绘制自身,最后调用paintChildren来绘制所有的子。具体流程可以参考JComponent里的paint方法.
public void update(Graphics g)
-
调用
paint
。不清除背景,而是查看ComponentUI.update
,它由paintComponent
调用。
JComponent:paint(Graphic g)由 Swing 调用,以绘制组件。应用程序不应直接调用 paint
,而是应该使用 repaint
方法来安排重绘组件。
此方法实际上将绘制工作委托给三个受保护的方法:paintComponent
、paintBorder
和 paintChildren
。按列出的顺序调用这些方法,以确保子组件出现在组件本身的顶部。一般而言,不应在分配给边框的 insets 区域绘制组件及其子组件。子类可以始终只重写此方法。只想特殊化 UI(外观)委托的 paint
方法的子类应该只重写 paintComponent
。
protected void paintComponent(Graphics g)
-
如果 UI 委托为非
null
,则调用该 UI 委托的 paint 方法。向该委托传递Graphics
对象的副本,以保护其余的 paint 代码免遭不可取消的更改(例如Graphics.translate
)。如果在子类中重写此方法,则不应该对传入到
Graphics
中的内容进行永久更改。例如,不应更改剪裁矩形
或修改转换。如果需要进行这些操作,您会发现根据传入的Graphics
创建一个新Graphics
并操作它会更容易一些。另外,如果不调用超类的实现,则必须遵守不透明属性,也就是如果此组件是不透明的,则必须以透明的颜色完全填充背景。如果不遵守不透明属性,则很可能看到可视化的人为内容。传入的
Graphics
对象可能具有与该对象上已安装的标识转换所不同的转换。在这种情况下,如果多次应用其他转换,则可能得到不可预料的结果。 -
protected void paintChildren(Graphics g)
-
绘制此组件的子组件。如果
shouldUseBuffer
为 true,则所有的组件祖先都没有缓冲区,并且组件子级可以使用缓冲区(如果有)。否则,祖先具有当前正在使用的缓冲区,并且子组件应该不使用缓冲区进行绘制。 -
public void print(Graphics g)
-
调用此方法以打印组件。此方法将导致对
printComponent
、printBorder
和printChildren
的调用。建议不重写此方法,而是重写前面提及的方法之一。此方法设置组件的状态,使得双缓冲区不被使用,例如直接在传入的Graphics
上完成绘制。
-
调用此方法以打印组件。此方法将导致对
-
绘制此组件的子组件。如果
-
protected void printComponent(Graphics g)
-
在打印操作期间调用此方法。实现此方法以对该组件调用
paintComponent
。如果要在打印时添加特殊的绘制行为,可重写此方法
-
protected void printChildren(Graphics g)
-
打印此组件的子组件。实现此方法以对该组件调用
paintChildren
。如果希望以不同于绘制的方式打印子组件,则重写此方法
-
打印此组件的子组件。实现此方法以对该组件调用
-
public void updateUI()
-
将 UI 属性重置为当前外观的值。
JComponent
的子类必须以如下方式重写此方法:public void updateUI() { setUI((SliderUI)UIManager.getUI(this); }
-
将 UI 属性重置为当前外观的值。
-
在打印操作期间调用此方法。实现此方法以对该组件调用