Dopo il coding.mof's reply, ho finalmente fatto quello che volevo. Tuttavia, volevo una risposta più completa a questa domanda, quindi ne fornirò una io stesso.
Quindi, i Renderizzatori di celle disegnano semplicemente il componente e non consentono alcuna interazione al suo interno. Mentre gli editor di celle lo fanno.
Inizialmente, tutte le celle di JTable sono componenti restituiti dal programma di rendering registrato. Tuttavia, quando viene selezionata una cella, questo componente viene sostituito da un componente che viene restituito dall'editor. Questi due possono effettivamente essere diversi componenti! Che sono abbastanza sicuro di poter sfruttare questo vantaggio e creare alcune celle funky: P
Ad ogni modo, in questo esempio, sia il renderer che l'editor visualizzano lo stesso componente, quindi creeremo un componente che verrà utilizzato da entrambi.
In primo luogo, abbiamo bisogno di creare un TableModel che restituisce la nostra ADT:
class MyClassTableModel extends DefaultTableModel {
List<MyClass> data;
public MyClassTableModel(List<MyClass> data) {
this.data = data;
}
public Class<?> getColumnClass(int columnIndex) { return MyClass.class; }
public int getColumnCount() { return 1; }
public String getColumnName(int columnIndex) { return "MyClass"; }
public int getRowCount() { return (data == null) ? 0 : data.size(); }
public Object getValueAt(int rowIndex, int columnIndex) { return data.get(rowIndex); }
public boolean isCellEditable(int rowIndex, int columnIndex) { return true; }
}
Ora, creiamo un componente che verrà condiviso tra il rendering e l'Editor:
class MyClassCellComponent extends JPanel() {
MyClass myClass;
public MyClassCellComponent() {
// initialize components (labels, buttons, etc.)
// add action listeners
}
public void updateData(MyClass myClass, boolean isSelected, JTable table) {
this.myClass = myClass;
// update buttons, labels etc. accordingly
}
}
L'isSelected e i parametri della tabella sono usati per rendere lo sfondo del pannello e sono opzionali.Ecco come il renderer utilizza il nostro componente:
class MyClassCellRenderer implements TableCellRenderer {
MyClassCellComponent panel;
public MyClassCellRenderer() {
panel = new MyClassCellComponent();
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
MyClass myClass = (MyClass)value;
panel.updateData(myClass, isSelected, table);
return panel;
}
}
Ed ecco come l'editor usa:
class MyClassCellEditor extends AbstractCellEditor {
MyClassCellComponent panel;
public MyClassCellEditor() {
panel = new MyClassCellComponent();
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
MyClass myClass = (MyClass)value;
panel.updateData(myClass, true, table);
return panel;
}
public Object getCellEditorValue() {
return null;
}
}
Questo è tutto. Ora possiamo semplicemente creare una JTable come segue:
JTable myClassTable = new JTable(new MyClassTableModel());
myClassTable.setDefaultRenderer(MyClass.class, new MyClassCellRenderer());
myClassTable.setDefaultEditor(MyClass.class, new MyClassCellEditor());
E abbiamo finito!
P.S. Sono abbastanza sicuro che possiamo combinare Renderer e Editor in una singola classe, estendere AbstractCellEditor e implementare TableCellRenderer, ma non sono sicuro delle prestazioni.
Ciò significa che non ho più bisogno del mio CellRenderer? Lo faccio in un CellEditor? – pek
No. Se si esegue questa operazione, verrà visualizzata una cella vuota. JTable utilizza internamente il renderer solo per la visualizzazione dei dati. Ma se si fa clic su una cella diventerà modificabile e verrà visualizzato il componente fornito dal celleditor. –
Sì, l'ho provato subito dopo che ti ho chiesto e in effetti questo è il caso. Grazie! – pek