Basic Swing Details
It don't mean a thing (if it ain't got that swing!)
Song Title, Duke Ellington
A window is a portion of the user's screen that serves as a smaller screen within the screen. A window has a border defining its outside edges and a title, usually given within the top border. In this section, we will tell you how to create simple windows using Swing.
There are lots of things you can put in a window when designing a GUI interface. We will start with some simple, but very useful, elements and show you how to build windows with these elements. The window elements we will introduce in this section are a way to close (that is, end) the window, a way to put text in the window, a way to color the window, and way to put a title on the window. This may not seem like much to do with a window, but this will introduce you to the basic methods for doing all kinds of programming with Swing. In future sections, we will use the techniques you learn here to introduce more sophisticated window features you can build with Swing.
This section has essentially one demonstration program, although we develop more than one version of the program. In this section, we are primarily interested in introducing you to some Swing details, so when we first present the program we deliberately oversimplify it. At the end of this section we rewrite this program in the style that you should follow when writing Swing programs.
Gotcha: Save All Your Work Before Running a Swing Program
Programs that use Swing can take control of your computer screen, mouse, and keyboard. If they go awry, and they often do, then the usual ways of communicating with the computer may be shut down. On a PC, this may require that you reboot your computer. On any system, this may require that you, in some sense, "restart the whole thing." If you are editing a file, or performing some other task, do not simply stop doing the editing but actually close the file before running any Swing program that you have not yet fully debugged. If the Swing program causes you to restart your computer, any open files may be damaged.
Programming Example: A Simple Window
Display 1 contains a Java program that produces a simple window using Swing.
Display 1A Very Simple Swing Demonstration Program
import javax.swing.*; /**************************************************** *A simple demonstration of a window constructed with Swing. *This is just a simple demo program and is not typical *of the style we will use in Swing programs. ****************************************************/ public class FirstSwingDemo { public static final int WIDTH = 300; public static final int HEIGHT = 200; public static void main(String[] args) { JFrame myWindow = new JFrame(); myWindow.setSize(WIDTH, HEIGHT); JLabel myLabel = new JLabel("Please don't click that button!"); myWindow.getContentPane().add(myLabel); WindowDestroyer myListener = new WindowDestroyer(); myWindow.addWindowListener(myListener); myWindow.setVisible(true); } }
Just about the only other thing it can do is disappear. If you click the close-window button, the program will end and the window will disappear. The picture shown is a typical example of the kind of window produced. The window may look slightly different on your system. Now, let's look at the code for this first GUI program.
The first line, repeated in what follows, says that the program uses the Swing library. Any program using the Swing library should contain this line at the beginning of the file containing the program (possibly along with other import statements).
import javax.swing.*;
The rest of the program is a simple class definition with only a main method. Let's look at the code in this main method. The first line creates an object of the class JFrame. That line is reproduced below:
JFrame myWindow = new JFrame();
The name myWindow is chosen by you, the programmer. The object myWindow is an object of the class JFrame. A JFrame in Swing is what you probably think of as a window. A JFrame is a very simple window, but among other things, it does have a border, a place for a title, and the close-window button that you expect to find on any window. (No title is used in this program.) Soon you will see that we do not normally use simple JFrame objects, but instead define a derived class of the class JFrame and use objects of the derived class. However, for this very first demonstration program we will use JFrame directly.
The next line, reproduced below, sets the size of the JFrame window:
myWindow.setSize(WIDTH, HEIGHT);
The method setSize is a method of the class JFrame and sets the size of the window.
Swing size units are discussed in a later subsection of this article. For now, simply note that this says the window is WIDTH units wide and HEIGHT units tall, and do not yet worry about what those units are.
The next line creates an object of class JLabel and names the object myLabel:
JLabel myLabel = new JLabel("Please don't click that button!");
The name myLabel is chosen by you the programmer. An object of the class JLabel is usually simply called a label and is a special kind of text that can be added to a JFrame (or to any of a number of other kinds of objects). The string for the label is given as an argument to the constructor for the JLabel class, so in this case the string of text for the label is "Please don't click that button!").
The next line of the program, given below, adds the label myLabel to the JFrame named myWindow:
myWindow.getContentPane().add(myLabel);
This requires a bit of explanation. Let's take this expression apart. The method getContentPane is a method of the class JFrame that produces the content pane of the JFrame. Every JFrame has a content pane. You do not add things directly to the JFrame. Instead you add things to the content pane of the JFrame. You can think of the content pane as the "inside" of the JFrame. So, myWindow.getContentPane() is the content pane of myWindow (the "inside" of myWindow). The label myLabel is added to myWindow.getContentPane() (that is, to the content pane of myWindow) using the method add. Every JFrame content pane has a method named add. The method add is already defined for you; you do not define it.
You close this window by clicking the close-window button. When you click that button, the window fires an event and sends it to a listener object. The listener object closes the window. In this program, the listener object is named myListener, which is a member of the class WindowDestroyer. The following line from the program creates a new object of the class WindowDestroyer and names it myListener:
indowDestroyer myListener = new WindowDestroyer();
You, the programmer, choose the name myListener. The next line, shown in what follows, associates the object myListener with the object (the window) myWindow, so that myListener will receive any event fired by the object myWindow:
myWindow.addWindowListener(myListener);
An object, like myListener, that receives events from an object is called a listener. A listener that listens to events from a window, such as clicking the close-window button, is known as a window listener. Associating the listener with the object it is listening to is called registering the listener.
An object of the class WindowDestroyer will close the window myWindow when myWindow fires an appropriate event. We need to define the class WindowDestroyer, but let's postpone that for a bit, and for now, just assume that the class WindowDestroyer has been defined so that, when the user clicks the close-window button of myWindow, the object myListener will close myWindow and end the program.
The last statement in main is a call to the method setVisible:
myWindow.setVisible(true);
This call to setVisible makes the window named myWindow visible on the screen. The method setVisible is a method of the class JFrame (and also a method in many other swing classes). With the argument true, as in Display 1, the object is displayed. If the argument false were to be used instead, then the object would not be shown.
That's the end of the code for main, but not the end of the program. The window just sits on the screen looking pretty until the user clicks the close-window button. At that point, an event e is fired by the object myWindow. The event e is sent to the listener object called myListener. The object myListener recognizes e as an event signaling that the object myWindow should be closed, and myListener then closes the window and ends the program.
The object myListener is a member of the class WindowDestroyer. We have been assuming that the class WindowDestroyer has already been defined, but you need to define it and compile it before you can really run the program in Display 1. So, let's define the class WindowDestroyer.
The listener class WindowDestroyer is defined in Display 2.
Display 2A Listener Class for Window Events
import java.awt.*; import java.awt.event.*; /******************************************************* *If you register an object of this class as a listener to any *object of the class JFrame, then if the user clicks the *close-window button in the JFrame, the object of this class *will end the program and close the JFrame. *******************************************************/ public class WindowDestroyer extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }
class JFrame) will often be a derived class of the class WindowAdapter. This is indicated by the phrase extends WindowAdapter on the first line of the class definition. A derived class of the class WindowAdapter, such as our class WindowDestroyer, inherits all its methods from WindowAdapter. Each of these methods automatically respond to a different kind of event. Normally, no new methods are added, because there already is a method for each kind of event. However, the way the event is handled is up to you and should depend on the window you are defining. So, normally, you would redefine (override) one or more of the method definitions that your class inherits from WindowAdapter.
The class WindowAdapter has a number of different methods, each of which processes a different kind of event. All these methods are inherited by the class WindowDestroyer. These inherited methods determine the names of the methods, but you need to determine what the methods do by redefining the methods. However, you only need to define (actually redefine) those methods that your window will use. For this application, the only kind of event that we need our listener class to respond to is an event that signals that the window should close. The method that handles those events is named windowClosing. So, we have only redefined the method windowClosing. The method definition is very simple; it simply executes the one command
System.exit(0);
and, as we explain in the following programming tip, this ends the program and so closes the window.
In order to run the program in Display 1, you must define and compile both the class FirstWindow in Display 1 and the class WindowDestroyer in Display 2. Note that the class WindowDestroyer is not a Swing class. It is a class that you the programmer must define. In this case we have defined it for you, but you should think of it as a class that you define.
Note that the import statements for the class WindowDestroyer are as follows:
import java.awt.*; import java.awt.event.*;
When you are defining a listener class, you must have these two import statements. These import statements simply tell the compiler where the definitions for WindowAdapter and for event handling are located. (You may recall that we said the AWT was a precursor of the Swing library. The class WindowAdapter and the event-handling model are in the AWT and that is why you see the name awt in the import statements.)
Java Tip: Ending a Swing Program
A GUI program is normally based on a kind of infinite loop. There may or may not be a Java loop statement in the program, but, normally, the GUI program still need not ever end. The windowing system normally stays on the screen until the user indicates that it should go away (for example, by clicking a close-window button). If the user never asked the system to go away, it would never go away. When you write a GUI program (using Swing), you need some way to say "End the program now." The following statement will end a Java program as soon as this statement is executed:
System.exit(0);
This will end any Java program. A Java program that uses System.exit does not have to use Swing, but we will often use this statement in Swing programs.
The number 0 given as the argument to System.exit is returned to the operating system. In many situations, you can use any number and the program will behave the same. But most operating systems use 0 to indicate a normal termination of the program and 1 to indicate an abnormal termination of the program (just the opposite of what most people would guess). Thus, if your System.exit statement ends your program normally, the argument should be 0. An example of using this System.exit statement can be found in the definition of the method windowClosing in Display 2.
Gotcha: Forgetting to Program the Close-Window Button
The following lines from Display 1 ensure that when the user clicks the close-window button, the program will end and the window will go away:
WindowDestroyer myListener = new WindowDestroyer(); myWindow.addWindowListener(myListener);
You need not use these exact lines to program the action of the close-window button. For example, you may define a class of your own in place of WindowDestroyer. However, you do need to do some programming to ensure that when the user clicks the close-window button, the GUI will do what you want it to. If you do not program the close-window button, then when the user clicks the close-window button, the window will disappear, but the program will not end. If your GUI has only one window, it will mean that you have no easy way to end the program. There is also the added confusion that, even though the program is still running, it looks like the program has ended because the window has disappeared.
Gotcha: Forgetting to Use getContentPane
Recall that in Display 1 we added the label myLabel to the JFrame named myWindow as follows:
myWindow.getContentPane().add(myLabel);
Because you are "adding myLabel to myWindow" you might be tempted to use the following instead:
myWindow.add(myLabel);
If you omit getContentPane(), as we did above, then your program will not work correctly. Moreover, the compiler will probably not warn you about this mistake and so you must be very careful to avoid this mistake.
More About Window Listeners
As with our window listener class named WindowDestroyer in Display 2, any window listener class is typically a derived class of the class WindowAdapter. The class WindowAdapter has a number of different methods, each of which is automatically invoked when the listener object is sent an event that matches that method. The methods and corresponding events are given in the table in Display 3. When you define a derived class of the class WindowAdapter, you only define those methods that you need. The class WindowDestroyer is only needed to close windows, and so when we defined WindowDestroyer, we only defined the method windowClosing. We will not need any of these methods except windowClosing, but Display 3 lists all the methods for completeness.
In discussing our definition of the class WindowDestroyer in Display 2, it would be more proper for us to say that we redefined the method windowClosing rather than saying we defined it. This is because we are changing the definition of windowClosing. If in the definition of a derived class of the class WindowAdapter you give no definition for a method (from Display 3), then the class inherits the definition from the class WindowAdapter. However, when a method is inherited without being redefined, the method seldom does what you want. The methods are only useful if they are overridden in some derived class, such as the class WindowDestroyer. The class WindowAdapter is a special kind of class known as an abstract class, which means that you cannot create an object of the class WindowAdapter using new WindowAdapter(). You can only use WindowAdapter as a base class when defining other classes.
Display 3Methods in the Class WindowAdapter |
public void windowOpened(WindowEvent e) Invoked when a window has been opened. |
public void windowClosing(WindowEvent e) Invoked when a window is in the process of being closed. Clicking the close-window button causes an invocation of this method. |
public void windowClosed(WindowEvent e) Invoked when a window has been closed. |
public void windowIconified(WindowEvent e) Invoked when a window is iconified. |
public void windowDeiconified(WindowEvent e) Invoked when a window is deiconified. |
public void windowActivated(WindowEvent e) Invoked when a window is activated. |
public void windowDeactivated(WindowEvent e) Invoked when a window is deactivated. |
Size Units for Screen Objects
When using Swing, the size of an object on the screen is measured in pixels. A pixel is the smallest unit of space on which your screen can write. Think of a pixel as a small rectangle that can have one of a small fixed number of colors and think of your screen as being paved with these little pixels. (It may help to think in terms of a simple black-and-white screen where a pixel is either black or white, even though most screens now offer more colors than just black and white.) The more pixels you have on your screen, the greater the resolution on your screen. That is, the more pixels you have, the more fine detail you can see.
The size of a pixel depends on the size of your screen and the resolution of your screen. Although Swing uses pixels as if they were units of length, they do not represent any fixed length. The length of a pixel will vary from one screen to another. On a screen with high resolution (lots of pixels), an object of size 300 by 200 will look very small. On a screen with low resolution (not many pixels), an object of size 300 by 200 will look very large. For example, consider the following statement from Display 1:
myWindow.setSize(WIDTH, HEIGHT);
which is equivalent to
myWindow.setSize(300, 200);
This says that the object myWindow (which happens to be a kind of window) will be 300 pixels wide and 200 pixels high, but the actual size will depend on the resolution of the screen you are using when you run the program.
Notice that although Java and Swing are portable and the code you write with Swing will run on any system that supports Java, the exact size of what you produce on the screen will vary from one screen to another. This is one feature of Java that is not as portable as would be ideal. To get the desired size for a window, you may need to change the dimensions to suit your particular screen size and screen resolution. However, it is only the absolute size that will vary. At least the relative size of things will be the same no matter where you run your Swing application. Moreover, for most window-like objects on most systems, after the window is displayed, the user can resize the window using the mouse.
More on setVisible
Consider the method setVisible, which is called in the program in Display 1. The particular line from Display 1 is the following:
myWindow.setVisible(true);
Every Swing object that can be displayed on the screen has a setVisible method.
The method setVisible takes one argument of type boolean. In other words, the argument to setVisible is either true or false. If w is an object, such as a window that can be displayed on the screen, then the call
w.setVisible(true);
will make w visible, and the call
w.setVisible(false);
will make w invisible.
You might think that displaying an object on the screen should happen automatically. After all, why would you define a window display unless you want it to be displayed on the screen? The answer is that you may not want it to be displayed at all times. You have undoubtedly worked with windowing systems where some windows come and go, either because they are no longer needed (like a pull-down menu after you make a choice), or because the window is covered by other windows. Swing cannot read the programmer's mind to determine when the window (or other GUI object) should be displayed and so the programmer must tell the system when to display the window. The programmer tells the system when to display the window by inserting a call to the method setVisible. If you rerun the program from Display 1 but omit the invocation of setVisible, then you will see nothing on the screen. The window will be constructed, but will not be displayed. (But be warned, if you eliminate the call to setVisible and then run the program in Display 1, you will then have no close-window button and so no way to end the program!)
Programming Example: A Better Version of Our First Swing Program
Display 4 and Display 5 together are a rewriting of the demonstration program in Display 1. This new version does essentially the same thing, except that it shows two rather than just one window. However, the new version (Display 4 and Display 5) is done in the style you should follow in writing your own GUI interfaces and programs. Notice that the definition of the window (Display 4) is in a class by itself (no pun intended). The window is then displayed in a program that uses the class (Display 5). A window class such as FirstWindow in Display 4 is typically a class for an input/output interface that can be used in any of a number of programs. Let's look more carefully at the class FirstWindow in Display 4.
Display 4A Swing Window Class
import javax.swing.*; /********************* *A simple window class. *********************/ public class FirstWindow extends JFrame { public static final int WIDTH = 300; public static final int HEIGHT = 200; public FirstWindow() { super(); setSize(WIDTH, HEIGHT); JLabel myLabel = new JLabel("Please don't click that button!"); getContentPane().add(myLabel); WindowDestroyer listener = new WindowDestroyer(); addWindowListener(listener); } }
Observe that FirstWindow is a derived class of the class JFrame. This is the normal way to define a windowing interface. The base class JFrame gives some basic window facilities and then the derived class adds whatever additional features you want in your windowing interface.
Note that the constructor in Display 4 starts by calling the constructor for the parent class JFrame with the line
super();
This ensures that any initialization that is normally done for all objects of type JFrame in fact will be done. When defining classes by inheritance from Swing classes, this is always safe and, in some other situations, absolutely necessary. There is one case where it is not necessary, and Display 4 is an example of that case. If the base-class constructor you call has no arguments, then it will be called automatically whether or not you put in super(); so, you could have omitted the invocation of super() in Display 4. However, if the base class constructor needs an argument, as it may in some other situations, then you must include a call to the base class constructor, super.
Note that almost all the initializing for the window FirstWindow in Display 4 is placed in the constructor for the class. That is as it should be. The initializations, such as setting the initial window size, should be part of the class definition and not actions performed by objects of the class (as they were in Display 1). All the initializing methods, such as setSize, getContentPane, and addWindowListener, are inherited from the class JFrame. Because they are invoked in the constructor for the window, the window itself is the calling object. In other words, a method invocation such as
setSize(WIDTH, HEIGHT);
is equivalent to
this.setSize(WIDTH, HEIGHT);
Similarly, the method invocation
getContentPane().add(myLabel);
is equivalent to
this.getContentPane().add(myLabel);
Aside from the fact that they are done in the constructor for a derived class, the details in the definition of FirstWindow in Display 4 are essentially the same as those details in Display 1.
Let's next consider the program Display 5, which uses the class FirstWindow in Display 4. All this program does is display two (identical) objects of the class FirstWindow. These two windows will probably be placed one exactly on top of the other. So, when you run it, it may look like only one window is displayed. However, if you use your mouse to move the top window, you will see a second window underneath it. If the class FirstWindow had been more complicated or more versatile, the program might have done more than just display the windows, but for a window class as simple as FirstWindow, there is not much else you can do with the window. (This is, after all, our first example of a windowing interface, and as such, is very simple.)
Display 5A Program that Uses the Class FirstWindow
import javax.swing.*; /****************************************************** *A simple demonstration of using a window class. To see *both windows you will probably have to move the top window. ******************************************************/ public class FirstWindowDemo { public static void main(String[] args) { FirstWindow window1 = new FirstWindow(); window1.setVisible(true); FirstWindow window2 = new FirstWindow(); window2.setVisible(true); } }
Note that almost all of the initializations for the windows in Display 5 have been moved to the constructor for the class FirstWindow. However, we have placed the invocations of the method setVisible in the application program that uses the window class FirstWindow. We could have placed an invocation of setVisible in the constructor for FirstWindow and omitted the invocation of setVisible from the application program (Display 5); we would have gotten the same results when we ran the application program. However, in normal situations, the application program knows when the window should be displayed, and so it is normal to put the invocation of the method setVisible in the application program. The programmer who gave the definition of the class FirstWindow cannot anticipate when a programmer who uses the window will want to make it visible (or invisible)
Programming Example: A Window with Color
Display 6 contains a slight variant of the class shown in Display 4. This version has two constructors. The default constructor is the same as that in Display 4 but with four new elements added. The new elements are the title "Second Window", a local variable named contentPane to hold the content pane of the JFrame, a background color (blue), and a new way to add the window listener. Let's consider these four new elements one at a time. For the moment, we are only considering the default constructor (the one with no arguments).
Display 6Another Simple Window Constructed with Swing
import javax.swing.*; import java.awt.*;//needed for the Color class public class SecondWindow extends JFrame { public static final int WIDTH = 200; public static final int HEIGHT = 200; public SecondWindow() { super(); setSize(WIDTH, HEIGHT); Container contentPane = getContentPane(); JLabel label = new JLabel("Now available in color!"); contentPane.add(label); setTitle("Second Window"); contentPane.setBackground(Color.blue); addWindowListener(new WindowDestroyer()); } public SecondWindow(Color customColor) { super(); setSize(WIDTH, HEIGHT); Container contentPane = getContentPane(); JLabel label = new JLabel("Now available in color!"); contentPane.add(label); setTitle("Second Window"); contentPane.setBackground(customColor); addWindowListener(new WindowDestroyer()); } }
We have given the window a title with the following method invocation
setTitle("Second Window");
The method setTitle is inherited from the class JFrame. (Recall that the class for our window is a derived class of the class JFrame.) The method setTitle takes one string argument and writes that string in the title bar of the window. There is no calling object for this invocation because it is in a constructor and the calling object is an implicit this. The preceding invocation is equivalent to
this.setTitle("Second Window");
Other method invocations in the constructor also have an implicit this.
Note the following line from the first constructor in Display 6:
Container contentPane = getContentPane();
This gives us a name, contentPane, for the content pane of the JFrame windowing GUI we are defining. Thus, an invocation of the method add can be written in the simpler form:
contentPane.add(label);
instead of the slightly more complex (and slightly less efficient) expression
getContentPane().add(label);
The important thing to note here is that the method getContentPane produces an object of type Container. We will say a bit more about the class Container later in this article. For now, all you need to know about the class Container is that it is the type to use for the object returned by the method getContentPane (that is, for the content pane of the JFrame).
In Display 6, we have also given the window a background color with the method call
contentPane.setBackground(Color.blue);
The method setBackground is another method that is inherited from the class JFrame. The method setBackground takes one argument, which is a color. The class Color contains constants for many of the common colors. Color.blue is a predefined constant that stands for the color blue. The color constants you have available are listed in Display 7. To see what each of these colors looks like, replace the constant Color.blue in Display 6 with the color you want to see.
Display 7The Color Constants |
|
Color.black Color.blue Color.cyan Color.darkGray Color.gray Color.green Color.lightGray |
Color.magenta Color.orange Color.pink Color.red Color.white Color.yellow |
The class Color is in the AWT package (library). So, when using these colors, you need the following import statement:
run the modified program. You can also define your own colors with the class Color, but we will not go into that topic until Chapter 15. Because the Color class is in the AWT package (library), the following import statement is needed when a class or program uses the Color class:
import java.awt.*;//needed for the Color class
(As we pointed out earlier, the AWT library is a precursor of the Swing library, but some of the classes in the AWT are need when you program in Swing.)
At the end of the first constructor definition, we added a listener for our window with the following invocation of the method addWindowListener:
addWindowListener(new WindowDestroyer());
Certain methods, such as addWindowListener, need objects as arguments, but once the object is given as an argument to the method, you never need to refer to it again in your programming. That means that you do not need a name for the argument. An argument, such as new WindowDestroyer() in the preceding invocation of the method addWindowListener, is a way to create an object and pass it as an argument to the method addWindowListener, and yet not have to give the argument a name. The invocation
addWindowListener(new WindowDestroyer());
is equivalent to the following:
WindowDestroyer listener = new WindowDestroyer(); addWindowListener(listener):
The only difference between the preceding two ways of adding a window listener is that in the first form, we do not bother to use a name for the object of type WindowDestroyer; and in the second two-line version, we give the listener object the name listener.
Now let's consider the second constructor. The second constructor is almost the same as the default constructor except for how it handles the background color. This second constructor has one parameter of type Color and sets the background color to this one parameter. You can easily see the difference between these two constructors by looking at the demonstration program in Display 8. The two windows produced are identical except that one has a blue background and one has a pink background. (As with the previous example, when you run the program in Display 8 one window will probably be on top of the other, so that it looks like you have only one window. Just use your mouse to move the top window, and you will see the other window.)
Display 8A Demonstration Program for SecondWindow
import java.awt.*;//for the class Color used in an argument. public class SecondWindowDemo { /****************************************************** *Creates and displays two windows of the class SecondWindow. ******************************************************/ public static void main(String[] args) { SecondWindow window1 = new SecondWindow(); window1.setVisible(true); SecondWindow window2 = new SecondWindow(Color.pink); window2.setVisible(true); } }
Some Methods of the Class JFrame
Display 9 contains some of the methods for the class JFrame. You will recall that JFrame is the basic class out of which you normally build windows. A window class is normally a derived class of the class JFrame, and so the window class inherits all these methods.
Display 9Some Methods in the Class JFrame
Method |
Description |
JFrame() |
Constructor for creating a new JFrame. |
JFrame(String title) |
Constructor for creating a new JFrame with the specified title. |
add |
JFrame has a method add, but it should not be used. (It is basically a useless inheritance from an ancestor class). To add something to a Jframe, use getContentPane(). |
void addWindowListener(WindowListener ear) |
Registers ear as a listener for events fired by the JFrame. |
Container getContentPane() |
Returns the content pane object of the JFrame. Note that the content pane that is returned is of type Container. |
void setBackground(Color c) |
Sets the background color to c. |
void setForeground(Color c) |
Sets the foreground color to c. |
void setSize(int width, int height) |
Resizes the window to the specified width and height. |
void setTitle(String title) |
Writes the title on the title bar of the window. |
void setVisible(boolean b) |
Makes the window visible if the argument is true. Makes it invisible if the argument is false. |
Layout Managers
We have seen that you can add a JLabel to a JFrame by using the method getContentPane to get the content pane of the JFrame, and then using the method add to add the JLabel to the content pane. For an example, look at Display 6. If you only add one label, it seems like there is no question of where the label goes, but what if you add two or more labels? How are they arranged? One on top of the other? One next to the other? Which is first, which is second, and so forth? That arranging is done by a special kind of object known as a layout manager. The layout manager arranges the items you add according to certain rules. Different layout managers follow different rules, and so you will have a good deal of control over how things are arranged in a windowing interface (that is, in a JFrame or similar GUI). Display 10 shows the BorderLayout manager.
Display 10Using the BorderLayout Manager
import javax.swing.*; import java.awt.*; /********************************************************** *Simple demonstration of using a layout manager to arrange labels. **********************************************************/ public class BorderLayoutDemo extends JFrame { public static final int WIDTH = 300; public static final int HEIGHT = 200; /***************************************************** *Creates and displays a window of the class BorderLayoutDemo. *****************************************************/ public static void main(String[] args) { BorderLayoutDemo gui = new BorderLayoutDemo(); gui.setVisible(true); } public BorderLayoutDemo() { setSize(WIDTH, HEIGHT); addWindowListener(new WindowDestroyer()); setTitle("Layout Demonstration"); Container content = getContentPane(); content.setLayout(new BorderLayout()); JLabel label1 = new JLabel("First label here."); content.add(label1, BorderLayout.NORTH); JLabel label2 = new JLabel("Second label there."); content.add(label2, BorderLayout.SOUTH); JLabel label3 = new JLabel("Third label anywhere."); content.add(label3, BorderLayout.CENTER); } }
First note one minor point that we have not seen before in our discussion of Swing. We have placed a demonstration main method in the class definition. Normally, a Swing GUI class is used to create and display a GUI in a main (or other method) in some other class. However, it is perfectly legal and sometimes convenient to place a main method in the GUI class definition so that it is easy to display a sample of the GUI. Note that the main that is given in the class itself is written in the same way as a main that is in some other class. In particular, you need to construct an object of the class, as in the following line from the main in Display 10:
BorderLayoutDemo gui = new BorderLayoutDemo();
Now let's move on to the things that are truly new in Display 10.
A layout manager is added to the GUI in Display 10 with the following line:
content.setLayout(new BorderLayout());
BorderLayout is a layout manager class, and so new BorderLayout() produces a new object of the class BorderLayout. This BorderLayout object is given the task of arranging components (in this case, labels) that are added to the GUI. The way you specify that this object (namely, new BorderLayout()) is given the task of arranging components is by making it an argument to the method setLayout. It may help to note that the above invocation of setLayout is equivalent to the following:
BorderLayout manager = new BorderLayout(); content.setLayout(manager);
Note that the method setLayout is invoked not by the JFrame itself, but by the content pane of the JFrame, which in this case is named content. This is because we actually add the labels to the content pane and not (directly) to the JFrame. In general, the invocation of setLayout should be made with the same object that you use to invoke add (and so far that has always been the content pane of a JFrame).
A BorderLayout manager places labels (or other components) into the five regions: BorderLayout.NORTH, BorderLayout.SOUTH, BorderLayout.EAST, BorderLayout.WEST, and BorderLayout.CENTER. Let's look at our example from Display 10. We added labels as follows:
JLabel label1 = new JLabel("First label here."); content.add(label1, BorderLayout.NORTH);
JLabel label2 = new JLabel("Second label there."); content.add(label2, BorderLayout.SOUTH);
JLabel label3 = new JLabel("Third label anywhere."); content.add(label3, BorderLayout.CENTER);
BorderLayout.NORTH, BorderLayout.SOUTH, BorderLayout.EAST, BorderLayout.WEST, and BorderLayout.CENTER are five constants defined in the class BorderLayout, although you do not have to think of them as anything more than five things that you now know how to spell and that specify the five regions for a border layout manager. Note that when you use a border layout manager, you give the region as a second argument to the method add, as in
content.add(label1, BorderLayout.NORTH);
Note that the labels (or other components to be added) need not be added in any particular order because the second argument completely specifies where the label is placed.
That seems to conclude our discussion of Display 10, except for one point. What became of the regions BorderLayout.EAST and BorderLayout.WEST? The answer is simple. They were not used. You need not use all five regions. If some regions are not used, then any extra space is given to the BorderLayout.CENTER region.
From our discussion, it sounds like you can place only one item in each region, but later in this article, we will see that there is a way to group items so that more than one item can (in effect) be placed in each region.
There are some standard predefined layout managers and you can also define your own layout managers. However, for most purposes, the predefined layout managers are all that you need, and we will not discuss how you can create your own layout manager classes. We will discuss the three most commonly used predefined layout managers: the border layout manager, which you have already seen, and the two layout managers we discuss next.
The simplest layout manager is the FlowLayout manager. An object of the class FlowLayout is a layout manager that arranges the components you add to a class in the most obvious way. The components are arranged one after the other, going from left to right. The components are laid out in the order in which you add them to the class using the method add. For example, if the class in Display 10 had used the FlowLayout manager, then it would use the following code:
content.setLayout(new FlowLayout());
JLabel label1 = new JLabel("First label here."); content.add(label1);
JLabel label2 = new JLabel("Second label there."); content.add(label2);
JLabel label3 = new JLabel("Third label anywhere."); content.add(label3);
Note that if we had used the FlowLayout manager, as in the above code, then the add method has only one argument. Also note that with a FlowLayout manager, the items are displayed in the order they are added, so that labels would be displayed all on one line as follows:
First label here.Second label there.Third label anywhere.
A GridLayout manager arranges components in rows and columns with each entry being the same size. For example, the following says to use a GridLayout manager with aContainer (which can be a content pane or other container).
aContainer.setLayout(new GridLayout(2, 3));
The two numbers given as arguments to the constructor GridLayout specify the number of rows and columns. This would produce the following sort of layout:
The lines will not be visible unless you do something special to make them visible. They are just to show you the region boundaries.
When using the GridLayout class, the method add has only one argument. The items are placed in the grid from left to right, first filling the top row, then the second row, and so forth. You are not allowed to skip any grid position (although we will later see that you can add something that does not show and so gives the illusion of skipping a grid position).
The three layout managers are summarized in Display 11.
Display 11Some Layout Managers
Layout Manager |
Description |
FlowLayout |
Displays components left to right in the same fashion that you normally write things on a piece of paper. |
BorderLayout |
Displays the components in five areas: north, south, east, west, and center. You specify which area a component goes into in a second argument of the add method. |
GridLayout |
Lays components out in a grid with each component stretched to fill its box in the grid. |
Programming Tip: Copy Other Programmers' Code
Before I get in trouble with any instructors, let me clarify what the title of this section does not mean. It does not mean that you should have somebody else do your assignments. What this means is that one very good way to learn how to program, and to produce good programs in a hurry, is to start out with a program that does something similar to what you want and then change it to do exactly what you want. For example, if you want to write a program for a window that has something written in it, you can start with the program in Display 10 and change the details. Code for Swing GUIs can be pretty complicated, and it is not easy to learn all the details of all the various predefined classes and methods. Sometimes, the best way to learn these details is to copy and change code until the details become routine.