2010-08-31 16 views
5

Quiero poder tener un JPanel en una celda con un JButton que hace algo de trabajo cuando se hace clic.JTable: Botones en el Panel personalizado en la Celda

Busqué tutoriales sobre editores de celdas, pero todos los ejemplos a hablar de la sustitución de la celda con otro componente (por ejemplo, reemplazar un int con un JTextField etc.) Mi situación es un poco diferente:

tengo el siguiente ADT

class MyClass { 
    public String title; 
    public String url; 
    public String path; 
    public int annotations; 
} 

Creé un modelo de celda de tabla personalizado que tiene 1 columna y la clase para esa columna es MyClass. Entonces creé un procesador de celdas para esa clase que devuelve un JPanel como se muestra aquí:

MyClass Cell Renderer

Como se puede ver, el JPanel contiene un botón. Quiero que este botón ejecute un JFrame cada vez que haga clic. ¿Algunas ideas?

Si va a sugerir Cell Editor, sea un poco más específico sobre cómo hacerlo. Si es posible, proporcione algún pseudocódigo.

Gracias.

P.S. Estoy bastante seguro de que el título de esta pregunta necesita algo de trabajo. ;)

Respuesta

7

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.

5
public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor { 

JComponent pan = new JPanel(); 

public MyTableCellEditor() { 
    pan.add(btn); 
    // add all elments you need to your panel 
    btn.addActionListener(/* the listener which will handle the events */); 
} 

public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int rowIndex, int vColIndex) { 
    btn.setText(/* according to row or whatever*/); 
    // set all elemnts of you panel to the according values 
    // or add dynamically an action listener 
    return pan; 
} 
public Object getCellEditorValue() { return new Void(); } 
} 

Así que en su oyente que tendrá que comprobar la selección de la tabla de manera que pueda responder de diferentes maneras para cada fila. Si desea mantener todos los elementos en una columna, puede reemplazar el JButton con su panel que contiene todos los componentes. La JTable reenviará todos los eventos a ese JPanel.

+0

¿Esto significa que ya no necesito mi CellRenderer? Acabo de convertirlo en un CellEditor? – pek

+0

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. –

+0

Sí, lo probé justo después de que te lo pregunté y de hecho este es el caso. ¡Gracias! – pek

0

Puede crear una tabla con varias columnas, luego puede agregar una columna separada para contener su botón. La clase Table Button Column le permite hacer esto fácilmente.

+1

Quería evitar esto porque quiero poder colocar mis componentes como quiera (como se ve en la captura de pantalla) y no uno al lado del otro. – pek

+0

Entonces aún podría ser más fácil tener dos columnas. Uno para sus datos y otro para el botón. Puede eliminar las líneas verticales de la tabla para que parezca una sola columna. – camickr

Cuestiones relacionadas