> ### Section 7.4
> Programming with Components

> THE TWO PREVIOUS SECTIONS described some raw materials that are available in the form of layout managers and standard GUI components. This section presents some programming examples that make use of those raw materials.

> ### An Example with Text Input Boxes

> As a first example, let's look at a simple calculator applet. This example demonstrates typical uses of `JTextFields`, `JButtons`, and `JLabels`, and it uses several layout managers. In the applet, you can enter two real numbers in the text-input boxes and click on one of the buttons labeled "+", "-", "*", and "/". The corresponding operation is performed on the numbers, and the result is displayed in a `JLabel` at the bottom of the applet. If one of the input boxes contains an illegal entry -- a word instead of a number, for example -- an error message is displayed in the `JLabel`.

> (Applet "SimpleCalculator" would be displayed here
> if Java were available.)

> When designing an applet such as this one, you should start by asking yourself questions like: How will the user interact with the applet? What components will I need in order to support that interaction? What events can be generated by user actions, and what will the applet do in response? What data will I have to keep in instance variables to keep track of the state of the applet? What information do I want to display to the user? Once you have answered these questions, you can decide how to lay out the components. You might want to draw the layout on paper. At that point, you are ready to begin writing the program.

> In the simple calculator applet, the user types in two numbers and clicks a button. The computer responds by doing a computation with the user's numbers and displaying the result. The program uses two `JTextField` components to get the user's input. The `JTextFields` do a lot of work on their own. They respond to mouse, focus, and keyboard events. They show blinking cursors when they are active. They collect and display the characters that the user types. The program only has to do three things with each `JTextField`: Create it, add it to the applet, and get the text that the user has input by calling its `getText()` method. The first two things are done in the applet's `init()` method. The third -- getting the user's input from the input boxes -- is done in an `actionPerformed()` method, which responds when the user clicks on one of the buttons. When a component is created in one method and used in another, as the input boxes are in this case, we need an instance variable to refer to it. In this case, I use two instance variables, `xInput` and `yInput`, of type `JTextField` to refer to the input boxes. The `JLabel` that is used to display the result is treated similarly: A `JLabel` is created and added to the applet in the `init()` method. When an answer is computed in the `actionPerformed()` method, the `JLabel's` `setText()` method is used to display the answer in the label. I use an instance variable named `answer`, of type `JLabel`, to refer to the label.

> The applet also has four `JButtons` and two more `JLabels`. (The two extra labels display the strings "x =" and "y =".) I use local variables rather than instance variables for these components because I don't need to refer to them outside the `init()` method.

> The applet as a whole uses a `GridLayout` with four rows and one column. The bottom row is occupied by the `JLabel`, `answer`. The other three rows each contain several components. Each of the first three rows is filled by a `JPanel`, which has its own layout manager and contains several components. The row that contains the four buttons is a `JPanel` which uses a `GridLayout` with one row and four columns. The `JPanels` that contain the input boxes use `BorderLayouts`. The input box occupies the Center position of the `BorderLayout`, with a `JLabel` on the West. (This example shows that `BorderLayouts` are more versatile than it might appear at first.) All the work of setting up the applet is done in its `init()` method:

>          public void init() {

>             /* Since I will be using the content pane several times,
>                declare a variable to represent it.  Note that the
>                return type of getContentPane() is Container. */

>             Container content = getContentPane();

>             /* Assign a background color to the applet and its
>                content panel.  This color will show through between
>                components and around the edges of the applet. */

>             setBackground(Color.gray);
>             content.setBackground(Color.gray);

>             /* Create the input boxes, and make sure that their background
>                color is white.  (They are likely to be white by default.) */

>             xInput = new JTextField("0");
>             xInput.setBackground(Color.white);
>             yInput = new JTextField("0");
>             yInput.setBackground(Color.white);

>             /* Create panels to hold the input boxes and labels "x =" and
>                "y = ".  By using a BorderLayout with the JTextField in the
>                Center position, the JTextField will take up all the space
>                left after the label is given its preferred size. */

>             JPanel xPanel = new JPanel();
>             xPanel.setLayout(new BorderLayout());
>             xPanel.add( new Label(" x = "), BorderLayout.WEST );
>             xPanel.add(xInput, BorderLayout.CENTER);

>             JPanel yPanel = new JPanel();
>             yPanel.setLayout(new BorderLayout());
>             yPanel.add( new Label(" y = "), BorderLayout.WEST );
>             yPanel.add(yInput, BorderLayout.CENTER);

>             /* Create a panel to hold the four buttons for the four
>                operations.  A GridLayout is used so that the buttons
>                will all have the same size and will fill the panel.
>                The applet serves as ActionListener for the buttons. */

>             JPanel buttonPanel = new JPanel();
>             buttonPanel.setLayout(new GridLayout(1,4));

>             JButton plus = new JButton("+");
>             plus.addActionListener(this);
>             buttonPanel.add(plus);

>             JButton minus = new JButton("-");
>             minus.addActionListener(this);
>             buttonPanel.add(minus);

>             JButton times = new JButton("*");
>             times.addActionListener(this);
>             buttonPanel.add(times);

>             JButton divide = new JButton("/");
>             divide.addActionListener(this);
>             buttonPanel.add(divide);

>             /* Create the label for displaying the answer in red
>                on a white background.  The label is set to be
>                "opaque" to make sure that the white background
>                is painted. */

>             answer = new JLabel("x + y = 0", JLabel.CENTER);
>             answer.setForeground(Color.red);
>             answer.setBackground(Color.white);
>             answer.setOpaque(true);

>             /* Set up the layout for the applet, using a GridLayout,
>                 and add all the components that have been created. */

>             content.setLayout(new GridLayout(4,1,2,2));
>             content.add(xPanel);
>             content.add(yPanel);
>             content.add(buttonPanel);
>             content.add(answer);

>             /* Try to give the input focus to xInput, which is the natural
>                place for the user to start. */

>             xInput.requestFocus();

>          }  // end init()

> The action of the applet takes place in the `actionPerformed()` method. The algorithm for this method is simple:

>           get the number from the input box xInput
>           get the number from the input box yInput
>           get the action command (the name of the button)
>           if the command is "+"
>              add the numbers and display the result in the answer label
>           else if the command is "-"
>              subtract the numbers and display the result in the label
>           else if the command is "*"
>              multiply the numbers and display the result in the label
>           else if the command is "/"
>              divide the numbers and display the result in the label

> There is only one problem with this. When we call `xInput.getText()` and `yInput.getText()` to get the contents of the input boxes, the results are `Strings`, not numbers. We need a method to convert a string such as "42.17" into the number that it represents. The standard class `Double` contains a static method, `Double.parseDouble(String)` for doing just that. So we can get the first number entered by the user with the commands: f

>              String xStr = xInput.getText();
>              x = Double.parseDouble(xStr);

> where `x` is a variable of type `double`. Similarly, if we wanted to get an integer value from the string, `xStr`, we could use a static method in the standard `Integer` class: `x = Integer.parseInt(xStr)`. This makes it easy to get numerical values from a `JTextField`, but one problem remains: We can't be sure that the user has entered a string that represents a legal real number. We could ignore this problem and assume that a user who doesn't enter a valid input shouldn't expect to get an answer. However, a more friendly program would notice the error and display an error message to the user. This requires using a "`try...catch`" statement, which is not covered until Chapter 9 of this book. My program does in fact use a `try...catch` statement to handle errors, so you can get a preview of how it works. Here is the `actionPerformed()` method that responds when the user clicks on one of the buttons in the applet:

>          public void actionPerformed(ActionEvent evt) {
>                  // When the user clicks a button, get the numbers
>                  // from the input boxes and perform the operation
>                  // indicated by the button.  Put the result in
>                  // the answer label.  If an error occurs, an
>                  // error message is put in the label.

>             double x, y;  // The numbers from the input boxes.

>             /* Get a number from the xInput JTextField.  Use
>                xInput.getText() to get its contents as a String.
>                Convert this String to a double.  The try...catch
>                statement will check for errors in the String.  If
>                the string is not a legal number, the error message
>                "Illegal data for x." is put into the answer and
>                the actionPerformed() method ends. */

>             try {
>                String xStr = xInput.getText();
>                x = Double.parseDouble(xStr);
>             }
>             catch (NumberFormatException e) {
>                   // The string xStr is not a legal number.
>                answer.setText("Illegal data for x.");
>                return;
>             }

>             /* Get a number from yInput in the same way. */

>             try {
>                String yStr = yInput.getText();
>                y = Double.parseDouble(yStr);
>             }
>             catch (NumberFormatException e) {
>                answer.setText("Illegal data for y.");
>                return;
>             }

>             /* Perform the operation based on the action command
>                from the button.  Note that division by zero produces
>                an error message. */

>             String op = evt.getActionCommand();
>             if (op.equals("+"))
>                answer.setText( "x + y = " + (x+y) );
>             else if (op.equals("-"))
>                answer.setText( "x - y = " + (x-y) );
>             else if (op.equals("*"))
>                answer.setText( "x * y = " + (x*y) );
>             else if (op.equals("/")) {
>                if (y == 0)
>                   answer.setText("Can't divide by zero!");
>                else
>                   answer.setText( "x / y = " + (x/y) );
>             }

>          } // end actionPerformed()

> The complete source code for the applet can be found in the file SimpleCalculator.java. (It contains very little in addition to the two methods shown above.)

> ### An Example with Sliders

> As a second example, let's look more briefly at another applet. In this example, the user manipulates three `JSliders` to set the red, green, and blue levels of a color. The value of each color level is displayed in a `JLabel`, and the color itself is displayed in a large rectangle:

> (Applet "RGBColorChooser" would be displayed here
> if Java were available.)

> The layout manager for the applet is a `GridLayout` with one row and three columns. The first column contains a `JPanel`, which in turn contains the `JSliders`. This panel uses another `GridLayout`, with three rows and one column. The second column, which contains the `JLabels`, is similar. The third column contains the colored rectangle. The component in this column is a `JPanel` which contains no components. The displayed color is the background color of the `JPanel`. When the user changes the color, the background color of the panel is changed and the panel is repainted to show the new color. This is one of the few cases where an object of type `JPanel` is used without either making a subclass or adding components to it.

> When the user changes the value on a `JSlider`, an event of type `ChangeEvent` is generated. In order to respond to such events, the applet implements the `ChangeListener` interface, which specifies the method "`public void stateChanged(ChangeEvent evt)`". The applet registers itself to listen for change events from each slider. The applet has instance variables to refer to the sliders, the labels, and the color patch. Note that since the `ChangeEvent` and `ChangeListener` classes are defined in the package `javax.swing.event`, the command "`import javax.swing.event.*;`" is added to the beginning of the program.

> Let's look at the code from the `init()` method for setting up one of the `JSliders`, `redSlider`:

>                 redSlider = new JSlider(0, 255, 0);
>                 redSlider.addChangeListener(this);

> The first line constructs a horizontal slider whose value can range from 0 to 255. These are the possible values of the red level in a color. The initial value of the slider, which is specified by the third parameter to the constructor, is 0. The second line registers the applet ("`this`") to listen for change events from the slider. The other two sliders are initialized in a similar way.

> In the `stateChanged()` method, the applet must respond to the fact that the user has changed the value of one of the sliders. The response is to read the values of all the sliders, set the labels to display those values, and change the color displayed on the color patch. (This is slightly lazy programming, since only one of the labels actually needs to be changed. However, there is no rule against setting the text of a label to the same text that it is already displaying.)

>          public void stateChanged(ChangeEvent evt) {
>                  // This is called when the user has changed the value on
>                  // one of the sliders.  All the sliders are checked,
>                  // the labels are set to display the correct values, and
>                  // the color patch is set to correspond to the new color.
>              int r = redSlider.getValue();
>              int g = greenSlider.getValue();
>              int b = blueSlider.getValue();
>              redLabel.setText(" R = " + r);
>              greenLabel.setText(" G = " + g);
>              blueLabel.setText(" B = " + b);
>              colorPatch.setBackground(new Color(r,g,b));
>          } // end stateChanged()

> The complete source code can be found in the file RGBColorChooser.java.

> ### Custom Component Examples

> Java's standard component classes are often all you need to construct a user interface. Sometimes, however, you need a component that Java doesn't provide. In that case, you can write your own component class, building on one of the components that Java does provide. We've already done this, actually, every time we've written a subclass of the `JPanel` class to use as a drawing surface. A `JPanel` is a blank slate. By defining a subclass, you can make it show any picture you like, and you can program it to respond in any way to mouse and keyboard events. Sometimes, if you are lucky, you don't need such freedom, and you can build on one of Java's more sophisticated component classes.

> For example, suppose I have a need for a "stopwatch" component. When the user clicks on the stopwatch, I want it to start timing. When the user clicks again, I want it to display the elapsed time since the first click. The textual display can be done with a `JLabel`, but we want a `JLabel` that can respond to mouse clicks. We can get this behavior by defining a `StopWatch` component as a subclass of the `JLabel` class. A `StopWatch` object will listen for mouse clicks on itself. The first time the user clicks, it will change its display to "Timing..." and remember the time when the click occurred. When the user clicks again, it will check the time again, and it will compute and display the elapsed time. (Of course, I don't necessarily have to define a subclass. I could use a regular label in my applet, set the applet to listen for mouse events on the label, and let the applet do the work of keeping track of the time and changing the text displayed on the label. However, by writing a new class, I have something that is reusable in other projects. I also have all the code involved in the stopwatch function collected together neatly in one place. For more complicated components, both of these considerations are very important.)

> The `StopWatch` class is not very hard to write. I need an instance variable to record the time when the user started the stopwatch. Times in Java are measured in milliseconds and are stored in variables of type `long` (to allow for very large values). In the `mousePressed()` method, I need to know whether the timer is being started or stopped, so I need another instance variable to keep track of this aspect of the component's state. There is one more item of interest: How do I know what time the mouse was clicked? The method `System.currentTimeMillis()` returns the current time. But there can be some delay between the time the user clicks the mouse and the time when the `mousePressed()` routine is called. I don't want to know the current time. I want to know the exact time when the mouse was pressed. When I wrote the `StopWatch` class, this need sent me on a search in the Java documentation. I found that if `evt` is an object of type `MouseEvent()`, then the function `evt.getWhen()` returns the time when the event occurred. I call this function in the `mousePressed()` routine.

> The complete `StopWatch` class is rather short:

>          import java.awt.event.*;
>          import javax.swing.*;

>          public class StopWatch extends JLabel implements MouseListener {

>             private long startTime;   // Start time of timer.
>                                       //   (Time is measured in milliseconds.)

>             private boolean running;  // True when the timer is running.

>             public StopWatch() {
>                   // Constructor.
>                super("  Click to start timer.  ", JLabel.CENTER);
>                addMouseListener(this);
>             }

>             public void mousePressed(MouseEvent evt) {
>                    // React when user presses the mouse by
>                    // starting or stopping the timer.
>                if (running == false) {
>                      // Record the time and start the timer.
>                   running = true;
>                   startTime = evt.getWhen();  // Time when mouse was clicked.
>                   setText("Timing....");
>                }
>                else {
>                      // Stop the timer.  Compute the elapsed time since the
>                      // timer was started and display it.
>                   running = false;
>                   long endTime = evt.getWhen();
>                   double seconds = (endTime - startTime) / 1000.0;
>                   setText("Time: " + seconds + " sec.");
>                }
>             }

>             public void mouseReleased(MouseEvent evt) { }
>             public void mouseClicked(MouseEvent evt) { }
>             public void mouseEntered(MouseEvent evt) { }
>             public void mouseExited(MouseEvent evt) { }

>          }  // end StopWatch

> Don't forget that since `StopWatch` is a subclass of `JLabel`, you can do anything with a `StopWatch` that you can do with a `JLabel`. You can add it to a container. You can set its font, foreground color, and background color. You can set the text that it displays (although this would interfere with its stopwatch function). You can even add a `Border` if you want.

> Let's look at one more example of defining a custom component. Suppose that -- for no good reason whatsoever -- I want a component that acts like a `JLabel` except that it displays its text in mirror-reversed form. Since no standard component does anything like this, the `MirrorLabel` class is defined as a subclass of `JPanel`. It has a constructor that specifies the text to be displayed and a `setText()` method that changes the displayed text. The `paintComponent()` method draws the text mirror-reversed, in the center of the component. This uses techniques discussed in Section 1. Information from a `FontMetrics` object is used to center the text in the component. The reversal is achieved by using an off-screen image. The text is drawn to the off-screen image, in the usual way. Then the image is copied to the screen with the following command, where `OSC` is the variable that refers to the off-screen image:

>            g.drawImage(OSC, widthOfOSC, 0, 0, heightOfOSC,
>                            0, 0, widthOfOSC, heightOfOSC, this);

> This is the version of `drawImage()` that specifies corners of destination and source rectangles. The corner `(0,0)` in `OSC` is matched to the corner `(widthOfOSC,0)` on the screen, while `(widthOfOSC,heightOfOSC)` is matched to `(0,heightOfOSC)`. This reverses the image left-to-right. Here is the complete class:

>          import java.awt.*;
>          import javax.swing.*;

>          public class MirrorLabel extends JPanel {

>             // Constructor and methods meant for use public use.

>             public MirrorLabel(String text) {
>                   // Construct a MirrorLable to display the specified text.
>                this.text = text;
>             }

>             public void setText(String text) {
>                   // Change the displayed text.  Call revalidate
>                   // so that the layout of its container can be
>                   // recomputed.
>                this.text = text;
>                revalidate();  // Tells container that size might have changed.
>                repaint();
>             }

>             public String getText() {
>                   // Return the string that is displayed by this component.
>                return text;
>             }

>             // Implementation.  Not meant for public use.

>             private String text; // The text displayed by this component.

>             private Image OSC;
>                  // An off-screen image holding the non-reversed text.

>             private int widthOfOSC, heightOfOSC;
>                  // Current size of the off-screen image, if one exists.

>             public void paintComponent(Graphics g) {
>                   // The paint method makes a new OSC, if necessary.  It writes
>                   // a non-reversed copy of the string to the the OSC, then
>                   // reverses the OSC as it copies it to the screen.
>                   // (Note:  color or font might have changed since the
>                   // last time paintComponent() was called, so I can't just
>                   // reuse the old image in the OSC.)
>                if (OSC == null || getSize().width != widthOfOSC
>                                     || getSize().height != heightOfOSC) {
>                    OSC = createImage(getSize().width, getSize().height);
>                    widthOfOSC = getSize().width;
>                    heightOfOSC = getSize().height;
>                 }
>                 Graphics OSG = OSC.getGraphics();
>                 OSG.setColor(getBackground());
>                 OSG.fillRect(0, 0, widthOfOSC, heightOfOSC);
>                 OSG.setColor(getForeground());
>                 OSG.setFont(getFont());
>                 FontMetrics fm = OSG.getFontMetrics(getFont());
>                 int x = (widthOfOSC - fm.stringWidth(text)) / 2;
>                 int y = (heightOfOSC + fm.getAscent() - fm.getDescent()) / 2;
>                 OSG.drawString(text, x, y);
>                 OSG.dispose();
>                 g.drawImage(OSC, widthOfOSC, 0, 0, heightOfOSC,
>                                 0, 0, widthOfOSC, heightOfOSC, null);
>             } // end paintComponent()

>             public Dimension getPreferredSize() {
>                    // Compute a preferred size that will hold the string plus
>                    // a border of 5 pixels.
>                FontMetrics fm = getFontMetrics(getFont());
>                return new Dimension(fm.stringWidth(text) + 10,
>                                         fm.getAscent() + fm.getDescent() + 10);
>             }

>          }  // end class MirrorLabel

> This class defines the method "`public Dimension getPreferredSize()`". This method is called by a layout manager when it wants to know how big the component would like to be. Standard components come with a way of computing a preferred size. For a custom component based on a `JPanel`, it's a good idea to provide a custom preferred size. As I mentioned in Section 1, every component has a method `setPrefferedSize()` that can be used to set the preferred size of the component. For our `MirrorLabel` component, however, the preferred size depends the font and the text of the component, and these can change from time to time. We need a way to compute a preferred size on demand, based on the current font and text. That's what we do by defining a `getPreferredSize()` method. The system calls this method when it wants to know the preferred size of the component. In response, we can compute the preferred size based on the current font and text.

> The `StopWatch` and `MirrorLabel` class define components. Components don't stand on their own. You have to add them to an applet or other container. Here is an applet that demonstrates a `MirrorLabel` and a `StopWatch` component:

> (Applet "ComponentTest" would be displayed here
> if Java were available.)

> The source code for this applet is in the file ComponentTest.java. The applet uses a `FlowLayout`, so the components are not arranged very neatly. The applet also contains a button, which is there to illustrate another fine point of programming with components. If you click the button labeled "Change Text in this Applet", the text in all the components will be changed. You can also click on the "Timing..." label to start and stop the StopWatch. When you do any of these things, you will notice that the components will be rearranged to take the new sizes into account. This is known as "validating" the container. This is done automatically when a standard component changes in some way that requires a change in preferred size or location. This may or may not be the behavior that you want. (Validation doesn't always cause as much disruption as it does in this applet. For example, in a `GridLayout`, where all the components are displayed at the same size, it will have no effect at all. I've chosen a `FlowLayout` for this example to make the effect more obvious.) A custom component such as `MirrorLabel` can call the `revalidate()` method to indicate that the container that contains the component should be validated. In the `MirrorLabel` class, `revalidate()` is called in the `setText()` method.

> ### A Null Layout Example

> As a final example, we'll look at an applet that does not use a layout manager. If you set the layout manager of a container to be `null`, then you assume complete responsibility for positioning and sizing the components in that container. For an applet, you can remove the layout manager with the command:

>                 getContentPane().setLayout(null);

> If `comp` is any component, then the statement

>                 comp.setBounds(x, y, width, height);

> puts the top left corner of the component at the point `(x,y)`, measured in the coordinated system of the container that contains the component, and it sets the width and height of the component to the specified values. You should only set the bounds of a component if the container that contains it has a null layout manager. In a container that has a non-null layout manager, the layout manager is responsible for setting the bounds, and you should not interfere with its job.

> Assuming that you have set the layout manager to `null`, you can call the `setBounds()` method any time you like. (You can even make a component that moves or changes size while the user is watching.) If you are writing an applet that has a known, fixed size, then you can set the bounds of each component in the applet's `init()` method. That's what done in the following applet, which contains four components: two buttons, a label, and a panel that displays a checkerboard pattern. This applet doesn't do anything useful. The buttons just change the text in the label.

> (Applet "NullLayoutDemo" would be displayed here
> if Java were available.)

> In the `init()` method of this applet, the components are created and added to the applet. Then the `setBounds()` method of each component is called to set the size and position of the component:

>          public void init() {

>             getContentPane().setLayout(null);  // I will do the layout myself!

>             getContentPane().setBackground(new Color(0,150,0));
>                                      // Set a dark green background.

>             /* Create the components and add them to the content pane.  If you
>                don't add them to the a container, they won't appear, even if
>                you set their bounds! */

>             board = new Checkerboard();
>                              // (Checkerboard is defined later in this class.)
>             getContentPane().add(board);

>             newGameButton = new JButton("New Game");
>             newGameButton.addActionListener(this);
>             getContentPane().add(newGameButton);

>             resignButton = new JButton("Resign");
>             resignButton.addActionListener(this);
>             getContentPane().add(resignButton);

>             message = new JLabel("Click \"New Game\" to begin a game.",
>                                                                JLabel.CENTER);
>             message.setForeground( new Color(100,255,100) );
>             message.setFont(new Font("Serif", Font.BOLD, 14));
>             getContentPane().add(message);

>             /* Set the position and size of each component by calling
>                its setBounds() method. */

>             board.setBounds(20,20,164,164);
>             newGameButton.setBounds(210, 60, 120, 30);
>             resignButton.setBounds(210, 120, 120, 30);
>             message.setBounds(0, 200, 330, 30);

>             /* Add a border to the content pane.  Since the return
>                type of getContentPane() is Container, not JComponent,
>                getContentPane() must be type-cast to a JComponent
>                in order to call the setBorder() method.  Although I
>                think the content pane is always, in fact, a JPanel,
>                to be safe I test that the return value really is
>                a JComponent. */

>             if (getContentPane() instanceof JComponent) {
>                ((JComponent)getContentPane()).setBorder(
>                                 BorderFactory.createEtchedBorder());
>             }
>          } // end init();

> It's reasonably easy, in this case, to get an attractive layout. It's much more difficult to do your own layout if you want to allow for changes of size. In that case, you have to respond to changes in the container's size by recomputing the sizes and positions of all the components that it contains. If you want to respond to changes in a container's size, you can register an appropriate listener with the container. Any component generates an event of type `ComponentEvent` when its size changes (and also when it is moved, hidden, or shown). You can register a `ComponentListener` with the container and respond to size change events by recomputing the sizes and positions of all the components in the container. Consult a Java reference for more information about `ComponentEvents`. However, my real advice is that if you want to allow for changes in the container's size, try to find a layout manager to do the work for you.

[ Next Section | Previous Section | Chapter Index | Main Index ]