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

Lesson 12.2 Frames & Friends

Frame, Toolkit & Window

In this lesson, you'll learn more about the methods of the Frame class. You'll also meet the Window class which can be used to create "splash" screens and screen savers, as well as the Toolkit class which can be used to discover a little about your user's environment.

If you want to find out more about the WindowListener methods, simply add a System.out.println() to each of seven "dummy" methods you added in GuiApp.java to fullfill the WindowListener interface contract.

This allows you to visually see when each of the particular WindowListener events is "fired". For instance, when your application first starts, you'll see that both the windowOpened() and the windowActivated() methods are called.

Most of the time, you won't override any of the WindowListener events except for windowClosing(). Occassionally, however, overriding the windowActivated() and windowDeactivated() methods is useful as well. You might, for example, want to start an animation when your Frame becomes active, and stop it when your user selects another window.

Component Methods

Frames, and Frame subclasses such as GuiApp, are descended from the Component class as well as from the Container class, so most of the methods you met when dealing with Components still hold true for Frames.

You can find out how big your Frame is by sending it the getSize() method. Unlike with an applet, however, the size returned is the size of the window, not just the "inside" part. This has some ramifications if you want to draw on the surface of your Frame.

This is the code you use to draw an X on a Panel or Applet. [This would be inside a paint() method.]

int w = getSize().width;
int h = getSize().height;
g.drawLine(0, 0, w-1, h-1);
g.drawLine(0, h-1, w-1, 0);

This code won't work correctly with a Frame, however; the X is partly consumed by the title bar and the border of the Frame. To get the same effect as with an applet, you have to use both the translate() method and the getInsets() method to adjust the size of your drawing area like this:
// 1. Remove borders from drawing size
int w = getSize().width - 
         (getInsets().left + getInsets().right);
int h = getSize().height - 
         (getInsets().top + getInsets().bottom);

// 2. Move point 0,0 to "client" area
g.translate(getInsets().left, getInsets().top);

// 3. Draw as usual
g.drawLine(0, 0, w-1, h-1);
g.drawLine(0, h-1, w-1, 0);

Back to Top

Resizing and Locating

You can change the overall size of a Frame by using the setSize() method. There are two versions:
setSize(Dimension d);
setSize(int width, int height);

As you've previously discovered, using setSize() with most components is tricky, because the layout manager is free to disregard your instructions. Frames, however, are not under the control of a layout manager, so your instructions work as expected.

There are two Component methods you can use to find out where your Frame is on the screen. Both return a Point object. [Remember that a Point has two public fields x and y].

Point p1 = getLocation();
Point p2 = getLocationOnScreen();

When used with a Frame object, both of these methods do exactly the same thing: they return the location of the upper-left corner of the Frame, relative to the upper-left corner of the screen. With other Components--a Button or Label, for instance--getLocation() returns a point relative to the Component's container.

Repositioning

You can change the location of a Frame by using the setLocation() method. There are two versions:
setLocation(int x, int y);
setLocation(Point p);

You can also change both size and location at the same time by using the setBounds() method. Again, there are two versions:

setBounds(Rectangle r);
setBounds(int x, int y, 
          int width, int height);
Back to Top

Other Frame Methods

In addition to the methods inherited from Component and Container, the Frame class has a few methods of its own. [Some of these it shares with its immediate ancestor, Window.]

When two windows appear on the screen, they can overlap each other. When this occurs, one window will appear to be "on top." [This is an illusion, of course. Your video display is a 2D plane.]

This illusion of depth is called the "Z-order". The Z-order of a window is normally changed by activating it or by activating another window. The active window normally comes to the "front". 

You can directly manipulate the Z-order of a Frame by calling one of these methods:

toFront();
toBack();

Frame Behavior

There are several useful methods that change the way the Frame behaves. For instance:
setResizable([true | false]);

allows you to make a non-resizable window. [The vertical bar in this instance means "OR". Pass true or false when calling setResizable().] By default, Frames are resizable, but that's not always desirable behavior.

If you want to change the title that appears at the top of your Frame, you can use this method:

setTitle(String);

You can also change the mouse cursor that appears when the mouse is moved over your Frame, using:

setCursor(int);

This method has been mostly superceded in Java 1.1 by the Component version of setCursor(), which takes a Cursor object as an argument. Using the Component version you can assign a separate mouse cursor to each of your controls, which is useful.

The Frame.setCursor() method is still needed, however, when you are trying to write a Java 1.0 applet.

When you call the Frame version of setCursor() pass one of these predefined static final constants:

DEFAULT_CURSOR
CROSSHAIR_CURSOR
TEXT_CURSOR
WAIT_CURSOR
SW_RESIZE_CURSOR
SE_RESIZE_CURSOR
NW_RESIZE_CURSOR
NE_RESIZE_CURSOR
N_RESIZE_CURSOR
S_RESIZE_CURSOR
W_RESIZE_CURSOR
E_RESIZE_CURSOR
HAND_CURSOR
MOVE_CURSOR

Because these are static final constants, you use them by referring to the name of the class like this:

setCursor(Frame.WAIT_CURSOR);
Back to Top

The Toolkit Class

Being able to size and reposition your Frames is useful, but what do you do when you want to size or reposition a Frame based upon the user's environment? 

This is a common requirement. You may want to make your Frame full screen, or center it, for instance. The Toolkit class lets you query your user's system to get the information you need to carry out these tasks.

Creating and Using a Toolkit

You create a Toolkit object by calling the static Toolkit method, getDefaultToolkit() like this:

Toolkit tk = Toolkit.getDefaultToolkit();

The Toolkit object you get back is specific to the system running the program. 

Most of the roughly two-dozen methods in the Toolkit class should not be used by your application--they are "glue" methods used to connect AWT components with their native "peers" on each O/S. 

Along with these "system" methods, however, are a handful of miscellaneous methods used by application programmers. Here are some examples.

Toolkit beep()

The AudioClip class allows you to have sound in your applets, but not in applications. Although it is no replacement for the AudioClip class, the Toolkit beep() method allows you to add at least some audible feedback to your application programs. The resulting sound is entirely platform dependent.

Here's an applet, Beep.java, that lets you try out the beep() method on your machine. What would you have to do to turn it into an application?
Beep.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class Beep extends Applet implements ActionListener
{
  public void init()
  {
      Button b = new Button("Beep");
      b.addActionListener(this);
      add(b);
  }
  public void actionPerformed(ActionEvent ae)
  {
      Toolkit tk = Toolkit.getDefaultToolkit();
      tk.beep();
  }
}

Back to Top

Image Methods

The beep() method is a poor replacement for the AudioClip class, but it's the only alternative when writing a GUI application. That's not true when it comes to Images, however.

In Lesson 11, you used the Applet getImage() method to retrieve the Images you wanted to display. One of the limitations of Applet getImage(), you'll recall, is that it can only retrieve an Image from the same place where your applet is located.

The two versions of getImage() provided by the Toolkit class have no such limitations. You can load an image from a local file using this version:

Image im = getImage(String);

You can also load an image from a remote server using this version:

Image im = getImage(URL);

To construct the URL object for this second version, you must import the java.net package, and use one of the URL constructors inside a try-catch block. You'll learn more about URL objects in the next lesson. 

For now, however, here's a brief application, Images.java, derived from the GuiApp class, that loads both a local file and a remote image, and paints them both on its surface.

To run Images.java, download the source code by clicking on the hyperlink, and place it in the same directory as GuiApp.java. Change the names of the graphics files as you like and then compile using javac as usual.

Run the program by using java like this:

C:\> java Images
On the Mac, you'll have to use JBindery to create an application. You might also want to copy the source code from MainFrame.java to the bottom of Images.java, removing the public in front of the class declaration.

On my machine, here's how the application looks:

Running the Images application.
Back to Top

Screen Size and Resolution

Besides getImage(), perhaps the most used methods in the Toolkit class is the one that allows you to find out the size of your user's screen. You can also find the screen resoultion [in pixels per inch], but I've found that much less useful.

Here are the two methods you use:

Dimension size = tk.getScreenSize();
Dimension res = tk.getScreenResolution();

Here's a small applet, Frames.java, that creates three Frames, and places them around your screen:
Frames.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class Frames extends Applet implements ActionListener
{
  Button open  = new Button("Open Frames");
  Button close = new Button("Close Frames");

  Toolkit tk = Toolkit.getDefaultToolkit();

  Frame f1, f2, f3;   public void init()
  {
    add(open);
    add(close);
    open.addActionListener(this);
    close.addActionListener(this);
  }   public void actionPerformed(ActionEvent ae)
  {
    if (ae.getSource() == open)
    {
      if (f1 == null)
      {
        // First time -- create Frame objects         int w = getSize().width;
        int h = getSize().height;

       Dimension size = tk.getScreenSize();

        f1 = new Frame("Top");
        f1.setBounds(0, 0, size.width, 150);

        f2 = new Frame("Left");
        f2.setBounds(0, 150, 
                   150, size.height-150);

        f3 = new Frame("Right");
        f3.setBounds(size.width-150, 150, 
                     150, size.height-150);
      }
      f1.show();
      f2.show();
      f3.show();
    }
    else
    {
      if (f1 != null)
      {
        f1.hide();
        f2.hide();
        f3.hide();
      }
    }
  }
}

Back to Top

The Window Class

The Window class creates "stand-alone" top-level windows much like the Frame class does, but Window objects are a little more primitive. 

Specifically, Window objects:

  • Have no border.
  • Cannot be resized.
  • Have no title bar.
  • Cannot contain a menu.
  • Must have a Frame object that "owns" them.
This means that Window objects aren't really suitable for use as a main application window. There are two or three places, however, where the Window's lack of decoration provides an advantage:
  • When used as a "splash panel". A splash panel is the identifying window that appears as an application is first loading.
  • When used as a "screen saver" window where the lack of a border is a benefit rather than a problem.
  • When used as a "tool-tip" window that must appear over the top of other windows and components.

A Splash Panel

Let's try using the Window class to build a splash panel that displays an image. Our splash panel will automatically center and size itself, and, after ten seconds, disappear.

Here are the steps to follow:

  • Create a new class that extends the Window class called SplashPanel. You have to import java.awt, but don't need java.applet.
  • Add three private fields: anImage named img, and two int fields, height and width
  • Add a constructor that takes a single argument, the Image to display. [Note that this must be an Image object, not the name of a file.] 
Your program should look like this:

import java.awt.*;
public class SplashPanel extends Window
{
  private Image img;
  private int width, height;

  public SplashPanel(Image img)
  {
  }
}

Back to Top

The Constructor

Your constructor has to do three things:
  • First it must call the superclass [Window] constructor. The Window constructor requires a Frame object, so the first line inside your SplashPanel constructor should be:

  • super(new Frame());
  • Next it must create a MediaTracker object and wait for the Image passed as an argument to completely arrive. Once the Image has completely arrived, assign it to the Image field img like this:

  • MediaTracker mt = new MediaTracker(this);
    mt.addImage(img, 0);
    try
    {
      mt.waitForID(0);
    }
    catch (InterruptedException e) { }
    this.img = img;
  • Finally, the constructor should size, position, and display the SplashPanel, using a Toolkit object to measure the screen, and using setBounds() to arrange it appropriately. Here's the code to do that:
  • Toolkit tk = Toolkit.getDefaultToolkit();
    Dimension size = tk.getScreenSize();

    width = size.width  / 3;
    height = size.height / 3;

    setBounds(width, height, width, height);
    show();

Painting the Panel

Inside paint() method, we need to do four things:
  1. Paint the background a nice, light gray.
  2. Draw the beveled edge around the panel.
  3. Draw the image in the center of the panel.
  4. Wait ten seconds and then destroy the window.

Here's the code that accomplishes each of these tasks. The step are numbered in the program to help you recognize each step:

public void paint(Graphics g)
{
  // 1. Fill the background
  g.setColor(Color.lightGray);
  g.fillRect(0, 0, width, height);

  // 2. Draw a beveled border
  for (int i = 0; i < 4; i++)
    g.draw3DRect(0+i, 0+i, width-(i*2),
                height-(i*2), true);

  // 3. Draw the image in the center of the panel
  g.drawImage(img, 4, 4,
              width-8, height-8, this);

  // 4. Wait for ten seconds and then disappear
  try
  {
    Thread.sleep(10000);
  }
  catch (InterruptedException ie) { }

  dispose();
}

Back to Top

Try It Out

You can download the code for SplashPanel.java if you'd like to change it to meet your needs. In the meantime, here's a short applet that uses the SplashPanel. By now, of course, you've already seen the applet at work.

SplashTest.java
import java.awt.*;
import java.applet.*;

public class SplashTest extends Applet
{
  public void start()
  {
    Image img = 
        getImage(getCodeBase(), "jol12.jpg");
    SplashPanel p = new SplashPanel(img);
  }
}


Something to Talk About

Suppose you wanted to write a screen saver using the Window class. How would you go about it?

Please continue to the next section of this lesson.

 

Back to Top

 

Content Developed by Stephen Gilbert, Licensed under a Creative Commons License
Published by the Sofia Open Content Initiative
© 2004 Foothill-De Anza Community College District &The William and Flora Hewlett Foundation