其实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);
}