![]() ![]() |
![]() |
![]() ![]() ![]() ![]() |
![]() |
This API describes the JList and JListBox classes implemented in Swing. Swing adds enhancements to the List class implemented in JDK 1.0, and introduces a new list-box class named JListBox.
A list box is a user-interface component that presents a scrollable list of items from which the user can select one or more items. It's desirable for the list to allow the items to be rendered in various user-selectable forms. The most prevalent kinds of renderings are as strings, as icons, or both.
The JDK1.1 java.awt.List control provides basic support for presenting a scrolling list of single-line strings. It supports both single and multiple selections, along with the usual list of operations for adding and removing string items from lists. Unfortunately, it isn't readily extensible towards a more general list model -- e.g., methods such as:
public synchronized String[] getItems(); public synchronized String getSelectedItem(); public synchronized String[] getSelectedItems();
Because of the lack of easily implemented support for these kinds of methods, it would be a messy proposition to create both an extended version of java.awt.List that could manage a list of objects and a delegate that could render them as strings (or whatever). Similarly, the selection/notification part of the existing API doesn't generalize nicely.
It would be convenient if one could add sets of items to the selection and remove sets of items from the selection, and if one could be notified of a single compound change. Currently, the API for changing the selection is:
public synchronized void select(int index); public synchronized void deselect(int index);
Currently, clients are notified of changes to the selection by ItemEvent messages, which specify the change in selection state for an individual index. This causes a great deal of event traffic for compound selection changes. For example, if you select indices 10 through 50, Listeners have to map from ItemEvent.getItem() (which returns an object we know is a String) back to indices.
Rather than trying to stretch the existing API into a more general component, Swing addresses these problems by providing two new components:
The JList component will not be deprecated in the immediate future. JListBox is the component that is being developed and extended in future releases of Swing.
The JList component implements the non-deprecated JDK1.1 java.awt.List API. The existing API provides integral scrolling, supports presenting a dynamic list of Strings, and has two selection modes: single select and multiple select. Here's a summary of the existing API:
public List(); public List(int rows); // default is 4 public List(int rows, boolean multipleMode); // default is false public int getItemCount(); public String getItem(int index); public synchronized String[] getItems(); public void add(String item); public synchronized void add(String item, int index); public synchronized void remove(String item); public synchronized void remove(int position); public synchronized void removeAll(); public synchronized void replaceItem(String newValue, int index) => public synchronized int getSelectedIndex(); public synchronized int[] getSelectedIndexes(); public synchronized String getSelectedItem(); public synchronized String[] getSelectedItems(); public Object[] getSelectedObjects(); public synchronized void select(int index); public synchronized void deselect(int index); public boolean isIndexSelected(int index); public boolean isMultipleMode() { public synchronized void setMultipleMode(boolean b); public int getVisibleIndex(); public synchronized void makeVisible(int index); public void addItemListener(ItemListener l); public void removeItemListener(ItemListener l); public void addActionListener(ActionListener l); public void removeActionListener(ActionListener l);
The JListBox component is a generalization of JList; it supports arbitrary rendering of items and a more flexible selection API. In respect to model-view-component (MVC) framework (see "Swing Architecture" document in this document set), JList delegates to two models: a ListDataModel and a ListSelectionModel. Default implementations of both models are created if necessary. (Rendering of List items is also delegated; in this case, any lightweight component can serve as a list-item renderer.) By default, a subclass of JLabel is used to render string list items.
The JListBox component is designed to make the standard collection types (array, Vector, and Hashtable) easy to present. For example, to present an array of string, one could write.
String[] strings = {"one", "two", "free", "four"}; ListBox listbox = new ListBox(strings);
To find out what row the user has selected, or the value of the selected row:
int index = listbox.getSelectedIndex(); Object value = listbox.getSelectedValue();
The contents of a ListBox need not be strings. In the following example a ListBox is used to present the image frames from an animation. In this case we're using a Vector instead of an array for the list data. Note that the icons are loaded from an "images" directory relative to the directory ListBox.class was loaded from.
for (int i = 0; i < images.size(); i++) { URL url = ListBox.class.getResource("images/" + "juggler" + i + ".gif"); icons.addElement(new ImageIcon(url)); } ListBox lb = new ListBox(icons);
Of course it's not necessary to provide the value for every row in a list at ListBox create time. For larger lists, or for lists whose length and contents are to be computed as needed, the developer can provide an implementation of the ListDataModel interface. ListDataModel is a simple Vector-like interface. Here's an example that shows how the contents of a very long list (not presented here) can be defined by a ListDataModel:
ListDataModel longList = new ListDataModelAdapter() { public int getSize() { return Integer.MAX_VALUE; } public Object getElementAt(int index) { return "Index " + index; } }; ListBox lb = new ListBox(longList);
In this example, we've extended ListDataModelAdapter, a utility class that implements ListDataModel. ListDataModelAdapter provides useful definitions for all ListDataModel methods except getSize() and getElementAt().
ListBox uses a single java.awt.Component to render the visible contents of a list. The component is used like a "rubber stamp" to paint each visible row: The ListBox does the following:
The rubber stamp must be a Container that implements CellRenderer, a simple interface that defines a object valued property:
public interface CellRenderer { void setValue(Object x); }
In the preceding examples, the ListBox implementation uses a predefined CellRenderer called JLabelCellRender to display strings or icons. In the example that follows, we define a new Cell Renderer that draws both an icon and a string:
class MyCellRenderer extends JLabel implements CellRenderer { final static ImageIcon longIcon = new ImageIcon("long.gif"); final static ImageIcon shortIcon = new ImageIcon("short.gif"); public void setValue(Object value) { String s = value.toString(); setText(s); setIcon((s.length > 10) ? lonIcon : shortIcon); } }; ListBox listbox = new ListBox(longList); listbox.setCellRenderer(new MyCellRenderer());
In the preceding example, the CellRender setValue() method just sets the text and icon properties of the label object to reflect the new value. Remember that only one instance of the CellRenderer is used to paint all the rows in the list. Each time the JListBox paints a row, it applies setValue() to the renderer and then uses getPreferredSize() and setBounds() to move it into place. Finally, it calls the renderer's paint() method.
As development of Swing continues, the entire ListSelectionModel API -- along with convenience methods such as getSelectedIndexValue() -- will be supported by JListBox.
This interface defines the methods components like ListBox use to get the value of each row in a list and the length of the list. Logically the model is a vector, indices vary from 0 to ListDataModel.getSize() minus 1. Any change to the contents or length of the data model must be reported to all of the ModelChangedListeners.
public interface ListDataModel { int getSize(); Object getElementAt(int index); void addModelChangedListener(ModelChangedListener l); void removeModelChangedListener(ModelChangedListener l); }
This interface represents the current state of the selection for any components that display a list of values with stable positive integer indices. The selection is modeled as a set of intervals, with each interval representing a contiguous range of selected list elements. List controllers can enforce more limited selections -- for instance, only one index at a time, or only one interval. All the methods for modifying the set of selected intervals take a pair of indices, index0 and index1, that represent a closed interval -- that is, the interval includes both index0 and index1. Note that index0 does not have to be less than or equal to index1. In most cases, the get methods use -1 to report an empty selection. All the ListSelectionModel methods handle -1 index gracefully.
public interface ListSelectionModel { void setSelectionInterval(int index0, int index1); void addSelectionInterval(int index0, int index1); void removeSelectionInterval(int index0, int index1); int getMinSelectionIndex(); int getMaxSelectionIndex(); boolean isSelectedIndex(int index); int getAnchorSelectionIndex(); int getLeadSelectionIndex(); void addListSelectionListener(ListSelectionListener x); void removeListSelectionListener(ListSelectionListener x); void clearSelection(); boolean isSelectionEmpty(); } public interface ListSelectionListener extends java.util.EventListener { void valueChanged(ListSelectionEvent e); } public class ListSelectionEvent extends java.util.EventObject { ListSelectionEvent(ListSelectionModel source, int firstIndex, int lastIndex); public int getFirstIndex(); public int getLastIndex(); }
ListSelectionModel provides three operations -- setSelectionInterval(), addSelectionInterval(), and removeSelectionInterval() -- for the set of selected indices. The add and remove selection interval methods are set union and set difference respectively. Calling setSelection(index0, index1) is equivalent to:
clearSelection(); addSelectionInterval(index0, index1);
-- except that only one ListSelectionEvent is generated. When a selection is being created via mouse "drag select," the controller should endeavor to update the selection in this fashion:
addSelectionInterval(anchorIndex, leadIndex);
-- where the anchorIndex is the index where the drag started. The getAnchorSelectionIndex() and getLeadSelectionIndex() methods return the most recent arguments to setSelectionInterval() or addSelectionInterval() where index0 is the "anchor" and index1 is the "lead". Some interfaces display these indices specially; for example, Windows displays the lead index with a dotted yellow outline.
The getMinSelectionIndex() and getMaxSelectionIndex() methods return the smallest and largest selection indices in the set, respectively.
All the selection methods must handle pairs of -1 indices, where -1, -1 means "no selection":
void setSelectionInterval(-1, -1); // clears the selection void addSelectionInterval(-1, -1); // no-op void removeSelectionInterval(-1, -1); // no-op int getMinSelectionIndex(); // -1 if selection is empty int getMaxSelectionIndex() // -1 if selection is empty boolean isSelectedIndex(-1) // returns false int getAnchorSelectionIndex(); // -1 if selection is empty int getLeadSelectionIndex(); // -1 if selection is empty
The following java.awt.List methods aren't deprecated but probably should be. Developer feedback is welcome.
public int getRows(); => now getItemCount() public synchronized void delItem(int position); => now removeItem() public void addItem(String item) => now add() public synchronized void addItem(String item, int index) => now add()
Version 0.4. Last modified 09/04/97.
Copyright © 1995-97 Sun
Microsystems, Inc. All Rights Reserved.