Java Programming   Java Programming
 |Sofia Home | Content Gallery |
Home
Syllabus
Schedule
Lessons
Assignments
Resources

Assignment 9 - Object Construction

For Assignment 9, you'll put what you've learned about composition to work. Composition, you'll remember is simply embedding objects inside other objects. Just like the universe you see around you is built from relatively similar components (atoms and molecules), yet is impressive in its variety and complexity, you can build sophisticated and useful objects just by combining the simple pieces you already know how to use.

For Assignment 9, you're going to combine a Scrollbar and a Label into a useful object called a "Spinner." A Spinner control is intended to solve the problem of getting bounded numeric input in a Graphical User Interface (GUI) world. 

A spinner control has two buttons, one that lets you increase the value and the other that lets you decrease the control's value. Here is an applet that uses three spinner controls to change its RGB values:

Note: If you are using IE and you cannot make the Spinner controls in the example shown here work correctly, you will need to update the Java Virtual Machine used by IE. The JVM that originally came with IE 5.0 had broken scrollbars. You can update at: 

http://www.microsoft.com/java/vm/dl_vm40.htm

To complete the homework, you'll have to understand: 
  • Create and initialize a Scrollbar object.
  • How to write constructors for your class.
  • How to call one constructor from another constructor using the method this().
  • How to handle the adjustmentListener() interface.
Information on the Scrollbar class can also be found in your text or the internet. You may also want to examine the Sun JavaDoc documentation for the class, which can be found in the java.awt package.
Back to Top

Step-By-Step Instructions 

Step 1

Define your component's attributes. Start by creating a new class named Spinner. Your new class will extend the Panel class, instead of extending the Applet class. You'll need to implement the AdjustmentListener interface, as well, which is as simple as adding the line:

implements AdjustmentListener
to the end of the class header. Remember to import the java.awt and java.awt.event packages. You don't need to import. java.applet.

Once you've set up the initial skeleton for your Spinner, add the following two fields:

  1. A private Scrollbar field named theBar. You don't have to initialize it, because you'll do that in the constructor.
  2. A private Label field, named theLabel. Initialize it with 4 empty spaces and align it to the right when you create it.
Step 2

Write a working constructor. Your working construct will take 4 arguments: 

  • an int named value
  • an int named min
  • an int named max
  • an AdjustmentListener named listener
In the body of your constructor you need to use these arguments to initialize the embedded Scrollbar component inside your Spinner. There are three tasks to complete in this step. You may want to compile after each task, just to make sure you're on the right track. After you've finished writing the constructor, compile one last time before going on.
1. Construct the Scrollbar

Your constructor will need to initialize your Scrollbar field (theBar) using the 5-argument Scrollbar constructor. Pass the following values to the constructor:

  • Scrollbar.VERTICAL
  • (max - value + min)
  • 1
  • min
  • max + 1
2. Hook up the Event System

When the user clicks on the Scrollbar contained in your Spinner, you will need to change the value displayed in the Spinner's Label field. To do that, you have to arrange for the Scrollbar object to notify your Spinner object whenever its value has changed. To do that:

  • Send the Scrollbar (theBar) the addAdjustmentListener() message, passing this as the argument like this:

In addition, those programs that make use of the Spinner class might also like to be notified whenever the Spinner object has changed its value. To meet this need, follow these steps:

  • Check to see if the 4th argument to your construtor [listener] was null
  • If it was not null, then send another addAdjustmentListener() message to your Scrollbar, passing listener as the argument. 
  • Note that this means both the Spinner object and the users of the Spinner class can both listen for events and respond appropriately.
3. Update the Interface

You need to display both the Label object and the Scrollbar object. Here's how:

  • Set the Font used in your Label field to a 12 point, bold font.
  • Set the layout manager to BorderLayout.
  • Add theLabel to the center and theBar to the east.
  • Update the text of theLabel. [See Step 3.1 for the code necessary to do this.]

At this point, your constructor is finished. [Note: Your code will not yet compile, because you haven't added the adjustmentValueChanged() method. As soon as you have completed Step 3 you should be able to compile your code.]

Back to Top
Step 3

Add the following methods to the Spinner class. These are the basic methods that make the Spinner "work".

1. Handle AdjustmentEvents

Whenever the user presses one of the arrows on the ends of the Scrollbar, the Scrollbar object generates an AdjustmentEvent. You need to start by adding the method necessary to respond to AdjustmentEvents

This method is named adjustmentValueChanged(). It returns no value, and takes a single AdjustmentEvent object as its argument. You can name the argument whatever you like, because we won't make any use of it.

Inside your method, send theLabel a setText() message, passing the argument: " " + getValue() + " " [a space on either side of getValue()]

2. Size the Spinner

We'll let Java take care of doing this. Just copy and insert the following method which helps the component resize itself correctly. [You'll learn more about getPreferredSize() next week.]
 

public Dimension getPreferredSize()
{
  return 
    new Dimension(theBar.getPreferredSize().width +
           theLabel.getPreferredSize().width,
           theLabel.getPreferredSize().height);
}
3. Retrieve the Spinner's Info

To get the information out of your Spinner object, you'll need to add a method named getValue(). The getValue() method will then ask the Scrollbar object for its value, do some fancy calculations, and return an answer.

Here are the specifications for getValue():

  • The method returns an int and takes no arguments
  • Inside the method, calculate the value of your Spinner by subtracting one from the Scrollbar's maximum value, and then subtracting the Scrollbar's current value. Finally, add the Scrollbar's minium value, and return the result. You can use the Scrollbar method getMinimum(), getMaximum() and getValue(), to acquire the values you need for your calculations.
Why the Strange Calculations?
The Java AWT Scrollbar class has no way to change the meaning of the up arrows and down arrows. The down arrow always increases the value of the Scrollbar. [Think of scrolling down a page. As you press the down arrow, the page number or line number increases.]

For a Spinner, that's really counter-intuitive. You expect the up-arrow to increase the Spinner value and the down-arrow to decrease it. To accomplish this, we need to subtract the current value from the maximum, and add the result to the minium. The extra 1 that gets involved is to make up for the width of the Scrollbar "thumb", which we initially set to 1 in the Scrollbar constructor.

Back to Top
Step 4

Test your Spinner. Compile the Spinner class and then test it using the following applet, along with a suitable HTML file:

TestSpin1.java
// Test the Spinner class
import java.awt.*;
import java.applet.*;

public class TestSpin1 extends Applet
{
  public void init()
  {
    add(new Spinner(5, 1, 10, null));
    add(new Spinner(1,-5, 5, null));
  }
}

This should work if you place the Spinner.class file in the same directory as TestSpin1.class. If your compiler complains that it cannot find the Spinner class, then do one of the following three things:

  • Check to see if you have a CLASSPATH by typing SET and looking for the entry named CLASSPATH. If you are using a compiler from JDK1.1.6 or later, you don't need a CLASSPATH except to use an external tool like JIKES. You can remove an existing CLASSPATH by typing SET CLASSPATH= and then pressing ENTER. Do not leave a space between the CLASSPATH and the =, and do not leave a space after the =.
  • If you are using JIKES or some other tool that requires a CLASSPATH, or if you are using a compiler earlier than JDK 1.1.6, then make sure that your CLASSPATH is set correctly. Examine the CLASSPATH from DOS, as in the previous section. If the CLASSPATH starts with ".\;", change that part to a simple period, followed by a semicolon. Your finished CLASSPATH should look like this, assuming you are using JDK1.1.8, and the files are stored in the directory C:\jdk1.1.8: [Note on JDK 1.2+, the runtime library is stored in a file named rt.jar, not in the file classes.zip.]
        CLASSPATH=.;C:\JDK1.1.8\lib\classes.zip
  • Forget about using separate files. Just copy Spinner.java to the bottom of your TestSpin1.java program, and remove the keyword public in front of the Spinner class header. This should work, even on platforms like the Mac, where setting the CLASSPATH correctly is a matter of black magic.

That's it. Compile it up, test it out, and see that it works. It should act just like the version shown under the listing.

Back to Top
Step 5

Complete the interface. Even though your Spinner works, it's not very full featured. You can easily fix that by adding the following four methods and constructors:

1. A Default Constructor

Let's assume that most users want to create Spinners that go from 1 to 10. You can accommodate such users by adding a default constructor that uses the method this() to call the working constructor you already wrote. Here's how:

  • Add a default constructor. Remember the default constructor does not take any arguments.
  • Inside the constructor, call this(), passing a value of 1, a min of 1, a max of 10, and a listener of null
2. An Overloaded Constructor

Many users won't be happy with the two constructors you've given them. Most of the time, Spinner users will want to change the minimum and maximum, but won't want to be notified when events occur. You can accommodate these users by adding another, third overloaded constructor that takes only three arguments. 

  • Use the this() method, as you did with the default constructor, to pass all of the arguments on to the working constructor. 
  • Pass null for the last value.
3. Changing the Value

Spinner users should not be restricted to simply creating Spinner objects, and then reading their values. They also need the ability to change the value that the Spinner control currently displays. You do this by writing a mutator method. 

  • Call your method setValue()
  • When your method is called, you will simply call the setValue() method in the Scrollbar class to do the work. (This is called delegation.) 
  • Before you pass the value on, however, you'll have to do a little calculation on the object. Look at the argument passed to the Scrollbar constructor (inside Spinner's working constructor) to determine the calculation that is required. Or, you may find the calculation used in getValue() a little easier to understand.
  • Theoretically, this should finish your work, but the Scrollbar only generates adjustment events when it is externally manipulated, not when its internal value changes. That means the Label associated with your Spinner won't get updated unless your repaint it. Look back at your adjustmentValueChanged() method, and add the same Label update code to the bottom of your setValue() method.
4. Changing the Unit Value 

By default, the value in the Spinner control changes by 1 whenever the user clicks on one of the up or down arrows. Often, however, users will want a Spinner that moves by some other increment. 

The Scrollbar class lets you change this by calling its setUnitIncrement() method. Add a method to the Spinner class, called setStepValue(), which simply calls the Scrollbar setUnitIncrement() method. No other calculation is required.

Test your Spinner class by downloading TestSpin2.java, and making sure it works like the example shown here. Notice that all three constructors are used as well as all of the methods. Note also that the Spinner objects each display a value when the applet starts, and the typing a value into the TextField and pressing ENTER will set the value for each of the three Spinners

When your Spinner class works like this one, you're all finished. Make sure you try changing a value using the TextField and that it works correctly.

Back to Top

Finishing Up 

Post your applet. Once you've tested your copy of the TestSpin2 applet locally, add it to the Assignment 9 HTML file on your Web site. Remember that you must send the .class file for both the Spinner class and the TestSpin2 class, as well as an updated HTML file. When you use FTP to send up your .class file, remember that it must be transferred using binary mode, not ASCII. 

 

Back to Top