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