Title: A review of GUI design goals
1A review of GUI design goals
- User interface code should be separate from
application code - The same information is often presented in
different places on a GUI each place should give
a mutually consistent view of the data - Any change in application data should be shown
quickly on the GUI, and in all places - Different users may require a different
look-and-feel for an application it should be
easy to change an applications look-and-feel
Goals 1 to 3 can be satisfied by applying the MVC
paradigm. Goal 4 is satisfied by the Swing
framework.
2Swing
- The Swing framework is rooted in MVC principles
- A Swing component is a view/controller pair
- A Swing component is associated with a model
- A Swing component is any JComponent subclass
3A Swing example text components
The model interface
Abstract class for all Swings text components.
An instance of a JTextComponent subclass contains
a reference to a model (an object whose class
implements Document). A JTextComponent subclass
instance also contains an object whose class
implements DocumentListener.
A model implementation class. An instance of
PlainDocument serves as the model for JTextField
objects.
4A Swing example text components
- Classes which implement the Document interface
serve as model classes for JTextComponent and its
subclasses - An instance of a class that implements Document
thus stores the state of a JTextField, a
JTextArea, or a JEditorPane component - In its simplest form, a document can be stored as
a linear sequence of characters - The only way in which a Document objects state
can be changed is by calling its insertString and
remove methods
model.insertString( 10, Jill, null )
5Every character typed into a JTextField component
causes the component to call insert on its model.
The JTextField component does not display the
character as it is entered! It updates its
display only in response to notifications from
the model.
6StudentFormView revisited
JTextField field new JTextField(
) field.addActionListener( ) / Method
actionPerformed. / public void actionPerformed(
ActionEvent e ) if( e.getSource( ) field
) try number
Integer.parseInt( field.getText( ) )
if( number gt 0 number lt 100 )
/ User has entered a valid percentage value.
/ else
/ User entered a number, but not valid
percent. /
catch( NumberFormatException e ) /
User didnt enter a number. /
- Recall the StudentFormView from the Course
application - To edit a students marks, the form provides a
series of JTextField components - Each JTextField component is associated with an
ActionListener to validate user input
7Validating input
- An ActionListener for a JTextField component is
notified only after the user has pressed the
return key while the JTextField has the focus - This sort of checking is known as action
validation checking is only carried out after a
user has finished their input - It is often preferable to use a different
technique known as change validation which
involves checking user input as they type
Change validation can be carried out easily using
a specialised model
8PercentageDocumenta specialised document model
1
0
0
0
The state of a PercentageDocument model is
subject to four constraints 1. Length of the
character sequence lt 3 2. Any characters in
the sequence must be digits 3. The sequence
should contain no leading zeros. 4. When
converted to a number, it should be lt 100.
a
b
c
0
1
0
9
9
9
9 JTextField fieldA new JTextField(
) JTextField fieldB new JTextField( ) /
Associate fieldB with a PercentageDocument.
/ fieldB.setDocument( new PercentageDocument( )
)
Note that in response to a request to insert a,
the PercentageDocument model rejects the request
and does not trigger a DocumentEvent.
10Multiple views
- Just like our model in the mvc framework can have
multiple views, so can a Swing model
fieldA, backed by a default PlainDocument model
fieldB, backed by a PercentageDocument model
A JTextArea component whose model is updated by a
DocumentListener registered on fieldBs model
MultipleDocumentView.java
11Multiple views
Note strictly speaking, the JTextField and
JTextArea instances cannot respond to
insertUpdate( ) calls as they do not implement
the DocumentListener interface. Recall that these
instances contain as part of their state a
AccessibleJTextComponent object which does
implement the interface it is this object to
which the insertUpdate( ) message is actually
sent. This diagram is an abstraction highlighting
key interactions.
12Swing components and models
- For each Swing component type, there is a
corresponding model interface - A JComponent will work with any object whose
class implements its model interface - The model interfaces differ but the MVC
principles are common
- Lets take a closer look at JTable / TableModel
13Structure
14Interaction
15Interaction
16The TableModel interface
- addTableModelListener( ) / removeTableModelListene
r( ) - registers / deregisters a view on the model
- getColumnClass( )
- Returns the class of object stored in a specified
column - A JTable component uses this to display data
- If a subclass of Number (e.g. Integer,
Percentage) is returned, the JTable
right-justifies data for this column - For Object and other subclasses of Object, a
JTable left-justifies the result of calling
toString() on objects in the column - getColumnName( )
- Returns the name heading of a particular column
a JTable component uses this to create a header - getRowCount( )
- Returns the number of rows stored in the model
17The TableModel interface
- getCellValueAt( )
- Returns a reference to the object held within a
specified cell of the model - isCellEditable( )
- Returns true if a specified cell is editable,
false otherwise - A JTable prevents users from editing cells that
the model says are uneditable - setValueAt( )
- For cells that are editable, this method allows
their value to be changed - This method is similar to Documents
insertString( ) and remove( ) methods since the
model can choose to accept or reject the new value
18AbstractTableModel
- AbstractTableModel implements all but the
getRowCount( ), getCoulmnCount( ), and
getValueAt( ) methods of the TableModel interface - AbstractTableModel also implements event handling
which is intended to be reused by subclasses - The fire( ) methods create TableModelEvent
objects and broadcast them to all registered
views - E.g. fireTableCellUpdated( ) creates an event
which describes a change made to a particular
cell - E.g. fireTableRowsUpdated( ) creates an event
which describes a change that has effected
multiple rows
AbstractTableModel is a good abstract class. It
implements the TableModel interface and adds
additional beaviour that is useful to subclasses.
To implement your own TableModel, all you need do
is inherit from AbstractTableModel and implement
3 methods.
19StudentFormView again
- A StudentFormView object is only able to show one
record at a time - However, a set of student results is naturally
stored and presented in a tabular form - Each row stores an individual student record
- Each column is used for a particular
student-record attribute
20(No Transcript)
21CourseTableModel
public class CourseTableModel extends
AbstractTableModel private
ListltStudentResultgt results new
VectorltStudentResultgt( ) public Object
getValueAt( int row, int col )
StudentResult result ( StudentResult
)results.get( row ) Object value
null switch( col ) case 0
// Student ID. value new
Integer( result.getStudentID() )
return value public
int getRowCount( ) return results.size(
) public int getColumnCount( )
return 7
Use of a Vector of StudentResult objects to
represent the models state.
Use the row argument to retrieve the
corresponding StudentResult object from results.
Use col to identify the StudentResult attribute
of interest.
The number of rows is simply the number of
StudentResult objects stored in results.
The number of columns is the number of attributes
per record (in other words the number of
StudentResult instance variables).
22What do we have?
- With very little effort, we have been able to
have Swings JTable class present a set of
StudentResult objects - However, by default, instances of
AbstractTableModel subclasses are not editable - AbstractTableModels isCellEditable( ) method
always returns false, regardless of the value of
the row and col arguments - To make our model editable, we need to override a
couple more methods isCellEditable( ) and
setValueAt( )
23CourseTableModel
public class CourseTableModel extends
AbstractTableModel / As before, plus
/ public boolean isCellEditable( int row,
int col ) if( col gt 2 col lt 6 )
return true return false
public void setValueAt( Object value, int row,
int col ) StudentResult result (
StudentResult )results.get( row )
switch( col ) case 3
result.setExamMark( ( Percentage )value )
result.setOverallMark(
) fireTableRowsUpdated( row, row )
Return true for all cells in columns 3 (exam), 4
(test), and 5 (assignment).
Use the row argument to located the StudentResult
object of interest.
Update the attribute identified by the col
argument.
Update the overall mark for the StudentObject we
have just modified.
Cause a TableModelEvent object to be fired and
sent to all registered views.
24CourseTableModel
- The implementation on the previous slide assumes
that only valid changes will be made - JTable allows any kind of data to be entered in
editable cells - Havent we met this problem of validating input
before?
public void setValueAt( Object value, int row,
int col ) StudentResult result (
StudentResult )results.get( row ) switch(
col ) case 3
result.setExamMark( ( Percentage )value )
Would throw a ClassCastException if a user
entered text into the JTable
25JTable
- To handle cell input, JTable uses a
DefaultCellEditor object, part of which is a
JTextField - We can write a subclass of DefaultCellEditor to
use a JTextField backed by a PercentageDocument
to restrict input as we did before - See the implementation of PercentageCellEditor
for the details
/ Main program / JTable view new JTable(
) view.setDefaultEditor( Percentage.class, new
PercentageCellEditor( new JTextField() ) ) /
Class CourseTableModel / public Class
getColumnClass( int col ) if( col gt 2
col lt 6 ) return Percentage.class
Tell the JTable that for any columns that store
Percentage objects, use the PercentageCellEditor
to edit them.
Override getColumnClass( ) in the model to return
the Percentage class for columns 3 to 5
26Pluggable CourseTableModel
To offer the assessment-policy flexibility of our
original MVC design, we can make CourseTableModel
delegate calculation of overall marks.
27Trees in Swing
- Swing includes support for representing tree
structures (TreeModel) and a component for
viewing/editing them (JTree) - TreeModel is similar to TableModel JTree is
similar to JTable! - Swings provision for trees is, however, a little
more complex than that for tables
28Trees in Swing
29Learning outcomes
- What is delegation and how does it differ from
inheritance? - What is the anatomy of the MVC architecture?
- What is the role of each part?
- What design objectives are fulfilled by MVC?
- What is the relationship between MVC and Swing?