Graphical User Interfaces

One picture is worth ten thousand words.

Designing graphical application is an excellent example of the use of inheritance, abstract classes, and interfaces.

Developing graphical user interfaces isn't similar to anything else in software engineering. There are no simple, bulletproof guidelines that lead to any sort of enlightenment. Kurt Godel (the great mathematician of all time) proved that it is impossible to create a closed system that does not depend on some knowledge outside of that system. If we paraphrase the great Godel, this means that we are not able to create the perfect GUI.

Every program that presents a Swing GUI contains at least one top-level Swing CONTAINER. For most programs, the top-level Swing containers are instances of JFrame, JDialog, or (for applets) JApplet. Each JFrame object implements a single main window, and each JDialog implements a secondary window, usually a temporary window to receive an additional information from the user (JOptionPane is an example of JDialog). Each JApplet object implements an applet's display area within a browser window. A top-level Swing container provides the support for painting and event handling.

A container class is used to hold other COMPONENTS. The role of containers is to determine how the components are organized and displayed. The component classes are JButton, JLabel, JTextField, JTextArea, JRadioButton, JComboBox, JList, JMenuBar and few more.

In addition to this there are the HELPER classes, like Font, Color, Graphics and more.

Frames:

A frame, implemented as an instance of the JFrame class, is a free standing window that has decorations such as a border, a title, and buttons for closing and iconifying the window. Applications with a GUI typically use at least one frame. Here is a simple example of working with frames

 
 
 
 
 
 
 
 
 
 
 
import javax.swing.*;
 
public class SimpleFrameDemo
{
   public static void main(String[] args)
   {
      // we call a constructor to set a title for the Frame
      JFrame frame = new JFrame("Simple Frame");
 
      //set the size of the frame
      frame.setSize(400, 300);
 
      // the frame is not displayed until you set this to true
      frame.setVisible(true);
 
      // this closes the frame
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   }
}

The screen of a computer is a grid of little squares called pixels. The color of each pixel can be set individually, and drawing on the screen just means setting the colors of individual pixels. A position of a pixel on the screen is specified by a pair of integer coordinates, (x,y). The upper left corner has coordinates (0,0). The x coordinate increases from left to right, and the y coordinate increases from top to bottom.

By default, a frame is displayed in the upper-left corner of the screen. You can move a frame to any location. Though you must know the screen size. This can be obtained by using Toolkit class:

        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();

Then the Dimension class field variables width and height will reveal the actual screen size. Finally

 
        frame.setLocation(screen.width-400, 0);

will move the frame to the upper-right corner.

See the code example SimpleFrameDemo.java

 

 

 

 

 

 

Panels:

In order to draw, you need something to draw on. Panels are used to group various components. Panels can contain another panels as well.

 
|-------------------------------|
| Frame                         |
| __________      ___________   |
| |Panel   |      |          |  |
| |        |      |   Panel  |  |
| |________|      |__________|  |
|                               |
| ____________________________  |
| |Panel                     |  |
| |                          |  |
| |__________________________|  |
|_______________________________|
 
 

To draw on a panel you need to override the paintComponent() method. A panel cannot be displayed on its own and must be added to an existing container. Every top-level container indirectly contains an intermediate container known as a content pane.

See the code example: SimplePanelDemo.java

 

Designing a layout:

Here is the relationship among components:

 
|-------------------------------------
| (JFrame)                           |
|                   (JTextField)     |
|    (JLabel)         _______        |
|  Enter an integer: |       |       |
|                     -------        |
|                                    |
|  (JTextArea)      (JPanel)         |
|               ---------------      |
|              |               |     |
|              |   (JButton)   |     |
|              |               |     |
|               ---------------      |
|____________________________________|
 
 

 

A JLabel object can display either text, an image, or both. You can specify where in the label's display area the label's contents are aligned by setting the vertical and horizontal alignment. By default, labels are vertically centered in their display area. Text-only labels are leading edge aligned, by default; image-only labels are horizontally centered, by default.

 

Here is the code that adds the button and label to the panel, and the panel to the frame:

 

frame = new JFrame(...);
button = new JButton(...);
label = new JLabel(...);
panel = new JPanel();
panel.add(button);
panel.add(label);
frame.getContentPane().add(panel, BorderLayout.CENTER);
 

 

Layout Manager:

The components in a container must be "laid out," which means setting their sizes and positions. It's possible to program the layout yourself, but ordinarily layout is done by a layout manager. A layout manager is an object associated with a container that implements some policy for laying out the components in that container. Different types of layout manager implement different policies.

 

 

FlowLayout - puts components in a left-to-right line, sized at their preferred size.

GridLayout - makes components equal in size and displays them in the requested number of rows and columns.

BorderLayout - puts components in five areas: north, south, east, west, and center.

BoxLayout  - arranges components either from top to bottom or from left to right.

 

 

Arrangement of components in a BorderLayout:

 
----------------------
|        North       |
|---------------------
|    |        |      |
|    |        |      |
|West| Center | East |
|    |        |      |
|    |        |      |
|---------------------
|        South       |
|____________________|
 

 

By default, a panel's layout manager is an instance of FlowLayout, which places the panel's contents in a row. You can easily make a panel use any other layout manager by invoking the setLayout method or specifying a layout manager when creating the panel. The syntax to set a layout manager is

 
container.setLayout(new GridLayout(2,3));
 
See the code example: PanelDemo.java.
 

Example: Calculator

-----------------
| display  area |
|---------------|
| 7 | 8 | 9 | / |
|---------------|
| 4 | 5 | 6 | * |
|---------------|
| 1 | 2 | 3 | - |
|---------------|
| 0 | . | = | + |
|---------------|
| Made in CMU   |
|_______________|
Here is a prototype:
// choose a proper layout
setLayout(new BorderLayout());
 
// north part of the layout
display = new JTextField("0");
display.setEditable(false);
add(display, BorderLayout.NORTH);
 
// center part of the layout
panel = new JPanel();
panel.setLayout(new GridLayout(4, 4));
 
// add 16 buttons
JButton button = new JButton(label);
//I explain this statement in the next paragraph
  button.addActionListener(this);
panel.add(button);
 
add(panel, BorderLayout.CENTER);
 
// south part of the layout
add(new JLabel("Made at CMU"), BorderLayout.SOUTH);
 

Event Handling:

 

Java graphics programming is event driven. This means that parts of application are executed when an event (event source)- button click, mouse move and others - is activated. The program then choose either to ignore the event or to respond to it.

 

If a class wants to respond to a user event, it must implement the interface that deals with the event. These interfaces are called event listeners. Each listener handles a specific kind of event. The following event listeners are available (there are more of them!):

 

 

 

            - keyboard event that occurs when a user types on a keyboard.

 - action event that occurs when a user takes an action such as a click on a button.

            - mouse event that occurs by a mouse click.

 - item event that occurs when an item such as a checkbox has been changed.

            - window event that occurs when  a window moves or resizes.

            - mouse event that occurs when a mouse moves.

 - window event that occurs when  user closes a window.

 

Let us outline a general scenario by looking at the most simple event - how JButton handles the mouse click. Every event handler requires three pieces of code.

1. To detect that a user clicks on a button, your class must be declared as an action listener

 
public class Demo extends JApplet implements ActionListener
{
 ...
}
 

2. You need to register the event source

 
JButton x = new JButton();
x.addActionListener(instanceOfYourClass);
 
When the user clicks on the button, the button fires an action event:
 
         ActionEvent
JButton   --------->  action listener (actionPerformed)
 

3. In the last step you are to implement the method actionPerformed

 
public void actionPerformed(ActionEvent e)
{
   //what do you do when a user clicks this button?
}
 
 

See the code example: EventDemo.java.

 

Most listener interfaces contain more than once method. For example, the MouseListener interface has five methods: mousePressed, mouseReleased, mouseEntered, mouseExited, and mouseClicked. You do not need to implement all these methods, but only those which you need. The others can have empty bodies.

See the code example: FlyingBalloon4XP.java.

 
 

Thread Concepts:

 

A thread is a single sequential flow of control within a program. Sequential programs have a beginning, an execution sequence, and an end. At any given time during the runtime of the program there is a single point of execution. A thread is similar to the sequential programs: it has a beginning, a sequence, and an end, and at any given time during the runtime of the thread, there is a single point of execution. However, a thread itself is not a program. It runs within a program, and it cannot run on its own.

Examples of multithreaded application:

From the programmer's point of view, a thread is a java object. It is created (like any other java object) from a Java class with new and an appropriate constructor. It has members and methods. It can be passed as a parameter, put in an array, etc. Each thread object has a run() method. The run method gives a thread something to do.

 

Creating a thread.

There are two techniques for creating a new thread of execution and providing a run method for it:

·                Exdending the class Thread, and overriding its run() method. 
1.      Declare a class to be a subclass of Thread
2.      Override the run method
3.      Create runnable object
4.    Start the thread            
See SimpleThread1.java and the equivalent implementation SimpleThread2.java
·                Implementing the Runnable interface  
1.      Declare a class that implements the Runnable interface.            
2.      Implement the run method            
3.      Create runnable object            
4.    Start the thread
See SimpleThread3.java

Why do we need the second approach? Why cannot we always extend the Thread class? Hint: Java has a single inheritance.