Concepts / Modifying a JList through its Model

Modifying a JList through its Model

A JList gets its items from a list model, the object that knows the actual list of items and the operations that can be performed on it.

  • Programming

Predicting Where a New Flavor Comes From

Imagine a small program that builds a list of ice cream flavors, displays them in a JList, and then adds one more flavor while the window is open. The new flavor appears on screen. The natural question is what, exactly, was changed in the program to make that happen. Before reading any theory, try to answer that question yourself. The answer determines how you will debug list problems in Swing for the rest of your work.

What do you think happens?

When the new flavor appears in the visible list, which object was changed in the program?

  • The JList on the screen

  • The list model that holds the flavors

  • The listener that responds to clicks

  • The window that contains the list

Reveal answer
Answer:

The list model that holds the flavors

The JList is only the view. The data itself is held by a separate model object, and the change is made to that model. The JList then redraws itself to reflect the new contents.

Three Cooperating Parts of a JList

A JList is best understood as several cooperating parts rather than one object. The list that appears in the window is only the view. Listener objects act as the controller, responding when the user clicks an item. The data itself is held by a third part, the model. The source names this object a ListModel, and it is the object that actually knows the list of items.

ListModelholds the actual itemsJListthe visible viewWindowwhat the user seesListener objectsrespond to clickssupplies itemsreacts to user clicksis drawn in
What does the model store versus what the JList displays, and how are the two objects linked? The model holds the data, the JList shows it, and listeners respond to user clicks.

The practical consequence is that the list you see is not where the data lives. If you want the list to show something different, the object to change is the model. Changing the JList directly is not the mechanism the source describes for adding or removing flavors.

A Model Is Data Plus Allowed Operations

Definition

A list model is the object that knows the actual list of items and the operations that can be performed on it. A model is defined not only by the data it contains but also by the set of operations allowed on that data.

This means choosing a model involves two decisions at once: what the model holds, and what you are allowed to do with it. Two lists that display the same items can behave very differently because their models offer different operations. When a list does not behave the way you expect, the first thing to check is which model class you are actually working with.

Array Models Versus DefaultListModel

When a JList is constructed directly from an array of objects, Swing creates a model for you. That model is deliberately simple. It can report how many items it contains and what those items are, and that is essentially all it can do. The source is explicit that there is no way to add items to this list or delete items from it. If your program needs that capability, you must use a different list model.

The model created from an array is not a DefaultListModel. This matters because the methods you can call depend on the actual class of the model, not on the fact that it belongs to a JList. DefaultListModel is a parameterized list model that supports adding and removing items, and it is the model to use for a modifiable list.

FeatureModel created from an arrayDefaultListModel
How it is createdSwing creates it when a JList is built from an arrayThe programmer creates it and holds a reference to it
Can show itemsYesYes
Can add itemsNo, according to the sourceYes, through methods such as addElement
Can delete itemsNo, according to the sourceYes, through removal methods
Is it a DefaultListModelNoYes

Operations available on the two kinds of list model, as described in the source

Keeping a Reference to the Model

The flavor program holds the DefaultListModel in a variable that is kept for the life of the program, rather than only inside the constructor call. This matters because a reference to the model is what lets you change the list later. If the model were created and passed straight into the JList constructor with no variable kept, you would have no handle to call add or remove methods on while the program runs.

java
Output
The visible list now shows Vanilla, Mint, and Peach.
Notes on the code
  • The model is stored in the variable flavors so it stays reachable.
  • The JList is given the model and displays whatever the model contains.
  • The final addElement call is made on the model, not on the JList.

How a Model Change Reaches the Screen

The mechanism behind the automatic update is an event. When a list model is modified, it generates an event of type ListDataEvent. The JList registers itself with its model as a listener for these events. When an event arrives, the JList responds by redrawing itself to reflect the new contents of the model.

Programcalls a method on the modelDefaultListModelchanges its dataJListregistered listenerVisible listredrawnaddElement(flavor)ListDataEventredraws itself
After addElement or a removal method is called on the model, what happens next, and in what order, before the screen updates?
  1. 1
    The program calls a method on the DefaultListModel, such as addElement.
  2. 2
    The model changes its data and generates a ListDataEvent.
  3. 3
    The JList, which registered as a listener, receives the event.
  4. 4
    The JList redraws itself to show the model's new contents.

The important consequence is that the programmer's only responsibility is the change to the model. No separate step is needed to repaint the list. This is why a bug where the screen is stale usually points to a broken link in the chain of model, event, and view rather than a missing repaint call.

Index Positions After a Removal

Once items are removed from the model, the positions of the remaining items change. Suppose the model holds three flavors, and you remove the item at index 1. The item that was at index 2 moves into index 1, and the remaining items are renumbered from the front. Tracing this shift is often the difference between a list that looks right and one that appears to show the wrong item.

Vanillaindex 0Mintremoved from index 1Peachmoves to index 1before removalbefore removal
After removing the item at index 1, which item moves into that position and what indexes do the remaining items have?
java
Output
Peach
Notes on the code
  • Removing index 1 deletes Mint from the model.
  • Peach shifts into index 1 because the model renumbers its items.
  • The source describes removal as one of the operations the model supports; removeElementAt is used here as an illustration.

Mistakes When Changing a JList

  • Common mistake

    Trying to add items to a list built directly from an array

    What it looks like

    A JList is created from a String array, and the program then tries to add a flavor to it.

    Why it fails

    The model Swing creates from an array can show items but cannot add or delete them.

    Do this instead

    Create a DefaultListModel, add the items to it, and pass that model to the JList.

  • Common mistake

    Losing the reference to the model

    What it looks like

    The DefaultListModel is created and passed straight into the JList constructor, with no variable kept.

    Why it fails

    Without a reference, the program has no way to call add or remove methods on the model later.

    Do this instead

    Store the model in a variable that stays in scope for as long as the program needs to modify the list.

  • Common mistake

    Calling methods on the JList to change its contents

    Why it fails

    The data is held by the model, and the add and remove operations act on that data.

    Do this instead

    Make the change on the model. The JList will redraw itself after it receives the event.

  • Common mistake

    Assuming item positions stay the same after a removal

    What it looks like

    After removing index 1, the program still expects Peach to be at index 2.

    Why it fails

    Remaining items are renumbered, so Peach moves into index 1.

    Do this instead

    Recheck positions after every removal before using an index.

Tracing a Wrong Result Back to Its Source

When the visible list does not match what you expected, work backward through the chain of model, event, and view, and ask at which step the result diverged. Start with the screen and move back: Did the JList redraw? Did it receive a ListDataEvent? Did the model change? Did the change happen on the model object the JList is actually using?

MEDIUM

A program builds a DefaultListModel holding Vanilla, Mint, and Peach, creates a JList from it, and then removes index 0. The screen still shows Vanilla at the top. Using the chain of model, event, and view, list the places you would check, in order, to locate the cause.

Hints
  • Ask first whether the removal was actually made on the model object the JList is displaying.
  • Next, ask whether the model generated a ListDataEvent and whether the JList was registered to receive it.
  • Finally, check whether the JList was given a different model than the one you changed.

Key Takeaways

  • A JList is a view. The items it displays are held by a separate list model, which also defines the operations allowed on those items.
  • A model created from an array can show items but cannot add or delete them; a DefaultListModel supports adding and removing items and is the model to use for a modifiable list.
  • Keep a reference to the DefaultListModel and make changes on the model; the model generates a ListDataEvent, and the registered JList redraws itself.
  • Removing an item shifts the positions of the remaining items, so recheck indexes after changes.
  • When a list shows something unexpected, trace backward through the chain of model, event, and view to find the step where the result diverged.