2012-12-02 31 views
5

通常,當使用JTableJTree時,用戶寫入並分配它是自己特定的單元格渲染器。理解swing的JTable和JTree的渲染器機制的難點

DefaultTableCellRenderer繼承用戶組件並實現渲染器方法getTableCellRendererComponent是非常普遍的。事實證明,DefaultTableCellRenderer實際上是從JLabel繼承的,因此在調用super(在render方法)時返回自己(this),因此用戶的渲染器也可以類似地返回自己(this)。

而且一切正常。

我的問題是怎麼回事?

每次該表調用該方法時,都會給出不同的參數,並根據這些參數更改輸出標籤。如果它確實是標籤的同一個實例 - 不應該根據最後一次調用此方法來更改它嗎? 這不是說所有表格的單元格都是由相同的標籤實例組成,它們擁有相同的值(最後一次調用渲染器方法的值)?

我已經在網上搜索,並且Swing的代碼中挖掘,並不能找到克隆拷貝構造函數,實際上覆制了輸出標籤的任何行爲。 我找不到任何證據表明(可能)擺動使用反射來重新實例化渲染器,每次從頭開始。

我看了Swing的tutorial on JTables,還有我能找到下一行:

您可能希望在一個表中的每個單元是一個組件。但是,出於性能原因,Swing表格的實現方式不同。 相反,單個單元格渲染器通常用於繪製包含相同類型數據的所有單元格。您可以將渲染器視爲可配置的油墨印記,表格用於將適當格式化的數據印到每個單元上。當用戶開始編輯單元格的數據時,單元格編輯器接管單元格,控制單元格的編輯行爲。

他們給出了一個提示,確實我所說的是正確的,但並沒有解釋它是如何實際完成的。

我無法得到它。你們可以嗎?

回答

10

這是flyweight pattern的實現。

當JTable重新繪製自身時,它啓動一個循環並遍歷每個必須繪製的單元格。

對於每個單元格,它都會使用與單元格相對應的參數調用渲染器。渲染器返回一個組件。該組件繪製在當前表格單元格對應的矩形中。

然後,渲染器被稱爲下一個小區,並且返回的部件(其具有不同的文本和彩色,例如),在對應於單元格的矩形塗等

試想一下,每個渲染器被調用的時候,返回的組件的屏幕截圖被獲取並粘貼到表格單元格中。

+1

+1屏幕比喻是一個很好的例子。我認爲最常用的是「郵票」,但截圖可能更清晰 – Robin

+1

謝謝。這個比喻證明了這個訣竅:)。現在理解了。 –

4

在ADITION改爲@ JB的如何JTableJTree使用flyweight pattern,請注意這兩個類如何提供公共方法getCellRenderer()getCellEditor()明確explication。檢查這些方法以查看JTable如何使用Class Literals as Runtime-Type Tokens按類別選擇渲染器或編輯器(如果沒有列指定)。在內部,JTable使用Hashtable defaultRenderersByColumnClass作爲實例存儲。

+0

另請參閱此相關的[示例](http://stackoverflow.com/a/7776211/230513)。 – trashgod

3

一些挖後,找到了下實現注意從DefaultTableCellRenderer documentation

實現注意:這個類的JLabel,一個標準組件類繼承。然而,JTable採用獨特的機制渲染其單元格,因此需要對其單元格渲染器稍作修改。表類定義了一個單元格渲染器,並將其用作表格中所有單元格的橡皮圖章;它渲染第一個單元格,更改該單元格渲染器的內容,將原點移動到新位置,重新繪製它,等等。標準的JLabel組件並不是用於這種方式,我們希望避免每次繪製單元格時觸發一次重新驗證。這會大大降低性能,因爲重新驗證消息將通過容器的層次結構傳遞,以確定是否會影響任何其他組件。由於渲染器在繪畫操作的整個生命週期中只是父對象,因此我們同樣希望避免與繪製操作的層次結構相關的開銷。因此,該類將重寫validate,invalidate,revalidate,repaint和firePropertyChange方法爲no-ops,並僅覆蓋isOpaque方法以提高性能。如果您編寫自己的渲染器,請牢記這一性能考慮因素。

這實際上是JB在上面解釋的。

感謝(快速)回答

+1

在'CellRendererPane'中可以找到類似的優化,由'TableUI'委託使用並在[此處](http://stackoverflow.com/a/7776211/230513)中進行說明。 – trashgod