7.3 Handling Selections


The JList class in Swing depends on a second model, this one to monitor the elements that have been selected by the user. As with the list data model, the programmer is given many places in which standard behavior can be altered or replaced when dealing with selections. Swing uses a simple interface for models that handle list selections (ListSelectionModel) and provides a default implementation (DefaultList-SelectionModel).

7.3.1 The ListSelectionModel Interface

The ListSelectionModel interface outlines the methods necessary for managing list selections. Selections are represented by a series of ranges, where each range is defined by its endpoints. For example, if the elements One, Two, Three, Six, Seven, and Nine were selected in the opening example of the chapter, the list selection model would contain three entries that specified the ranges {1,3}, {6,7}, and {9,9}. All selection indices are zero-based, and the ranges are closed, meaning both endpoint indices are included within the selection. If only one element is present in a range, such as with Nine, both endpoints are identical.

7.3.1.1 Properties

Table 7-5 shows the properties of the ListSelectionModel interface. The first four properties of the list selection model can be used to retrieve various indices that are currently selected in the list. The anchorSelectionIndex and leadSelectionIndex properties represent the anchor and lead indices of the most recent range of selections, as illustrated in Figure 7-2. The maxSelectionIndex and minSelectionIndex properties return the largest and smallest selected index in the entire list, respectively.

Table 7-5. ListSelectionModel properties

Property

Data type

get

is

set

Default value

anchorSelectionIndex

int

·

 

·

 

leadSelectionIndex

int

·

 

·

 

maxSelectionIndex

int

·

     

minSelectionIndex

int

·

     

selectionEmpty

boolean

 

·

   

selectionMode

int

·

 

·

 

valueIsAdjusting

boolean

·

 

·

 

The selectionMode property defines the type of selections that the user may make in the list. This property can take one of three constants representing a single selection, a single range of selections, or multiple ranges of selections. The default (since SDK 1.3) is multiple ranges of selections. (The selectionMode constants are outlined in greater detail in Table 7-6.) The selectionEmpty property is a boolean indicating whether there are any selections. If there are no selections anywhere in the list, the property is set to true.

Setting the valueIsAdjusting property to true indicates that the object is sending a series of selection change events. For example, when the user is dragging the mouse across the list, the object can set this property to true, which indicates that the selection change events are part of a series. When the series has been completed, the property should be set to false. The receiver may wish to delay action until all events have been received.

In versions prior to 1.4, discontiguous selection events generated by clicking while holding down Ctrl (or Command, depending on the L&F) set the valueIsAdjusting property to true, without ever sending a closing event with the property equal to false. Unless you're using SDK 1.4 or later, it is safest to pay attention to this property only for lists that support a single selection.

7.3.1.2 Constants

The constants shown in Table 7-6 are used in conjunction with the selectionMode property of the ListSelectionModel interface.

Table 7-6. Constants for the ListSelectionModel interface

Constant

Data type

Description

MULTIPLE_INTERVAL_SELECTION

int

The user can make selections of several ranges at a time.

SINGLE_INTERVAL_SELECTION

int

The user can select only one range of items at a time.

SINGLE_SELECTION

int

The user can select only one item at a time.

7.3.1.3 Methods
public abstract void addSelectionInterval(int index1, int index2)

Add a group of list elements, ranging from index1 to index2 (including both endpoints), to the selection list. If the current selection mode supports only single selections, the method selects only the element at index2. This method must trigger a ListSelectionEvent describing the resulting change.

public abstract void removeSelectionInterval(int index1, int index2)

Remove the group of list elements from index1 to index2 (including both endpoints) from the selection list, whether the elements are selected or not. This method must trigger a ListSelectionEvent describing any changes it makes.

public abstract void clearSelection( )

Clear all selections from the data model. This method must trigger a ListSelectionEvent, indicating that the entire selection has been cleared.

public abstract void insertIndexInterval(int index, int length, boolean before)

Synchronize the selection list after an addition to the list data. If before is true, this method inserts length elements into the selection list starting before index. If before is false, the method inserts length elements after index. All added elements are unselected. The indices of any selected elements following them will be updated. If the changes do affect the selection, the method must trigger a ListSelectionEvent reflecting the changes to the selection list.

public abstract void removeIndexInterval(int index1, int index2)

Synchronize the selection list after a deletion in the list data. This method removes the indices between index1 and index2 from the selection model and renumbers entries that come later in the list. If the changes do affect the selection, the method must trigger a ListSelectionEvent reflecting the changes to the selection list.

public abstract boolean isSelectedIndex(int index)

Is true if the specified index is currently selected.

public abstract void setSelectionInterval(int index1, int index2)

Clear all selections and reset the selection to cover the range between index1 and index2. If the selection mode allows only a single selection, the element referenced by index2 is selected. This method must trigger a ListSelectionEvent describing the change, if there is one.

While reading through the above interface, you may have been puzzled to find no way to get a list of all selected items. Even though you'd expect this to be a responsibility of the selection model, you must instead get this information from the JList itself.

7.3.1.4 Events

The ListSelectionModel interface declares the addListSelectionListener( ) and removeListSelectionListener( ) event subscription methods for notifying other objects of selection changes. These selection changes come in the form of ListSelec-tionEvent objects.

public void addListSelectionListener(ListSelectionListener l)
public void removeListSelectionListener(ListSelectionListener l)

Add or remove a listener interested in receiving list selection events. The listener objects are notified each time a change to the list selection occurs.

7.3.2 The DefaultListSelectionModel Class

Swing provides a default implementation of the list selection interface called DefaultListSelectionModel. This class implements accessors for each of the ListSelectionModel properties and maintains an EventListenerList of change listeners. If you thought about how to implement all the behavior specified by the ListSelectionModel interface while reading about it on the last few pages, you probably realized that the code for all this is quite complex and tedious. We're glad Sun provides a default implementation!

The DefaultListSelectionModel can chain ListSelectionEvent objects in a series to notify listeners of a change in the selection list. This is common, for example, when the user is dragging the mouse across the list. In this case, a series of selection change events can be fired off with a valueIsAdjusting property set to true, which indicates that this event is only one of many. The listener may wish to delay any activity until all the events are received. When the chain of selections is complete, an event is sent with the valueIsAdjusting property set to false, which tells the listener that the series has completed. (Relying on this final event prior to SDK 1.4 is safe only for lists that don't support selection ranges.)

7.3.2.1 Properties

Table 7-7 lists the properties of the DefaultListSelectionModel. Almost all the properties are implementations of the properties defined by the ListSelectionModel interface. The only new property, leadAnchorNotificationEnabled, designates whether the class fires change events over leadSelectionIndex and anchorSelectionIndex each time it fires a series of notification events. (Recall that the anchor selection is at the beginning of the selection range while the lead selection is the most recent addition to the selection range.) If the property is false, only the elements selected or deselected since the last change are included in the series.

Table 7-7. DefaultListSelectionModel properties

Property

Data type

get

is

set

Default value

anchorSelectionIndex

int

·

 

·

-1

leadAnchorNotificationEnabled

boolean

 

·

·

true

leadSelectionIndex

int

·

 

·

-1

maxSelectionIndex

int

·

   

-1

minSelectionIndex

int

·

   

Integer.MAX_VALUE

selectionEmpty

boolean

 

·

 

true

selectionMode

int

·

 

·

MULTIPLE_INTERVAL_SELECTION

valueIsAdjusting

boolean

·

 

·

false

7.3.2.2 Events

The DefaultListSelectionModel uses the ListSelectionEvent to signal that the list selection has changed. The event notifies interested listeners of a modification to the selection data and tells which elements were affected.

public void addListSelectionListener(listSelectionListener 1)
public void removeListSelectionListener(listSelectionListener 1)

Add or remove a listener from the list of objects interested in receiving ListSelectionEvents.

public EventListener[] getListeners(Class listenerType)

You need to pass in the type of listener you're interested in (generally ListSelectionListener.class) and cast the result to that specific type (available since SDK 1.3).

public ListSelectionListener[] getListSelectionListeners( )

Return an array of all the list selection listeners that have been registered (available since SDK 1.4).

7.3.2.3 Constructor
public DefaultListSelectionModel( )

The default constructor. It initializes a list selection model that can be used by a JList or JComboBox component.

7.3.2.4 Method
public Object clone( ) throws CloneNotSupportedException

Return a clone of the current selection model. You should be aware that the event listener list is not cloned. This sort of problem is a small part of why the entire clone mechanism has fallen out of favor in Java.

7.3.2.5 Working with the ListSelectionModel

The following example is a modified version of our earlier list example. This one has its own ListSelectionListener that reports each list selection event as it occurs.

// SimpleList2.java // import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; public class SimpleList2 extends JPanel {     String label[] = { "Zero","One","Two","Three","Four","Five","Six",                        "Seven","Eight","Nine","Ten","Eleven" };     JList list;     public SimpleList2( ) {         setLayout(new BorderLayout( ));         list = new JList(label);         JButton button = new JButton("Print");         JScrollPane pane = new JScrollPane(list);         DefaultListSelectionModel m = new DefaultListSelectionModel( );         m.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);         m.setLeadAnchorNotificationEnabled(false);         list.setSelectionModel(m);         list.addListSelectionListener(new ListSelectionListener( ) {             public void valueChanged(ListSelectionEvent e) {                 System.out.println(e.toString( ));             }         });         button.addActionListener(new PrintListener( ));         add(pane, BorderLayout.NORTH);         add(button, BorderLayout.SOUTH);     }     public static void main(String s[]) {          JFrame frame = new JFrame("List Example");          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          frame.setContentPane(new SimpleList2( ));          frame.pack( );          frame.setVisible(true);     }     // An inner class to respond to clicks of the Print button     class PrintListener implements ActionListener {         public void actionPerformed(ActionEvent e) {             int selected[] = list.getSelectedIndices( );             System.out.println("Selected Elements:  ");             for (int i=0; i < selected.length; i++) {                 String element =                       (String)list.getModel( ).getElementAt(selected[i]);                 System.out.println("  " + element);             }         }     } }

Try running this code and selecting a couple of items in the list. If you drag the mouse from item 0 to item 5, you get the following output (the detailed contents of the JList have been omitted for readability since they don't change from line to line):

javax.swing.event.ListSelectionEvent[ source=javax.swing.JList[...] firstIndex= 0  lastIndex= 1 isAdjusting= true ] javax.swing.event.ListSelectionEvent[ source=javax.swing.JList[...] firstIndex= 1  lastIndex= 2 isAdjusting= true ] javax.swing.event.ListSelectionEvent[ source=javax.swing.JList[...] firstIndex= 2  lastIndex= 3 isAdjusting= true ] javax.swing.event.ListSelectionEvent[ source=javax.swing.JList[...] firstIndex= 3  lastIndex= 4 isAdjusting= true ] javax.swing.event.ListSelectionEvent[ source=javax.swing.JList[...] firstIndex= 4  lastIndex= 5 isAdjusting= true ] javax.swing.event.ListSelectionEvent[ source=javax.swing.JList[...] firstIndex= 0  lastIndex= 5 isAdjusting= false ]

Each entry describes a change in selection. The first five entries recognize that a change of selection has occurred between one element and the next as the mouse was dragged. In this case, the former was deselected, and the latter was selected. However, note that the isAdjusting property was true, indicating that this is potentially one in a series of changes. When the mouse button is released, the list knows that the drag has stopped and fires a ListSelectionEvent with the isAdjusting property set to false, repeating the last changed index.

7.3.3 ListSelectionEvent

Much like the ListDataEvent, the ListSelectionEvent specifies a change by highlighting those elements in the selection list that have altered. Note that a ListSelectionEvent does not indicate the new selection state of the list element, only that some change has occurred. You should not assume that the new state is the opposite of the previous state; always check with the event source to see what the current selection state really is.

7.3.3.1 Properties

There are four properties in the ListSelectionEvent, as shown in Table 7-8.

Table 7-8. ListSelectionEvent properties

Property

Data type

get

is

set

Default value

firstIndex

int

·

     

lastIndex

int

·

     

sourceo

Object

·

     

valueIsAdjusting

boolean

·

     

ooverridden

7.3.3.2 Constructor
public ListSelectionEvent(Object source, int firstIndex, int lastIndex, boolean isAdjusting)

This constructor takes a reference to the object that is firing the event, as well as the bounding indices and a boolean indicating whether the event is expected to be followed by another. Note that firstIndex should always be less than or equal to lastIndex.

7.3.3.3 Methods
public String toString( )

Provide human-readable string output of the event properties for debugging.

7.3.4 ListSelectionListener

The ListSelectionListener interface, as the means of receiving ListSelectionEvents, consists of only one method: valueChanged( ). This method must be implemented by any listener object interested in changes to the list selection model.

public abstract void valueChanged(ListSelectionEvent e)

Notify the listener that one or more selection elements have changed.

7.3.4.1 Listening for ListSelectionEvents

Here is a brief example that demonstrates how to use ListSelectionListener and the ListSelectionEvent. The example creates a series of checkboxes that accurately mirror the current selections in the list by listening for selection events. Some results from playing with the program are shown in Figure 7-6.

Figure 7-6. Monitoring list selection events
figs/swng2.0706.gif
//  SelectionMonitor.java // import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; public class SelectionMonitor extends JPanel {     String label[] = { "Zero","One","Two","Three","Four","Five","Six",                        "Seven","Eight","Nine","Ten","Eleven","Twelve" };     JCheckBox checks[] = new JCheckBox[label.length];     JList list;     public SelectionMonitor( ) {         setLayout(new BorderLayout( ));         list = new JList(label);         JScrollPane pane = new JScrollPane(list);         // Format the list and the buttons in a vertical box.         Box rightBox = new Box(BoxLayout.Y_AXIS);         Box leftBox = new Box(BoxLayout.Y_AXIS);         // Monitor all list selections.         list.addListSelectionListener(new RadioUpdater( ));         for(int i=0; i < label.length; i++) {             checks[i] = new JCheckBox("Selection " + i);             checks[i].setEnabled(false);             rightBox.add(checks[i]);         }         leftBox.add(pane);         add(rightBox, BorderLayout.EAST);         add(leftBox, BorderLayout.WEST);     }     public static void main(String s[]) {          JFrame frame = new JFrame("Selection Monitor");          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          frame.setContentPane(new SelectionMonitor( ));          frame.pack( );          frame.setVisible(true);     }     // Inner class that responds to selection events to update the buttons     class RadioUpdater implements ListSelectionListener {         public void valueChanged(ListSelectionEvent e) {             // If either of these are true, the event can be ignored.             if ((!e.getValueIsAdjusting( )) || (e.getFirstIndex( ) == -1))                 return;             // Change the radio button to match the current selection state for each             // list item that reported a change.             for (int i = e.getFirstIndex( ); i <= e.getLastIndex( ); i++) {                 checks[i].setSelected(((JList)e.getSource( )).isSelectedIndex(i));             }         }     } }

If you're running this example under SDK 1.4 or later, experiment with Swing's new support for keyboard-driven selection. Try typing the first letter, or few letters, of some of the list elements, and watch the selection jump around. Notice that if you type te, the selection starts by selecting Two and then jumps to Ten, but neither event reports an isAdjusting value of true. This feature is examined in more depth in the discussion of the getNextMatch( ) method.

Remember that a ListSelectionEvent does not inform you of the new selection state of an element that has changed. You might be tempted to conclude that if you receive a ListSelectionEvent, the selection state for the target element would simply be the opposite of what it was before. This is not true. The selection state cannot be determined from the ListSelectionEvent; it must be determined by querying the event source.



Java Swing
Graphic Java 2: Mastering the Jfc, By Geary, 3Rd Edition, Volume 2: Swing
ISBN: 0130796670
EAN: 2147483647
Year: 2001
Pages: 289
Authors: David Geary

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net