agregar java swing jtable jbutton

java - agregar - Haciendo clic en JButton dentro de una JTable



agregar jbutton a jtable java (6)

Aquí está mi solución

ButtonEditor.java

public abstract class ButtonEditor extends DefaultCellEditor implements ActionListener { private static final long serialVersionUID = 1L; /** The cell''s row. */ protected int row; /** The cell''s column. */ protected int column; /** The cell''s column. */ protected JTable table; /** The button we are editing. */ protected JButton button; /** The panel used when editing. */ protected JPanel panel = new JPanel(new GridBagLayout()); /** Constructor */ public ButtonEditor() {super(new JCheckBox());} /** * This method is called when the user try to modify a cell. * In this case it will be called whenever the user click on the cell. * @param table * @param value * @param isSelected * @param row * @param column * @return JPanel The JPanel returned contains a JButton with an ActionListener. */ @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { this.row = row; this.column = column; this.table = table; button = (JButton) value; //prevent to add the action listener everytime the user click on the cell. if(button.getActionListeners().length == 0) button.addActionListener(this); panel.add(button); panel.setBackground(table.getGridColor()); return panel; } /** * Return a renderer for JButtons. The result is a button centered in the table''s cell. * @return */ public static TableCellRenderer getRenderer() { return new TableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JPanel panel = new JPanel(new GridBagLayout()); panel.add((JButton) value); panel.setBackground(table.getGridColor()); return panel; } }; }

}

Y aquí está cómo usarlo:

Demo.java

table.setDefaultRenderer(JButton.class, ButtonEditor.getRenderer()); table.setDefaultEditor(JButton.class, new ButtonEditor() { @Override public void actionPerformed(ActionEvent e) { //handle clicks here. for example: if(column == 5) { System.out.Println(row); button.setFocusPainted(false); } } });

Aquí está la captura de pantalla de lo que quiero hacer:

Lo que sucede allí es que JButton se muestra correctamente, pero no ocurre nada cuando hago clic en él. Después de buscar, he encontrado que el Object devuelto por table.getValueAt() es una cadena en lugar de un JButton ...

Aquí está el código:

tblResult = new JTable(data,cols) { public TableCellRenderer getCellRenderer( int row, int column ) { return new ClientsTableRenderer(); } };

Lo uso para poblar en tiempo de ejecución la JTable: ( tblResult ahora es Clients.rblResult )

SwingUtilities.invokeLater( new Runnable() { public void run() { DefaultTableModel aModel = new DefaultTableModel() { //setting the jtable read only @Override public boolean isCellEditable(int row, int column) { return false; } }; String[] cols = {"N°","Société", "TVA", "CP", "Ville", ""}; aModel.setColumnIdentifiers(cols); Object[] temp = new Object[6]; for(int i=0;i<result.length;i++) { temp[0] = result[i].custNumber; temp[1] = result[i].name; temp[2] = result[i].tva; temp[3] = result[i].cp; temp[4] = result[i].city; temp[5] = "Consulter"; aModel.addRow(temp); } Clients.tblResult.setModel(aModel); Clients.tblResult.addMouseListener(new JTableButtonMouseListener(Clients.tblResult)); }} );

Aquí la clase ClientsTableRenderer

public class ClientsTableRenderer extends JPanel implements TableCellRenderer { @Override public Component getTableCellRendererComponent( final JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setBackground(Color.WHITE); if(column < 5) { JLabel label = new JLabel(value.toString()); JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER,0,9)); panel.setBackground(Color.WHITE); panel.add(label); this.add( panel); } else { JButton button = new JButton(value.toString()); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { System.out.println("Clicked !"); } }); JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER,0,3)); panel.setBackground(Color.WHITE); panel.add(button); this.add(panel); } return this; } }

Y finalmente, el JTableButtonMouseListener ():

public class JTableButtonMouseListener extends MouseAdapter { private final JTable table; public JTableButtonMouseListener(JTable table) { this.table = table; } @Override public void mouseClicked(MouseEvent e) { int column = table.getColumnModel().getColumnIndexAtX(e.getX()); int row = e.getY()/table.getRowHeight(); System.out.println("Col :"+column + "row:"+row); if (row < table.getRowCount() && row >= 0 && column < table.getColumnCount() && column >= 0) { Object value = table.getValueAt(row, column); System.out.println("Value :"+value.getClass().getName()); if (value instanceof JButton) { ((JButton)value).doClick(); } } } }

Soy amablemente nuevo en Java, la ayuda sería muy apreciada :)

Gracias por adelantado !


El problema es que JButton ya no existe cuando está pintado en la tabla. Esos componentes solo se usan para crear un ''sello'' cuando se procesa la tabla. No hay un botón real presente.

Hay una manera de permitirle hacer clic en el botón y mantener su tabla no editable , pero está lejos del código correcto. Solo un resumen rápido para una posible solución (no tengo tiempo en este momento para dar un ejemplo completo de código)

  • adjuntar un oyente de ratón a la mesa
  • cuando recibe un clic del mouse, determine la celda en la que se produjo el clic del mouse
  • pregunte en el procesador de tabla por el componente para esa celda
  • utilice la ubicación del clic del mouse para determinar si hay un botón presente en el componente del paso anterior en esa ubicación en particular
  • si es así, haz clic en el botón api (el método doClick )

Y esta ni siquiera es la parte sucia del código. Dado que su procesador (con suerte) no devuelve un nuevo JButton cada vez, debe en su ActionListener que se adjunta a la pista de control de JButton para qué componente se produjo realmente el clic. Una posible solución es mantener una referencia al valor del modelo de tabla para el que creó la última vez un JButton (de modo que en el método getCellRendererComponent un seguimiento de la fila / columna), pero no estoy seguro de si este es el mejor enfoque.

Como dije, una posible solución pero lejos de ser elegante.

La forma más fácil es hacer que esa columna sea editable y usar un editor, como se señala en otras respuestas




Prueba esto:

import java.awt.Color; import java.awt.Component; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.DefaultCellEditor; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.UIManager; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableModel; public class TableWithButtonDemo { private JFrame frame = new JFrame("Table Demo"); private String[] columnNames = { "String", "Integer", "Float", "" }; private Object[][] data = { { "Dummy", new Integer(12), new Float(12.15), "Consulter" } }; private TableModel model = new DefaultTableModel(data, columnNames) { private static final long serialVersionUID = 1L; public boolean isCellEditable(int row, int column) { return column == 3; } }; private JTable table = new JTable(model); public TableWithButtonDemo() { table.getColumnModel().getColumn(3).setCellRenderer(new ClientsTableButtonRenderer()); table.getColumnModel().getColumn(3).setCellEditor(new ClientsTableRenderer(new JCheckBox())); table.setPreferredScrollableViewportSize(table.getPreferredSize()); table.setShowHorizontalLines(true); table.setShowVerticalLines(false); JScrollPane scroll = new JScrollPane(table); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(scroll); frame.pack(); frame.setLocation(150, 150); frame.setVisible(true); } public static void main(String[] args) throws Exception { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); EventQueue.invokeLater(new Runnable() { public void run() { new TableWithButtonDemo(); } }); } class ClientsTableButtonRenderer extends JButton implements TableCellRenderer { public ClientsTableButtonRenderer() { setOpaque(true); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setForeground(Color.black); setBackground(UIManager.getColor("Button.background")); setText((value == null) ? "" : value.toString()); return this; } } public class ClientsTableRenderer extends DefaultCellEditor { private JButton button; private String label; private boolean clicked; private int row, col; private JTable table; public ClientsTableRenderer(JCheckBox checkBox) { super(checkBox); button = new JButton(); button.setOpaque(true); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { fireEditingStopped(); } }); } public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { this.table = table; this.row = row; this.col = column; button.setForeground(Color.black); button.setBackground(UIManager.getColor("Button.background")); label = (value == null) ? "" : value.toString(); button.setText(label); clicked = true; return button; } public Object getCellEditorValue() { if (clicked) { JOptionPane.showMessageDialog(button, "Column with Value: "+table.getValueAt(row, 1) + " - Clicked!"); } clicked = false; return new String(label); } public boolean stopCellEditing() { clicked = false; return super.stopCellEditing(); } protected void fireEditingStopped() { super.fireEditingStopped(); } } }


Sobrecargue su modelo de tabla y establezca isCellEditable (int, int) return false para las celdas con botones.

Funciona muy bien con un MouseListener agregado a la mesa.