AIS BIIS
UI Construction using Java
Exercise 1 of 2
Linking Widgets
Background
One of the UI components you have been given is a simple starfield. This is a relatively simple component and, amongst other things, the data fields which determine the position of the visual elements (the dots) are fixed (the starfield uses the field ‘X1’ and ‘Y1’ for x and y coordinates, respectively). It would be useful if these settings could be changed.
Strategy
We will build two list widgets. Each will hold a list of all the potential fields for use in mapping to the axes, one for the x axis and the other for the y axis. By double-clicking an item in a list, that item will be used to position all records in the starfield for the corresponding axis. The effect will take place immediately on double-clicking of the list item.
Stage 1 Examine the existing Starfield Program
¾
We shall be using JDK 1.1.7. Check your environment to make sure it’s set up for this version of Java. If you haven’t done so already, you will need to make sure that/local/java/jdk/bin
setenv CLASSPATH .: /local/java/jdk/lib/classes.zip
Notice that the CLASSPATH value starts with ‘.’ which refers to the current directory. This enables Java to find the classes you have defined.
Note:
If you need to use the Java Swing widget classes, you will need to add the Swing library to your classpath. Here’s the command to set it up correctly:
setenv CLASSPATH .:/local/java/contrib/SwingSet/swing-1.0.2/swingall.jar:/local/java/jdk/lib/classes.zip
We won’t be using the Swing widgets in this exercise.
Create a directory called is3-java-ex1. Download all the exercise files into it. These can be accessed from:http://www.dcs.gla.ac.uk/~pdg/teaching/ais/biis/TradeViewer
You will also find documentation on all the classes here, so you might want to keep a browser open.
Build and run TradeViewer. Use the usual methods, viz., the commandsjavac *.java
java TradeViewer
Notice that you can
However, the dots in the starfield are mapped using the X field in the record for the x axis and theY field for the y axis. This mapping cannot be changed even though there are other numeric fields in the record.
Stage 2 Creating the Axis Field Selection Lists
TradeViewer consists of several embedded panels. Here they are with the names of the classes to which each panel belongs:
We’re now going to start the job of adding the two lists to the TradeViewer for selecting the values to use for the x and y axis. We will be working with the starFieldPanel, adding the field lists to it. We could add the field lists directly into the starFieldPanel. Instead, let’s make a new panel and put it to the right of the starfield.
Open StarFieldPanel.java in your favourite text editor. You'll need access to this later.
In a separate file called AxisListPanel.java, create a new class AxisListPanel which is a subclass of Panel. To begin with, this will hold nothing. Its constructor will look like this:public AxisListPanel() {
// initialise presentation
setBackground(Color.white); // or choose another color
}
Add an instance of AxisListPanel to the StarFieldPanel so that it will appear to the right of the starfield. This will require putting this line into the StarFieldPanel’s constructor:this.add("East", new AxisListPanel());
You can build and run your new program now to see the empty panel. The axisListPanel should appear as a very thin vertical strip along the right-hand side of the starfield.
Now in AxisListPanel’s constructor, we’ll add the list widgets. Including what we’ve already done, the constructor consists of these steps:Use a GridLayout to arrange the widgets in the AxisListPanel. The following will create a grid of two rows, one above the other, each of one column:
setLayout(new GridLayout(2,1));
At this stage you can combine the list widget creation with adding it to the panel. Here’s the line for one:
add(new List(5));
We don’t yet know the size of the list, so a default of 5 is used for the moment.
You can build and run your new program now to see the empty lists. Make sure there are two separate lists, one above the other.Stage 3 Putting Items in the Lists
So far, the list widgets have no items in them. To add items, we need to install a set of values in each list. Do this in the AxisListPanel constructor method (or you might package them in another method which is called from the constructor). The steps are:The values are accessible as a vector of field labels (Strings) from the source domain object (the object which holds the data being displayed). The relevant method in SourceDomain is:
public Vector numericFieldLabels()
// returns labels of fields which are reals or integers
You’ll need to get a handle on the source domain object:.
We're going to need to refer to the parent StarFieldPanel again later, so add an instance variable to the AxisListPanel definition to hold a reference to its parent. Parameterise the AxisListPanel constructor so that a reference to the parent starFieldPanel is passed in and initialise the new variable in the constructor.
We can use the vector of field labels to:
public int size()
public Object elementAt(int index)
Use the following List method to add the elements:
public void add(String s)
Don’t forget to cast the value returned by elementAt() to a String.
See hint 1 if you want help with this step.
Check your new components by compiling and running the program.Stage 4 Extracting the List Selection Events
The new list widgets generate special item selection events. We shall have to create listeners for them and new event handler objects to handle the listeners’ events.
Define two new subclasses of Object called XListHandler and YListHandler. Each should implement ActionListener. They will need an instance variable to hold a reference to the parent AxisListPanel, initialised in their constructor methods. Each will have one method which will call the axisListPanel to update the starfield (this will be covered in stage 5):public void actionPerformed(ActionEvent ae) {
// send parent the label of the selected item
System.out.printn("Item label selected is " + ae.getActionCommand());
}
For the moment, we will just print the value returned by the list-generated event.
See hint 2 if you want help.
We will need to create one instance each of XListHandler and YListHandler. Create them in the constructor for AxisListPanel. Here’s an example for the XListHandler (asssuming here that your x labels widget is called 'foo'):foo.addActionListener(new XListHandler(this));
Question:
What does ‘this’ refer to here? Why do you need to use it?
Compile and execute your prototype. You should see the correct item identifier on standard output each time you double-click the list.Stage 5 Linking the Lists to the Starfield
The final stage is to use the information in the list item event to get hold of the right field and use it in the starfield. StarFieldView has the following method for updating its display:
public void loadData(int xAxisField, int yAxisField) {
// construct a starfield mapping data in field with index xAxisField
// to the x axis and data in field yAxisField to the y axis
This is the method which the axisListPanel will call when it’s notified of a new axis selection by one of the listHanders.
In stage 4 we extracted the label of the selected list item. First, we shall pass this to the AxisListPanel for handling. Create stubbed methods in AxisListPanel to receive the labels.public void updateXAxis(String itemLabel) {
// get index of the field called itemLabel from the source domain
// update the starfield based on the x and y field indices
}
public void updateYAxis(String itemLabel) {
// get index of the field called itemLabel from the source domain
// update the starfield based on the x and y field indices
}
Since only one list can be double-clicked at a time, we’ll need a way to store the other field index for use when calling loadData(). Create two int variables in AxisListPanel, xAxisIndex and yAxisIndex. Initialise them to 0 and 1, respectively (the default indices for the starfield).
To complete the updateAxis methods, we need to query the source domain once more. SourceDomain includes a method which will return the index of a field given its label:
public int indexOfField(String fieldLabel)
Using this method and StarField’s loadData() method, complete the bodies of updateXAxis() and updateYAxis().
See hint 3 for help with this.
Insert calls to the appropriate AxisListPanel update methods in the actionPerformed() methods of XListHandler and YListHandler.
That’s it. Build and test your program.
Hints
Hint 1: The AxisListPanel constructor
public AxisListPanel(StarFieldPanel parent) {
this.parent = parent;
// initialise presentation
setBackground(Color.white);
setLayout(new GridLayout(2,1));
// get the field labels from the source domain
Vector labels = parent.starFieldView().sourceDomain().numericFieldLabels();
// create the list widgets
List xList = new List(labels.size());
List yList = new List(labels.size());
// put labels into the widgets
for (int i=0; i <labels.size(); i++)
xList.addItem((String)labels.elementAt(i);
for (int i=0; i < labels.size(); i++)
yList.addItem((String)labels.elementAt(i);
// add the widgets to the panel
add(xList);
add(yList);
}
Hint 2: XListHandler
class XListHandler implements ActionListener {
AxisListPanel axisListPanel;
public XListHandler(AxisListPanel panel) {
this.axisListPanel = panel);
}
public void actionPerformed(ActionEvent ae) {
// send parent the label of the selected item
System.out.println("Item label selected is " + ae.getActionCommand());
}
}
Hint 3: UpdateXAxis()
public void updateXAxis(String fieldLabel) {
// updates the starfield based on a new x axis
// determined by the value in field named fieldLabel
xAxisIndex = parent.starFieldView().sourceDomain().indexOfField(fieldLabel);
parent.starFieldView().loadData(xAxisIndex, yAxisIndex);
}