Here is the screenshot of what I want to do :
What\'s happening there
This Table Button Column from Rob Camick may fit your needs.
This articles provides an easier approach to your problem without adding MouseListeners and computing if the click is actually on the button or not:
http://web.archive.org/web/20100623105810/http://ivolo.mit.edu/post/A-Simple-Pattern-for-Embedding-Components-into-a-Swing-JTable.aspx
Here is my solution
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;
}
};
}
}
And here is how to use it:
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);
}
}
});
The problem is that the JButton
no longer exists when painted in the table. Those components are only used to create a 'stamp' when the table is rendered. There is no actual button present.
There is a way to allow you to click on the button, and still keep your table non-editable, but it is far from proper code. Just a quick outline for a possible solution (I do not have the time at this moment to give a full code example)
doClick
method)And this is not even the dirty part of the code. Since your renderer (hopefully) does not return a new JButton
each time, you should in your ActionListener
which is attached to the JButton
keep track of for which component the click actually occurred. A possible solution is to keep a reference to the table model value for which you the last time created a JButton
(so in the getCellRendererComponent
method keep track of the row/column), but I am unsure whether this is the best approach.
As said, a possible solution but far from elegant.
The easiest way is to just make that one column editable and use an editor, as pointed out in other answers
Overload your Table model, and set isCellEditable(int, int) return false for the cells with buttons.
It works great in with a MouseListener added to the table.
Try this:
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();
}
}
}