How do I add an ActionListener to a JCheckBox?

So my program takes in a .csv file and loads the data and displays it. When data is loaded in, it creates a new JCheckBox for every column header there is in the data. How do I add an ActionListener such that when the user ticks/unticks any of the boxes, it should do a certain function?

When data is loaded in, it updates the JPanel by the code:

    public void updateChecklistPanel(){

        checklistPanel.removeAll();
        checklistPanel.setLayout(new GridLayout(currentData.getColumnNames().length, 1, 10, 0));
        for (String columnName : currentData.getColumnNames()){
            JCheckBox checkBox = new JCheckBox();
            checkBox.setText(columnName);
            checklistPanel.add(checkBox);
        }
        checklistPanel.revalidate();
        checklistPanel.repaint();
    }

I also have the following at the bottom:

    @Override
    public void actionPerformed(ActionEvent e) {

        if (e.getSource() == newDataFrameItem){
            newFile();
            System.out.println("New DataFrame Loaded in");
        }
        if (e.getSource() == loadDataFrameItem){
            loadFile();
            System.out.println(".csv Data loaded into DataFrame.");
        }
        if (e.getSource() == saveDataFrameItem){
            System.out.println("Saved the data to a .csv file");
        }

    }

What I’m trying to do is that when a checkbox is unticked, it should hide a column in the JTable and when ticked, it should redisplay the column.

Answer

Introduction

It took me a while, but I came up with the following JTable GUI. Here’s the starting display.

JCheckBox Table GUI 1

Here’s the GUI after I remove the item description.

JCheckBox Table GUI 2

Here’s the GUI after I remove the item price.

JCheckBox Table GUI 3

Here’s the GUI after I add the columns back.

JCheckBox Table GUI 4

Explanation

I created an Item class to hold one item.

I created an Inventory class to hold a List of Item instances and a String array of the column headers.

I created the JFrame and two JPanels. One JPanel holds the JTable and the other holds the JCheckBoxes. I used Swing layout managers to create the JPanels.

So far, so basic. Creating the JTable took a bit of effort. I wanted to display the item price as currency, but that wasn’t important for this example GUI.

I created an ActionListener to add and remove columns from the JTable. I had to experiment a bit. The TableColumnModel addColumn method appends the column to the table.

I had to create a DisplayTableColumn class to hold a TableColumn and a boolean that tells me whether or not to display the TableColumn. I wound up removing all the columns from the JTable and adding all the columns back to the JTable so that I could maintain the column sequence. I probably ran 100 tests before I could get this code to work.

Code

Here’s the complete runnable code.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class JCheckBoxTableGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new JCheckBoxTableGUI());
    }
    
    private final Inventory inventory;
    
    private final InventoryTableModel tableModel;
    
    private JFrame frame;
    
    private JTable table;
    
    public JCheckBoxTableGUI() {
        this.tableModel = new InventoryTableModel();
        this.inventory = new Inventory();
        
        String[] columns = inventory.getTableHeader();
        for (String column : columns) {
            tableModel.addColumn(column);
        }
        
        List<Item> items = inventory.getInventory();
        for (Item item : items) {
            Object[] object = new Object[5];
            object[0] = item.getItemNumber();
            object[1] = item.getItemName();
            object[2] = item.getItemDescription();
            object[3] = item.getItemQuantity();
            object[4] = item.getItemPrice();
            tableModel.addRow(object);
        }
    }

    @Override
    public void run() {
        frame = new JFrame("JCheckBox Table GUI");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(createTablePanel(), BorderLayout.CENTER);
        frame.add(createSelectionPanel(), BorderLayout.AFTER_LINE_ENDS);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JPanel createTablePanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        table = new JTable(tableModel);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        table.getColumnModel().getColumn(0).setPreferredWidth(100);
        table.getColumnModel().getColumn(1).setPreferredWidth(150);
        table.getColumnModel().getColumn(2).setPreferredWidth(150);
        table.getColumnModel().getColumn(3).setPreferredWidth(100);
        table.getColumnModel().getColumn(4).setPreferredWidth(100);
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setPreferredSize(new Dimension(620, 300));
        panel.add(scrollPane, BorderLayout.CENTER);
        
        return panel;
    }
    
    private JPanel createSelectionPanel() {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        JPanel innerPanel = new JPanel(new GridLayout(0, 1, 5, 5));
        
        ColumnListener listener = new ColumnListener(this);
        String[] columns = inventory.getTableHeader();
        for (String column : columns) {
            JCheckBox checkBox = new JCheckBox("Display " +  column);
            checkBox.addActionListener(listener);
            checkBox.setActionCommand(column);
            checkBox.setSelected(true);
            innerPanel.add(checkBox);
        }
        
        panel.add(innerPanel);
        
        return panel;
    }
    
    public JTable getTable() {
        return table;
    }
    
    public JFrame getFrame() {
        return frame;
    }
    
    public class ColumnListener implements ActionListener {
        
        private final JCheckBoxTableGUI frame;
        
        private final List<DisplayTableColumn> displayColumns;

        public ColumnListener(JCheckBoxTableGUI frame) {
            this.frame = frame;
            this.displayColumns = new ArrayList<>();
            
            TableColumnModel tcm = frame.getTable().getColumnModel();
            for (int index = 0; index < tcm.getColumnCount(); index++) {
                TableColumn tc = tcm.getColumn(index);
                displayColumns.add(new DisplayTableColumn(tc, true));
            }
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            JCheckBox checkBox =  (JCheckBox) event.getSource();
            String column = event.getActionCommand();
            TableColumnModel tcm = frame.getTable().getColumnModel();
            
            for (int index = 0; index < displayColumns.size(); index++) {
                DisplayTableColumn dtc = displayColumns.get(index);
                if (dtc.isShowTableColumn()) {
                    tcm.removeColumn(dtc.getTableColumn());
                }
            }
            
            int columnIndex = getColumnIndex(column);
            displayColumns.get(columnIndex).setShowTableColumn(
                    checkBox.isSelected());
            
            for (int index = 0; index < displayColumns.size(); index++) {
                DisplayTableColumn dtc = displayColumns.get(index);
                if (dtc.isShowTableColumn()) {
                    tcm.addColumn(dtc.getTableColumn());
                }
            }
            
            frame.getFrame().pack();
        }
        
        private int getColumnIndex(String column) {
            for (int index = 0; index < displayColumns.size(); index++) {
                DisplayTableColumn dtc = displayColumns.get(index);
                if (column.equals(dtc.getTableColumn().getHeaderValue())) {
                    return index;
                }
            }
            
            return -1;
        }
        
    }
    
    public class DisplayTableColumn {
        
        private boolean showTableColumn;
        
        private final TableColumn tableColumn;

        public DisplayTableColumn(TableColumn tableColumn, boolean showTableColumn) {
            this.tableColumn = tableColumn;
            this.showTableColumn = showTableColumn;
        }

        public boolean isShowTableColumn() {
            return showTableColumn;
        }

        public void setShowTableColumn(boolean showTableColumn) {
            this.showTableColumn = showTableColumn;
        }

        public TableColumn getTableColumn() {
            return tableColumn;
        }
        
    }
    
    public class InventoryTableModel extends DefaultTableModel {

        private static final long serialVersionUID = 1L;

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex <= 2) {
                return String.class;
            } else if (columnIndex == 3) {
                return Integer.class;
            } else {
                return Integer.class;
            }
        }

    }
    
    public class Inventory {
        
        private final List<Item> inventory;
        
        private final String[] tableHeader;
        
        public Inventory() {
            this.tableHeader = new String[] { "Item Number", "Item Name", 
                    "Item Description", "Item Quantity",
                    "Item Price" };
            
            this.inventory = new ArrayList<>();
            
            inventory.add(new Item("X101111", "Samsung Camera", " ", 20, 69.99));
            inventory.add(new Item("X101112", "Samsung Monitor", " ", 10, 279.99));
            inventory.add(new Item("X101113", "Samsung Smartphone", " ", 110, 599.99));
            inventory.add(new Item("X101114", "Apple Watch", " ", 20, 1259.99));
            inventory.add(new Item("X101115", "Sony Playstation 5", " ", 0, 399.99));
        }

        public String[] getTableHeader() {
            return tableHeader;
        }

        public List<Item> getInventory() {
            return inventory;
        }
        
    }
    
    public class Item {
        
        private int itemPrice;
        private int itemQuantity;
        
        private final String itemNumber;
        private final String itemName;
        private final String itemDescription;
        
        public Item(String itemNumber, String itemName, 
                String itemDescription, int itemQuantity, double itemPrice) {
            this.itemNumber = itemNumber;
            this.itemName = itemName;
            this.itemDescription = itemDescription;
            this.itemQuantity = itemQuantity;
            setItemPrice(itemPrice);
        }

        public int getItemPrice() {
            return itemPrice;
        }

        public void setItemPrice(double itemPrice) {
            this.itemPrice = (int) Math.round(itemPrice * 100.0);
        }

        public int getItemQuantity() {
            return itemQuantity;
        }

        public void setItemQuantity(int itemQuantity) {
            this.itemQuantity = itemQuantity;
        }

        public String getItemNumber() {
            return itemNumber;
        }

        public String getItemName() {
            return itemName;
        }

        public String getItemDescription() {
            return itemDescription;
        }
        
    }

}

Leave a Reply

Your email address will not be published. Required fields are marked *