"JTable is Swing's component for displaying data in rows and columns — a natural fit for database-backed applications where records are displayed and updated in real time."- Claude 2026
A JTable displays data in a grid of rows and columns, similar to a spreadsheet. It is the natural Swing component for showing database query results — each row in the table corresponds to a row in the database, and each column corresponds to a field.
Like JList, a JTable uses a model to hold its data. The standard model is DefaultTableModel, which lets you define column headers and add rows of data programmatically. When the model is updated, the table display updates automatically.
JList
JTable
DefaultTableModel
Holds the table's data — column names and rows of values. Pass it to the JTable constructor and update it to refresh the display.
Appends a row of values to the table. Each element in the array corresponds to a column.
Clears all rows from the table. Useful for refreshing the display after a database change.
Returns the index of the currently selected row, or -1 if nothing is selected.
Returns the value in a specific cell, useful for reading a selected row's data.
Always wrap a JTable in a JScrollPane so column headers remain visible and the table can scroll when rows exceed the visible area.
The complete application is a Party Roster GUI backed by a SQLite database. It demonstrates the full loop: connecting to the database on startup, loading records into a JTable, and allowing the user to add and delete records with the table refreshing automatically after each change.
The interface uses a BorderLayout with three regions:
BorderLayout
import javax.swing.*; import javax.swing.table.*; import java.awt.*; import java.awt.event.*; import java.sql.*; public class PartyRoster extends JFrame { static final String URL = "jdbc:sqlite:game.db"; private DefaultTableModel tableModel; private JTable table; private JTextField nameField; private JComboBox<String> classCombo; private JButton addButton, deleteButton; public PartyRoster() { setTitle("Party Roster"); setSize(550, 400); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout(new BorderLayout(5, 5)); // --- Table (Center) --- String[] columns = {"ID", "Name", "Class"}; tableModel = new DefaultTableModel(columns, 0) { // Make cells non-editable public boolean isCellEditable(int row, int col) { return false; } }; table = new JTable(tableModel); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); table.getColumnModel().getColumn(0).setMaxWidth(50); add(new JScrollPane(table), BorderLayout.CENTER); // --- Input Form (North) --- JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); nameField = new JTextField(12); classCombo = new JComboBox<>(new String[]{"Warrior", "Mage", "Archer", "Rogue"}); addButton = new JButton("Add"); inputPanel.add(new JLabel("Name:")); inputPanel.add(nameField); inputPanel.add(new JLabel("Class:")); inputPanel.add(classCombo); inputPanel.add(addButton); add(inputPanel, BorderLayout.NORTH); // --- Delete Button (South) --- deleteButton = new JButton("Delete Selected"); add(deleteButton, BorderLayout.SOUTH); // --- Event Handlers --- addButton.addActionListener(e -> { String name = nameField.getText().trim(); String charClass = (String) classCombo.getSelectedItem(); if (!name.isEmpty()) { insertCharacter(name, charClass); nameField.setText(""); loadTable(); } }); deleteButton.addActionListener(e -> { int row = table.getSelectedRow(); if (row != -1) { int id = (int) tableModel.getValueAt(row, 0); deleteCharacter(id); loadTable(); } }); // Load data from database on startup loadTable(); setVisible(true); } private void loadTable() { tableModel.setRowCount(0); try (Connection conn = DriverManager.getConnection(URL); PreparedStatement stmt = conn.prepareStatement("SELECT * FROM characters"); ResultSet rs = stmt.executeQuery()) { while (rs.next()) { tableModel.addRow(new Object[]{ rs.getInt("id"), rs.getString("name"), rs.getString("class") }); } } catch (SQLException e) { JOptionPane.showMessageDialog(this, "Error loading data: " + e.getMessage()); } } private void insertCharacter(String name, String charClass) { String sql = "INSERT INTO characters (name, class) VALUES (?, ?)"; try (Connection conn = DriverManager.getConnection(URL); PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setString(1, name); stmt.setString(2, charClass); stmt.executeUpdate(); } catch (SQLException e) { JOptionPane.showMessageDialog(this, "Error inserting: " + e.getMessage()); } } private void deleteCharacter(int id) { String sql = "DELETE FROM characters WHERE id = ?"; try (Connection conn = DriverManager.getConnection(URL); PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setInt(1, id); stmt.executeUpdate(); } catch (SQLException e) { JOptionPane.showMessageDialog(this, "Error deleting: " + e.getMessage()); } } public static void main(String[] args) { SwingUtilities.invokeLater(() -> new PartyRoster()); } }
import java.sql.*; public class SetupDB { static final String URL = "jdbc:sqlite:game.db"; public static void main(String[] args) { try (Connection conn = DriverManager.getConnection(URL); Statement stmt = conn.createStatement()) { // Create table stmt.execute(""" CREATE TABLE IF NOT EXISTS characters ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, class TEXT NOT NULL ) """); // Clear any existing data for a clean demo stmt.execute("DELETE FROM characters"); // Insert sample characters stmt.execute("INSERT INTO characters (name, class) VALUES ('Hero', 'Warrior')"); stmt.execute("INSERT INTO characters (name, class) VALUES ('Zara', 'Mage')"); stmt.execute("INSERT INTO characters (name, class) VALUES ('Fletch', 'Archer')"); stmt.execute("INSERT INTO characters (name, class) VALUES ('Dray', 'Rogue')"); System.out.println("Database created: game.db"); System.out.println("Table created: characters"); System.out.println("Sample data inserted."); } catch (SQLException e) { System.out.println("Setup failed: " + e.getMessage()); } } }
SetupDB.java
PartyRoster.java
javac SetupDB.java PartyRoster.java
java -cp .:sqlite-jdbc-3.51.3.0.jar SetupDB
java -cp .:sqlite-jdbc-3.51.3.0.jar PartyRoster
On Windows, replace : with ; in the classpath.
:
;