One of the most important things about Java is that it allows the user to interact with your applications. Since Java applets are by nature graphical, GUIs are very important in writing applets. They are also important for stand-alone applications. GUI stands for Graphical User Interface. It is the part of the program that the user sees and interacts with. Java provides a vast array of predefined GUI objects, such as buttons, text fields, menus, windows, and more. In this lesson, we're going to look at how to use these GUI objects, we'll take a look at layouts, and we'll learn about handling events.
First let's see what GUI components are available.
|Name||What it is|
|MenuBar||The menu bar at the top of the window|
|Menu||A menu on the menu bar, such as File or Edit|
|Button||A clickable button|
|List||A list of selectable choices|
|Choice||A popup menu of choices|
|CheckboxGroup||A group of checkboxes acting together|
|Checkbox||A checkbox like in HTML|
|TextField||A single-line text blank; can be set to be uneditable|
|TextArea||A multi-line TextField; can be set to be uneditable|
There are a couple of other GUI components, but they more advanced, and less useful. The ones listed in the table are the ones you'll be using the vast majority of the time. For an example of what the components look like, click on the button below. To make the example go away again, click on the button a second time.
Now let's look at the code behind that example.
I'm not going to discuss this code in depth at this point. I have presented it here mainly as a reference to see how each Component is dealt with. After finishing this lesson, though, you should be able to follow this code fairly easily.
Before we discuss how to really use these objects, we need to talk about how GUIs are
There are two general classes of GUI objects, Containers and Components. Containers are things you can put Components in. It is possible for a Container to be a Component. (In fact, they always are.) So, you can put a Container into another Container. All of the objects in the above example are Components. Containers are things like Frames, Windows, Canvases, and Applets. Because an Applet is a Container, you can add Buttons and other Components directly to it.
There are also things called LayoutManagers. LayoutManagers control the way the Components are arranged inside of a Container. There are five basic LayoutMangers, and they're listed below. LayoutManagers make it easy to layout a GUI by doing all of the hard parts for you.
And finally, there are things called Events. An event happens when the user does something with the GUI, such as clicking on a button or entering text in a field. When an event happens, an Event is created and must be handled by the GUI. This is the way GUIs function in Java. Every Component (and Containter) can have an event handler to respond to Events. We'll see more about these at the end of this lesson.
All of the Components in the above example need some form of layout (except for the Menu and MenuBar). The layout determines how the components will be arranged on the screen. A Container's layout is controlled by a LayoutManager. Java has a pretty good variety of LayoutManagers to choose from:
|Name||What it is|
|BorderLayout||Each component is placed against an edge or in the center as specified by "North," "South," "East," "West" or "Center"|
|CardLayout||Only displays a single component at a time. Methods are available for cycling through the components|
|FlowLayout||Arranges the components in rows from left to right, filling each row as much as possible before starting a new row.|
|GridBagLayout||The most complex of the layouts. It works rather similarly to tables in HTML|
|GridLayout||Lays out the components into cells in a grid, one Component per cell. You have to specify the height and/or width of the layout in cells.|
Various Containers, such as Applet, Panel, Window and Frame, have different default LayoutManagers. Applet, for instance, defaults to FlowLayout.
Let's look now at examples of the five LayoutManagers. You can click once on any of the buttons below to bring up an example of that LayoutManager. Click on the button a second time to remove it.
Click on the button labeled "BorderLayout." First we're going to look at the BorderLayout LayoutManager.
Short, sweet, to the point. This class extends Frame, which is why it can stand alone.
It has a constructor which calls its parent's constructor. It also has an init() method
which lays out the GUI components. First of all, init() declares the LayoutManager to use,
BorderLayout in this case, by using a method of Container, setLayout(). When we create the
new BorderLayout we pass it two numbers. Those numbers are the size of the gap to leave
between the Components. In this example, we've specified a 3 pixel horizontal and 3 pixel
Next, we instantiate five buttons and give them all names. Then we add them to the Container with the add() method. When using a BorderLayout, we must tell the Container where we want to add the Components. So, in the add() method we specify one of the four directions.
NOTE: The directions have to be "Center", "North", "South", "East" and "West" exactly. The first letter must be capitalized and they must be in quotes. Also note that only one Component can be in each location. So, a BorderLayout can have at most 5 Components. We will see a way around this a little later.
Now, go back up, click again on BorderLayout to dispose of the example. Click on FlowLayout.
As you can see, FlowLayout is even easier than BorderLayout to use! This program works
in exactly the same way as the last except that the add() method doesn't specify a
direction. That is because FlowLayout just sticks the Components into the Container in
the order they're added. When it has filled up one row, it starts a new one.
Here the big difference is that when we create the FlowLayout object, we pass it two numbers and a constant. The numbers are still the horizontal and vertical gaps. The constant specifies when in it's space each Component should be placed. FlowLayout.CENTER says to center each Component in its area. FlowLayout.LEFT and FlowLayout.RIGHT are the other two possibilities.
Now, resize the example. Make it smaller. What happened? The Buttons moved to fit into the new shape of the screen. Now go back and bring up the BorderLayout example. Resize it. What happened there? The Buttons' sizes cahnged, but they stayed in the same places. That's the way BorderLayout works.
O.K. Get rid of both examples and click on GridLayout.
Again, the code looks very similar. The difference to note here is that when we
declare the LayoutManager in init() (with the setLayout() method), we now give it
four numbers. They are the number of columns, the number or rows, the horizontal
gap and the vertical gap respectively. With GridLayout you must specify what size
the grid will be. If you want, you can pass a 0 to the number of columns or rows,
and the GridLayout will compute the other dimension from the number of Components
Resize this one. Just like BorderLayout, the Buttons change size but not position. However, unlike BorderLayout, all of the Buttons remain the same size.
Kill the GridLayout and bring up the CardLayout
This one is a little different. We have this new method called handleEvent(). This method
is an event handler. (Duh.) And there's a reason it's here. The CardLayout only displays
one Component at a time. To switch among Components, we use the next(), previous(), first()
and last() methods of CardLayout; I've chosen to use the next() method. In order to run
the next method, I added the event handler. I won't discuss how it works here. That comes
a little later. Click on the Button. The visible Component should switch to a new
Notice another difference. In the previous examples we've created the LayoutManager on the fly in the setLayout() method. This time we've created a variable to store the CardLayout. Why? Well, the next() method has to be invoked on the appropriate CardLayout object. So, we keep a copy of our CardLayout to use with next(). We could've also just used ((CardLayout)this.getLayout()).next(this) to call next() and not have had to worry about keeping a copy of the CardLayout, but that's a little more complicated.
Alright, get rid of the CardLayout and click on GridBagLayout.
Now this one is quite a bit different. We have a new method, constrain() which we use
in init() to lay out the Components. Also, we're keeping a copy of the GridBagLayout, as
we did with the CardLayout, and for much the same reason.
What does the constrain() method do, and why do we need it? Well, to lay out the Components with a GridBagLayout we need another object, GridBagConstraints. GridBagConstraints is an object which contains all of the formatting information needed to do the layout. With a GridBagConstraints, we can set specific constraints for each Component. In the previous examples, all Components were treated the same. In GridBagLayout, every Component can have a different set of constraints.
We use the GridBagConstraints object by setting each constraint variable and then binding those settings to the Component with the setConstraints() method of GridBagLayout. Below is a table of the variables in GridBagConstraints.
We created a new constrain() method because every object must be configured using a GridBagConstraints object, and it was easier to create a method than to replicate the code once for every Component.
Now, resize the example window. Notice that different buttons grow and shrink at different rates. That is because we told them to. GridBagLayout is by far the most versatile and useful of the LayoutManagers.
|gridx, gridy||Specify the grid position of the Component. The constant GridBagConstraints.RELATIVE tells the GridBagLayout to position them like a FlowLayout|
|gridwidth, gridheight||Specify the size in cells of the Component. Similar to ROLSPAN and COLSPAN in HTML|
|fill||Specifies in which directions if any the Component will change size when the window is resized. Can equal GridBagConstraints.HORIZONTAL, GridBagConstraints.VERTICAL, GridBagConstraints.BOTH or GridBagConstraints.NONE|
|ipadx, ipady||Specify internal padding for the Component. Effectively increases the minimum size needed by the Component|
|insets||An Inset object used to set the margins between objects|
|anchor||Specifies which side of the cell to have the Component stay against if the window grows and the Component doesn't. Can be any of the eight cardinal directions or center, in the following format: GridBagConstraints.NORTHEAST|
|weightx, weighty||Specify how the Component should grow in proportion to other components. Similar to the * notation for Frames in HTML. If ComponentA has weightx = 1.0 and ComponentB has weightx = 2.0, ComponentB will grow twice as fast in the x direction.|
Now, in some LayoutManagers like BorderLayout and CardLayout, you're limited in how many Components you can have visible at a time. There is a very simple way around this. In the java.awt package there is a class called Panel. A Panel in a Container, so you can put Components in it. But, as all Containers are, it is also a Component. All you have to do is put Components into a Panel, and then add the Panel to your LayoutManager. It will be treated as a single Component for placement, even though it contains several.
Go up and click on the button labeled "Panel."
This is a slightly modified version of our GridLayout example. Let's step through it.
In init(), the first thing we do is instantiate a Panel. We'll use this Panel to fit two Buttons into a single cell of the GridLayout. Next we set the LayoutManager of the Frame to a GridLayout with 3 rows and 1 column and a cell spacing of 3. Then we set the LayoutManager of the Panel to a GridLayout with 1 row and 2 columns, also with a cell spacing of three. All Containers need a LayoutManager. We instantiate four Buttons. Then we add button2 and button3 to the Panel. Finally, we add button1, button2 and our Panel to the Frame.
Looking at the example, what you see is that we have successfully thwarted GridLayout's attempts at making everything the same. The middle row has more Buttons than the other two. In actuality, there is only one Component in the middle row, but that Component contains two Buttons.
Now, bring the GridBagLayout example back up. Notice that the two look very similar. Now resize them. A-ha! The difference is that the GridLayout, as always, resizes everything the same. The GridBagLayout allows for each Component to have a different set of constraints.
Close the GridBagLayout and Panel examples and bring up Panel 2.
Here we have a CardLayout. CardLayout only lets one Component be visible at a time. But
what if that Component is a Container? Click on the button a few times a see what happens.
button2 and button3 are both visible at the same time. That's because the visible
Component is a Panel, and button2 and button3 are contained in the Panel.
Notice that the Frame uses CardLayout and the Panel uses GridLayout. Every Container in your GUI can have a different LayoutManager if you like. Also, you can nest Containers as deeply as you like. The only limit is room on the screen.
There are several Containers, and they're all a little different. For windows that stand on their own like these examples, Frame is good. For grouping Components in layouts, Panel is the best.
At this point, you should be able to go back to the very first example, the one I said I wasn't going to explain, and it should make sense.
Now that we have seen how to lay out Components and what kinds of Components we can lay out, let's look at the stuff that really makes GUIs work, the eventHandlers.
In both of the examples using CardLayout, I added in an event handler to react when the user clicks on a button. Otherwise, we wouldn't have been able to cycle through the Components in the layout. Event handlers are the way you're given to react to user input. Almost everything the user does results in an Event being generated.
First let's look at the kinds of events that can be generated.
|Name||When it occurs|
|ACTION_EVENT||Signifies that the user did something. The exact meaning depends on which Component the event occured for.|
|GOT_FOCUS||Signifies that the user brought the Component into focus, i.e. if the user types something, the Component will receive it.|
|KEY_ACTION||User pressed a function key|
|KEY_ACTION_RELEASE||User released a function key|
|KEY_PRESS||User pressed a regular key|
|KEY_RELEASE||User released a regular key|
|LIST_SELECT||User selected an item from a List|
|LIST_DESELECT||User deselected an item from a List|