How do I create a scrollable JTable component?

To create a scrollable JTable component we have to use a JScrollPane as the container of the JTable. Besides, that we also need to set the table auto resize mode to JTable.AUTO_RESIZE_OFF so that a horizontal scroll bar displayed by the scroll pane when needed. If we do not turn off the auto resize mode, the columns of the table will be resized to fit the available window size.

package org.kodejava.swing;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import java.awt.BorderLayout;
import java.awt.Dimension;

public class ScrollableJTable extends JPanel {
    public ScrollableJTable() {
        initializeUI();
    }

    private static void showFrame() {
        JPanel panel = new ScrollableJTable();
        panel.setOpaque(true);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setTitle("Scrollable JTable");
        frame.setContentPane(panel);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ScrollableJTable::showFrame);
    }

    private void initializeUI() {
        setLayout(new BorderLayout());
        setPreferredSize(new Dimension(500, 250));

        JTable table = new JTable(20, 20);

        // Turn off JTable's auto resize so that JScrollPane will show a horizontal
        // scroll bar.
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

        JScrollPane pane = new JScrollPane(table);
        add(pane, BorderLayout.CENTER);
    }
}

Below is the result of the code snippet above.

Scrollable JTable Component Demo

Scrollable JTable Component Demo

How do I programmatically select JTable’s columns?

This program shows you how to select some columns in the JTable programmatically. Below we demonstrates how to select columns using the setColumnSelectionInterval() method, remove or clear column selection using removeColumnSelectionInterval() method and use the addColumnSelectionInterval() to add more columns to the previously selected columns.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;

public class JTableColumnSelectProgrammatically extends JPanel {
    public JTableColumnSelectProgrammatically() {
        initializePanel();
    }

    public static void showFrame() {
        JPanel panel = new JTableColumnSelectProgrammatically();
        panel.setOpaque(true);

        JFrame frame = new JFrame("JTable Column Selection");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setContentPane(panel);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(JTableColumnSelectProgrammatically::showFrame);
    }

    private void initializePanel() {
        setLayout(new BorderLayout());
        setPreferredSize(new Dimension(500, 500));

        final JTable table = new JTable(new MyTableModel());
        table.setFillsViewportHeight(true);
        JScrollPane pane = new JScrollPane(table);

        JLabel label1 = new JLabel("From col: ");
        final JTextField field1 = new JTextField(3);
        JLabel label2 = new JLabel("To col: ");
        final JTextField field2 = new JTextField(3);
        JButton select = new JButton("Select");
        JButton clear = new JButton("Clear");
        JButton add = new JButton("Add another one");

        // Enables column selection mode and disable row
        // selection mode.
        table.setColumnSelectionAllowed(true);
        table.setRowSelectionAllowed(false);

        // Select columns based on the input.
        select.addActionListener(event -> {
            int index1 = 0;
            int index2 = 0;
            try {
                index1 = Integer.parseInt(field1.getText());
                index2 = Integer.parseInt(field2.getText());
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }

            if (index1 <= 0 || index2 <= 0 ||
                    index1 > table.getColumnCount() ||
                    index2 > table.getColumnCount()) {
                JOptionPane.showMessageDialog(table, "Selection out of range!");
            } else {
                table.setColumnSelectionInterval(index1 - 1, index2 - 1);
            }
        });

        // Clears column selection
        clear.addActionListener(e -> {
            table.removeColumnSelectionInterval(0, table.getColumnCount() - 1);
            field1.setText("");
            field2.setText("");
        });

        // Add one more column after the last selected column.
        add.addActionListener(event -> {
            int index2 = 0;
            try {
                index2 = Integer.parseInt(field2.getText());
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }

            index2 = index2 + 1;
            if (index2 <= table.getColumnCount()) {
                table.addColumnSelectionInterval(index2 - 1, index2 - 1);
                field2.setText(String.valueOf(index2));
            }
        });

        JPanel command = new JPanel(new FlowLayout());
        command.add(label1);
        command.add(field1);
        command.add(label2);
        command.add(field2);
        command.add(select);
        command.add(clear);
        command.add(add);

        add(pane, BorderLayout.CENTER);
        add(command, BorderLayout.SOUTH);
    }

    public static class MyTableModel extends AbstractTableModel {
        private final String[] columns = {"ID", "NAME", "AGE", "A STUDENT?"};
        private final Object[][] data = {
                {1, "Alice", 20, Boolean.FALSE},
                {2, "Bob", 10, Boolean.TRUE},
                {3, "Carol", 15, Boolean.TRUE},
                {4, "Mallory", 25, Boolean.FALSE}
        };

        public int getRowCount() {
            return data.length;
        }

        public int getColumnCount() {
            return columns.length;
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            return data[rowIndex][columnIndex];
        }

        @Override
        public String getColumnName(int column) {
            return columns[column];
        }

        // This method is used by the JTable to define the default
        // renderer or editor for each cell. For example if you have
        // a boolean data it will be rendered as a checkbox. A
        // number value is right aligned.
        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return data[0][columnIndex].getClass();
        }
    }

}

Below is the screen capture of the program.

Programmatically Select JTable Column

Programmatically Select JTable Column

How do I right-align numbers data in JTable component?

To right-align numbers type of data in JTable cells we need to implements a TableModel. The TableModel‘s interface getColumnClass(int index) implementation return the class of the cell values, this information is used by JTable component to setup a default renderer and editor for the column.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;

public class JTableNumberRightAlign extends JPanel {
    public JTableNumberRightAlign() {
        initializeUI();
    }

    public static void showFrame() {
        JPanel panel = new JTableNumberRightAlign();
        panel.setOpaque(true);

        JFrame frame = new JFrame("JTable Number Align");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setContentPane(panel);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(JTableNumberRightAlign::showFrame);
    }

    private void initializeUI() {
        setLayout(new BorderLayout());
        setPreferredSize(new Dimension(500, 500));

        JTable table = new JTable(new NumberTableModel());
        table.setFillsViewportHeight(true);

        JScrollPane pane = new JScrollPane(table);
        add(pane, BorderLayout.CENTER);
    }

    static class NumberTableModel extends AbstractTableModel {
        String[] columns = {"STUDENT ID", "NAME", "YEARS", "SCORE"};
        Object[][] data = {
                {"S001", "ALICE", 10, 8.75},
                {"S002", "BOB", 10, 7.50},
                {"S003", "CAROL", 10, 9.00},
                {"S004", "MALLORY", 10, 8.50}
        };

        public int getRowCount() {
            return data.length;
        }

        public int getColumnCount() {
            return columns.length;
        }

        @Override
        public String getColumnName(int column) {
            return columns[column];
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            return data[rowIndex][columnIndex];
        }

        // This method is used by the JTable to define the default
        // renderer or editor for each cell. For example if you have
        // a boolean data it will be rendered as a checkbox. A
        // number value is right aligned.
        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return data[0][columnIndex].getClass();
        }
    }
}

Here is the result of the program:

JTable Number Right Align

JTable Number Right Align

How do I render boolean value as checkbox in JTable component?

To make a JTable renders a boolean as a checkbox in the table cell we need to tell the table that a cell stores a boolean type of data. To do this we have to implement a TableModel for the JTable component.

TableModel‘s getColumnClass(int columnIndex) must return the type of data stored in a cell. When it returns that the column stored a Boolean data, JTable displays a checkbox as the default renderer or editor for that cell.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;

public class JTableBooleanAsCheckbox extends JPanel {
    public JTableBooleanAsCheckbox() {
        initializeUI();
    }

    public static void showFrame() {
        JPanel panel = new JTableBooleanAsCheckbox();
        panel.setOpaque(true);

        JFrame frame = new JFrame("JTable Boolean as Checkbox");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setContentPane(panel);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(JTableBooleanAsCheckbox::showFrame);
    }

    private void initializeUI() {
        setLayout(new BorderLayout());
        setPreferredSize(new Dimension(500, 500));

        JTable table = new JTable(new BooleanTableModel());
        table.setFillsViewportHeight(true);
        JScrollPane pane = new JScrollPane(table);
        add(pane, BorderLayout.CENTER);
    }

    static class BooleanTableModel extends AbstractTableModel {
        String[] columns = {"STUDENT ID", "NAME", "SCORE", "PASSED"};
        Object[][] data = {
                {"S001", "ALICE", 90.00, Boolean.TRUE},
                {"S002", "BOB", 45.50, Boolean.FALSE},
                {"S003", "CAROL", 60.00, Boolean.FALSE},
                {"S004", "MALLORY", 75.80, Boolean.TRUE}
        };

        public int getRowCount() {
            return data.length;
        }

        public int getColumnCount() {
            return columns.length;
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            return data[rowIndex][columnIndex];
        }

        @Override
        public String getColumnName(int column) {
            return columns[column];
        }

        // This method is used by the JTable to define the default
        // renderer or editor for each cell. For example if you have
        // a boolean data it will be rendered as a checkbox. A
        // number value is right aligned.
        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return data[0][columnIndex].getClass();
        }
    }
}

Here is the result of the program:

JTable render Boolean as Checkbox

JTable render Boolean as Checkbox

How do I disable or enable JTable cell selection?

Disables or enables JTable‘s cell selection can be done by calling the setCellSelectionEnabled(boolean cellSelectionEnabled) method. This method accept a boolean value. Calling this method also changes the state of table’s row and column selection respectively.

To completely remove the selection capability from JTable component we can change its focusable state to false by calling the setFocusable(boolean focusable) method.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;

public class JTableDisableSelection extends JPanel {
    public JTableDisableSelection() {
        initializePanel();
    }

    public static void showFrame() {
        JPanel panel = new JTableDisableSelection();
        panel.setOpaque(true);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("JTable Disable Selection");
        frame.setContentPane(panel);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(JTableDisableSelection::showFrame);
    }

    private void initializePanel() {
        setLayout(new BorderLayout());
        setPreferredSize(new Dimension(500, 500));

        JTable table = new JTable(new PremiereLeagueTableModel());
        table.getColumnModel().getColumn(0).setMinWidth(200);

        // Disable table's cell selection.
        table.setCellSelectionEnabled(false);

        // Settings table focus to false completely remove selection
        // capability from the table component.
        table.setFocusable(false);

        JScrollPane pane = new JScrollPane(table);
        add(pane, BorderLayout.CENTER);
    }

    static class PremiereLeagueTableModel extends AbstractTableModel {
        // TableModel's column names
        private final String[] columnNames = {
                "CLUB", "MP", "W", "D", "L", "GF", "GA", "GD", "PTS"
        };

        // TableModel's data
        private final Object[][] data = {
                {"Chelsea", 8, 6, 1, 1, 16, 3, 13, 19},
                {"Liverpool", 8, 5, 3, 0, 22, 6, 16, 18},
                {"Manchester City", 8, 5, 2, 1, 16, 3, 13, 17},
                {"Brighton", 8, 4, 3, 1, 8, 5, 3, 15},
                {"Tottenham", 8, 5, 0, 3, 9, 12, -3, 15}
        };

        public int getRowCount() {
            return data.length;
        }

        public int getColumnCount() {
            return columnNames.length;
        }

        @Override
        public String getColumnName(int column) {
            return columnNames[column];
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            return data[rowIndex][columnIndex];
        }
    }
}
Disable or Enable JTable Cell Selection

Disable or Enable JTable Cell Selection