Layouts are a fundamental part of the GXT library. They provide the ability to create complex application layouts easily. However, with this power, comes a level of complexity. A solid understanding of layouts is key to using the library effectively.
Before getting into GXT layouts, it will be helpful to understand how GWT Panels work. With GWT Panels, the panel itself is responsible for creating the panel's markup and inserting its children at the appropriate location. Let's dig into an example of using a GWT Panel. We will use a VerticalPanel with 2 children. A GWT VerticalPanel uses a HTML table for its element and inserts its children into table cells.
We first create a new GWT VerticalPanel:
At this point, the panel has created its initial html elements. In this case, the table and table body are created:
We now add a child to the panel. The panel will create a new table row and insert the child into the rows cell.
Results in this markup:
Let's add one more child widget to the panel:
Results in this markup:
The important thing to remember is that GWT Panels create their markup as changes are made. If we remove the first label from our example, the table row would be removed immediately.
LayoutContainer is a concrete Container with support for Layouts. Unlike GWT Panels, LayoutContainer does not physically connect its child components to the container's DOM. Rather, it is the job of the layout, to both build the internal structure of the container, and to connect the child widgets.
Let's go back to our GWT VerticalPanel example and use the same exercise using a GXT LayoutContainer and Layout. For this example, we will use a TableLayout as our layout.
First, we create our LayoutContainer and assign a TableLayout:
At this time, no HTML elements have been created. Contrast this to GWT Panels where the HTML elements are created immediately and the child are inserted as they are added.
Next, we add our first child label:
Again, at this time no HTML elements have been created. We then add the second child label:
Just as the first child, adding the second child results in no HTML elements being created.
In order for the container's HTML to be created and children inserted, the container's layout must execute. There are several ways in which the layout can execute. For now, let's go with the simplest case in which the layout executes when the container is attached. "Attached" is a GWT term that indicates the widget is part of browser's DOM. Attaching and Detaching could be a subject on its own, let's just assume it means when the widget is added to and removed from the page.
When we add the container to the RootPanel, the container will be attached, and the container's layout will execute:
The TableLayout executes and it creates the container HTML structure, then inserts each child into its table cell. Here is the markup:
Ok, the markup should look similiar to the GWT VerticalPanel. Also, GXT has its own VerticalPanel which is just a LayoutContainer that uses a TableLayout internally.
Let's now add another child. Keep in mind that a child is not inserted into the containers DOM by the container itself. The layout is responsible for this.
At this point, the containers markup will be exactly the same as before the third child was added. In order for the third label to be rendered we need to execute the container's layout. In this case, we will do it manually since the container is already attached.Now the markup looks like this:
TableLayout is a little boring, when it comes to layouts, since it does not size or position any of its children. For the next example, we will use a RowLayout to achieve a more advanced layout.
In this example we will have a single column with 3 children. We want the height of the first child to be its calculated height. We will give a specific height to the 3rd widget and the second widget's height will use the rest of the vertical space.
As a side note, consider HTML percentage values. In some situations, this may work. However, for exact control of widget sizing, clipping, and overflow, percentage values will not work. GXT shines building desktop like application layouts, where precise control is needed.
Many GXT layouts, including RowLayout, can be used in conjunction with LayoutData. LayoutData are configuration objects assigned to each child widget, that provides the layout additional information to be used when executing the layout.
First we will start by creating are new container, giving it a size, and assigning a layout:
Now we need to add our children. At this time we will also create a RowData instance for each child. The RowData will be used by RowLayout to determine how to "layout" its children.
When RowLayout executes, it will size and position its children, using the provided RowData. Say we wanted to add a 5px margin around the 3 children, you could do this:
As you can see, layouts provide a great deal of power when constructing your layouts. The next important concept with layouts, is cascading layout execution.
Previously, we discussed 2 ways of executing a container's layout. One, the layout is executed when the container is attached and two, layout() is called manually on the container. There are 2 other ways in which a layout will be executed.
After a container executes its layout, it looks and sees if any of its children are containers. When it finds a child container, it then executes its layout. So as long as there is a chain of containers, the exectution of layouts will cascade to the child containers. This is a very important concept as you can layout a top level container, and the child containers will have a chance to adjust their layouts as well.
A container's layout will also execute when its size is adjusted. This is default behavior, and can be disabled. This is another important concept as it means that if a container's size is changed, the layout has a chance to update based on the container's new size.