Layout Managers

  1. Overview

    1. Goal: Assign space, size, and a position to each set of objects in a container

      1. Position: the object's x/y coordinates
      2. Size: the object's width/height
      3. Space: the size of the region in which an object is placed: The size of the region could be bigger than the object's size

    2. Issues

      1. How to assign a position to an object
      2. How to assign a size to an object
      3. How to assign space to an object
      4. How to align an object when the space it is assigned exceeds its size
      5. How to assign a new position/space/size to an object when it's window or container is re-sized

  2. General Strategy for Layout Algorithms

    1. Bottom-up pass: Ask each component for its preferredSize and aggregate the sizes
    2. Top-down pass: Assign each component its position, space, and size

  3. Layout in Java

    1. Overview of Java Layout

      1. Java has the notion of containers and components. Containers are objects that can contain other objects and components are either containers or primitive objects.
      2. Each container has a layout algorithm associated with it
      3. Java supports different layout algorithms. However, since it is not possible to pass function pointers in Java, we must instead place each layout algorithm in a class. The class is also able to store state information that helps with the layout of the container. An instance of the appropriate layout manager is assigned to a container using the container's setLayout method.
      4. Each component specifies three quantities to assist the layout manager
        1. preferredSize: it's preferred width/height
        2. minimumSize: the minimum size it wants to be displayed at
        3. maximumSize: the maximum size it wants to be displayed at
      5. All layout managers take components' preferredSize into account when computing the initial size of a window. However, when a window is re-sized, then these three quantities may be ignored by the layout manager.

    2. Java's layout managers

      1. Border Layout: For top-level of an application and putting pallettes around a canvas object
        1. Divides a container into 5 regions and when you add an object to a container, you specify which region it should be placed in.
          1. center
          2. page_start (north)
          3. page_end (south)
          4. line_start (west)
          5. line_end (east
        2. Can specify horizontal/vertical gaps between regions
        3. Respects preferredWidth for East/West regions and preferredHeight for North/South regions
        4. Center region gets all of the extra space

      2. Flow Layout: Horizontally lays out objects at their natural size.

        1. When the container is re-sized

          1. If the container is not wide enough to accommodate all the objects, then the flow layout uses multiple rows
          2. If the container is wider than the combined width of the objects, then the row of objects is left-aligned, centered, or right-aligned depending on the alignment that is specified when the instance of the FlowLayout algorithm is created.

        2. Parameters to the algorithm

          1. hgap: horizontal space between objects
          2. vgap: vertical space between objects
          3. alignment: how to align the rows if the rows' width is less than the width of the container. Options are left/centered/right.

    3. Grid Layout: Lays out objects in a table with each object having the same width/height

      1. Typically used for tool pallettes
      2. Sets width to the max width component and the height to the max height component: Hence only the preferred width of the max width component and the preferred height of the max height component are respected
      3. Parameters
        1. hgap: horizontal space between objects
        2. vgap: vertical space between objects
        3. Can specify number of rows and/or columns: can set either to 0 but not both. For example, if you set rows to 0 and columns to 3, then there can be an infinite number of rows and each row will have up to three objects.
      4. When you resize the container, the space is divided evenly among the objects
      5. The order in which you add objects to the container determines the order in which they are laid out
        1. If you specify the number of columns, then objects are laid out left-to-right, top-to-bottom
        2. If you set the number of columns to 0, then objects are laid out top-to-bottom, left-to-right.

    4. Box Layout: Lays out objects in either vertical/horizontal stacks (rows) and it provides a variety of layout controls

      1. Parameters: Can choose axis for layout

        1. horizontal: BoxLayout.LINE_AXIS
        2. vertical: BoxLayout.PAGE_AXIS

      2. When resizing the container

        1. For horizontal layout, it tries to respect preferredHeight.

          1. as you increase the width, BoxLayout increases the width of each object up to its maximum preferred width
          2. as you decrease the width, BoxLayout decreases the width of each object down to its minimum preferred width

        2. For vertical layout, it tries to respect preferredWidth

          1. as you increase the height, BoxLayout increases the height of each object up to its maximum preferred height
          2. as you decrease the height, BoxLayout decrease the height of each object down to its minimum preferred height

        3. Fillers: fillers are invisible objects that allow you to control the spacing between objects. Filler objects are added to containers like other visible objects

          1. Rigid Area: invisible object that gives you fixed space between two objects (use rigid areas rather than horizontal/vertical struts for fixed space because horizontal/vertical struts have infinite height/width that can mess up layout calculations)

            Examples

            1. Box.createRigidArea(new Dimension(10, 0)): creates a horizontal box 10 pixels wide and 0 pixels high--would be added to a horizontal layout to put 10 pixels between two objects
            2. Box.createRigidArea(new Dimension(0, 10)): creates a vertical box 10 pixels high and 0 pixels wide--would be added to a vertical layout to put 10 pixels between two objects

          2. Glue objects: invisible objects that expand/shrink as space is allocated to or removed from a container

            1. each glue object is made the same size as all other glue objects
            2. common uses
              • keep objects "squashed" against sides of the container
              • center objects in the middle of the container
              • evenly space objects in the container
            3. types of glue
              • horizontal glue: has 0 minimum width and infinite maximum width (essentially has 0 height)
              • vertical glue: has 0 minimum height and infinite maximum height (essentially has 0 width)

        4. Creating a BoxLayout manager

          1. JPanel foo = new JPanel(new BoxLayout(BoxLayout.LINE_AXIS));
          2. Box foo = Box.createHorizontalBox(); -- Box is a container object that uses the box layout manager

    5. Gridbag Layout: Good for dialog boxes and general layouts.
      1. Roughly lays out objects in a grid but with different sized rows and columns.
      2. Objects can span multiple rows/columns
      3. Can control how objects are aligned/anchored in their assigned space
      4. Too complicated to be discussed in this course

  4. Important methods associated with layout managers

    1. JFrame methods

      1. pack(): invokes layout manager on the JFrame's content pane.
        1. The layout manager will size the window so that it's just big enough to accommodate the objects at their preferred width and height
        2. You should always call the pack method right before you make the JFrame visible
        3. If you want a window to resize itself after adding or removing a component from a JPanel, you will need to call the pack method
      2. getContentPane(): gets container object for the JFrame--you should downcast this object to a JPanel

    2. JPanel methods

      1. setLayout(instance of layout manager): sets layout manager
      2. add(component, parameters): adds components to a container and the parameters provide layout hints. For example, with a BorderLayout manager you would provide a parameter specifying the region where the object should be placed
      3. revalidate(): indicates that the layout manager for this panel must be called to re-layout the panel's components. You should call this method any time you add or remove components from a panel.
      4. repaint(): indicates that the panel should be repainted. You should call this method after calling revalidate() since you want the panel redrawn after it's been laid out

  5. Debugging: Put garish borders around objects to see what their size is