Después de coding.mof's reply, finalmente hice lo que quería. Sin embargo, quería una respuesta más completa para esta pregunta, por lo que me proporcionaré una.
Por lo tanto, Cell Renderers simplemente dibuja el componente y no permite ninguna interacción dentro de él. Mientras que los editores de celulares lo hacen.
Inicialmente, todas las celdas en la JTable son componentes que son devueltos por el renderizador registrado. Sin embargo, cuando se selecciona una celda, este componente se reemplaza por un componente que devuelve el editor. ¡Estos dos realmente pueden ser componentes diferentes! Estoy bastante seguro de que puede aprovechar esto y crear algunas celdas funky: P
De todos modos, en este ejemplo, tanto el renderizador como el editor muestran el mismo componente, por lo que crearemos un componente que se usará Por ambos.
En primer lugar, tenemos que crear un TableModel que devuelve nuestra 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; }
}
Ahora, creamos un componente que será compartido entre el Procesador y el 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
}
}
El isSelected y los parámetros de la tabla se utilizan para representar el fondo del panel y son opcionales.Aquí es cómo el procesador utiliza nuestro 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;
}
}
Y aquí es cómo el editor lo utiliza:
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;
}
}
Eso es todo. Ahora podemos simplemente crear una JTable de la siguiente manera:
JTable myClassTable = new JTable(new MyClassTableModel());
myClassTable.setDefaultRenderer(MyClass.class, new MyClassCellRenderer());
myClassTable.setDefaultEditor(MyClass.class, new MyClassCellEditor());
¡Y listo!
P.S. Estoy bastante seguro de que podemos combinar el Renderizador y el Editor en una única clase. Extiende AbstractCellEditor e implementa TableCellRenderer, pero no estoy seguro del rendimiento.
¿Esto significa que ya no necesito mi CellRenderer? Acabo de convertirlo en un CellEditor? – pek
No. Si hiciera esto, se mostraría una celda en blanco. JTable utiliza internamente el procesador solo para mostrar datos. Pero si hace clic en una celda, se volverá editable y se mostrará el componente provisto por la celda. –
Sí, lo probé justo después de que te lo pregunté y de hecho este es el caso. ¡Gracias! – pek