13.1 Drawing Text


Java's Application Programming Interface (API) has an enormous number of classes containing fields and methods for creating and manipulating GUI's. In early versions of Java, these classes formed Java's Abstract Windowing Toolkit (AWT) but these have, to a large extent, been superseded in more recent releases of the language by a collection of classes called Swing. Together, Swing and a version of the AWT that is much expanded from its original structure, form the Java Foundation Classes (JFC). The JFC is a huge collection and, in this chapter, we will only scrape its surface but there is enough material here to enable you to create GUI's that should be adequate for a wide variety of programs.
We start our study of GUI's very much as we did in Chapter 1, with a program that displays the message "Hello, world". This time, however, the message will be contained in a window like those in the system in which you are working.

 

Example 1

The following program creates and displays a window that contains a greeting to the world.

import javax.swing.JFrame;
import javax.swing.JComponent;
import java.awt.Graphics;

public class GUIGreet
{
   public GUIGreet()
   {
      JFrame frame = new JFrame("Graphical Greeting");
      frame.setSize(400,100);  
      frame.add(new Drawing());
      frame.setVisible(true);
   }
   
   public static void main (String[] args)
   {
      new GUIGreet();
   }

   class Drawing extends JComponent
   {
      public void paint (Graphics g)
      {
         g.drawString("Hello, world",150,50);

      }
   }
}
 

If you run this program, it should produce a window like the following:


This window can be resized, dragged around the screen, minimized, and so on - just like any other window in your system. As you can see, this program contains many new features of the language. Let us now take a look at these new items.

  1. import javax.swing.JFrame;
    As we have said before, Java's classes are organized into units called packages. Up to now, the Java classes that you have been dealing with may all have been in the package
    java.lang, the core package of the language. Here, however, we need classes from other packages. The five import statements at the beginning of the program tell the compiler that we will be using certain classes in other packages. If we did not use import, we would have to specify the full name of any class outside java.lang. For example, without import, the statement
  JFrame frame = new JFrame();

would have had to be rewritten as

  javax.swing.JFrame frame = new javax.swing.JFrame();

 

  1. public GUIGreet()
    The purpose of the constructor is to set up a window to display the output of the program.

 

  1. JFrame frame = new JFrame(“Graphical Greeting”);
    The main method starts to create the window by constructing a JFrame object that we have called
    frame. A JFrame object acts as a top-level container for other objects. The string argument of the JFrame constructor appears in the title bar that runs along the top of the window.

 

  1. frame.setSize(400,100);
    The method
    setSize, as the name implies, sets the dimensions of the window that will be displayed when the program starts running. In drawing to a screen, the unit of measure is the pixel, the smallest unit of resolution for that screen. Our window is 400 pixels wide and 100 pixels high.

 

  1. frame.add(new Drawing());
    Now, we construct a new
    Drawing object and add it to the window using the add method of the JFrame class.

 

  1. frame.setVisible(true);
    A call to the
    setVisible method with the argument true is required to enable us to see the image.

 

  1. class Greeting extends JComponent
    The class
    Greeting is defined by extends to be a subclass of the class JComponent in the package javax.swing. Therefore it inherits all of that class's methods. The inherited method that we will be using in this program is paint.

 

  1. public void paint(Graphics g)
    This method overrides the
    paint method of the class JComponent so that it will paint whatever we want on our component. The parameter of the method is a Graphics object that is created by Java and assigned to g when the paint method is called. The object g stores the properties (such as colour, font size, and so on) associated with the component's area of the screen. The paint method is called by Java whenever the application should be drawn (or redrawn) onto the screen.

 

  1. g.drawString("Hello, world",150,50);
    This statement uses the
    drawString method from the Graphics class to draw the contents of a string. The last two arguments give the coordinates (in pixels) of the left end of the baseline of the first character in the string. The first coordinate gives the horizontal distance of this point from the left side of the area while the second coordinate gives the vertical distance from the top. Here, then, the message will start 150 pixels from the left, with its base 50 pixels below the top. It is,therefore, roughly in the centre of the component.



When we run the program, the
main method executes and terminates but the window stays on the screen until we close it with our mouse. What is happening here is an example of multi-threading. Up to now, our programs have executed code and, once they have finished that task, they have stopped automatically. When we create a window, however, this starts the execution of a new, separate process (or thread) that operates in response to events such as mouse clicks, button presses, and so on. We refer to programs that operate in response to events as being event driven. Discussion of events and responses to them will be one of the primary topics of this chapter.
As our program stands, it has one major problem. Even when we close the window, the program keeps running! To terminate the program, we must do whatever our system requires. You might be able to do this by pressing
[ctrl]C but the actions necessary to kill a program vary from one environment to another. If we want the program to stop when the window is closed, we must explicitly add a feature that allows the program to respond to the window-closing event by halting the thread. The procedure for doing this involves the use of a number of features that we have not yet seen. We give the code here (so that you can write programs that terminate) but we will defer our discussion of it until later in the chapter.

Example 2

The following code, inserted into the constructor for GUIGreet in example 1, will cause the program to terminate when the window defined by frame is closed.

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 


The size and style of the text displayed in a window can be controlled using the class
java.awt.Font. To change to something other than the default font, we must specify a font name, a style, and a size. We do this by first constructing a Font object, passing it a font, style, and size. The basic choices for font are "Serif", "SansSerif", and "Monospaced". The style should be one of the constants Font.PLAIN, Font.BOLD, Font.ITALIC, or Font.BOLD+Font.ITALIC. The size is specified in points. To give you a feeling for point measurements, the size of this text should be (about) ten points. (We say "about" because, at the time that this was written, the final style of the text had not been determined.) A Font object can be used in drawing by invoking the setFont method from the Graphics class to apply the font to a Graphics object, as shown in the next example.

Example 3

The following fragment could be used in a paint method to draw the word "tiny".

 
        Font smallMonoFont = new Font("Monospaced",Font.PLAIN,6);
        g.setFont(smallMonoFont);
        g.drawString("tiny",50,50);

One other way in which we can improve our program is to simplify the import statements. Rather than writing an import statement for each class that we want to use (outside the package java.lang), we can use an asterisk as a "wild card" character to say, in effect, that we want to be able to use any class in a particular package. For our example, we can replace the statements

 
        import javax.swing.JFrame;
        import javax.swing.JPanel;
        import java.awt.Container;
        import javax.swing.JComponent;
        import java.awt.Graphics;
        import java.awt.event.WindowEvent;
 

with these statements

 
        import javax.swing.*;
        import java.awt.*;
        import java.awt.event.*;


In the next example, we again greet the world. Now, however, we incorporate a simplified set of import statements, code to terminate the program when the window is closed and a more impressive font for our salutation.

Example 4

Here is the code for our revised version of our greeting to the world.

import javax.swing.*;
import java.awt.*;

public class RevisedGreet
{
   public RevisedGreet()
   {
      JFrame frame = new JFrame("Big Greeting");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(400,100);  
      frame.add(new Drawing());
      frame.setVisible(true);
   }
   
   public static void main (String[] args)
   {
      new RevisedGreet();
   }

   class Drawing extends JComponent
   {
      public void paint (Graphics g)
      {
         Font largeSerifFont = new Font("Serif", Font.PLAIN, 40);
         g.setFont(largeSerifFont);
         g.drawString("Hello, world",100,50);

      }
   }
} 

The window produced by this program should look like this.

Exercise 13.1

  1. How would you set the title of a window to be Sample?
  2. Rewrite the lines that would have to be changed in the program Example 1 if the import statements were omitted.
  3. In Example 1, explain what would happen if the call to drawString were changed to
    g.drawString("Hello world",0,0);
  4. What changes would have to be made in Example 4 to produce a greeting that was
    1. italicized?
    2. bold and italicized?
  5. Write a program that will draw your name and address in a window, as they would appear on an envelope. Try to have the output appear near the centre of the window.