2012-12-02 12 views
5

Spesso, quando si utilizzano le scritture di utente JTable o JTree e assegnarlo è il proprio renderer di celle specifico.Difficoltà a comprendere il meccanismo di rendering di swing JTable e JTree

È molto comune ereditare il componente dell'utente da DefaultTableCellRenderer e implementa il metodo di rendering getTableCellRendererComponent. Si scopre che DefaultTableCellRenderer infatti eredita da JLabel, quindi restituisce se stesso (this) quando viene chiamato a super (nel metodo di rendering) e quindi il renderer dell'utente può analogamente restituire se stesso (questo).

E tutto funziona bene.

La mia domanda è come può essere?

Ogni volta che questo metodo viene chiamato dalla tabella, vengono assegnati parametri diversi e l'etichetta di uscita viene modificata come funzione di questi parametri. Se è effettivamente la stessa istanza dell'etichetta - non dovrebbe essere modificato in base all'ultima chiamata a questo metodo? Non significa che tutte le celle della tabella sono infettate composte dalla stessa istanza dell'etichetta, che contiene lo stesso valore (valore dell'ultima chiamata al metodo di rendering)?

Ho cercato sul web, e scavare nel codice di swing, e non poteva trovare alcun atto di clone o costruttore di copia che duplica in realtà l'etichetta di uscita. Non sono riuscito a trovare alcuna prova che (forse) swing usi la riflessione per riattivare il renderer ogni volta da zero.

Ho letto l'oscillazione del tutorial on JTables, e non ci sono riuscito a trovare le prossime righe:

ci si potrebbe aspettare ogni cella di una tabella per essere un componente. Tuttavia, per motivi di prestazioni, le tabelle Swing vengono implementate in modo diverso. Invece, un renderer a cella singola viene generalmente utilizzato per disegnare tutte le celle che contengono lo stesso tipo di dati. Si può pensare al renderer come a un timbro di inchiostro configurabile che la tabella usa per stampare in modo appropriato i dati formattati su ogni cella. Quando l'utente inizia a modificare i dati di una cella, un editor di celle assume la direzione della cella, controllando il comportamento di modifica della cella.

Danno un suggerimento, che in effetti quello che sto dicendo è corretto, ma non spiegano come il suo effettivamente compiuto.

Non riesco a capirlo. Qualcuno di voi?

risposta

10

È un'implementazione di flyweight pattern.

Quando JTable si ripresenta, inizia un ciclo e scorre su ogni cella che deve essere dipinta.

Per ogni cella, richiama il renderer con gli argomenti corrispondenti alla cella. Il renderer restituisce un componente. Questo componente è dipinto nel rettangolo corrispondente alla cella della tabella corrente.

Poi il rendering è chiamato per la cella successiva, e il componente restituito (che ha un testo e colore diverso, per esempio), è dipinto nel rettangolo corrispondente alla cella, ecc

Immaginiamo che ciascun quando viene richiamato il renderer, viene catturato e incollato uno screenshot del componente restituito nella cella della tabella.

+1

+1 La metafora dello screenshot è buona. Ho pensato che il più usato fosse un 'francobollo' ma lo screenshot potrebbe essere più chiaro – Robin

+1

Grazie. la metafora certenly fa il trucco :). ora è capito. –

4

In adition a @ JB chiaro explication di come JTable e JTree utilizzare il flyweight pattern, notare come entrambe le classi forniscono metodi pubblici getCellRenderer() e getCellEditor(). Esaminare questi metodi per vedere come JTable utilizza Class Literals as Runtime-Type Tokens per selezionare un renderer o un editor per classe, se nessuno è specificato dalla colonna. Internamente, JTable utilizza uno Hashtable defaultRenderersByColumnClass per l'archiviazione di istanza.

+0

Vedere anche questo relativo [esempio] (http://stackoverflow.com/a/7776211/230513). – trashgod

3

Dopo qualche scavo, hanno trovato la nota successiva implementazione da DefaultTableCellRenderer documentation:

Attuazione Nota: Questa classe eredita da JLabel, una classe di componente standard. Tuttavia, JTable utilizza un meccanismo unico per il rendering delle sue celle e pertanto richiede un comportamento leggermente modificato dal suo renderer di celle. La classe table definisce un renderer a cella singola e lo utilizza come un timbro di gomma per il rendering di tutte le celle nella tabella; esegue il rendering della prima cella, modifica il contenuto di tale renderer di celle, sposta l'origine nella nuova posizione, la ridisegna e così via. Il componente JLabel standard non è stato progettato per essere utilizzato in questo modo e vogliamo evitare l'attivazione di un rinnovo ogni volta che la cella viene disegnata. Ciò ridurrebbe notevolmente le prestazioni poiché il messaggio di convalida sarebbe passato alla gerarchia del contenitore per determinare se eventuali altri componenti sarebbero interessati. Dato che il renderer è solo genitoriale per la durata di un'operazione di pittura, allo stesso modo vogliamo evitare l'overhead associato alla camminata della gerarchia per le operazioni di pittura. Quindi questa classe sovrascrive i metodi validate, invalidate, revalidate, repaint e firePropertyChange come no-op e sostituisce il metodo isOpaque esclusivamente per migliorare le prestazioni. Se scrivi il tuo riproduttore, tieni presente questa considerazione sulle prestazioni.

Questo è essenzialmente ciò che JB ha spiegato sopra.

Grazie per le risposte (rapide)

+1

Le ottimizzazioni simili si trovano in 'CellRendererPane', utilizzate dal delegato' TableUI' e illustrate [qui] (http://stackoverflow.com/a/7776211/230513). – trashgod

Problemi correlati