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.
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?
Reveal 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.
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
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.
| Feature | Model created from an array | DefaultListModel |
|---|---|---|
| How it is created | Swing creates it when a JList is built from an array | The programmer creates it and holds a reference to it |
| Can show items | Yes | Yes |
| Can add items | No, according to the source | Yes, through methods such as addElement |
| Can delete items | No, according to the source | Yes, through removal methods |
| Is it a DefaultListModel | No | Yes |
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.
The visible list now shows Vanilla, Mint, and Peach.- The model is stored in the variable flavors so it stays reachable.
- The
JListis given the model and displays whatever the model contains. - The final
addElementcall is made on the model, not on theJList.
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.
- 1The program calls a method on the
DefaultListModel, such asaddElement. - 2The model changes its data and generates a
ListDataEvent. - 3The
JList, which registered as a listener, receives the event. - 4The
JListredraws 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.
Peach- 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;
removeElementAtis 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 likeA JList is created from a String array, and the program then tries to add a flavor to it.
Why it failsThe model Swing creates from an array can show items but cannot add or delete them.
Do this insteadCreate 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 likeThe DefaultListModel is created and passed straight into the JList constructor, with no variable kept.
Why it failsWithout a reference, the program has no way to call add or remove methods on the model later.
Do this insteadStore 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 failsThe data is held by the model, and the add and remove operations act on that data.
Do this insteadMake 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 likeAfter removing index 1, the program still expects Peach to be at index 2.
Why it failsRemaining items are renumbered, so Peach moves into index 1.
Do this insteadRecheck 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?
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
JListis displaying. - Next, ask whether the model generated a
ListDataEventand whether theJListwas registered to receive it. - Finally, check whether the
JListwas given a different model than the one you changed.
Key Takeaways
- A
JListis 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
DefaultListModelsupports adding and removing items and is the model to use for a modifiable list. - Keep a reference to the
DefaultListModeland make changes on the model; the model generates aListDataEvent, and the registeredJListredraws 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.