COMP1406/1006 - Design and Implementation of Computer Applications Winter 2006

 2  Applications and LayoutManagers


What's in This Set of Notes?

We look here at how to create a graphical user interface (i.e., with windows) in JAVA.   Creating GUIs in JAVA requires adding components onto windows.   We will find out how to do this as well as look at an interesting JAVA feature called a "LayoutManager" that automatically arranges components on the window.   This allows us to create simple windows without having to worry about resizing issues.

Here are the individual topics found in this set of notes (click on one to go there):


 2.1 Creating a Basic GUI Application

Recall that a Graphical User Interface (GUI) is a user interface that has one or more windows.

frame:

  • is the JAVA terminology for a window (i.e., its a window frame)
  • represented by the Frame and JFrame classes in JAVA
  • used to show information and handle user interaction
  • has no security restrictions ... can modify files, perform I/O, open network connections to other computers, etc..
  • The following code creates a basic window frame in JAVA and shows it on the screen:
    javax.swing.JFrame frame = new javax.swing.JFrame("This appears at the top of the window");
    frame.setSize(300, 100);
    frame.setVisible(true);
    Here is what it looks like:
    Although this code for bringing up a new window can appear anywhere, we typically designate a whole class to represent the window (that is, the JAVA application).   This also helps to separate the model and the user interface.   So here are the steps involved with creating your own JAVA application that uses a main window (frame):
    1. Create a new class (separate from model classes) to represent your application.
    2. Make this class extend JFrame (or Frame if you want to use the older AWT classes ... more on this later).
    3. Create a constructor method that sets the window title (specified as a parameter) and any other settings as well such as background color.
    4. Include a main() method as a starting point for the application which is similar to the above code.
    So here is the template that you should use:
    import javax.swing.*; //needed to use swing components e.g. JFrame
    public class FirstApplication  extends JFrame {
        public FirstApplication(String title) {
            super(title);        // Set the title of the window
            setDefaultCloseOperation(EXIT_ON_CLOSE);  // allow window to close
            setSize(300, 100);   // Set the size of the window
        }
        public static void main(String args[]) {
             // Instantiate a FirstApplication object so you can display it
             FirstApplication frame =  new FirstApplication("FirstApplication Example");
             frame.setVisible(true); // Show the window now
        }
    }
    Note that we make use of the following instance method for JFrame objects to set the size of the frame: If we do not set the size, the window shows up so small that we only see part of the title bar.

    When frames are created, they do not appear on the screen.   They are essentially hidden.   To make the window visible and give control to your application window, we use the setVisible method:

    which either shows or hides the window according to the boolean value supplied.

    Note that we specified for the application to EXIT_ON_CLOSE.   This is necessary since we want the application to stop running when the window is closed.   This is typical behaviour for all applications that run under windowing operating system environments.

    To test the application, just compile and run it as you normally do.

    What happens ?  ... A new application window should come up with the title that we specified. 
    Try changing the size of the window.   
    What happens if we set visibility to false ? ... The application starts but nothing is displayed.  Press CNTRL + C to stop it.

    What other choices do we have when the window is closed ?

    We could have used:

        // window is not closed
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

        // window is hidden...the program keeps running
        setDefaultCloseOperation(HIDE_ON_CLOSE);

        // window is hidden and disposed of (more later)
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
     
    It is possible to alter the look and feel of our application's windows in JAVA.   We can have our windows look like standard windows applications, like standard cross-platform JAVA applications or any look and feel that we would like.  To do this, we merely need to add a few lines to our code to tell the user interface manager (UIManager) that we would like all of our windows to have a certain standard look and feel to them.   Here is what we need to add BEFORE we make our frame:

            try {
            UIManager.setLookAndFeel(aLookAndFeel);
        } catch(Exception e) {}
            JFrame.setDefaultLookAndFeelDecorated(true);
        // ... now make our frame as usual

    Here, aLookAndFeel can be any "LookAndFeel" available in Java.   Here are just some examples:
    To illustrate, consider an example of a simple window (which we will show how to construct later).   We can add the following lines of code to the main method in order to choose a particular look and feel:

    import java.awt.event.*;
    import javax.swing.*;
    public class NoLayoutExample  extends JFrame {

        public NoLayoutExample(String name) {
            // Code for building the window ... we will see this later
        }

        public static void main(String[] args) {
            try {
                UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
            } catch(Exception e) {}
            JFrame.setDefaultLookAndFeelDecorated(true);
            JFrame frame = new NoLayoutExample("Example Using Cross-Platform L&F");
            frame.setVisible(true);
        }
    }

    Here are some snapshots of the application using the cross-platform l&f, the System (i.e., windows) l&f and the motif l&f:







    If you have some spare time on your hands, you can try experimenting with other looks and feels ... you can even create your own ;).


     2.2 Components and Containers

    Our windows that we make will need to have various components on them.  Components are objects on our window that have a visual representations (e.g., labels, lists, scroll bars, buttons, text fields, menubars, menus).  They may allow the user to interact with them (e.g., lists, scroll bars, buttons, text fields, menus). Components may also be grouped together, much like adding elements to an ArrayList.  In fact, most components in JAVA can contain other components as their sub-parts.   This brings up the notion of a Container.

    Containers:

    So, a container of components is conceptually "like" an ArrayList of Objects:

    There are two main sets of visual components and containers for user interface design in JAVA:

    i)    AWT (Abstract Window Toolkit)

    Here is just a portion of the component hierarchy.  The red classes are Swing classes, while the yellow ones are AWT classes:

    There are some interesting things to note:

    Now, how is everything held together ? One of the most commonly used containers is called a Panel:
    A Panel is:
    • the simplest container class
    • is itself contained (i.e., it itself is contained within a container)
    • provides space in which an application can attach any other component (including other panels)
    • does not create a separate window of its own like Frame.

    Think of a panel as a bulletin board that you can fill with components and then you can place the bulletin board anywhere as a component itself.

    All JFrames have a JPanel at the top level to which everything is added.  For simple "single-panel" windows, we can simply access this panel by sending the getContentPane() method to our JFrame, and then call add() to put components onto it:

            JFrame frame = new JFrame("MyApplication");
            frame.getContentPane().add(aComponent);
            frame.getContentPane().add(anotherComponent);
            frame.getContentPane().add(yetAnotherComponent);

    We will see more on this in our upcoming examples.

    Note that the diagram above did not expand the Component hierarchy ... there are also standard AWT components that are similar to those of the Swing set.   Now let us look at the Swing JCompoment hierarchy in more detail.   Here are some of the JComponent subclasses for common components (shown in yellow) that are placed onto windows:

    Notice that all these JComponents start with a "J".  Also notice that there are different kinds of buttons and text-based components.

    In addition to these classes, there are some more advanced classes (some of which we will look at later).   Below are two more pieces of the JComponent hierarchy (note that there was too much to show on one picture so it has been split into multiple pictures):

       

    There are even more subclasses ... those dealing with menus will be shown later.

    All JComponents have the following state:
    1. Location, Width and Height (in pixels):
    1. Vertical and Horizontal Alignment
    1. Background and Foreground Colors:
    The background is the "fill" color behind the text, while the foreground is usually used as the text color.
    1. Font Types and Font Sizes:
    You can choose the type of font on your component (e.g., button, text field etc.):

    JComponent  c = ... ;
    c.setFont(new Font("SansSerif", Font.BOLD, 12));
    1. Ability to be Enabled/Disabled:
    Sometimes we want to disable a component so that it cannot be selected or controlled by the user.   We can enable and disable components at any time on our program.
    1. Ability to be Hiden/Shown:
    In fact, there are many more attributes that we can set for components and we will investigate some more of them throughout the course.


    Using JPanels in a Basic Application

    An application's window may contain many components.   It is often the case that an arrangement of components may be similar (or duplicated) within different windows.   For example, an application may require a name, address and phone number to be entered at different times in different windows.   It is a good idea to share component layouts among the similar windows within an application.

    To do this, we often lay out components onto a panel and then place the panel on our window.   We can place the created panel on many different windows with one line of code ... this can dramatically reduce the amount of GUI code that you have to write.
    We will follow this approach.  The typical steps for creating an application are as follows:
    1. create a subclass of JPanel containing your application components (i.e., add components one at a time to the panel)
    2. create subclass of JFrame and add your panel to it.
    3. test it to see if it looks the way you want it to.
    Although we could have simply added our components directly to a JFrame, this will allow us to re-use the JPanel (perhaps in some future application).  We will be seeing many examples later in which we do not make a separate JPanel.   The reason for doing the examples without a JPanel is so that the example code is simpler to explain in the notes.

    Here is an example in which we create a simple application with two classes.  The first class is a special kind of panel (we will make it a subclass of JPanel).  We will add two labels and 2 buttons to the panel.   The second class is a frame that will hold the panel and represent the main application.  Here is the panel file that specifies the objects to be placed on the window:

    import javax.swing.*;
    import java.awt.*; //needed to use components setting methods (e.g., colors, fonts)
    public class PanelWithFourComponents extends JPanel {
       
        public PanelWithFourComponents() {
            // Create and add a simple JLabel to the panel
            JLabel plainLabel = new JLabel("Plain Small Label");
            add(plainLabel);

            // Create a 2nd JLabel with a 32pt bold italic Serif font
            // and a "brain.gif" picture to the left of the text.
            // Make the label have a red background and white text.

            JLabel fancyLabel = new JLabel("Fancy Big Label");
            fancyLabel.setFont(new Font("Serif", Font.BOLD | Font.ITALIC, 32));
            fancyLabel.setIcon(new ImageIcon("brain.gif"));
            fancyLabel.setHorizontalAlignment(JLabel.RIGHT);
            fancyLabel.setBackground(Color.red);
            fancyLabel.setOpaque(true);
            fancyLabel.setForeground(Color.white);
            add(fancyLabel);

            // Create a JButton
            JButton button1 = new JButton("Button");
            button1.setBackground(Color.blue);
            button1.setForeground(Color.yellow);
            add(button1);

            // Create a 2nd JButton, this one with an icon
            JButton button2 = new JButton("Brain", new ImageIcon("brain.gif"));
            button2.setBackground(SystemColor.control);
            add(button2);

            // Set the background color of the panel
            setBackground(Color.green);
        }
    }

    Notice the following: Here is the main application file:
    import javax.swing.*;
    public class SimplePanelTestFrame extends JFrame {
        
        public SimplePanelTestFrame(String title) {
            super(title);  // Must be first line
            
            add(new PanelWithFourComponents());
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(650, 200);
        }

        public static void main(String args[]) {
            JFrame frame = new SimplePanelTestFrame("SimplePanel Example");
            frame.setVisible(true);
        }
    }
    Note the following: We will have to make sure that the brain.gif file is in the directory from where our code is running.


     


     2.4  Layout Managers

    As we all know ... JAVA was developed for the internet and JAVA applications were meant to be run within an internet browser.  Since browsers are often resized, the application's components need to be rearranged so that they ALL fit on the browser window at all times.  In fact, JAVA provides a mechanism called a Layout Manager that allows the automatic arrangement (i.e., layout) of the components of an application.
  • Layouts are set for a panel using the setLayout() method.   If set to null, then no layout manager is used.
  • So why should we use a LayoutManager ? Before we look at some of these layout managers, we will first see how to lay components out without using them.

    2.4.1  Null Layout

    We can actually set the layout for our window panel to be null so that we have full control on the exact locations of all objects.   This means that we are NOT using a layout manager.   So, we must arrange the components on our own.

    The advantages of not having any layout manager are:

    The disadvantages are: To choose to use no layout manager, we just send the following message to a panel: We must then specifically place all of our components by using the following:
    //set the location of the component within its container
    void setLocation(int x, int y);

    //set the dimensions of the component
    void setSize(int width, int height);

    Things to note: Components are added to containers by using the add() method as before: Example

    Here is an example showing how to build a simple window with a text field, a list, and two buttons.   First, we need to sketch out the window on paper:


    Here is the code:

    import javax.swing.*;
    public class NoLayoutExample extends JFrame {
        public NoLayoutExample(String name) {
            super(name);

            // Choose to lay out components manually
            setLayout(null);

            //The text field
            JTextField newItemField = new JTextField();
            newItemField.setLocation(10,10);
            newItemField.setSize(150,25);
            add(newItemField);

            //The Add button
            JButton addButton = new JButton("Add");
            addButton.setMnemonic('A');
            addButton.setLocation(175, 10);
            addButton.setSize(100,25);
            add(addButton);

            //The List
            String[] stuff = {"Apples", "Oranges", "Grapes", "Pineapples", "Cherries"};
            JList itemsList = new JList(stuff);
            JScrollPane scrollPane = new JScrollPane(itemsList,
                ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
            scrollPane.setLocation(10,45);
            scrollPane.setSize(150,150);
            add(scrollPane);

            //The Remove button
            JButton removeButton = new JButton("Remove");
            removeButton.setMnemonic('R');
            removeButton.setLocation(175,45);
            removeButton.setSize(100,25);
            add(removeButton);

            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(290, 230); // manually computed sizes
            setResizable(false);
        }

        public static void main(String[] args) {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch(Exception e) {}
            JFrame.setDefaultLookAndFeelDecorated(true);
            JFrame frame = new NoLayoutExample("Without a Layout Manager");
            frame.setVisible(true);
        }
    }

    Note the following:

    Here is what the window looks like when running our code:




    2.4.2  FlowLayout
    • components are arranged horizontally from left to right, like lines of words in a paragraph.
    • if no space left on current "line", components flow to next line
    • components are centered horizontally on each line by default
    • often used to arrange buttons in a panel

    There are three constructors:

    public FlowLayout();
    public FlowLayout(int align);
    public FlowLayout (int align, int hGap, int vGap);

    Example

    Here is a simple example that adds 5 buttons (two with icons) to a panel which uses a FlowLayout.
    import java.awt.*;
    import javax.swing.*;
    public class FlowLayoutManagerExample extends JFrame {
    public FlowLayoutManagerExample (String title) {
    super(title);

    setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
    add(new JButton("one"));

    add(new JButton("two"));
    add(new JButton("three"));
    add(new JButton("four", new ImageIcon("brain.gif")));
    add(new JButton(new ImageIcon("brain.gif")));

    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(500, 200);

    }
    public static void main(String args[]) {
        FlowLayoutManagerExample frame = new FlowLayoutManagerExample("Flow Layout Example");
      
    frame.setVisible(true);
    }
    }
    Here is the result obtained when the application is run:


    Notice

    Try resizing the window to 300x200.  The components will be rearranged accordingly:


    2.4.3  BorderLayout
    • This is the default layout for a JFrame
    • Divides the container into regions: north, south, east, west and center. 
    • Regions are specified using class constants (BorderLayout.NORTH, BorderLayout.SOUTH, etc....)
    • A single component (which may itself be a container) fills each region

    There are two useful constructors:

    Example

    In this example, we add 4 buttons along the north, south, east and west of the window.  We also make use of our previous code which created a panel with 2 labels and 2 buttons and add this to the center of the pane, just for fun.
    import java.awt.*;
    import javax.swing.*;
    public class BorderLayoutManagerExample extends JFrame {
    public BorderLayoutManagerExample (String title) {
         super
    (title);

    // the JFrame already has a border layout by default, but
    // by doing this, we also get to specify a 2 pixel gap (i.e.,
    // margin) between components.
    setLayout(new BorderLayout(2,2));

    add(BorderLayout.NORTH, new JButton("North"));
    add(BorderLayout.SOUTH, new JButton("South"));
    add(BorderLayout.EAST, new JButton("East"));
    add(BorderLayout.WEST, new JButton("West", new ImageIcon("brain.gif")));
    add(BorderLayout.CENTER, new PanelWithFourComponents());

    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(500, 300);

    }
    public static void main(String args[]) {
        BorderLayoutManagerExample frame = new BorderLayoutManagerExample(
    "Border Layout Example");
     
        frame.setVisible(true);

    }
    }
    Here is the result:

    Note that you do NOT have to put something in all of the border locations.   You may simply want to just use the top/bottom or perhaps left/right/bottom.   A common situation is to have a panel of components along the bottom or side of a window.

    For example, by using this code (which makes a panel of buttons on the bottom of the window):

            JPanel buttonPanel = new JPanel();
            buttonPanel.add(new JButton("Add"));
            buttonPanel.add(new JButton("Remove"));
            buttonPanel.add(new JButton("Insert"));
            buttonPanel.add(new JButton("Edit"));
            buttonPanel.add(new JButton("Details"));
            add(BorderLayout.SOUTH, buttonPanel);
            add(BorderLayout.CENTER, new JTextArea());

    we obtain this window:


    Or, perhaps we would like to place some buttons on the right side of the window and maybe a status pane or progress bar on the bottom.   The following code does this (while making use of a GridLayout ... which we will talk about soon):

            JPanel buttonPanel = new JPanel();
            buttonPanel.setLayout(new GridLayout(6,1,10,10));
            buttonPanel.add(new JButton("New"));
            buttonPanel.add(new JButton("Open"));
            buttonPanel.add(new JButton("Save"));
            buttonPanel.add(new JButton("Compile"));
            buttonPanel.add(new JButton("Run"));
            buttonPanel.add(new JButton("Quit"));
            add(BorderLayout.EAST, buttonPanel);
           
            JTextField statusPane = new JTextField("This is like a status pane");
            statusPane.setBackground(Color.gray);
            statusPane.setForeground(Color.white);
            add(BorderLayout.SOUTH, statusPane);
            add(BorderLayout.CENTER, new JTextArea());

    produces this window:



    As you can see below, the window still resizes nicely automatically:



    2.4.4  CardLayout
    • Layout manager for a container....each component is treated as a "card"
    • Displays components one a time, only one is visible at a time
    • Often used for swapping panels of components in and out
    • Used for managing a set of panels that present themselves as a stack of tabbed folders
    • User can interact with cards like a slide show

    There are two constructors:

    Stacking methods include the following:

    Example

    This example creates a window with three cards which are displayed using a CardLayout manager.   Since only one card can be shown at a time, only one image appears on the window.   We can select the image by using the show() method for the card layout manager to specify which one to show.   Later in the notes, we will see how to hook up some buttons to get the cards showing as a slide show when buttons are pressed.
    import java.awt.*;
    import javax.swing.*;
    public class CardLayoutManagerExample extends JFrame {
    private CardLayout cardLayoutManager;
    public CardLayoutManagerExample(String title) {
    super(title);

    CardLayout layoutManager = new CardLayout(0,0);
    setLayout(layoutManager);

    // Add (and give names to) components using the layout manager
    JLabel first = new JLabel(new ImageIcon("trilobot.jpg"));
    JLabel second = new JLabel(new ImageIcon("laptop.jpg"));
    JLabel third = new JLabel(new ImageIcon("satelite.jpg"));
    add(
    "first", first);

    add("second", second);
    add("third", third);

    // Pick the component to show, in this case, the first
    layoutManager.show(getContentPane(), "first");
            
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(200,172);

    }

    public static void main(String args[]) {
         CardLayoutManagerExample frame =  new CardLayoutManagerExample(
    "Card Layout Example");

       
    frame.setVisible(true);
    }

    }
    Notice that the show() method requires us to pass in something called the "contentPane".  This is actually the "hidden" JPanel of the JFrame on which everything is placed.   Here is what the window looks like when run:



    If we were to have changed the 2nd parameter in the show() method to "second" or "third", we would get the other images showing instead:

       

    Note that we are simply showing cards that have a single JLabel on them (which has a picture on it).   However, remember that you can actually place any JComponent or Container (e.g., JPanel) on the card.   So, for example, we could have added our PanelWithFourComponents as a single card.



    2.4.5  GridLayout
    • Lays out its components into a rectangular grid
    • Often used for calendar or spreadsheet type user interfaces
    • Components must be added row by row, left to right

    There are two constructors:

    Example

    We have already seen in our BorderLayout manager example that we can create a simple grid of buttons.  There we created a 6 row, 1 column panel of buttons which were all equally sized:

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridLayout(6,1,10,10));
        buttonPanel.add(new JButton("New"));
        buttonPanel.add(new JButton("Open"));
        buttonPanel.add(new JButton("Save"));
        buttonPanel.add(new JButton("Compile"));
        buttonPanel.add(new JButton("Run"));
        buttonPanel.add(new JButton("Quit"));

    Now let us create a window with a 6x8 grid of components on them.   For simplicity, we will use all JButtons and randomly set their colors to white or black.   We can easily modify the code to have images on the buttons or text, or even to replace the buttons with arbitrary components or panels.
    import java.awt.*;
    import javax.swing.*;
    public class GridLayoutManagerExample extends JFrame {

        public GridLayoutManagerExample(String title) {
            super(title);
           
            setLayout(new GridLayout(6,8,5,5));

            for (int row=1; row<=6; row++)
                for (int col=1; col<=8; col++) {
                    JButton b = new JButton();
                    if (Math.random() < 0.5)
                        b.setBackground(Color.black);
                    else
                        b.setBackground(Color.white);
                    add(b);
                }
                   
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(250, 200);
        }
        public static void main(String args[]) {
            GridLayoutManagerExample frame = new GridLayoutManagerExample("Grid Layout Example");
            frame.setVisible(true);
        }
    }
    Here is the result:

    Notice that the buttons are all evenly sized and evenly spaced.  There is some extra margin along the right and bottom as leftover space that cannot be evenly distributed among the buttons.   This example shows the entire window using the GridLayout, but remember that any JPanel can use this layout so this grid can be applied to a panel that is only one of many components in a window.

    2.4.6  GridBagLayout
    • For complicated layout needs (typically very useful ... since we have full control).
    • Also arranges components in a grid, but the exact grid size is not explicitly defined.
    • Rows and columns of grid may have different sizes (see image below)
    • Components can occupy (i.e., span across)  multiple rows and columns (see image below)
    • For each component, there is an elaborate set of constraints for determining how much space is used by the component

    We will create GridBagConstraint objects.

    Here is an example of a window showing the breakdown of the components onto a grid:
    We will now take a look at the many constraints which we can use for each component:

    In order to fully understand the effects of these constraints, you should create an example piece of code and try changing the values.  Resize the window to see the effects of your changes.  Experience is best to help you understand.

    Example

    This example represents a kind of "recipe" that you can follow when using the GridBagLayout managers.   The example is taken from Core Java 2 volume 1-Fundamentals, by C.S. Horstmann and G. Cornell, Sun Microsystems, 1999.

    Step 1:
    Sketch out the component layout on a piece of paper (i.e., the way you want the window to look).   Note that it will not ALWAYS look the EXACT way that you want it to when its done, but you can get a rough idea as to the layout:


     

    Step 2/3:
    Identify the different components (i.e., labels, text fields, lists etc...) and add grid lines to your drawing such that the small components are each contained in a cell and the larger components span multiple cells.  Label the rows and columns of your grid with 0,1,2,3, ... You can now read off the gridx, gridy, gridwidth, and gridheight values.


     

    Step 4:
    Now worry about the resizing issues.   For each component, ask yourself whether it needs to fill its cell horizontally or vertically.  If not, how do you want it aligned ?  This tells you the fill and anchor parameters.

    Step 5:
    Set all weights to 100. However, if you want a particular row or column to always stay at its default size, set the weightx or weighty to 0 in all components that belong to that row or column.   MAKE SURE that at least one component in each row and column has a non-zero weight!!

    Step 6:
    Write the code. Carefully double-check your settings for the GridBagConstraints. One wrong constraint can ruin your whole layout and waste you hours of time :(.   Also, it is often the case that some components act strangely when the window is resized.   It sometimes seems as though your weight settings are being ignored.   This is often due to the way that the GridBagLayout manager tries to determine starting (or preferred) sizes for the components.   So, it is sometimes necessary to specify that your objects are to be treated equally in this regard.  You can do this by setting the preferred size of your growable components to some similar value.  For example:  scrollPane.setPreferredSize(new Dimension(10,10));   It is likely that you may have to play a little with the insets and margins of your components to get them to the size that you want.

    Step 7:
    Compile, run, and enjoy.   Note that your gridlines may not always be exactly where you wanted them and that your components may not be the size that you want.   You may have to play around by adding additional grid lines and specifying that a component spans multiple grid cells.

    Here is an example of a recipe browser build using the above steps.  Look at the code and pay particular attention to the gridx, gridy, gridwidth, and gridheight values.  Notice there is a lot of repeated code that can be shortened if, for example, all the JLabels are laid out together and their constraint settings reused.

    import java.util.*;
    import java.awt.*;
    import javax.swing.*;
    public class RecipeBrowser extends JFrame {

         public RecipeBrowser(String name) {
              super(name);
             
              GridBagLayout layout = new GridBagLayout();
              GridBagConstraints constraints = new GridBagConstraints();
              setLayout(layout);

              JLabel label = new JLabel("Categories");
              constraints.gridx = 0;
              constraints.gridy = 0;
              constraints.gridwidth = 1;
              constraints.gridheight = 1;
              constraints.weightx = 0; // don't grow horizontally
              constraints.weighty = 0; // don't grow vertically
              constraints.anchor = GridBagConstraints.WEST;
              layout.setConstraints(label, constraints);
              add(label);

              label = new JLabel("Recipes");
              constraints.gridx = 1;
              constraints.gridy = 0;
              constraints.gridwidth = 1;
              constraints.gridheight = 1;
              constraints.weightx = 0; // don't grow horizontally
              constraints.weighty = 0; // don't grow vertically
              layout.setConstraints(label, constraints);
              constraints.anchor = GridBagConstraints.WEST;
              add(label);

              JList categories = new JList();
              categories.setPrototypeCellValue("xxxxxxxxxxx");
              JScrollPane scrollPane = new JScrollPane(categories,
                  ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
              constraints.gridx = 0;
              constraints.gridy = 1;
              constraints.gridwidth = 1;
              constraints.gridheight = 1;
              constraints.fill = GridBagConstraints.BOTH;
              constraints.weightx = 1;
              constraints.weighty = 1;
              layout.setConstraints(scrollPane, constraints);
              add(scrollPane);

              JList recipes = new JList();
              recipes.setPrototypeCellValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
              scrollPane = new JScrollPane(recipes,
                  ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
              constraints.gridx = 1;
              constraints.gridy = 1;
              constraints.gridwidth = 1;
              constraints.gridheight = 1;
              constraints.fill = GridBagConstraints.BOTH;
              constraints.weightx = 1;
              constraints.weighty = 1;
              layout.setConstraints(scrollPane, constraints);
              add(scrollPane);

              label = new JLabel("Ingredients");
              constraints.gridx = 0;
              constraints.gridy = 2;
              constraints.gridwidth = 1;
              constraints.gridheight = 1;
              constraints.weightx = 0; // don't grow horizontally
              constraints.weighty = 0; // don't grow vertically
              layout.setConstraints(label, constraints);
              add(label);

              JTextArea ingredients = new JTextArea();
              scrollPane = new JScrollPane(ingredients,
                  ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
              constraints.gridx = 0;
              constraints.gridy = 3;
              constraints.gridwidth = 2;
              constraints.gridheight = 1;
              constraints.fill = GridBagConstraints.BOTH;
              constraints.weightx = 1;
              constraints.weighty = 1;
              layout.setConstraints(scrollPane, constraints);
              add(scrollPane);

              label = new JLabel("Directions");
              constraints.gridx = 0;
              constraints.gridy = 4;
              constraints.gridwidth = 1;
              constraints.gridheight = 1;
              constraints.weightx = 0; // don't grow horizontally
              constraints.weighty = 0; // don't grow vertically
              layout.setConstraints(label, constraints);
              add(label);

              JTextArea directions = new JTextArea();
              scrollPane = new JScrollPane(directions,
                  ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
              constraints.gridx = 0;
              constraints.gridy = 5;
              constraints.gridwidth = 2;
              constraints.gridheight = 1;
              constraints.fill = GridBagConstraints.BOTH;
              constraints.weightx = 1;
              constraints.weighty = 1;
              layout.setConstraints(scrollPane, constraints);
              add(scrollPane);
             
              setDefaultCloseOperation(EXIT_ON_CLOSE);
              setSize(300,300);
         }

         public static void main(String[] args) {
              JFrame frame = new RecipeBrowser("A La Carte");
              frame.setVisible(true);
         }
    }


    Here are some interesting tips/points about the code above:
    Here is the result:

    Note that we can adjust how much "space" each component takes according to the weightx and weighty settings.   For example, currently we have these settings:

    COMPONENT
    weightx
    weighty
    category list
    1
    1
    recipe list
    1
    1
    ingredients text area
    1
    1
    directions text area
    1
    1

    We can change these weights to allow the categories list to be wider than the recipe list and the Ingredients area to be larger (in the y) than the lists and the directions area to be smaller (in the y) than the lists as follows:

    COMPONENT
    weightx
    weighty
    category list
    2
    2
    recipe list
    1
    2
    ingredients text area
    1
    3
    directions text area
    1
    1

    We would then get the following look:



    So, by playing with the weights, you can usually achieve the desired look, after some trial and error.
    Note that we can also make some nice margins around the window and components.   We can set the insets for each component by using:

    constraints.insets(new Insets(top, left, bottom, right));

    where top, left, bottom and right are set as follows for our components:

    COMPONENT
    top
    left
    bottom
    right
    categories label
    10
    10
    0
    0
    recipes label
    10 10 0
    0
    categories list
    10 10 0
    0
    recipes list
    10 10 0
    10
    ingredients label
    10 10 0
    0
    ingredients text area
    10 10 0
    10
    directions label
    10 10 0
    0
    directions text area
    10 10 10
    10

    We obtain this nice look:




    Try making the following window ... shown before and after resizing:



    For each component, we need to determine how it grows:
    Here is the code:

    import java.awt.*;
    import javax.swing.*;
    public class GridBagLayoutManagerExample extends JFrame {

         public GridBagLayoutManagerExample(String name) {
              super(name);
             
              GridBagLayout layout = new GridBagLayout();
              GridBagConstraints constraints = new GridBagConstraints();
              setLayout(layout);

              JTextField newItemField = new JTextField();
              constraints.gridx = 0;
              constraints.gridy = 0;
              constraints.gridwidth = 1;
              constraints.gridheight = 1;
              constraints.fill = GridBagConstraints.BOTH;
              constraints.insets = new Insets(12, 12, 3, 3);
              constraints.weightx = 10;
              constraints.weighty = 0;
              layout.setConstraints(newItemField, constraints);
              add(newItemField);

              JButton addButton = new JButton("Add");
              addButton.setMnemonic('A');
              constraints.gridx = 1;
              constraints.gridy = 0;

              constraints.gridwidth = 1;
              constraints.gridheight = 1;

              constraints.fill = GridBagConstraints.HORIZONTAL;
              constraints.insets = new Insets(12, 3, 3, 12);
              constraints.anchor = GridBagConstraints.NORTHWEST;
              constraints.weightx = 0;
              constraints.weighty = 0;
              layout.setConstraints(addButton, constraints);
              add(addButton);

              String[] stuff = {"Apples", "Oranges", "Grapes", "Pineapples", "Cherries"};
              JList itemsList = new JList(stuff);
              JScrollPane scrollPane = new JScrollPane(itemsList,
                  ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
              constraints.gridx = 0;
              constraints.gridy = 1;

              constraints.gridwidth = 1;
              constraints.gridheight = 1;

              constraints.fill = GridBagConstraints.BOTH;
              constraints.insets = new Insets(3, 12, 12, 3);
              constraints.anchor = GridBagConstraints.CENTER;
              constraints.weightx = 10;
              constraints.weighty = 1;
              layout.setConstraints(scrollPane, constraints);
              add(scrollPane);

              JButton removeButton = new JButton("Remove");
              removeButton.setMnemonic('R');
              constraints.gridx = 1;
              constraints.gridy = 1;

              constraints.gridwidth = 1;
              constraints.gridheight = 1;

              constraints.fill = GridBagConstraints.HORIZONTAL;
              constraints.insets = new Insets(3, 3, 0, 12);
              constraints.anchor = GridBagConstraints.NORTH;
              constraints.weightx = 0;
              constraints.weighty = 0;
              layout.setConstraints(removeButton, constraints);
              add(removeButton);

              setDefaultCloseOperation(EXIT_ON_CLOSE);
              setSize(400,300);
         }

         public static void main(String[] args) {
              JFrame frame = new GridBagLayoutManagerExample("Example");
              frame.setVisible(true);
         }
    }

    It is interesting to see how other components in the same row and column actually affect the other components.   For example, assume that the textField had a fill set to HORIZONTAL instead of BOTH.   Its height would then be different since it would take up only the height that is needed for the component by default instead of taking up the height of the grid cell that it lies in ... which depends on the height of the add button.   Also, for example, the width of the Add button depends on the width of the Remove button since it has a fill HORIZONTAL which takes up the width of the whole cell ... which depends on the width of the Remove button.  

    To see this, we will set the fill to HORIZONTAL for the text field and set the internal padding of the Remove button to ipadx = 20; ipady = 10.   Here is the result as expected:

    Before changes 
    After changes

    So you can see ... things can get quite complicated.   Make sure to practice a lot with this particular layout manager.


    2.4.7  BoxLayout
    • components are arranged horizontally from left to right, or vertically from top to bottom.
    • much like flow layout, except there is no wraparound when space runs out.
    • often used to arrange components  in a panel

    Here is the one constructor:

    public BoxLayout(Container panel, int axis);

    Example

    Here is a simple example that adds some components to a panel which uses a BoxLayout.

    import java.awt.*;
    import javax.swing.*;
    public class BoxLayoutManagerExample extends JFrame {
        
        public BoxLayoutManagerExample (String title) {
            super(title);

            setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));

            add(new JButton("one"));
            add(new JButton("two"));
            add(new JButton("three"));
            add(new JButton("four", new ImageIcon("brain.gif")));
            add(new JButton(new ImageIcon("brain.gif")));
           
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(200, 300);
        }
        
        public static void main(String args[]) {
            BoxLayoutManagerExample frame =  new BoxLayoutManagerExample("Box Layout Example");
            frame.setVisible(true);
        }
    }

    Here are three screen snapshots.   The first two show the results of the above code which "lines up" the components along the X_AXIS.   Notice how the components DO NOT wrap around to the next line when the window is shrunk.   The last snapshot shows the arrangement that would be obtained if the Y_AXIS was used.