Tutorial

TableLayout

This layout manager was loosely inspired by the HTML table. It has all the power of the GridBagLayout, but is much easier to use.

The Layout Manager Concept

Container is a Component class which contains one or more other components. Every container has a layout manager which arranges the positions and sizes of the components in the container.

The container is given a certain amount of screen space for its components. The layout manager then needs to figure out how to size and position the container's components within this space. It can use any algorithm it wants. It does not need to fill all the space nor does it need to prevent components from overlapping.

The TableLayout

The TableLayout lays out components in a table format. The table has rows and columns which are typically not all the same width or height (if you need constant width and height, consider using the GridLayout).

You usually need to define the number of columns in the table (the default is 1, which is typically not what you want). As components are added to the container, they are placed in the next available column of the current row. When a row is filled, the next component adds a row and is placed in the first column.

Consider this code:

JPanel panel = new JPanel(new TableLayout("cols=3"));
panel.add(new JButton("0"));
panel.add(new JButton("1"));
panel.add(new JButton("2"));
panel.add(new JButton("3"));
panel.add(new JButton("4"));

This generates the following layout:

I started numbering with "0" because, for the TableLayout, the first column is column 0. In this example, we see a three-column table, with each JButton component added to the next available column. Since there are only five components, the last "slot" is left empty.

Attributes

The above example is very simple because only one attribute was given to the TableLayout ("cols=5"). Attributes are instructions to the TableLayout which tell it how to lay out each component in the table or the table as a whole.

The format of the attributes is similar to HTML attributes. The attributes are case insensitive and can be separated with any white space. Attributes which take a value are followed by an '=' and then an integer. Here's an example: "cols=6 rgap=2 cgap=5 w".

Attributes are evaluated from left to right. If you duplicate an attribute, the right-most one wins.

Some attributes apply only to the table as whole. You pass them in a String given either in the TableLayout constructor or in the setTableAttributes() method.

The remaining attributes apply to the components in the container. Of these, some can also be specified along with the table attributes. These become the defaults for all components in the table. This is one of the features which makes the TableLayout easy to use.

Here is the complete list of attributes:

Name Description Has Value? Default Scope
cols Number of columns Yes 1 Table
col Place Component in this column Yes Next empty column Component
skip Skip a number of columns Yes 0 Component
rspan, cspan Row and column spanning Yes 1 Component
titop, tibottom, tileft, tiright Table insets Yes 0 Table
rgap, cgap Row and column gaps Yes 0 Table
itop, ibottom, ileft, iright Component insets Yes 0 Table/Component
tn, tne, te, tse, ts, tsw, tw, tnw, tc, tf, tfh, tfv Table placement and fill No tf Table
n, ne, e, se, s, sw, w, nw, c, f, fh, fv Component placement and fill No f Table/Component
rweight, cweight Row and column weights Yes 0 Table/Component

Rows and Columns

As I stated above, you will almost always specify the number of columns in the table. Components are then placed in the table from left to right, adding new rows as necessary.

You can override the default component placement somewhat with "col" and "skip". With "col", you specify the column number in which the component should be placed. If you have already passed the given column, the layout adds another row and places the Component in the column on that new row.

"skip" allows you to skip a number of cells. If the layout reaches the end of the row, skipping continues on the next row.

You can also make a component span multiple rows or columns with rspan and cspan. Components added later will skip over any occupied cells, which is important to note for row spanning.

Let's take the example above and make it use these attributes:

JPanel panel = new JPanel(new TableLayout("cols=3"));
panel.add(new JButton("0"));
panel.add(new JButton("1"),"skip=1");
panel.add(new JButton("2"), "col=1");
panel.add(new JButton("3"), "rspan=2");
panel.add(new JButton("4"), "cspan=2");

Spacing

The space the TableLayout works with is inside the container's insets. Some containers have insets of 0 (e.g. JPanel) and most don't allow you to alter the insets. Since you will often want to control the space between the table and the edges of the container, an "extra" table inset can be given: titop, tibottom, tileft and tiright (in the "ti" prefix, the "t" stands for "table" and the "i" stands for "inset").

Within a cell, you can create space between the cells edges and the component in the cell. The attributes are itop, ibottom, ileft and iright.

You can also add space between cells in the table. This space is only placed between cells; never along the edges of the table. This allows you to nest table layouts and keep consistent cell spacing. The attributes used are rgap and cgap and their default value is 0.

Here is our example with the addition of table and cell insets plus cell spacing. Note that we specify the cell insets and spacing when we define the table attributes. This means that all components will get the same insets and spacing without having to duplicate this information for each individual component. We override the default insets for one of the components.

JPanel panel = new JPanel(
  new TableLayout(
    "cols=3 rgap=3 cgap=3 " +
    "titop=5 tibottom=5 tileft=5 tiright=5 " +
    "itop=2 ibottom=2 ileft=2 iright=2"));
panel.add(new JButton("0"));
panel.add(new JButton("1"), "skip=1");
panel.add(new JButton("2"), "itop=0 ibottom=0 ileft=0 iright=0 col=1");
panel.add(new JButton("3"), "rspan=2");
panel.add(new JButton("4"), "cspan=2");

Here's what we get:

Placement and Filling

Given that you have something to draw and a space to draw it in, you have some choices as to where to place it and how to fill it, particularly when the available area is bigger than required. So far, except for the insets, we've allowed the table to completely fill the available container space and we've allowed each component to completely fill its table cell.

Placement attributes allow you to place a component centered or in one of eight compass directions within its cell. It's easier to demonstrate than to describe:

JPanel panel = new JPanel(new TableLayout("cols=3"));
panel.add(new JButton("1"), "nw");
panel.add(new JButton("2"), "n");
panel.add(new JButton("3"), "ne");
panel.add(new JButton("4"), "w");
panel.add(new JButton("5"), "c");
panel.add(new JButton("6"), "e");
panel.add(new JButton("7"), "sw");
panel.add(new JButton("8"), "s");
panel.add(new JButton("9"), "se");

Using the placement attributes, a component is left at its preferred size. Then it is moved to the designated edge or corner (or center) of the cell.

There are placement attributes for the table itself. These are just like the component placement attributes, but start with a "t". You can find these in the attribute table above. Like the component, the table is set to its preferred size and moved to the edge, corner or center of the container.

The entire table can be placed within the container using tn, tne, te, tse, ts, tsw, tw, tnw and tc (the "t" prefix is for "table").

Fill attributes allow you to fill the item to cover all available space. Horizontal and vertical filling are handled separately. For tables, the attributes are tfh, tfv and tf. "tf" fills in both directions. For Components, use fh, fv and f. For instance, if we change just the first line of the example to:

JPanel panel = new JPanel(new TableLayout("cols=3 tnw"));

We get

The table is at its preferred size and placed in the northwest corner of the container. Since the preferred sizes of the buttons are all the same, the cells appeared to be filled even though they still have the same placement attributes as before.

Instead of placing a component within a cell, you can have it stretch to fill the cell, either vertically, horizontally or both. Here's our example:

JPanel panel = new JPanel(new TableLayout("cols=3"));
panel.add(new JButton("1"), "c fh");
panel.add(new JButton("2"), "f");
panel.add(new JButton("3"), "c fh");

Since the default is "f", we turn off filling by using "c". Then we can fill horizontally, vertically or in both directions.

The "f" in the second component is redundant, since this is the default. But keep in mind that you can define the default placement or fill by specifying it in the table attributes. For example,

JPanel panel = new JPanel(new TableLayout("cols=3 nw"));

would place all components in the top left corner of each cell, unless a component overrides the default.

When combining placement and fill attributes, the rules are:

  • Placement attributes turn off all filling.
  • Fill attributes turn off placement, but only in the fill direction.

So, for example, "n fh" will stretch a component horizontally, but will attach its top edge at the top of the cell.

Weighting

By setting the "weight" of each row or column, you can control how the rows and columns are allocated space when there is more space available than is needed (given the preferred sizes of the components).

The default is to equally distribute the extra space to all cells. This is not always what you want. Sometimes you'd like some rows or columns to stretch while others stay a fixed size. This is easy to do: assign the rows and columns you want to stretch a weight of 1 ("rweight" for row weight and "cweight" for column weight). Here's an example. To keep it simple, we'll stretch components "1" and "3" horizontally, while the rest of the components are fixed.

JPanel panel = new JPanel(new TableLayout("cols=5"));
panel.add(new JButton("0"));
panel.add(new JButton("1"), "cweight=1");
panel.add(new JButton("2"));
panel.add(new JButton("3"), "cweight=1");
panel.add(new JButton("4"));

There are a few things to keep in mind about weighting. The weight of a row is the largest weight of any component in the row. The advantage is that you only have to set the row weight for one component in a row and the column weight for one component in the column.

Keep in mind that assigning the same weight to two rows or columns does not make them the same size! Weighting only describes how excess space is distributed to the cells. If the two components have different preferred sizes, the row or column sizes won't be equal.

Also remember that what we resize is the cell, not the component! If you want the component to stretch, make sure it fills in the appropriate direction.

There's a subtlety to weighting: weighting is only used when there is excess space available given the components' preferred sizes. When there is not enough space for preferred sizes, space is taken away from cells equally, regardless of the weighting. However, components that shrink to their minimum allowed size will not shrink further.

There is further detail on all attributes, but particularly on weighting in the TableLayout API.

Summary

The TableLayout is both powerful and easy-to-use. After reading this tutorial, you should examine the example programs provided. One program places TableLayout head-to-head with GridBagLayout. The other example simulates the GridBagExplorer written by Eric Burke. I call it TableExplorer. It allows you to place some JButtons in a container and dynamically change the table and component attributes. I used this program to create the examples on this page.