4

I am trying to make a dynamic table that fetches data from a database and adds those data in separate rows..I want to add an extra cell with each row(dynamically) that contains two buttons...and on clicking those buttons some event should occur only on the respective row..
(P.S: I have managed to fetch data from the database and add it to the table though..)

Here is an example:

_____________________________________________________________
ID  | Name | Application for leave | Accept/Reject           |
--------------------------------------------------------------
1   |AD    | xxxxxxxxxxxxxxxxxx    |AcceptButton RejectButton| 
2   |SD    | xxxxxxxxxxxxxxxxxx    |AcceptButton RejectButton|
3   |PD    | xxxxxxxxxxxxxxxxxx    |AcceptButton RejectButton|
4   |DD    | xxxxxxxxxxxxxxxxxx    |AcceptButton RejectButton|
5   |MD    | xxxxxxxxxxxxxxxxxx    |AcceptButton RejectButton|
--------------------------------------------------------------

The AcceptButton and RejectButton should be dynamically added with each row during runtime..If I press the AcceptButton or RejectButton that row should automatically get deleted and the row with the respective ID in the database should get updated..

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Code Zero
  • 113
  • 2
  • 9
  • 1
    Take a look at [this blog post](http://tips4java.wordpress.com/2009/07/12/table-button-column/) – Robin Jul 10 '13 at 07:52
  • 1
    Can you show us what you have tried so far? – mthmulders Jul 10 '13 at 07:53
  • @Robin: Okhay...that answers a small part of my question.. – Code Zero Jul 10 '13 at 07:57
  • @mthmulders : you wanna see a screenshot of the window? – Code Zero Jul 10 '13 at 07:58
  • @CodeZero According to your summary, you have tried something to add two buttons in a single cell, but it didn't work. If you show us how you tried to achieve that (relevant code snippets, _maybe_ a screenshot of what it looks like) we might be able to help you. But its hard to assist you when we don't see what your attempts look like. – mthmulders Jul 10 '13 at 08:02
  • @mthmulders: I haven't managed to add any buttons... Here is screenshot of what I did and what I want to do: http://oi42.tinypic.com/11hgty0.jpg – Code Zero Jul 10 '13 at 08:08
  • @CodeZero In that case your title is a bit misleading. Please see http://www.whathaveyoutried.com. – mthmulders Jul 10 '13 at 08:12
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Jul 10 '13 at 08:29

3 Answers3

9

There are a few things you need to get this to work.

  • A table model that can support the required functionality, namely the removal of the rows
  • A cell renderer capable of rendering the buttons within a single cell
  • A cell editor capable of providing the editing functionality, so you can determine which button was clicked and take appropriate actions

Start by taking a look at How to use Tables for more details

enter image description here

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;

public class MultiButtonTable {

    public static void main(String[] args) {
        new MultiButtonTable();
    }

    public MultiButtonTable() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                MyTableModel model = new MyTableModel();
                model.add(new Data(1, "AD", "Blah 1"));
                model.add(new Data(2, "SD", "Blah 2"));
                model.add(new Data(3, "PD", "Blah 3"));
                model.add(new Data(4, "DD", "Blah 4"));
                model.add(new Data(5, "MD", "Blah 5"));

                JTable table = new JTable(model);
                AcceptRejectRenderer renderer = new AcceptRejectRenderer();
                table.getColumnModel().getColumn(3).setCellRenderer(renderer);
                table.getColumnModel().getColumn(3).setCellEditor(new AcceptRejectEditor());
                table.setRowHeight(renderer.getTableCellRendererComponent(table, null, true, true, 0, 0).getPreferredSize().height);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class Data {

        private int id;
        private String name;
        private String application;

        public Data(int id, String name, String application) {
            this.id = id;
            this.name = name;
            this.application = application;
        }

        public int getID() {
            return id;
        }

        public void setID(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getApplication() {
            return application;
        }

        public void setApplication(String application) {
            this.application = application;
        }
    }

    public class MyTableModel extends AbstractTableModel {

        private List<Data> data;

        public MyTableModel() {
            data = new ArrayList<>(25);
        }

        @Override
        public String getColumnName(int column) {
            String value = null;
            switch (column) {
                case 0:
                    value = "ID";
                    break;
                case 1:
                    value = "Name";
                    break;
                case 2:
                    value = "Application for leave";
                    break;
                case 3:
                    value = "Accept/Reject";
                    break;
            }
            return value;
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            Class value = Object.class;
            switch (columnIndex) {
                case 0:
                    value = Integer.class;
                    break;
                case 1:
                    value = String.class;
                    break;
                case 2:
                    value = String.class;
                    break;
            }
            return value;
        }

        @Override
        public int getRowCount() {
            return data.size();
        }

        @Override
        public int getColumnCount() {
            return 4;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            Data obj = data.get(rowIndex);
            Object value = null;
            switch (columnIndex) {
                case 0:
                    value = obj.getID();
                    break;
                case 1:
                    value = obj.getName();
                    break;
                case 2:
                    value = obj.getApplication();
                    break;
                case 3:
                    break;
            }
            return value;
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            if (columnIndex == 3) {

                System.out.println(aValue);

                Data value = data.get(rowIndex);
                if ("accept".equals(aValue)) {
                    System.out.println("Accepted");
                } else {
                    System.out.println("Rejected");
                }
                fireTableCellUpdated(rowIndex, columnIndex);
                remove(value);

            }
        }

        public void add(Data value) {
            int startIndex = getRowCount();
            data.add(value);
            fireTableRowsInserted(startIndex, getRowCount() - 1);
        }

        public void remove(Data value) {
            int startIndex = data.indexOf(value);
            System.out.println("startIndex = " + startIndex);
            data.remove(value);
            fireTableRowsInserted(startIndex, startIndex);
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return columnIndex == 3;
        }
    }

    public class AcceptRejectPane extends JPanel {

        private JButton accept;
        private JButton reject;
        private String state;

        public AcceptRejectPane() {
            setLayout(new GridBagLayout());
            accept = new JButton("Accept");
            accept.setActionCommand("accept");
            reject = new JButton("Reject");
            reject.setActionCommand("reject");

            add(accept);
            add(reject);

            ActionListener listener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    state = e.getActionCommand();
                    System.out.println("State = " + state);
                }
            };

            accept.addActionListener(listener);
            reject.addActionListener(listener);
        }

        public void addActionListener(ActionListener listener) {
            accept.addActionListener(listener);
            reject.addActionListener(listener);
        }

        public String getState() {
            return state;
        }
    }

    public class AcceptRejectRenderer extends DefaultTableCellRenderer {

        private AcceptRejectPane acceptRejectPane;

        public AcceptRejectRenderer() {
            acceptRejectPane = new AcceptRejectPane();
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            if (isSelected) {
                acceptRejectPane.setBackground(table.getSelectionBackground());
            } else {
                acceptRejectPane.setBackground(table.getBackground());
            }
            return acceptRejectPane;
        }
    }

    public class AcceptRejectEditor extends AbstractCellEditor implements TableCellEditor {

        private AcceptRejectPane acceptRejectPane;

        public AcceptRejectEditor() {
            acceptRejectPane = new AcceptRejectPane();
            acceptRejectPane.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            stopCellEditing();
                        }
                    });
                }
            });
        }

        @Override
        public Object getCellEditorValue() {
            return acceptRejectPane.getState();
        }

        @Override
        public boolean isCellEditable(EventObject e) {
            return true;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            if (isSelected) {
                acceptRejectPane.setBackground(table.getSelectionBackground());
            } else {
                acceptRejectPane.setBackground(table.getBackground());
            }
            return acceptRejectPane;
        }
    }
}

The key areas to pay attention to are the AcceptRejectRenderer and AcceptRejectEditor, the setValueAt, remove, isCellEditable of the MyTableModel and the setCellRenderer and setCellEditor methods of in the constructor....

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
4
  • cell cann't nest two JComponents because default JComponent/JLabel (returns by Renderer) haven't implemented any LayoutManager in API (in compare with JFrame/JDialog... or JPanel), have to set proper LayoutManager (Grid/BoxLayout) and important is to override PrederredSize, don't do that, road to troubles

  • there are three ways

    1. add JPanel with two JButtons as Renderer and Editor too (search here for RollOver effect for JButtons Component as renderers components)

    2. use JCheckBox (built_in Boolean support for Renderer and Editor too)

    3. use two JRadioButtons in ButtonGroup

      • with JRadioButton as Renderer and Editor too

      • (better, nicer, easier) with JRadioButtons in ButtonGroup as Renderer and JComboBox as Editor

mKorbel
  • 109,525
  • 20
  • 134
  • 319
1

Use a CellRenderer to render the two buttons on the column.

The overriden method could look something like this :

@Override
public Component getTableCellRendererComponent(JTable table, Object value,
                       boolean isSelected, boolean hasFocus, int row, int column)
{
    component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);


     JPanel buttonPanel = new JPanel();

    //create buttons and add to JPanel. 

    //add an action listener to each of the buttons

    //Return this JPanel at the end of the method.

    return buttonPanel;

}

In the actionPerformed() method for the delete button, find the row that you want to delete. You have the table object. From the table object you can then get the model object. In your model object you should have a method like, getRowForRowNumber(..), where you can pass in the row paramters.

now once you have a reference to your row after clicking the button you just need to go to the backend, update your delete action, remove it from the model, and perform a fireTableDataChanged().

Oliver Watkins
  • 12,575
  • 33
  • 119
  • 225