|
|
To aid in building ListModel classes, the AbstractListModel class is provided. As its name implies, this is an abstract class. It manages the ListDataListeners and contains methods to fire events to those listeners. Extensions of this class must manage the data in the list and implement the getSize and getElementAt methods. Extending the AbstractListModel class allows the model to manage the data in the list without concerning itself with the listeners.
An example of a ListModel is shown in Listing 10.7. The CustomListModel class extends the AbstractListModel class to inherit the ListDataModelListeners management functionality contained in the parent class. The CustomListModel class is a data model that grows and shrinks over time. It configures a JFC timer to receive notifications every UPDATE_TIME milliseconds. In the actionPerformed method called by the timer, the model adds or removes an item from the list depending on if the list is currently growing or shrinking. The size of the list is bounded by 0 and the maxSize attribute. The actionPerformed method fires the appropriate event to notify listeners of the change in the model.
An interesting observation can be made by looking at the getElementAt method in the CustomListModel class. The class does not contain a data structure, such as an array or vector, for the elements in the list. This is a key concept of the JFC architecture. The model need not contain all the data contained in the model at any given time. It only needs to be capable of returning any element in the model when its requested. For example, a JFC model can be used as the front end to a database. The database can contain thousands of records, but the JFC model does not need to load the entire table locally when it is created. Indeed, if a record is not requested, the model never needs to retrieve that record. The model can retrieve the records on demand.
In other circumstances, it may make more sense to preload all the data into the model so its immediately available for display. The architecture of the JFC is flexible enough that the model developer can decide what is best for the current model being implemented.
Listing 10.7 The CustomListModel Class
package com.foley.list;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* CustomListModel is a list data model that grows
* and shrinks over time. The data elements are calculated
* on demand.
*
* @author Mike Foley
**/
public class CustomListModel extends AbstractListModel
implements ActionListener {
/**
* The current size of the data model.
**/
private int size = 0;
/**
* The maximum size that the data model will grow to.
**/
private int maxSize = 25;
/**
* True if we are growing, false if we are shrinking.
**/
private boolean growing;
/**
* The timer interval. This determines how
* often the data in the model changes.
**/
private static final int UPDATE_TIME = 500;
/**
* CustomListModel, constructor
* <p>
* Initialize the model to a size of 0, and growing.
* Create a timer and start it.
**/
public CustomListModel() {
size = 0;
growing = true;
//
// Create a Timer that will call
// our actionPerformed method event
// UPDATE_TIME milliseconds.
//
Timer timer = new Timer( UPDATE_TIME, this );
timer.start();
}
/**
* getSize, from ListModel.
* <p>
* @return The length of the list.
**/
public int getSize() {
return( size );
}
/**
* getElementAt, from ListModel.
* <p>
* @return The value at the specified index.
* @param index The index of the requested element.
**/
public Object getElementAt( int index ) {
return( Model Element: + index );
}
/**
* actionPerformed, from ActionListener.
* <p>
* Our timer has expired. If we are growing, increment
* the size of the model by one. If we have hit the maximum
* size for the model, change the direction so the next time
* we are called, we will decrement. Fire an interval added
* event to notify listeners that a new element is in the model.
* <p>
* If we are decrementing, reduce the model size and fire an
* interval removed event. If the size gets to zero, change the
* direction so we grow the next time this method is called.
* <p>
* @param event The event causing this method to be called.
**/
public void actionPerformed( ActionEvent event ) {
if( growing ) {
//
// We are getting bigger.
//
int origSize = getSize();
size += 1;
if( maxSize - 1 <= size ) {
growing = false;
}
fireIntervalAdded( this, origSize, origSize );
} else {
//
// We are getting smaller.
//
size -= 1;
if( size < 1 ) {
growing = true;
}
fireIntervalRemoved( this, size, size );
}
} // actionPerformed
} // CustomListModel
|