Java - JButton in a JTable cell

Now we shall discuss how to include a JButton in a table cell.

ButtonJTable.java

     
    /*
     * ButtonJTable.java
     *
     * Created on Aug 3, 2013, 02:57:58 PM
     */
    package me.dhanoop.forblog;

    import java.awt.Component;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    import javax.swing.JTable;
    import javax.swing.UIManager;
    import javax.swing.table.DefaultTableModel;
    import javax.swing.table.TableCellRenderer;

    /**
     *
     * @author dhanoopbhaskar
     */
    public class ButtonJTable extends javax.swing.JFrame {

        private JButton tableData = null;

        /** Creates new form ButtonJTable */
        public ButtonJTable() {
            initComponents();
            customizeTable();
        }

        /** This method is called from within the constructor to
         * initialize the form.
         * WARNING: Do NOT modify this code. The content of this method is
         * always regenerated by the Form Editor.
         */
        @SuppressWarnings("unchecked")
        // 
        private void initComponents() {

            dbScrollPane = new javax.swing.JScrollPane();
            dbTable = new javax.swing.JTable();

            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

            dbTable.setModel(new javax.swing.table.DefaultTableModel(
                new Object [][] {

                },
                new String [] {
                    "Title 1"
                }
            ));
            dbScrollPane.setViewportView(dbTable);

            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
            getContentPane().setLayout(layout);
            layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(dbScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 226, javax.swing.GroupLayout.PREFERRED_SIZE)
            );
            layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(dbScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
            );

            pack();
        }// 

        /**
         * @param args the command line arguments
         */
        public static void main(String args[]) {
            java.awt.EventQueue.invokeLater(new Runnable() {

                public void run() {
                    new ButtonJTable().setVisible(true);
                }
            });
        }
        // Variables declaration - do not modify
        private javax.swing.JScrollPane dbScrollPane;
        private javax.swing.JTable dbTable;
        // End of variables declaration

        private void customizeTable() {
            Object[] columnNames = new Object[1];
            columnNames[0] = "Button";
            String buttonString = "Click Me";
            Object[][] rowData = new Object[1][1];
            rowData[0][0] = buttonString;
            DefaultTableModel tableModel = new DBTableModel(rowData, columnNames);
            dbTable.setModel(tableModel);
            tableData = new JButton(buttonString);
            tableData.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showMessageDialog(new JFrame(), "I'm clicked!", "ButtonJTable", JOptionPane.INFORMATION_MESSAGE);
                }
            });

            dbTable.getColumnModel().getColumn(0).setCellEditor(new ButtonCellEditor(new JCheckBox()));
            dbTable.getColumnModel().getColumn(0).setCellRenderer(new TableCellRenderer() {

                public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                    if (isSelected) {
                        setForeground(table.getSelectionForeground());
                        setBackground(table.getSelectionBackground());
                    } else {
                        setForeground(table.getForeground());
                        setBackground(UIManager.getColor("Button.background"));
                    }
                    tableData.setText((value == null) ? "" : value.toString());
                    return tableData;
                }
            });

            dbTable.updateUI();
        }
    }

DBTableModel.java

     
    package me.dhanoop.forblog;

    import javax.swing.table.DefaultTableModel;

    /**
     *
     * @author dhanoopbhaskar
     */
    public class DBTableModel extends DefaultTableModel {

        public DBTableModel(Object[] columns) {
            super(columns, 0);
        }

        public DBTableModel(Object[][] data, Object[] columns) {
            super(data, columns);
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return true;
        }
    }

The following is the key snippet in the program.

Here we do mainly two things:

  1. Changing the CellEditor of the ColumnModel of the column at position 0 (zero) of the table.

  2. Changing the CellRenderer of the ColumnModel of the column at position 0 (zero) of the table. 

Unlike JComboBox and JCheckBox, for JButton we don’t have a suitable constructor. 

    public javax.swing.DefaultCellEditor(javax.swing.JTextField); 
    public javax.swing.DefaultCellEditor(javax.swing.JCheckBox);
    public javax.swing.DefaultCellEditor(javax.swing.JComboBox);

The above are the ONLY available constructors for DefaultCellEditor. Hence we have to create fully customized DefaultCellEditor for JButton.

     
        private void customizeTable() {
            Object[] columnNames = new Object[1];
            columnNames[0] = "Button";
            String buttonString = "Click Me";
            Object[][] rowData = new Object[1][1];
            rowData[0][0] = buttonString;
            DefaultTableModel tableModel = new DBTableModel(rowData, columnNames);
            dbTable.setModel(tableModel);
            tableData = new JButton(buttonString);
            tableData.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showMessageDialog(new JFrame(), "I'm clicked!", "ButtonJTable", JOptionPane.INFORMATION_MESSAGE);
                }
            });

            dbTable.getColumnModel().getColumn(0).setCellEditor(new ButtonCellEditor(new JCheckBox()));
            dbTable.getColumnModel().getColumn(0).setCellRenderer(new TableCellRenderer() {

                public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                    if (isSelected) {
                        setForeground(table.getSelectionForeground());
                        setBackground(table.getSelectionBackground());
                    } else {
                        setForeground(table.getForeground());
                        setBackground(UIManager.getColor("Button.background"));
                    }
                    tableData.setText((value == null) ? "" : value.toString());
                    return tableData;
                }
            });

            dbTable.updateUI();
        }

Please find below an example of such a customized DefaultCellEditor

ButtonCellEditor.java

     
    package me.dhanoop.forblog;

    import java.awt.Component;
    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.JOptionPane;
    import javax.swing.JTable;

    /**
     *
     * @author dhanoopbhaskar
     */
    public class ButtonCellEditor extends DefaultCellEditor {

        private JButton button = null;
        private String buttonText = null;
        private boolean isClicked;

        public ButtonCellEditor(JCheckBox checkBox) {
            super(checkBox);
            button = new JButton();
            button.setOpaque(true);
            button.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    fireEditingStopped();
                }
            });
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value,
                boolean isSelected, int row, int column) {
            if (isSelected) {
                button.setForeground(table.getSelectionForeground());
                button.setBackground(table.getSelectionBackground());
            } else {
                button.setForeground(table.getForeground());
                button.setBackground(table.getBackground());
            }
            buttonText = (value == null) ? "" : value.toString();
            button.setText(buttonText);
            isClicked = true;
            return button;
        }

        @Override
        public Object getCellEditorValue() {
            if (isClicked) {
                JOptionPane.showMessageDialog(button, "I'm clicked!", "ButtonJTable", JOptionPane.INFORMATION_MESSAGE);
            }
            isClicked = false;
            return buttonText;
        }

        @Override
        public boolean stopCellEditing() {
            isClicked = false;
            return super.stopCellEditing();
        }

        @Override
        protected void fireEditingStopped() {
            super.fireEditingStopped();
        }
    }