Difficoltà a comprendere il meccanismo di rendering di swing JTable e JTree

Spesso, quando si usa JTable o JTree utente scrive e lo assegna come un proprio riproduttore di celle specifico.

È 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 output 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 significherebbe 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 ho scavato nel codice di Swing, e non sono riuscito a trovare alcun atto di clone o copy constructor che effettivamente duplichi l’etichetta di output. Non sono riuscito a trovare alcuna prova che (forse) swing usi la riflessione per ritriggersre il renderer ogni volta da zero.

    Ho letto il tutorial di Swing su JTables e lì ho trovato le righe seguenti:

    Potresti aspettarti che ogni cella di una tabella sia 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 spiegare come sia stato realizzato.

    Non riesco a capirlo. Qualcuno di voi?

    È un’implementazione del modello del peso mosca .

    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.

    Quindi il renderer viene chiamato per la cella successiva e il componente restituito (che ha un testo e un colore diverso, ad esempio), viene dipinto nel rettangolo corrispondente alla cella, ecc.

    Immagina che ogni volta che viene chiamato il programma di rendering, uno screenshot del componente restituito venga prelevato e incollato nella cella della tabella.

    In aggiunta alla chiara spiegazione di @ JB su come JTable e JTree usano il modello di peso mosca , si noti come entrambe le classi forniscono metodi pubblici getCellRenderer() e getCellEditor() . Esaminare questi metodi per vedere come JTable utilizza Class Literals come token di tipo Runtime per selezionare un renderer o un editor per class, se nessuno è specificato dalla colonna. Internamente, JTable utilizza un Hashtable defaultRenderersByColumnClass per l’archiviazione dell’istanza.

    Dopo alcuni scavi, trova la prossima nota di implementazione dalla documentazione di DefaultTableCellRenderer :

    Nota di implementazione: questa class eredita da JLabel, una class 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 class 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’triggerszione 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 class 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 (veloci) risposte