Lectures 18-19

CSC120: Programming I - Spring 2002
Prof. Christian A. Duncan
csc120@mail.cs.miami.edu

Announcements

GUIs

Applications which interact with the user in a windowing environment are typically referred to as GUIs or Graphical User Interface(s). These applications present the user with windows, buttons, menu bars, all the typical stuff one has come to love, hate, and need in using a computer program. (Remember how much you probably hated using a text editor with only keyboard input). These applications are also able to be aware of actions such as moving, clicking, or dragging the mouse, even pressing a key - rather than entering in values. So far, our applications have interacted with the user in a very primitive way: input and output from the terminal window - SavitchIn and System.out. With GUIs, we can be more creative, modern, flexible, ... but there is a price. GUI applications are not as short as other ones. And how could they be, you need to set up everything they way you want it... which takes time and coding but that doesn't mean that it is very hard.

There are two main parts to building a GUI:

There are certain things to be aware of for both parts. First, there are many ways to go about building GUI applications. We are only going to see a few very basic, but powerful, ways. The Java APIs are indispensable when building GUIs, as are IDE, integrated development environments. IDEs are designed to combine the text editing and compiling in one large system. Java has several such IDEs available including Forte, JBuilder, and CodeWarrior. Applications like Forte are designed to make GUI development easier by generating a lot of the code for you. But before you ever use such a tool, you should understand what the code it develops is actually doing. Otherwise, if something needs to be tweaked you won't have a clue how to do it... you'd be dependent on Forte. Another reason is that you will then grow to appreciate having IDEs available. If we have time in one lab, I shall have the TAs present Forte (or another IDE) - one of the very last lab sessions. Now, let us look at each part of GUI development separately.

Basic Swing: Setting up the Interface

There are many ways to set up the GUI, and Swing is just one such package available to you. The first thing you almost always need to create is a basic window (or Frame), though sometimes you may want to create multiple ones. A window is just another object of type JFrame. Note: there are other options as well so rather than say this every time I will leave it understood that every rule probably has at least one alternative, ok.

Again, a window is just another object of type JFrame and how do we create an instance of JFrame? Exactly, new JFrame(). Now, the JFrame class has several methods available many of which are inherited from its ancestors:
java.lang.Object -> java.awt.Component -> java.awt.Container -> java.awt.Window -> java.awt.Frame -> java.awt.JFrame
Some of the more useful methods are illustrated below:

JFrame win = new JFrame();
win.setSize(int, int);   // Set the size in pixels...
win.setTitle(String);    // Set the title of the window
win.setVisible(boolean); // Make window visible or invisible (hidden - default)
// There are others which we will get to in a bit...
One of the best ways to learn about GUI development is to look at code that has already been written. The Class BlackAdderOne sets up a basic Gui but does not yet deal with any events.

Components and Containers

Components are the basic building blocks of all GUI programs. Nearly everything you will use is a subclass of Component including: Some components are called Containers. Containers are simply Components which can contain other components. Examples of Containers include: To add a component (which could also be a container!) to a container use the method: someContainer.add(Component someComponent) or someContainer.add(Component someComponent, int extraInfo).
As is probably apparent, these methods basically add components to the container. What isn't clear is where these components get placed. This issue is dealt with by LayoutManagers.

WARNING
But first, a note about the JFrame container. Unlike the other containers, you do not add a component directly to a JFrame. The code will compile but won't run... for fairly obscure reasons (for now anyway), you must first get a subcontainer of the JFrame and add stuff there. Thus, to add a JButton to a JFrame do something like the following:

JFrame win = // Some JFrame (win is just used for reference)
             // typically "this" replaces "win"
JButton button = new JButton("Druck Mich");
Container subCont = win.getContentPane(); // Get subContainer
subCont.add(button);  // Insert button here!

-----------
DO NOT DO
-----------
win.add(button); // Will compile but won't run!!!!

LayoutManagers

Every Container has an associated LayoutManager. The job of a LayoutManager, duh, is to manage the layout of the components in the container. The LayoutManager itself is not a class one can use directly instead you use subclasses of LayoutManager. (NOTE: well, actually, that isn't quite true either, they are implemented classes.. but that is another issue). There are many different LayoutManager subclasses available: There are two basic steps to setting the layoutManager: create an instance of it and set it. This can usually be done in one step.
Container con = // SomeContainer (like a JFrame's subcontainer!)
// Creates a borderLayout and sets it for this container
con.setLayout(new BorderLayout());
Note, some Layout constructors require arguments (for example, GridLayout should be passed the number of rows and columns in the grid.) After creating and setting the manager, we add components to the container. Note, some containers take additional information, namely BorderLayout managers. Here are a few examples:
Container con1 and con2 are someContainers (like a JFrame)

con1.setLayout(new BorderLayout());
con1.add(someComponent, BorderLayout.SOUTH);
con1.add(otherComponent, BorderLayout.CENTER);

con2.setLayout(new GridLayout(2,3));
con2.add(oneComponent);  // goes in (0,0)
con2.add(twoComponent);  // goes in (0,1)
con2.add(threeComponent); // goes in (0,2)
con2.add(fourComponent); // goes in (1,0)
// and so on...

JPanel

You can't mix different layout managers but you can use Containers creatively to get interesting results. For example, you could have one Container have a BorderLayout manager. Then create a second container (best way: use JPanel) which then has a FlowLayout manager. Add components to the second container. Finally place this container in the other Container and in the NORTH region.
Container mainC;
mainC.setLayout(new BorderLayout());
JPanel topPanel = new JPanel();
topPanel.setLayout(new FlowLayout());
topPanel.add(new JButton("Open"));
topPanel.add(new JButton("Close"));
topPanel.add(new JButton("Exit"));
mainC.add(topPanel, BorderLayout.NORTH);
Tips
To use a Component you haven't used before, read the APIs. Look over the documentation that comes with the class as well as the constructors and methods that are available, both defined in that class and inherited from super classes. About 75% of the methods available will be useless for your purposes but some of the others will be reasonable.

Remember that the components are designed to be about the same for each subclass for ease of use. So, if you know how to use JTextField you can easily learn how to use JTextArea. It is mostly a matter of knowing what is available and how they can be put together.

A Basic JFrame

When creating your main program, you should extend JFrame (for purposes that hopefully will become clearer later) rather than creating an actual JFrame. The following segment gives a simple example to doing this:
public class FooFrame extends JFrame {
   // The constructor sets up everything
   // except making it visible...
   public FooFrame() {
      // Notice, "this" versus "con".
      this.setSize(100, 200); // set size
      this.setTitle("FooFrames rule!");
      Container con = this.getContentPane();
      con.add(new JLabel("Foo Bar Foo"));
      con.setBackground(Color.black);
      con.setForeground(Color.white);
   }

   // This allows us to RUN an application
   //   Simply creates one instance of FooFrame
   public static void main(String[] args) {
      JFrame win = new FooFrame(); // Why does this work?
      win.setVisible(true);
   }      
}

All Together Now

In the class BlackAdderOne, we have created a Frame which has a few buttons to increment and decrement a counter. However, none of the buttons work! Why not? Well, we haven't told the program to do anything yet. Certainly, we can't expect the JVM to be intelligent enough to know that we want the counter to increment. At least, not yet anyway. :-)

Writing code which responds to actions, like pressing a button, is the topic of the next (few) lectures: Event Handling.
However, for the curious at hear, the final (basic) code is written in class BlackAdder. It uses another class WindowDestroyer, which shall be discussed next lecture.