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
Esta columna de botón de tabla de Rob Camick puede ajustarse a sus necesidades.
Este artículo proporciona un enfoque más fácil para su problema sin agregar MouseListeners y calcular si el clic está realmente en el botón o no:
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.