Home Java Java-tips GUI Tutorial GUI Tutorial I - FIRST DRAFT

Ask Questions?

View Latest Questions

Advertisement


 
 

GUI Tutorial I - FIRST DRAFT
Posted on: July 26, 2006 at 12:00 AM
The tutorial presents model programs of increasing capability.

Table of Contents

GUI Tutorial I - FIRST DRAFT

Table of contents

  1. Introduction
  2. Tiny Window - The smallest window you can build.
  3. Tiny Window with subclass in two source files
  4. Dog Years - GUI only - This is the GUI interface, but it doesn't respond to a button click.
  5. Dog Years - GUI and "Model/Logic" - The DogYears program that performs the conversion.
  6. Next Steps - Where to go from here.

Introduction

Summary. This is an introduction to writing Graphical User Interfaces (GUIs). You will be able to do many programming projects after reading this tutorial. The tutorial presents model programs of increasing capability. The second (unwritten) tutorial covers additional topics such as menus, text areas, check boxes, additional layouts, graphics, threads, etc.

Prerequisites. Your should have a basic understanding of expressions, if statements, classes, and methods. If you are taking a programming course, this should fit comfortably in the middle of learning Java. You don't need to know arrays, collections, or exceptions.

The price of flexibility. Java's flexibility provides the experienced programmer with many alternatives from which to choose, but choices are a problem for the beginner because only a few are good, and the others typically lead to an unhappy programming life.

Dog house. When you're building something small, almost any approach works. For example, to build a dog house, you don't need clear plans, can easily patch up mistakes, etc. Building a house requires both more skills and the use of good techniques. A good dog-house builder isn't necessarily going to be good at building houses, much less office buildings.

This tutorial is intended to keep simple things simple, yet present techniques which scale up to house size. You'll be able to build substantial programs using these skills, but the Java equivalent of commercial buildings requires techniques which are beyond the scope of this tutorial.

Rationale. When you build your first GUI programs, I suggest you imitate the examples. Eventually you will want to know why certain choices were made and about alternatives. Or perhaps you will see different ways presented in different text books and wonder if they are better, worse, or just different. Or you're reading this and already know about building GUI interfaces, but question the choices here. To answer these questions after you understand how to build GUIs, read Rationale for GUI tutorial decisions.

Read-compute-write versus event-driven programming

Read-compute-write. Most programmers start with a common model for programming: read input data, process the input data, write the output data. This might even be done in a loop to process more than one set of input data. The essential mindset is that the programmer is in control at all times. This is a very useful paradigm, but GUI programming requires you to change your thinking, and to give up this feeling of total control. It may feel uncomfortable at the beginning, but you'll get used to it.

Event-driven programming. The GUI programming style is referred to as event-driven programming. In this type of programming you set up the graphical user interface, initialize things, then you stop doing anything! The program just sits there doing nothing. When the user clicks on a button (or something similar), a listener method is called. You implement the actions associated with the button in the listeners. In other words, it's the user who chooses which methods to execute. They don't think about it quite this way, but you will.

Remaining to do

Explain components, write final example which separates logic from GUI, image to point out individual components, run-time vs initialization, model vs GUI, add programming problems, divide into time manageable chunks, ...

2. Tiny Window - Your first window

Let's start by learning how to build the simplest possible window.

The following is a very small program that creates a window. It doesn't do anything, and it's so small you might have a hard time finding it in the upper left corner of your screen.

A default JFrame can do a few things -- it understands minimize and maximize, it can be dragged from the title bar, and it can be resized. If you resize it, you'll notice that the content pane is completely empty -- we haven't added any components to it yet.

Close box. One thing that the default JFrame doesn't handle well is the close box. The default close box simply makes the window invisible, but doesn't stop the program! You must explicitly make the close box do something. A good choice for simple programs is to terminate the program.

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
// File   : gui-tutorial/tw/TinyWindow.java
// Purpose: Creates a very small window!
//          This is just about the smallest GUI program you can write.
//          It does nothing, but you can see that the close box works
//          and the window can be resized.
// Author : Fred Swartz
// Date   : 2005-06-17

import javax.swing.*;                                           //Note 1

////////////////////////////////////////////////////// class TinyWindow
class TinyWindow {
    // ===================================================== method main
    public static void main(String[] args) {
        JFrame window;                                          //Note 2
        window = new JFrame();                                  //Note 3
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //Note 4
        window.setVisible(true);                                //Note 5
    }                                                           //Note 6
}

Notes

  1. This import statement gets all of the Swing classes, although we only use the JFrame class here. Normally there are a couple of other imports of other common packages..
  2. The common idea of "window" is implemented by the JFrame class.
  3. Create a JFrame object..
  4. Make the application quit when the close box is clicked.
  5. After the window has been constructed in memory, display it on the screen. The setVisible call also starts a separate thread to monitor user interaction with the interface.
  6. When we are finished setting up and displaying the window, don't call System.exit(0); We don't want to stop the program. Although main returns here, execution continues because of the call to setVisible(true), A GUI program builds the user interface, then just "goes to sleep" until the user does something.

2. Example - Tiny Window with subclass

This is a reimplementation of the TinyWindow program, but using the common style of building windows by defining a subclass of JFrame. Because I didn't like the idea of showing a completely empty constructor, although it would have run OK, a call on setTitle was added to put text in the window's title bar, as you can see in the stretched version of this window below.

In the follow examples, all work of creating the contents of the JFrame is in the constructor.

Two classes. This has been divided into two classes, one containing the main program and one containing the JFrame subclass. It's perhaps more common to just stick the main program into one of the other classes, for example the subclass of JFrame, but that confuses the issues somewhat. For clarity I've separated them.

Two classes in one file. Each class can, and probably should be, put in a separate file.

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
// File   : gui-tutorial/tw2/TinyWindow2.java
// Purpose: Illustrate common JFrame subclass style for GUI
// Author : Fred Swartz
// Date   : 2005-06-09 (Primorsko, Bulgaria), 2005-06-19

import javax.swing.*;                                          //Note 1

////////////////////////////////////////////////// class TinyWinSubclass
class TinyWindow2 {

    //====================================================== method main
    public static void main(String[] args) {
        TinyWindowGUI2 window = new TinyWindowGUI2();          //Note 2
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Note 3
        window.setVisible(true);                               //Note 4
    }
}


/////////////////////////////////////////////////////// class TinyWinGUI
class TinyWindowGUI2 extends JFrame {                          //Note 5

    //====================================================== constructor
    public TinyWindowGUI2() {                                  //Note 6
        //... Set window characteristics
        setTitle("Tiny Window using JFrame Subclass");         //Note 7
    }
}

Notes

  1. "import javax.swing.*" is used to import JFrame. Importing all class in javax.swing is common practice and doesn't seem to be slower than importing only the one class.
  2. Create a new object (instance) of our own window class.
  3. Setting the default close action makes sure the program quits when the close box is clicked.
  4. setVisible(true) makes the window visible and starts GUI monitoring code.
  5. This new class is a subclass of JFrame (extends JFrame). This means it can do everything a JFrame can, in addition to what we define in it.
  6. A "constructor" is like a method, and is used to initialize a class. You can tell the difference between a constructor and a normal method by two characteristics: (1) It has the same name as the class, and (2) It has not return type.
  7. Because TinyWindowGUI2 is a subclass of JFrame, we're calling methods in "ourself", and it's not necessary to write an object in front of the call. We can write the "setTitle" call alone as here, or we can put "this." in front of it to clarify that this method is in this class or one of its ancestors.

Note there are two .class files

The Java compiler produces a ".class" file for each class. Although there is only one ".java" source file, the two classes defined in it each produce its own ".class" file.

3. Tiny Window with classes in two source files

Here is the previous example, but divided into two files. The source code is the same, except that each file has to have its own import statements.

Because you can put more than once source class in a file, the advantage of separate source files is not immediately obvious. As programs become larger, they are simple easier to maintain if the major classes are in separate files. You should get used to doing this because you will have to when you start working on larger programs.

Order of compilation. You need to create two .java files, one for each class, in the same directory (folder). Because one of these classes references the other (TinyWindow3 references TinyWindowGUI3 , but not vice versa), you should compile TinyWindowGUI3 first.

Execution. When you run this program, you must run the class which contains the main program.

Main program class

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
// File   : gui-tutorial/tw2/TinyWindow3.java
// Purpose: JFrame subclass style for GUI using two source files.
// Author : Fred Swartz
// Date   : 2005-06-19

import javax.swing.*;

class TinyWindow3 {

    public static void main(String[] args) {
        TinyWindowGUI3 window = new TinyWindowGUI3();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setVisible(true);
    }
}

GUI class

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
// File   : gui-tutorial/tw3/TinyWindowGUI3.java
// Purpose: This is the JFrame subclass in a separate file
// Author : Fred Swartz
// Date   : 2005-06-19

import javax.swing.*;

class TinyWindowGUI3 extends JFrame {

    //========================================= constructor
    public TinyWindowGUI3() {
        //... Set window characteristics
        setTitle("Tiny Window using JFrame Subclass");
    }
}

Make sure you can compile and run this program before moving to the next section.

4. Dog Years - GUI only

Dog years? We'll work on a really simple problem -- converting a dog's age into it's "equivalent" human age. The logic of the problem (multiplying by 7) is trivial so that we can concentrate on building the GUI.

This section shows how to build a graphical user interface, but it doesn't connect the button to a listener method which does the calculation. That will come in the next section.

You'll find that a lot of problems, especially beginning programming assignments, fit into this form: some input fields, a button that performs the computation, and some output fields that display the result. You should be able to take this program and modify it to solve these problems without too much work.

This program adds the following to the user interface

The previous example showed how to create a JFrame subclass, set the title, and make it visible. This section just about completes all tasks that you have to do to build a graphical user interface. After you have completed this, there's only one more think to do to make the program completely workable.

  • Create components. You have to create components that are used in the interface - this interface has labels (JLabel), text fields (JTextField), and a button (JButton). These are the parts used to build the dog house.
  • Content pane. There are two things you can add to a window - a menu bar (although this program doesn't have one) and the content pane (typically using a JPanel) that holds all the components. This is the area that you're going to build the doghouse on.
  • Layout. Every content pane has a layout that tells how to position and size the components. You don't have to specify the pixel position and size of each component; it's the layout's job to do that for you. This program uses FlowLayout, which is simple layout that arranges the components left-to-right. If the window is resized, it may flow the components on to another line if necessary. We'll look at better layouts in a later tutorial.
  • Add components to content pane. After you've set the layout, add each component to the content pane.
  • Pack. The pack() method call tells the content pane that you're finished adding components, and that it can do the layout now.

The DogYears window

DogYears user interface

[TODO: Identify the parts in this image with arrows and text.]

Components

Here's a very short summary of the components used in this example. Examples show the common constructor calls, and show the essential methods.

JLabel
Purpose: Typically used to display fixed text.
JLabel nameLabel = new JLabel("Name");

Usage: Because there is usually no need to refer to the label again, it is common to pass it directly to the add() method without saving in in a variable first.

content.add(new JLabel("Name"));

More: Read about additional options at JLabel. [TODO: JLabel pages need complete rewrite.]

JTextField
Purpose: Input or output of one line of text.

Constructor: The parameter specifies the approximate width of the text field as a number of characters.

JTextField myNameField = new JTextField(12);

Methods: The most common methods get and set the field's text. The following converts the text in a field to upper case.

String name = myNameField.getText();
String upperName = name.toUpperCase();
myNameField.setText(upperName);

Usage: Because it will be necessary to refer to the field from a listener, it should be defined as an instance variable.

More: Read about additional options at JTextField. [TODO: needs complete rewrite.]

JButton
Purpose: To call a listener when the the user clicks on it.

Constructor: The parameter specifies the text on the button.

JButton convertButton = new JButton("Convert To Uppercase");

Usage: When the listener is called, there is usually no reason to refer to the button, so it can be put in a local, not instance, variable.

Methods: addActionListener() must be called to associate a listener with the button.

convertButton.addActionListener(new convertAction());

More: Read about additional options at JButton. [TODO: needs complete rewrite.]

The DogYears main program

This looks just like the TinyWindow main program, except that instead of a simple JFrame, it uses a subclass of JFrame which has been extended to show that GUI that we want.

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
// File   : gui-tutorial/d1/DogYears.java
// Purpose: Main program for Dog Year Converter.
// Author : Fred Swartz
// Date   : 2005-06-06

import javax.swing.*;   // For JFrame reference.

/////////////////////////////////////////////////// class DogYears
class DogYears {

    //================================================ method main
    public static void main(String[] args) {
        DogYearsGUI_1 window = new DogYearsGUI_1();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setVisible(true);
    }
}

The DogYears GUI

This program produces a user interface, but there is no listener for the button so it doesn't do anything yet.

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
// File   : gui-tutorial/d1/DogYearsGUI_1.java
// Purpose: Use textfields and button to convert dog to human years.
//          NOTE: The button does nothing in this version.
// Author : Fred Swartz
// Date   : 2005-06-06

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

///////////////////////////////////////////////////// class DogYearsGUI_1
class DogYearsGUI_1 extends JFrame {

    //======================================= instance variables //Note 1
    private JTextField myHumanYearsTF = new JTextField(10);      //Note 2
    private JTextField myDogYearsTF   = new JTextField(10);
    private JButton    myConvertBtn   = new JButton("Convert");  //Note 3


    //====================================================== constructor
    public DogYearsGUI_1() {
        //... Create content panel, set layout
        JPanel content = new JPanel();                           //Note 4
        content.setLayout(new FlowLayout());   // Use FlowLayout //Note 5

        //... Add the components to the panel.
        content.add(new JLabel("Dog Years"));  // Create, add label //Note 6
        content.add(myDogYearsTF);             // Add input field
        content.add(myConvertBtn);             // Add button
        content.add(new JLabel("Human Years"));// Create, add label
        content.add(myHumanYearsTF);           // Add output field

        this.setContentPane(content);                            //Note 7
        this.pack();                                             //Note 8

        //... Set window characteristics
        this.setTitle("Dog Year Converter");
    }
}

Notes

  1. Instance variables are created when an object is created (instantiated). They can be referenced by any of the constructors or methods in a class. They should be declared private. This program uses the convention of beginning instance variable names with "m_". This practice is highly recommended for clarity in reading the code.
  2. This declares and initializes a text field to be approximately 10 characters wide.
  3. This declares and initializes a button with the text "Convert" showing on it. There is no "listener" attached to this button yet, so it doesn't do anything. That will be added in the next example.
  4. Components must be placed on the content pane in the JFrame. There are two ways to do this: (1) Get the existing content pane and work with that, or (2) Create a new content pane (usually a JPanel) and then set the content pane of the JFrame to that. The second approach is used here.
  5. A layout manager should be explicitly set for the content pane.
  6. Because labels are usually not referred to again, there is no need to put them into a named variable.
  7. The content pane of this JFrame is now set to the JPanel that we created earlier, named "content".
  8. After the content pane of the JFrame has been set and populated with components, it's necessary to call pack() to do the layout -- that is to set the location and size of each of the components.

5. DogYears with GUI and "Model/Logic"

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
// File   : gui-tutorial/d1/DogYearsGUI_1.java
// Purpose: Use textfields and button to convert dog to human years.
//          A button listener has been added in this version.
// Author : Fred Swartz
// Date   : 2005-06-06

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

///////////////////////////////////////////////////// class DogYearsGUI_2
class DogYearsGUI_2 extends JFrame {

    //======================================= instance variables //Note 1
    private JTextField myHumanYearsTF = new JTextField(3);       //Note 2
    private JTextField myDogYearsTF   = new JTextField(3);
    private JButton    myConvertBtn   = new JButton("Convert");  //Note 3


    //====================================================== constructor
    public DogYearsGUI_2() {                                     //Note 4
        // 1... Add listener to button.
        myConvertBtn.addActionListener(new ConvertBtnListener()); //Note 5

        // 2... Create content panel, set layout
        JPanel content = new JPanel();                           //Note 6
        content.setLayout(new FlowLayout());   // Use FlowLayout //Note 7

        // 3... Add the components to the content panel.
        content.add(new JLabel("Dog Years"));  // Create, add label //Note 8
        content.add(myDogYearsTF);             // Add input field
        content.add(myConvertBtn);             // Add button
        content.add(new JLabel("Human Years"));// Create, add label
        content.add(myHumanYearsTF);           // Add output field

        // 4... Set this window's attributes, and pack it.
        this.setTitle("Dog Year Converter");
        this.setContentPane(content);                            //Note 9
        this.pack();                                             //Note 10
    }


    //================================================ ConvertBtnListener
    class ConvertBtnListener implements ActionListener {         //Note 11
        public void actionPerformed(ActionEvent e) {
            //... Get the value from the dog years textfield.
            String dyStr = myDogYearsTF.getText();               //Note 12
            int dogYears = Integer.parseInt(dyStr);

            //... Convert it - each dog year is worth 7 human years.
            int humanYears = dogYears * 7;                      //Note 13

            //... Convert to string and set human yrs textfield
            myHumanYearsTF.setText("" + humanYears);             //Note 14
        }
    }
}

Notes

  1. Instance variables are created when an object is created (instantiated). They can be referenced by any of the constructors or methods in a class. They should be declared private. This program uses the convention of beginning instance variable names with "my". This, or a similar practice, is highly recommended for clarity in reading the code.
  2. This declares and initializes a text field to be approximately 3 characters wide.
  3. This declares and initializes a button with the text "Convert" showing on it. There is no "listener" attached to this button yet, so it doesn't do anything. That will be added in the next example.
  4. The GUI constructor will typically perform the following chores: (1) Finish up the components (creating, setting attributes, adding listeners, ...). (2) Create a content pane and set the layout. (3) Add the components. (4) Set frame attributes, including the content pane, and pack it to do the layout.
  5. This creates an association between the button and an object. When the button is clicked, it will call the actionPerformed method of that object.
  6. Components must be placed on the content pane in the JFrame. There are two ways to do this: (1) Get the existing content pane and work with that, or (2) Create a new content pane (usually a JPanel) and then set the content pane of the JFrame to that. The second approach is used here.
  7. A layout manager should be explicitly set for the content pane.
  8. Because labels are usually not referred to again, there is no need to put them into a named variable.
  9. The content pane of this JFrame is now set to the JPanel that we created earlier, named "content".
  10. After the content pane of the JFrame has been set and populated with components, it's necessary to call pack() to do the layout -- that is to set the location and size of each component.
  11. There are many ways to define a listener. This is one of most common - define an inner class that "implements ActionListener", and in that class define the actionPerformed() method.
  12. Get the text from a JTextField with a call to its getText() method. This always returns a string. In this case the string must be converted to a number before it can be used in the computation.
  13. This is the essential "logic" or "model" of the problem. It's so simple that I put it here in the listener. It would be better in the separate class, or at least a method. The magic number 7 should also be made into a named constant..
  14. Set the value of a JTextField by calling its setText() method and passing a string to it.

Programming problems

[TODO]

Next Steps

Rationale

To keep from interrupting the flow of this tutorial, a number of topics are discussed on some pages. You might find some questions answered there.

Rationale for GUI design decisions - Java offers many ways to write GUI programs. This gives the rationale for choices made in this tutorial, as well as alternatives, both good and bad. Don't read this until you're comfortable with the topics in this tutorial -- it will probably cause more confusion than help until you understand the basics.

Next Tutorial

The next section of the tutorial, as yet unwritten, will cover the following topics.

  • Separation of the logic/model from the interface. An OOP example will be developed which has a real model.
  • Additional components will be introduced.
  • Additional layouts will be covered.
Copyright 2005 Fred Swartz
Advertisement


DMCA.com