Ming's Java UI Basics for Non-Java Programmers Part II

by Ming-Yee Iu

6 Making Your Own Objects

So far, you've seen how to use objects in order to create a simple window with a button in it; however, the true power of Java can't be achieved unless you learn how to make your own objects. That's what this section discusses.

6.1 Motivation

So far, we've seen how to create a window with a button in it by creating a java.awt.Frame object and then adding a java.awt.Button object to it. What we want to do now is to create a new type of object that will represent a window with a button in it. When you create and then invoke the show() method, a window with a button will pop up. This way, you don't have to manually add a button to the window each time. Although there are many different programming approaches for doing this, a common way of doing this in Java is to start with the java.awt.Frame object and then to add new functionality that will cause it automatically add a button to itself when it is used.

6.2 Terminology (i.e. More Technical Jargon)

Before going any further, it is important that certain terms are properly defined. Words such as "object" have a somewhat ambiguous meaning, so it is often useful to use a more formal terms that have more exact and well-defined meanings. Although these words are, essentially, computer jargon, it's useful to know them because most other books use them and because their precise meanings help avoid confusion.

The type of an object is known as a class. For example, if you have a java.awt.Button object, then the class of the object is java.awt.Button. The actual object itself is known as an instance of a class or as just an instance. For example, in the following line of code

  java.awt.Button okButton = new java.awt.Button("OK");

creates an instance of java.awt.Button (previously, I probably referred to this as creating a java.awt.Button object).

So to clarify, the type of an object is a class. Objects of a certain type are instances of that class. To create a new class is to create a new type of object.

Note: because the formal terminology is sort of obscure, I'll often use the less formal and more ambiguous terminology in this document in places.

6.3 Subclassing

As we saw previously, java.awt.Frame is the class used for creating and displaying windows. We want to create a new class that, basically, does all the things that java.awt.Frame does but also automatically adds a button to itself. Let's call this new class ButtonWindow because it will be used to create windows with buttons in them. So basically, we want to create a new class by starting with java.awt.Frame and adding new features to it.

This is known as inheritance because the new ButtonWindow class you create will inherit all the functionality of java.awt.Frame and then add new functionality to it. This is also sometimes referred to as subclassing.

This inheritance relationship is often denoted using an inheritance diagram.

[Picture of ButtonWindow inheriting from java.awt.Frame]

Although the above diagram is useful sometimes, below is a more suggestive diagram of what inheritance means.

[Picture of ButtonWindow wrappering java.awt.Frame (methods listed on right?)]

By inheriting or subclassing from java.awt.Frame, ButtonWindow "wraps" itself around a java.awt.Frame. When a command is sent to a ButtonWindow object, it usually just passes right through to the java.awt.Frame object inside. Or, more precisely, when a method is invoked on an instance of ButtonWindow, it is passed through to the instance of java.awt.Frame inside of it. Whenever you create a ButtonWindow object, it will contain a java.awt.Frame object inside of it. And if you send a setSize() command to this ButtonWindow object, it will be sent to the java.awt.Frame object inside of it. So, essentially, when you set the size of a ButtonWindow, you are merely setting the size of the java.awt.Frame. The ButtonWindow doesn't know how to set its size, so instead, the command is passed on to java.awt.Frame which does understand how to set the size of a window.

[Picture of commands passing through ButtonWindow to java.awt.Frame]

This is the behaviour you want. You WANT the ButtonWindow to understand all the same commands that java.awt.Frame does. Since all commands sent to a ButtonWindow automatically pass through to a java.awt.Frame object, the ButtonWindow seems to understand all the same commands as a java.awt.Frame and respond in the same way.

But if the ButtonWindow simply behaves exactly the same as a java.awt.Frame, how do you add new functionality to the ButtonWindow? You do this by intercepting commands. For example, when an object is first created, the special constructor method of the object is invoked that will properly initialize the object. You can set up the ButtonWindow to intercept the constructor and do its own setup instead.

[Picture of interception of commands being sent]

When the show() command is sent to the ButtonWindow, you can intercept that as well and properly position the button inside of the window. You can then pass the show() command onto the Frame that is wrappered by the ButtonWindow so that the window actually gets shown/

6.4 Making a New ButtonWindow Class

In Java, every class must be put in a file with the same name as the class. For this reason, our ButtonWindow class must go inside a file ButtonWindow.java. The general format for a new class is
public class name-of-class
{
  // Code for the class goes here
}

Therefore, to create the ButtonWindow class, you would put the following code in ButtonWindow.java:

public class ButtonWindow
{
  // Code for the ButtonWindow
}

Things to note:

If you compile the above code (using javac ButtonWindow.java), it should be properly understood by the Java compiler. Although the above code properly specifies a new class, you need to type in some more stuff to tell the compiler that ButtonWindow inherits from java.awt.Frame. You do this with the extends keyword.

public class ButtonWindow extends java.awt.Frame
{
  // Code for the ButtonWindow
}

Things to note:

6.5 Using Your New Class

So far, your ButtonWindow will behave exactly the same as the java.awt.Frame class. In fact, you can use it in your code exactly as if it were a java.awt.Frame.
public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object
    java.awt.Frame window = new ButtonWindow();
  
    // Resize the window only
    window.setSize(500, 50);
  
    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window.show();
  
    // Wait for 5 seconds
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the window using the dispose command
    window.dispose();
  }
}

Things to note:

[picture of stuff that gets passed on and not passed on in ButtonWindw]

6.6 Constructor Chaining

As mentioned earlier, when a constructor is invoked, Java does not automatically pass on the constructor to an object's superclass. For this reason, you have to make new constructors yourself. This is the format of a constructor
public class name-of-class
{
  public name-of-class( /* parameters go here */ )
  {
    // Code for the constructor goes here
  }
}

Here is what the constructor would look like for the ButtonWindow:

public class ButtonWindow extends java.awt.Frame
{
  public ButtonWindow()
  {
    super();
  }
}

Things to note:

Now let's add a constructor that will allow you to pass in the title of the window.

public class ButtonWindow extends java.awt.Frame
{
  // Default constructor that makes a window with the
  // title "no title"
  public ButtonWindow()
  {
    super("No Title");
  }
  
  // Constructor that allows you to pass in a string to
  // be used as a title
  public ButtonWindow(java.lang.String title)
  {
    super(title);
  }
}

Things to note:

Now that you've added constructors to your class, you can use them when you create your object

  java.awt.Frame window = new ButtonWindow("Title here");

6.7 Adding New Methods

So now we need an easy way to add a button to this window. We'll add a new method to the class that we can call to add the button for us.

[Picture of this]

This is the format for methods:

public class name-of-class
{
  public return-type name-of-method( /* parameters go here */ )
  {
    // Code for the method goes here
  }
}

Things to note:

So here's what a bunch of different methods might look like

  // Returns an integer (takes no arguments)
  int getSize()
  
  // Prints a string. Doesn't return anything, so it uses
  // void as its return type
  void printStuff(java.lang.String stuff)
  
  // Sets the width and height of something
  void setSize(int width, int height)
  
  // Causes your computer to explode
  void selfDestruct()

Things to note:

Now let's add a method to our class that will add a button to the window

public class ButtonWindow extends java.awt.Frame
{
  // Constructors
  public ButtonWindow()
  { super("No Title"); }
  
  // ...
 
  // Adds a button to the window
  public void addButton()
  {
    // Create a button with "Click Me!" on it
    java.awt.Button button = new java.awt.Button("Click Me!");
    
    // Add the button to the window
    this.add(button);
  }
}

Things to note:

In Java, if you don't specify an object to send a command to, it automatically sends the command to itself (ie the object it is currently in). So we actually don't need all the "this" things in the code. So the following code is equivalent to the above code

  // Adds a button to the window
  public void addButton()
  {
    // Create a button with "Click Me!" on it
    java.awt.Button button = new java.awt.Button("Click Me!");
    
    // Add the button to the window
    add(button);
  }

So in MyProgram.java, we can easily add a button to the ButtonWindow with just one line now

public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object and add a button to it
    ButtonWindow window = new ButtonWindow();
    window.addButton();
  
    // Resize the window only
    window.setSize(500, 50);
  
    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window.show();
  
    // Wait for 5 seconds
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the window using the dispose command
    window.dispose();
  }
}

Things to note:

Of course, we want the ButtonWindow to automatically add the button to itself, so we'll modify the constructor of ButtonWindow to automatically add a button to the window when the object is first created.

public class ButtonWindow extends java.awt.Frame
{
  // Constructors
  public ButtonWindow()
  {
    super("No Title"); 
    addButton();
  }
  
  public ButtonWindow(java.lang.String title)
  {
    super(title);
    addButton();
  }
 
  // Adds a button to the window
  public void addButton()
  {
    // Add the button with "Click Me!" on it to the window
    add( new java.awt.Button("Click Me!") );
  }
}

Things to note:

6.8 Instance Variables

It would be nice if you could send a command to a ButtonWindow instance to change the text that is on the button. We can do this by adding a new method called changeButtonText()
public class ButtonWindow extends java.awt.Frame
{
  // Constructors
  public ButtonWindow()
    { super("No Title"); addButton(); }
  public ButtonWindow(java.lang.String title)
    { super(title); addButton(); }
 
  // Adds a button to the window
  public void addButton()
  {
    // Add the button with "Click Me!" on it to the window
    java.awt.Button button = new java.awt.Button("Click Me!");
    add( button );
  }
  
  // Change the text on the button
  public void changeButtonText(java.lang.String text)
  {
    // Change the text on the button
  }
}

Unfortunately, in order to change the text on the button, we need to send a setLabel() command to the button. The problem is that we no longer have access to the button object since we've "abandoned" it. When we created an instance of the java.awt.Button object in addButton(), we put it into a variable called button. Unfortunately, variables only exist in-between of the curly braces. So if we can't access the button variable in the changeButtonText() method.

To get around this, we use what are known as instance variables. These are variables that are part of the object and that all the methods of the object can access. Instance variables are exactly the same as regular variables except they are put outside of all of the methods. This makes sense because if a variable only exists in-between the curly braces, by being outside of any of the methods, it implies that the variable exists in the object and can be accessed by all of the methods.

public class ButtonWindow extends java.awt.Frame
{
  // Constructors
  public ButtonWindow()
    { super("No Title"); addButton(); }
  public ButtonWindow(java.lang.String title)
    { super(title); addButton(); }
  
  // Have a variable called button for holding the button
  // that's in the window
  public java.awt.Button button;
 
  // Adds a button to the window
  public void addButton()
  {
    // Add the button with "Click Me!" on it to the window
    button = new java.awt.Button("Click Me!");
    add( button );
  }
  
  // Change the text on the button
  public void changeButtonText(java.lang.String text)
  {
    button.setLabel(text);
  }
}

Things to note:

6.9 Overriding Methods

Now, whenever we create the window, a button is automatically added to it. It is also possible to change the text on the button. What we'll do now is to modify the ButtonWindow object so that when you show it, both the window and the button will always come up at the same location and with the same size.

What we'll do is to intercept the show() command. When the ButtonWindow is "shown," the button and window will be repositioned into good locations.

Even though java.awt.Frame already understands the show() method, intercepting this method is done in exactly the same way as creating a new method.

public class ButtonWindow extends java.awt.Frame
{
  // Constructors
  public ButtonWindow()
    { super("No Title"); addButton(); }
  public ButtonWindow(java.lang.String title)
    { super(title); addButton(); }
  
  // Have a variable called button for holding the button
  // that's in the window
  public java.awt.Button button;
 
  // Adds a button to the window
  public void addButton()
  {
    // Add the button with "Click Me!" on it to the window
    button = new java.awt.Button("Click Me!");
    add( button );
  }
  
  // Change the text on the button
  public void changeButtonText(java.lang.String text)
  {
    button.setLabel(text);
  }
  
  // Intercepts the show() method so that the window and
  // button can be layed-out nicely
  public void show()
  {
    // Disable the layout manager
    setLayout(null);
  
    // Position the window in a nice location
    setBounds(20, 20, 200, 200);
  
    // Now position the button within the window
    button.setBounds(50, 50, 50, 50);
  
    // Now let the java.awt.Frame show the window
    super.show();
  }
}

Things to note:

In MyProgram.java, we can now use the ButtonWindow and have a window with a button pop-up:

public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object and show it
    ButtonWindow window = new ButtonWindow();
    window.show();
  
    // Wait for 5 seconds
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the window using the dispose command
    window.dispose();
  }
}

6.10 A Note About Packages and Namespaces

to come later

[Prev] [Next]

[Home]


Last updated November 18, 1998.
Maintained by Ming-Yee Iu
.

sending commands / messages to objects
consistency in terminology