List Models


You have gotten the view to represent part of the equation: Tell "someone" to do "something" when the user clicks Add. You know that the result of clicking Add should be that the courses panel shows a new course. You want your view class to treat these as two discrete operations; you'll implement logic elsewhere to connect the two.

The view should allow client code to pass a Course object and, as a result, display the course object. It doesn't care how the Course object comes into being. Add a new test to CoursesPanelTest:

 package sis.ui; import junit.framework.*; import javax.swing.*; import java.awt.*; import java.awt.event.*; import sis.studentinfo.*; import static sis.ui.CoursesPanel.*; public class CoursesPanelTest extends TestCase {    ...    public void testAddCourse() {       Course course = new Course("ENGL", "101");       panel.addCourse(course);       JList list = panel.getList(COURSES_LIST_NAME);       ListModel model = list.getModel();       assertEquals("ENGL 101", model.getElementAt(0).toString());    }    ... } 

The test sends the addCourse message to the CoursePanel. It then extracts the underlying model of the JList. A list model is a collection class that notifies the JList when something in the collection changes.

The JList view needs to show a useful representation of the objects contained in the model. To do so, JList code sends the toString message to each object in the model. The final line in the test asserts that the printable representation of the first object in the model is the concatenated department and course number.

 package sis.ui; import javax.swing.*; import java.awt.*; import java.awt.event.*; import sis.studentinfo.*; public class CoursesPanel extends JPanel {    ...    private DefaultListModel coursesModel = new DefaultListModel();    ...    private void createLayout() {            JLabel coursesLabel =          createLabel(COURSES_LABEL_NAME, COURSES_LABEL_TEXT);       JList coursesList = createList(COURSES_LIST_NAME, coursesModel);       ...    }    ...    void addCourse(Course course) {       coursesModel.addElement(course);    }    ...    private JList createList(String name, ListModel model) {       JList list = new JList(model);       list.setName(name);       return list;    } } 

A list model is a class that implements the interface javax.swing.ListModel. For JList objects, you will normally use the ListModel implementation class DefaultListModel. Interestingly, the ListModel interface declares no interface methods for adding elements. DefaultListModel does (addElement). You will want to declare the model reference (coursesModel) as being of the implementation type DefaultListModel and not of the interface type ListModel.

In the CoursesPanel method createList, you now pass a ListModel reference to the JList as you construct it. The addCourse method takes the Course passed to it and stuffs it into the model.

Use of toString

I mentioned in Lesson 9 that you should not depend upon the toString method for production code. A toString method is generally more useful for developer-related debugging activities. A developer might need to change Course output from the form:

 ENGL 101 

to something like:

 [Course:ENGL,101] 

The modified string would be inappropriate for the CoursesPanel user interface view. Another conflict can arise if two different views must show Course information in different formats.

In either case, you can and should introduce a display adapter class that wraps each course and provides the toString definition needed. You store these adapter objects in the JList model.

The user now wants to see a hyphen between each department and course number in the list. Modify the test to require this new display format:


 public void testAddCourse() {    Course course = new Course("ENGL", "101");    panel.addCourse(course);    JList list = panel.getList(COURSES_LIST_NAME);    ListModel model = list.getModel();    assertEquals("ENGL-101", model.getElementAt(0).toString()); } 

A simple implementation of the adapter class is to have it subclass Course and override the definition of toString.

 package sis.ui; import sis.studentinfo.*; class CourseDisplayAdapter extends Course {    CourseDisplayAdapter(Course course) {       super(course.getDepartment(), course.getNumber());    }    @Override    public String toString() {       return String.format(          "%s-%s", getDepartment(), getNumber());    } } 

The CoursesPanel addCourse method must change:

 void addCourse(Course course) {A    coursesModel.addElement(new CourseDisplayAdapter(course)); } 

Later, when you need to write code to obtain a Course selected in the list box, you'll need to extract the target Course from its adapter.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

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