Sometimes the placement of graphic controls such as buttons doesn't matter, but often it does. In this example, a simple calculator applet, the placement of the buttons that serve as the keys of the calculator is critical.
We will have our hands full just managing the layout. Implementing the actions is not the subject of this example.
Applet is an example of a container class in Java -- a class whose objects can graphically contain controls or other containers. By contrast, Buttons are not containers; you can't put anything into a Button. To put something into a container object, you send it an add message, with an argument that specifies the item being added. Container objects such as Applets rely on LayoutManager objects to guide the placement of their contents.
Programmers can control the way Applets or other container objects place their contents by creating a LayoutManager object of their choice and sending it as an argument to a setLayout message to the container, as shown in the following code:
public class TestApplet extends Applet
public void Init( )
setLayout (new FlowLayout ( )); //sends a setLayout message to itself
The FlowLayout manager causes the controls to be placed one after the other in the order in which they were added to the container. The controls start in the upper left corner and proceed to the right. Depending on the particular container, they may or may not "wrap around" to the space below when they reach the right end of the container. If a FlowLayout is used for the Calculator applet, its appearance would be unacceptable.
The BorderLayout manager views the container as divided into five regions; north, south, east, west, and center. It allows the programmer to assign controls to these regions. The controls assigned to the north and south are stretched out horizontally to cover the top and bottom borders of the container, the controls assigned to east and west are stretched vertically to fill the sides between the north and south controls, and the control in the center gets what's left. Obviously we can't rely on BorderLayout -- there are 19 controls, not 5. If we put the 7, 8, 9, -, and 4 to positions north, west, center, east, and south, it would be unattractive.
One can, however, choose to use fewer than five positions, a technique that will be put to good use below.
Java provides the Panel class that, when combined with the layout managers described above, allows us to accomplish our goal.
The Panel class is the simplest container class one can imagine -- just about the only thing you can do with a Panel object is assign it a layout manager and start adding objects. The trick to using Panels is to divide one's applet region into different Panels, each containing a handful of the applet's controls. This makes it easier to lay out the controls; just a few are given to each Panel. The Panels themselves can be contained in other Panels and or in the applet itself.
The design strategy is shown below.
The Label object, which we use to display the result of a calculation, and the Panel objects that contain the Buttons are added to the applet in FlowLayout fashion.
The first three rows of keys on the calculator are Panels containing four Buttons in a row -- perfect for a FlowLayout layout manager. The 1 and 2 keys are placed in a Panel using BorderLayout and occupy west and east. This Panel is itself placed in another Panel along with the 0 key. By using BorderLayout again with 1 and 2 in north and 0 in south, we get the effect of stretching out the 0 key as desired.
In order for this strategy to work, we must guarantee that our Buttons have the same basic size (unless stretched by a BorderLayout). We do this by labeling each Button with a single character and using a fixed-width font (i.e., all letters are the same width, even, for example, I and W).
To prevent the Panels of the applet from extending horizontally in unfavorable ways, we can force the applet to assume a certain size by using the resize method. The arguments to this method are the desired width and height of the calculator. We compute these by examining the components of the applet itself. For example, row1 is a variable that holds a reference to the Panel object that contains the first row of Buttons. The width of that row, plus a little bit of elbow room, is the width we desire for the applet itself; the code follows:
The height of a row is the same as the height of a button. There are five rows of buttons, plus the text field, and there is spacing between the rows. Multiplying button height by 8, as follows, easily accommodates the height of the applet:
8 * num1.getsize( ).height
Once the applet is resized,
setSize(row1.getSize( ).width, 8 * num1.getSize( ),height);
all its components must be laid out again. This is accomplished by invoking the applet's validate method.
This calculation, unfortunately cannot be done within init -- at that point the sizes for the Panels, Buttons, and so on, have not yet been computed by the system. So we carry out this calculation and the resize operation in the paint method.
If you use the designer to create the interface, follow the guidelines below: