Java GUI with Lists and Tabbed Panes

"Java's JList and JTabbedPane components let you build richer, more organized interfaces — displaying collections of data and grouping related controls into tabs."- Claude 2026

Processing Arrays of Objects and List of Objects

In previous pages we worked with individual objects. In real applications you often need to manage a collection of objects — a roster of characters, an inventory of items, a list of scores. Java gives us two main tools for this:

In a GUI application, ArrayList is generally more useful because the number of items is often unknown at compile time — users add and remove entries dynamically.

Example: Array of Character Objects
public class Character {

    private String name;
    private String charClass;

    public Character(String name, String charClass) {
        this.name = name;
        this.charClass = charClass;
    }

    public String getName()      { return name; }
    public String getCharClass() { return charClass; }

    // toString is used when displaying the object in a JList
    @Override
    public String toString() {
        return name + " (" + charClass + ")";
    }

    public static void main(String[] args) {

        // Array of Character objects
        Character[] party = {
            new Character("Hero",    "Warrior"),
            new Character("Zara",    "Mage"),
            new Character("Fletch",  "Archer")
        };

        // Process the array with a for-each loop
        for (Character c : party) {
            System.out.println(c);
        }

    }

}
Hero (Warrior)
Zara (Mage)
Fletch (Archer)
TIP: Overriding toString() in your class controls how objects are displayed as text — including when they appear in a JList. Without it, Java displays the object's memory address instead of something readable.
Example: ArrayList of Character Objects
import java.util.ArrayList;

ArrayList<Character> party = new ArrayList<>();

party.add(new Character("Hero",   "Warrior"));
party.add(new Character("Zara",   "Mage"));
party.add(new Character("Fletch", "Archer"));

// Process with a for-each loop
for (Character c : party) {
    System.out.println(c.getName() + " is a " + c.getCharClass());
}

// Remove by index
party.remove(0);

System.out.println("Party size after removal: " + party.size());
Hero is a Warrior
Zara is a Mage
Fletch is a Archer
Party size after removal: 2
JList Components and Updating

A JList displays a scrollable list of items in the GUI. It does not manage its own data directly — instead it uses a model to hold the data. The standard model for a JList is DefaultListModel, which works like an ArrayList that automatically updates the display whenever items are added or removed.

JList Key Methods

listModel.addElement(item)

Adds an item to the end of the list and updates the display automatically.

listModel.removeElementAt(index)

Removes the item at the given index and updates the display.

jList.getSelectedIndex()

Returns the index of the currently selected item, or -1 if nothing is selected.

jList.getSelectedValue()

Returns the selected item object, or null if nothing is selected.

listModel.getSize()

Returns the number of items currently in the list.

Example: Creating a JList
import javax.swing.*;
import java.awt.*;

public class PartyRoster extends JFrame {

    private DefaultListModel<String> listModel;
    private JList<String> partyList;

    public PartyRoster() {
        setTitle("Party Roster");
        setSize(300, 250);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        // Create the model and pre-populate it
        listModel = new DefaultListModel<>();
        listModel.addElement("Hero (Warrior)");
        listModel.addElement("Zara (Mage)");
        listModel.addElement("Fletch (Archer)");

        // Create the JList backed by the model
        partyList = new JList<>(listModel);

        // Wrap in a scroll pane in case the list grows long
        JScrollPane scrollPane = new JScrollPane(partyList);
        scrollPane.setPreferredSize(new Dimension(250, 150));

        add(scrollPane);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new PartyRoster());
    }

}
TIP: Always wrap a JList in a JScrollPane. Without it, items that overflow the visible area are simply cut off with no way to scroll to them.
Adding and Removing Values from a List

The power of DefaultListModel is that changes to the model are immediately reflected in the JList on screen. This makes it straightforward to wire up Add and Remove buttons — read input from a text field, update the model, and the display takes care of itself.

Example: Add and Remove Buttons
import javax.swing.*;
import java.awt.*;

public class PartyRoster extends JFrame {

    private DefaultListModel<String> listModel;
    private JList<String> partyList;
    private JTextField nameField;
    private JButton addButton, removeButton;

    public PartyRoster() {
        setTitle("Party Roster");
        setSize(320, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        listModel = new DefaultListModel<>();
        listModel.addElement("Hero (Warrior)");
        listModel.addElement("Zara (Mage)");
        listModel.addElement("Fletch (Archer)");

        partyList = new JList<>(listModel);
        JScrollPane scrollPane = new JScrollPane(partyList);
        scrollPane.setPreferredSize(new Dimension(280, 150));

        nameField    = new JTextField(15);
        addButton    = new JButton("Add");
        removeButton = new JButton("Remove Selected");

        // Add: read the text field and append to the model
        addButton.addActionListener(e -> {
            String name = nameField.getText().trim();
            if (!name.isEmpty()) {
                listModel.addElement(name);
                nameField.setText("");
            }
        });

        // Remove: get the selected index and remove it
        removeButton.addActionListener(e -> {
            int index = partyList.getSelectedIndex();
            if (index != -1) {
                listModel.removeElementAt(index);
            }
        });

        add(scrollPane);
        add(nameField);
        add(addButton);
        add(removeButton);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new PartyRoster());
    }

}
Tabbed Panes

A JTabbedPane organizes the GUI into multiple tabs — each tab holds a separate JPanel with its own set of components. This is useful when an application has distinct sections that would be cluttered if shown all at once.

Building a tabbed pane involves three steps:

  1. Create a JTabbedPane
  2. Create a JPanel for each tab and add components to it
  3. Add each panel to the tabbed pane with a tab label using addTab()
import javax.swing.*;
import java.awt.*;

public class CharacterApp extends JFrame {

    public CharacterApp() {
        setTitle("Character App");
        setSize(400, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JTabbedPane tabs = new JTabbedPane();

        // --- Tab 1: Party Roster ---
        JPanel rosterPanel = new JPanel(new FlowLayout());
        rosterPanel.add(new JLabel("Party members will appear here."));
        tabs.addTab("Roster", rosterPanel);

        // --- Tab 2: Add Character ---
        JPanel addPanel = new JPanel(new FlowLayout());
        addPanel.add(new JLabel("Name:"));
        addPanel.add(new JTextField(12));
        addPanel.add(new JButton("Add to Roster"));
        tabs.addTab("Add Character", addPanel);

        // --- Tab 3: Settings ---
        JPanel settingsPanel = new JPanel(new FlowLayout());
        settingsPanel.add(new JCheckBox("Show health bars"));
        settingsPanel.add(new JCheckBox("Enable sound"));
        tabs.addTab("Settings", settingsPanel);

        add(tabs);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new CharacterApp());
    }

}
Complete GUI Application
This complete example brings everything from this page together — a JTabbedPane with three tabs: a roster tab with a JList, an add/remove tab for managing the list, and a detail tab that updates automatically using a ListSelectionListener whenever a character is selected in the Roster tab.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

public class CharacterApp extends JFrame {

    // Shared data
    private DefaultListModel<String> listModel;
    private ArrayList<String[]> characters; // each entry: [name, class]

    // Roster tab
    private JList<String> partyList;

    // Add/Remove tab
    private JTextField nameField;
    private JComboBox<String> classCombo;
    private JButton addButton, removeButton;

    // Detail tab
    private JLabel nameLabel;
    private JLabel classLabel;
    private JLabel countLabel;

    public CharacterApp() {
        setTitle("Character App");
        setSize(420, 320);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Initialize shared data
        characters = new ArrayList<>();
        listModel  = new DefaultListModel<>();

        // Pre-populate
        addCharacter("Hero",   "Warrior");
        addCharacter("Zara",   "Mage");
        addCharacter("Fletch", "Archer");

        JTabbedPane tabs = new JTabbedPane();

        // ---- Tab 1: Roster ----
        JPanel rosterPanel = new JPanel(new BorderLayout());

        partyList = new JList<>(listModel);
        partyList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        rosterPanel.add(new JScrollPane(partyList), BorderLayout.CENTER);
        rosterPanel.add(new JLabel("Select a character, then click the Detail tab to view their info."), BorderLayout.SOUTH);

        tabs.addTab("Roster", rosterPanel);

        // ---- Tab 2: Add / Remove ----
        JPanel addPanel = new JPanel(new FlowLayout());

        nameField  = new JTextField(10);
        classCombo = new JComboBox<>(new String[]{"Warrior", "Mage", "Archer"});
        addButton    = new JButton("Add");
        removeButton = new JButton("Remove Selected");

        addButton.addActionListener(e -> {
            String name      = nameField.getText().trim();
            String charClass = (String) classCombo.getSelectedItem();
            if (!name.isEmpty()) {
                addCharacter(name, charClass);
                nameField.setText("");
                updateCount();
            }
        });

        removeButton.addActionListener(e -> {
            int index = partyList.getSelectedIndex();
            if (index != -1) {
                characters.remove(index);
                listModel.removeElementAt(index);
                updateCount();
            }
        });

        addPanel.add(new JLabel("Name:"));
        addPanel.add(nameField);
        addPanel.add(new JLabel("Class:"));
        addPanel.add(classCombo);
        addPanel.add(addButton);
        addPanel.add(removeButton);

        tabs.addTab("Add / Remove", addPanel);

        // ---- Tab 3: Detail ----
        // Updates automatically when a character is selected in the Roster tab
        JPanel detailPanel = new JPanel(new GridLayout(3, 1, 5, 5));

        nameLabel  = new JLabel("Name: —");
        classLabel = new JLabel("Class: —");
        countLabel = new JLabel("Party size: " + characters.size());

        detailPanel.add(nameLabel);
        detailPanel.add(classLabel);
        detailPanel.add(countLabel);

        tabs.addTab("Detail", detailPanel);

        // Listen for selection changes in the JList and update the Detail tab
        partyList.addListSelectionListener(e -> {
            if (!e.getValueIsAdjusting()) {
                int index = partyList.getSelectedIndex();
                if (index != -1) {
                    String[] c = characters.get(index);
                    nameLabel.setText("Name: "  + c[0]);
                    classLabel.setText("Class: " + c[1]);
                } else {
                    nameLabel.setText("Name: —");
                    classLabel.setText("Class: —");
                }
            }
        });

        add(tabs);
        setVisible(true);
    }

    private void addCharacter(String name, String charClass) {
        characters.add(new String[]{name, charClass});
        listModel.addElement(name + " (" + charClass + ")");
    }

    private void updateCount() {
        countLabel.setText("Party size: " + characters.size());
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new CharacterApp());
    }

}
Running the Application

Save the file as CharacterApp.java, then compile and run from the terminal:

  1. Download and install the Java Development Kit (JDK) if you haven't already.
  2. Compile: javac CharacterApp.java
  3. Run: java CharacterApp
→ This page was created with help from Gemini and Claude AI.