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. 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.
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, ...
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
}
|
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
}
}
|
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.
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.
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);
}
}
|
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.
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.
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.
pack() method
call tells the content pane that you're finished
adding components, and that it can do the layout
now.
[TODO: Identify the parts in this image with arrows and text.]
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 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.]
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.]
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.]
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);
}
}
|
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");
}
}
|
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
}
}
}
|
[TODO]
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.
The next section of the tutorial, as yet unwritten, will cover the following topics.