qooxdoo: Working with Layouts

Exclusive offer: get 50% off this eBook here
qooxdoo Beginner's Guide

qooxdoo Beginner's Guide — Save 50%

Develop Rich Internet Applications (RIA) with qooxdoo book and ebook

£18.99    £9.50
by Mohamed Raffi Rajesh Kumar Bachu | December 2011 | Beginner's Guides Open Source

Over the past few years, all the major internet or enterprise applications are developed or migrated to Rich Internet Application to support all the features that are provided in the desktop applications. This helps organizations keep the end users happy and also improves application deployment and maintenance. qooxdoo is a stable, open source RIA framework. If you are waiting and watching for the right time to migrate your application to qooxdoo, this is the right time!

In this article by Rajesh Kumar Bachu and Mohamed Raffi, authors of qooxdoo Beginner's Guide, we'll cover the following topics:

  • Widgets
  • Containers
  • Panels
  • Layout managers
  • Layouts

(For more resources on this topic, see here.)

qooxdoo uses the generic terminology of the graphical user interface. So, it is very easy to understand the concepts involved in it.. The basic building block in qooxdoo is termed a widget. Each widget (GUI component) is a subclass of the Widget class. A widget also acts as a container to hold more widgets. Wherever possible, grouping of the widgets to form a reusable component or custom widget is a good idea. This allows you to maintain consistency across your application and also helps you to build the application quicker than the normal time. It also increases maintainability, as you need to fix the defect at only one place. qooxdoo provides a set of containers too, to carry widgets, and provides public methods to manage.

Let's start with the framework's class hierarchy:

Base classes for widgets

qooxdoo framework abstracts the common functionalities required by all the widgets into a few base classes, so that it can be reused by any class through object inheritance. Let's start with these base classes.

qx.core.Object

Object is the base class for all other qooxdoo classes either directly or indirectly. The qx.core.Object class has the implementation for most of the functionalities, such as, object management, logging, event handling, object-oriented features, and so on.

A class can extend the qx.core.Object class to get all the functionalities defined in the this class. When you want to add any functionality to your class, just inherit the Object class and add the extra functionalities in the subclass.

The major functionalities of the Object class are explained in the sections that follow.

Object management

 

The Object class provides the following methods for object management, such as, creation, destruction, and so on:

  • base(): This method calls base class method
  • dispose(): This method disposes or destroys the object
  • isDisposed(): This method returns a true value if the object is disposed
  • toString(): This method returns the object in string format
  • toHashCode(): This method returns hash code of the object

Event handling

The Object class provides the following methods for event creation, event firing, event listener, and so on:

  • addListener(): This method adds the listener on the event target and returns the ID of the listener
  • addListenerOnce(): This method adds the listener and listens only to the first occurrence of the event
  • dispatchEvent(): This method dispatches the event
  • fireDataEvent(): This method fires the data event
  • fireEvent(): This method fires the event
  • removeListener(): This method removes the listener
  • removeListenerById(): This method removes the listener by its ID, given by addListener()

Logging

The Object class provides the following methods to log the message at different levels:

  • warn(): Logs the message at warning level
  • info(): Logs the message at information level
  • error(): Logs the message at error level
  • debug(): Logs the message at the debugging level
  • trace(): Logs the message at the tracing level

Also, the Object class provides the methods for setters and getters for properties, and so on.

qx.core.LayoutItem

LayoutItem is the super most class in the hierarchy. You can place only the layout items in the layout manager. LayoutItem is an abstract class. The LayoutItem class mainly provides properties, such as, height, width, margins, shrinking, growing, and many more, for the item to be drawn on the screen. It also provides a set of public methods to alter these properties. Check the API documentation for a full set of class information.

qx.core.Widget

Next in the class hierarchy is the Widget class, which is the base class for all the GUI components. Widget is the super class for all the individual GUI components, such as, button, text field, combobox, container, and so on, as shown in the class hierarchy diagram. There are different kinds of widgets, such as, containers, menus, toolbars, form items, and so on; each kind of widgets are defined in different namespaces. We will see all the different namespaces or packages, one-by-one, in this article.

A widget consists of at least three HTML elements. The container element, which is added to the parent widget, has two child elements—the decoration and the content element. The decoration element decorates the widget. It has a lower z-index and contains markup to render the widget's background and border styles, using an implementation of the qx.ui.decoration.IDecorator interface. The content element is positioned inside the container element, with the padding, and contains the real widget element.

Widget properties

Common widget properties include:

 

  • Visibility: This property controls the visibility of the widget. The possible values for this property are:
    • visible: Makes the widget visible on screen.
    • hidden: Hides the widget, but widget space will be occupied in the parent widget's layout. This is similar to the CSS style visibility:hidden.
    • exclude: Hides the widget and removes from the parent widget's layout, but the widget is still a child of its parent's widget. This is similar to the CSS style display:none.
    • The methods to modify this property are show(), hide(), and exclude(). The methods to check the status are isVisible(), isHidden(), and isExcluded().

  • Tooltip: This property displays the tooltip when the cursor is pointing at the widget. This tooltip information consists of toolTipText and toolTipIcon. The different methods available to alter this property are:
    • setToolTip()/getToolTip(): Sets or returns the qx.ui.tooltip.ToolTip instance. The default value is null.
    • setToolTipIcon()/getToolTipIcon(): Sets or returns the URL for the icon. The default value is null.
    • setToolTipText()/getToolTipText(): Sets or returns the string text. It also supports the HTML markup. Default value is null.
  • Text color: The textColor property sets the frontend text color of the widget. The possible values for this property are any color or null.
  • Padding: This property is a shorthand group property for paddingTop, paddingRight, paddingBottom and paddingLeft of the widget. The available methods are setPadding() and resetPadding(), which sets values for top, right, bottom, and left padding, consecutively. If any values are missing, the opposite side values will be taken for that side. Also, set/get methods for each padding side are also available.
  • Tab index: This property controls the traversal of widgets on the Tab key press. Possible values for this property are any integer or null. The traversal order is from lower value to higher value. By default, tab index for the widgets is set in the order in which they are added to the container. If you want to provide a custom traversal order, set the tab index accordingly. The available methods are setTabIndex() and getTabIndex(). These methods, respectively set and return the integer value (0 to 32000) or null.
  • Font: The Font property defines the font for the widget. The possible value is either a font name defined in the theme, or an instance of qx.bom.Font, or null.
      The available methods are:
    • setFont(): Sets the font
    • getFont(): Retrieves the font
    • initFont(): Initializes the font
    • resetFont(): Resets the font
  • Enabled: This property enables or disables the widget for user input. Possible values are true or false (Boolean value). The default value is true. The widget invokes all the input events only if it is in the enabled state. In the disabled state, the widget will be grayed out and no user input is allowed. The only events invoked in the disabled state are mouseOver and mouseOut. In the disabled state, tab index and widget focus are ignored. The tab traversal focus will go to the next enabled widget. setEnabled()/getEnabled() are the methods to set or get a Boolean value, respectively.
  • Selectable: This property says whether the widget contents are selectable. When a widget contains text data and the property is true, native browser selection can be used to select the contents. Possible values are true or false. The default value is false. setSelectable(), getSelectable(), initSelectable(), resetSelectable(), and toggleSelectable() are the methods available to modify the Selectable property.
  • Appearance: This property controls style of the element and identifies the theme for the widget. Possible values are any string defined in the theme; the default value is widget. setAppearence(), getAppearence(), initAppearence(), and resetAppearence() are the methods to alter the appearance.
  • Cursor: This property specifies which type of cursor to display on mouse over the widget. The possible values are any valid CSS2 cursor name defined by W3C (any string) and null. The default value is null. Some of the W3C-defined cursor names are default, wait, text, help, pointer, crosshair, move, n-resize, ne-resize, e-resize, se-resize, s-resize, sw-resize, w-resize, and nw-resize. setCursor(), getCursor(), resetCursor(), and initCursor() are the methods available to alter the cursor property.

qx.application

The starting point for a qooxdoo application is to write a custom application class by inheriting one of the qooxdoo application classes in the qx.application namespace or package. Similar to the main method in Java, the qooxdoo application also starts from the main method in the custom application class.

qooxdoo supports three different kinds of applications:

  • Standalone: Uses the application root to build full-blown, standalone qooxdoo applications.
  • Inline: Uses the page root to build traditional web page-based applications, which are embedded into isles in the classic HTML page.
  • Native: This class is for applications that do not involve qooxdoo's GUI toolkit. Typically, they only make use of the IO (AJAX) and BOM functionality (for example, to manipulate the existing DOM).

Whenever a user creates an application with the Python script, a custom application class gets generated with a default main method. Let's see the custom application class generated for our Team Twitter application. After generation, the main function code is edited to add functionality to communicate to the RPC server and say "hello" to the qooxdoo world. The following code is the content of the Application.js class file with an RPC call to communicate with the server:

/** * This is the main application class of your custom application "teamtwitter" */ qx.Class.define("teamtwitter.Application", { extend : qx.application.Standalone, members : { /** * This method contains the initial application code and gets called during startup of the application * @lint ignoreDeprecated(alert) */ main : function() { // Call super class this.base(arguments); // Enable logging in debug variant if (qx.core.Variant.isSet("qx.debug", "on")) { // support native logging capabilities, e.g. Firebug for Firefox qx.log.appender.Native; // support additional cross-browser console. Press F7 to toggle visibility qx.log.appender.Console; } /* Below is your actual application code... */ // Create a button var button1 = new qx.ui.form.Button("First Button", "teamtwitter/test.png"); // Document is the application root var doc = this.getRoot(); // Add button to document at fixed coordinates doc.add(button1, {left: 100, top: 50}); // Add an event listener button1.addListener("execute", function(e) { var rpc = new qx.io.remote.Rpc(); rpc.setCrossDomain( false ); rpc.setTimeout(1000); var host = window.location.host; var proto = window.location.protocol; var webURL = proto + "//" + host + "/teamtwitter/.qxrpc"; rpc.setUrl(webURL); rpc.setServiceName("qooxdoo.test"); rpc.callAsync(function(result, ex, id){ if (ex == null) { alert(result); } else { alert("Async(" + id + ") exception: " + ex); } }, "echo", "Hello to qooxdoo World!"); }); } } });

We've had an overview of the class hierarchy of the qooxdoo framework and got to know the base classes for the widgets. Now, we have an idea of the core functionalities available for the widgets, the core properties of the widgets, and the methods to manage those properties. We've received more information on the application in the qooxdoo framework.

Now, it is time to learn about the containers.

Containers

A container is a kind of widget. It holds multiple widgets and exposes public methods to manage their child widgets. One can configure a layout manager for the container to position all the child widgets in the container. qooxdoo provides different containers for different purposes.

Let's check different containers provided by the qooxdoo framework and understand the purpose of each container. Once you understand the purpose of each container, you can select the right container when you design your application.

Scroll

Whenever the content widget size (width and height) is larger than the container size (width and height), the Scroll container provides vertical, or horizontal, or both scroll bars automatically. You have to set the Scroll container's size carefully to make it work properly. The Scroll container is used most commonly if the application screen size is large.

The Scroll container has a fixed layout and it can hold a single child. So, there is no need to configure the layout for this container.

The following code snippet demonstrates how to use the Scroll container:

// create scroll container
var scroll = new qx.ui.container.Scroll().set({
width: 300,
height: 200
});
// adding a widget with larger widget and height of the scroll
scroll.add(new qx.ui.core.Widget().set({
width: 600,
minWidth: 600,
height: 400,
minHeight: 400
})); // add to the root widget.
this.getRoot().add(scroll);

The GUI look for the preceding code is as follows:

Stack

The Stack container puts a widget on top of an old widget. This container displays only the topmost widget. The Stack container is used if there are set of tasks to be carried out in a flow. An application user can work on each user interface one-by-one in order.

The following code snippet demonstrates how to use the Stack container:

// create stack container
var stack = new qx.ui.container.Stack();
// add some children
stack.add(new qx.ui.core.Widget().set({
backgroundColor: "red"
}));
stack.add(new qx.ui.core.Widget().set({
backgroundColor: "green"
}));
stack.add(new qx.ui.core.Widget().set({
backgroundColor: "blue"
}));
this.getRoot().add(stack);

The GUI look for the preceding code is as follows:

Resizer

Resizer is a container that gives flexibility for resizing at runtime. This container should be used only if you want to allow the application user to dynamically resize the container.

The following code snippet demonstrates how to use the Resizer container:

var resizer = new qx.ui.container.Resizer().set({
marginTop : 50,
marginLeft : 50,
width: 200,
height: 100
});
resizer.setLayout(new qx.ui.layout.HBox());
var label = new qx.ui.basic.Label("Resize me <br>I'm resizable");
label.setRich(true);
resizer.add(label);
this.getRoot().add(resizer);

The GUI look for the preceding code is as follows:

Composite

This is a generic container. If you do not want any of the specific features, such as, resize on runtime, stack, scroll, and so on, but just want a container, you can use this container. This is one of the mostly used containers.

The following code snippet demonstrates the Composite container usage. A horizontal layout is configured to the Composite container. A label and a text field are added to the container. The horizontal layout manager places them horizontally:

// create the composite
var composite = new qx.ui.container.Composite()
// configure a layout.
composite.setLayout(new qx.ui.layout.HBox());
// add some child widgets
composite.add(new qx.ui.basic.Label("Enter Text: "));
composite.add(new qx.ui.form.TextField());
// add to the root widget.
this.getRoot().add(composite);

The GUI look for the preceding code is as follows:

Window

Window is a container that has all features, such as, minimize, maximize, restore, and close. The icons for these operations will appear on the top-right corner. Different themes can be set to get the look and feel of a native window within a browser. This window is best used when an application requires Multiple Document Interface (MDI) or Single Document Interface (SDI). The following code snippet demonstrates a window creation and display:

var win = new qx.ui.window.Window("First Window");
win.setWidth(300);
win.setHeight(200);
// neglecting minimize button
win.setShowMinimize(false);
this.getRoot().add(win, {left:20, top:20});
win.open();

The GUI look for the preceding code is as follows:

TabView

The TabView container allows you to display multiple tabs, but only one tab is active at a time. The TabView container simplifies the GUI by avoiding the expansive content spreading to multiple pages, with a scroll. Instead, the TabView container provides the tab title buttons to navigate to other tabs. You can group the related fields into each tab and try to avoid the scroll by keeping the most-used tab as the first tab and making it active. Application users can move to other tabs, if required.

TabView is the best example for the stack container usage. It stacks all pages one over the other and displays one page at a time. Each page will have a button at the top, in a button bar, to allow switching the page. Tabview allows positioning the button bar on top, bottom, left, or right. TabView also allows adding pages dynamically; a scroll appears when the page buttons exceed the size.

The following code snippet demonstrates the usage of TabView:

var tabView = new qx.ui.tabview.TabView();
// create a page
var page1 = new qx.ui.tabview.Page("Layout",
"icon/16/apps/utilitiesterminal.png");
// add page to tabview
tabView.add(page1);
var page2 = new qx.ui.tabview.Page("Notes",
"icon/16/apps/utilitiesnotes.png");
page2.setLayout(new qx.ui.layout.VBox());
page2.add(new qx.ui.basic.Label("Notes..."));
tabView.add(page2);
var page3 = new qx.ui.tabview.Page("Calculator", "icon/16/apps/
utilities-calculator.png");
tabView.add(page3);
this.getRoot().add(tabView, {edge : 0});

The GUI look for the preceding code is as follows:

GroupBox

GroupBox groups a set of form widgets and shows an effective visualization with the use of a legend, which supports text and icons to describe the group. As with the container, you can configure any layout manager and allow adding a number of form widgets to the GroupBox.

Additionally, it is possible to use checkboxes or radio buttons within the legend. This allows you to provide group functionalities such as selecting or unselecting all the options in the group. This feature is most important for complex forms with multiple choices.

The following code snippet demonstrates the usage of GroupBox:

// group box
var grpBox = new qx.ui.groupbox.GroupBox("I am a box");
this.getRoot().add(grpBox, {left: 20, top: 70});
// radio group box
var rGrpBox = new qx.ui.groupbox.RadioGroupBox("I am a box");
rGrpBox.setLayout(new qx.ui.layout.VBox(4));
rGrpBox.add(new qx.ui.form.RadioButton("Option1"));
rGrpBox.add(new qx.ui.form.RadioButton("Option2"));
this.getRoot().add(rGrpBox, {left: 160, top: 70});
// check group box
var cGrpBox = new qx.ui.groupbox.CheckGroupBox("I am a box");
this.getRoot().add(cGrpBox, {left: 300, top: 70});

The GUI look for the preceding code is as follows:

We got to know the different containers available in the qooxdoo framework. Each container provides a particular functionality. Based on the information displayed on the GUI, you should choose the right container to have better usability of the application.

Containers are the outer-most widgets in the GUI. Once you decide on the containers for your user interface, the next thing to do is to configure the layout manager for the container. Layout manager places the child widgets in the container, on the basis of the configured layout manager's policies. Now, it's time to learn how to place and arrange widgets inside the container, that is, how to lay out the container.

qooxdoo Beginner's Guide Develop Rich Internet Applications (RIA) with qooxdoo book and ebook
Published: December 2011
eBook Price: £18.99
Book Price: £30.99
See more
Select your format and quantity:

(For more resources on this topic, see here.)

Layout managers

Layout managers control the position, size, and arrangement of all the widgets inside the container. The qooxdoo framework provides different layout managers for different purposes, for example, to arrange widgets horizontally or vertically, to place the widgets in rows and columns such as in a grid, to place the widgets at the corners, to place the widgets at fixed points, and so on.

When a user resizes the web page, the qooxdoo layout engine prompts the layout manager to recalculate and reposition the widgets in the container.

The different criteria or properties involved in laying out the screen are discussed in the sections that follow.

Size hint of the widget and its parent widget

Size hint is nothing but a map of boundaries, widths, and heights, and it's been calculated based on the widgets' internal widgets. qooxdoo provides two different methods to calculate and get the size hints of a widget, mentioned next:

  • getSizeHint(Boolean compute): This default value for compute is true, so it automatically computes and returns the result. Otherwise, it returns the cached values.
  • computeSizeHint(): This computes the size hints of the layout and returns the result. One can override this protected method in order to redesign the default algorithm.

Layout properties

The layout properties are the properties which are related to the widget's layout. These properties are pixel, flex, and percentage of width. One can set a map of all layout properties for an individual widget while adding the widget. To set this, use the setLayoutProperties() method and specify the map. Map supports different key values, such as, left, right, top, bottom, width, height, flex, and so on; values for all these properties can be given in terms of fixed pixels (integer values), or percentages (string values). Some layout-specific properties also can be given in this map. One such property is clearLayoutProperties(). This property clears the stored map of properties.

Flex is another property, which specifies the priority for the children to occupy space in the total available space. This defines the flexibility of the widget. A higher flex value gives more space for that widget. For example, if two widgets are placed in a widget such as split pane and if the first widget's flex is 1 and the second widget's flex is 2, the total space of the split pane is considered as three parts; the first widget will occupy one part and the second widget will occupy two parts.

Auto sizing

By default, widgets are configured with some computed values for all the layout properties. So, the qooxdoo framework doesn't force the developer to set the values for any property. A developer can just create a widget and add it to the container. Most of the time, the widgets look good. If that requires any modification, the developer can modify the properties so that the layout manager takes them into consideration during the computation. For example, the widget's default value for allowGrowX or allowGrowY is true. So, the widget automatically gets resized based on the available room.

Growing or shrinking

The GUI should be dynamic; it should get adjusted within the available space. If the available room is less, the widgets should automatically shrink, and if more, they should grow according to the available room (see the following screenshot):

Overflow

Consider a scenario where the widget size is larger than the available room and the widget cannot shrink. In this scenario, the overflow property is used. If the overflow property is set to true, qooxdoo displays the whole widget by providing the required scroll bar.

qooxdoo framework provides a different set of layouts. The basic implementation is given in an abstract class (qx.ui.layout.Abstract). All the custom layouts must derive from the Abstract layout class and provide implementation for the getSizeHint(), renderLayout() and invalidateLayoutCache() methods. All the layouts provided by qooxdoo are in the qx.ui.layout package:

Let's check different layout managers provided by the qooxdoo framework and understand the purpose of each layout manager. Once you understand the purpose of each layout manager, you can select the right layout managers when you design your application.

Basic

This layout is very simple and is the first layout given in the qooxdoo framework. Basic layout is used to position the children in the top and left coordinates of the container.

To add any widget into a container configured with Basic layout, you should specify a map with the left and top properties. The default value for each of the properties is 0.

The following code snippet demonstrates the Basic layout. To differentiate the added widgets, let's set a different background color for each widget. For the main container, let's set white as the background color. Now, we will try adding a widget at the (100,100) position and another at the default values:

 

var container = new qx.ui.container.Composite(new qx.ui.layout.
Basic());
// adds a widget at (100,100) point.
container.add(new qx.ui.core.Widget().set({backgroundColor : "blue"}),
{left: 100, top: 100});
// adds a widget at (0,0) point.
container.add(new qx.ui.core.Widget().set({backgroundColor :
"green"}));
container.set({backgroundColor : "white"});

Features of the Basic layout are as follows:

  • Basic positioning using the left and top properties
  • Respects minimum and maximum dimensions without shrinking/growing
  • Margins for top and left side (including negative ones)
  • Respects right and bottom margins in the size hint
  • Auto sizing

Canvas

This layout is also a simple layout and it provides extended features to the Basic layout. With this layout manager, you can position a widget relative to top, left, right, and bottom coordinates. It also allows setting the widget sizes (width and height), in terms of percentages.

The following code snippet demonstrates the Canvas layout:

var container = new qx.ui.container.Composite(new qx.ui.layout.
Canvas());
// simple positioning
container.add(new qx.ui.core.Widget().set({backgroundColor : "blue"}),
{top: 10, left: 10});
// stretch vertically with some pixel distance to the parent's top
// and bottom border
container.add(new qx.ui.core.Widget().set({backgroundColor :
"black"}), {top: 40, right: 50, bottom: 10});
// percent positioning and size
container.add(new qx.ui.core.Widget().set({backgroundColor :
"green"}), {left: "50%", top: "50%", width: "25%", height: "40%"});
container.set({backgroundColor : "white"});

Features of the Canvas layout are:

  • Pixel dimensions and locations
  • Percent dimensions and locations
  • Stretching between left/right and top/bottom
  • Minimum and maximum dimensions
  • Children automatically shrink to minimum dimensions if not enough space available
  • Auto sizing (ignoring percent values)
  • Margins (also negative ones)
  • In both Basic and Canvas layouts the spacing between the widgets cannot be specified and the overlapping of widgets is possible

Dock

The Dock layout allows you to add the widgets at the four edges of the container and the center of the container. This layout is very similar to the border layout in Java Swing. The different properties allowed in the map are edge, width, and height. The width and height properties support only the percentage values; the possible values for the edge property are north, east, west, south, and center.

The following sample code snippet demonstrates how to create and use the Dock layout:

var layout = new qx.ui.layout.Dock();
var w1 = new qx.ui.core.Widget();
var w2 = new qx.ui.core.Widget();
var w3 = new qx.ui.core.Widget();
var w4 = new qx.ui.core.Widget();
var w5 = new qx.ui.core.Widget();
w1.set({backgroundColor : "blue"});
w2.set({backgroundColor : "black"});
w3.set({backgroundColor : "green"});
w4.set({backgroundColor : "red"});
w5.set({backgroundColor : "orange"});
var container = new qx.ui.container.Composite(layout);
// add w1 in north edge
container.add(w1, {edge:"north"});
// add w2 in south edge
container.add(w2, {edge:"west"});
// add w3 in center
container.add(w3, {edge:"center"});
// add w4.in south edge
container.add(w4, {edge:"south"});
// add w5 in east side
container.add(w5, {edge:"east"});
container.set({backgroundColor : "white"});
this.getRoot().add(container);

The Dock layout adds the widget on the edge of the container and utilizes maximum available space on that edge, while adding widgets into the container. Thus, the following widget takes the remaining space. To have a clear understanding, just change the order of adding w1, w2, w3, w4, and w5, and check the output alignment of the widgets.

There is no restriction on the number of widgets on each side; the user can add any number of widgets on each side.

Features of the Dock layout are:

  • Percent width for left-/right-/center-attached child widgets
  • Percent height for top-/bottom-/center-attached child widgets
  • Minimum and maximum dimensions
  • Prioritized growing/shrinking (flex)
  • Auto sizing
  • Margins and spacings
  • Alignment in orthogonal axis (For example, alignX of north-attached)
  • Different sort options for children

HBox

This layout allows you to add the widgets horizontally to container from left to right in a row. The properties map for this layout can have two properties, namely, width and flex, where width is percentage value and the flex is an integer value to specify the flexibility of the widget. You can specify the spacing between the widgets in this layout.

The following code snippet demonstrates how to create and configure the HBox layout with spacing of 4 between the widgets:

var layout = new qx.ui.layout.HBox();
layout.setSpacing(4); // apply spacing
var container = new qx.ui.container.Composite(layout);
container.add(new qx.ui.core.Widget().set({backgroundColor :
"blue"}));
container.add(new qx.ui.core.Widget().set({backgroundColor :
"black"}));
container.add(new qx.ui.core.Widget().set({backgroundColor :
"green"}));
container.set({backgroundColor : "white"});
this.getRoot().add(container);

Features of the HBox layout are:

  • Minimum and maximum dimensions
  • Prioritized growing/shrinking (flex)
  • Margins (with horizontal collapsing)
  • Auto sizing (ignoring percent values)
  • Percent widths (not relevant for size hint)
  • Alignment (child property, qx.ui.core.LayoutItem.alignX, is ignored)
  • Horizontal spacing (collapsed with margins)
  • Reversed children layout (from last to first)

  • Vertical children stretching (respecting size hints)

Similarly, the tweet information contains the username and time of the tweet. Those two labels were added in HBox. The username label allows clicking on it, so that the application displays the user information.

The following code snippet demonstrates the HBox layout in our Team Twitter application:

// create user label
var user = new qx.ui.basic.Label("<a style = 'color: rgb(126, 26,
26);'>" + this.getUserName() + "</a>");
user.setRich(true);
user.setSelectable(true);
user.setCursor("pointer");
user.addListener("click", this.userNameClicked, this);
// create time label
var dateTime = new qx.ui.basic.Label(" at " + this.getTime() + " on "+
this.getDate());
//create HBox layout manager and those two labels
var tweetInfo = new qx.ui.container.Composite();
tweetInfo.setLayout(new qx.ui.layout.HBox());
tweetInfo.add(user);
tweetInfo.add(dateTime);

VBox

Similar to HBox layout, the VBox layout manager allows you to add the widgets vertically to container from top to bottom in a column. You can specify the spacing between the widgets in this layout.

The following code snippet demonstrates how to create and configure the VBox layout with a spacing of 4 between the widgets:

var layout = new qx.ui.layout.VBox();
layout.setSpacing(4); // apply spacing
var container = new qx.ui.container.Composite(layout);
container.add(new qx.ui.core.Widget().set({backgroundColor :
"blue"}));
container.add(new qx.ui.core.Widget().set({backgroundColor :
"black"}));
container.add(new qx.ui.core.Widget().set({backgroundColor :
"green"}));
container.set({backgroundColor : "white"});
this.getRoot().add(container);

Features of the VBox layout are:

  • Minimum and maximum dimensions
  • Prioritized growing/shrinking (flex)
  • Margins (with vertical collapsing)
  • Auto sizing (ignoring percent values)
  • Percent heights (not relevant for size hint)
  • Alignment (child property, qx.ui.core.LayoutItem#alignY, is ignored)
  • Vertical spacing (collapsed with margins)
  • Reversed children layout (from last to first)
  • Horizontal children stretching (respecting size hints)

Flow

The Flow layout positions the widgets in a flow manner or wraps the widgets within the available space. This layout manager follows the HBox layout initially, and, when the layout manager cannot accommodate the added widget horizontally adjacent to the previously added widget, the added widget will be placed in the next line; the same algorithm is followed for all the horizontal lines. This layout manager is useful when you want to add dynamic content in a container or to add multiple widgets of same type in a container.

The properties map for this layout supports only the lineBreak property, which breaks the line and places the following widgets in a new line. The Flow layout also supports the individual widgets alignment properties and the spacing between the widgets.

The following code snippet demonstrates the Flow layout:

this.tagCloud = new qx.ui.container.Composite();
// setting a Flow layout to the composite container
this.tagCloud.setLayout(new qx.ui.layout.Flow(5,5));
for (var i=0; i<this.tagsArray.length; i++) {
// create tag label
var tagLabel = new qx.ui.basic.Label("<a style = 'color: rgb(126, 26,
26); text-decoration:underline'>" + this.tagsArray[i] + "</a>");
tagLabel.setRich(true);
tagLabel.setSelectable(true);
tagLabel.setCursor("pointer");
tagLabel.addListener("click", this.tagClicked, this);
this.tagCloud.add(tagLabel);

Features of the Flow layout are:

  • Reversing children order
  • Manual line breaks
  • Horizontal alignment of lines
  • Vertical alignment of individual widgets within a line
  • Margins with horizontal margin collapsing
  • Horizontal and vertical spacing
  • Height–for-width calculations
  • Auto sizing

Grid

The Grid layout places the widgets in terms of two-dimensional rows and columns. It also supports the spanning of multiple rows or columns. This is one of the most useful layouts to prepare any form with labels and the input text fields, and so on.

The property map for this layout supports the row, column with row index, and column index consecutively; rowSpan and colSpan specify the number of rows or columns to span.

The following code snippet demonstrates the usage of the Grid layout:

// setting a grid layout to the composite container
this.setLayout(new qx.ui.layout.Grid(5,5));
// adding the created fields
this.add(userImg, {row : 0, column:0, rowSpan : 2});
this.add(this.twtData, {row : 0, column:1, colSpan : 2});
this.getLayout().setColumnWidth(1, 300);
this.add(hbox, {row : 1, column:1});
this.add(more, {row : 1, column:2});

Features of the Grid layout are:

  • Flex values for rows and columns
  • Minimal and maximal column and row sizes
  • Manual setting of column and row sizes
  • Horizontal and vertical alignment
  • Horizontal and vertical spacing
  • Column and row spans
  • Auto sizing

qooxdoo framework provides a wide range of layout managers from a simple to a complex layout manager. We have learnt the different layout managers, layout manager features, and usage of each layout manager.

Time for action – designing layout managers for Team Twitter

Now that we have learnt the different containers and layout managers provided by the qooxdoo framework, let's design the layouts for our Team Twitter application.

  1. Set the layout manager to the UserLoginForm class. Identify the correct layout manager and set the layout manager for the user login form. The user login form should take the input of username and password, validate the credentials, and allow the user to login. It should also allow the user to go to the registration form. To place those created widgets into the form, we can go for a Grid layout, where we can show the fields in terms of rows and columns. So, the best suitable layout for this form is the Grid layout. It will look good if we display a border with a title for the login form, therefore the best container for this widget is the GroupBox container. We had already created the <TeamTwitterHomeDir>\source\class\ teamtwitter\ui\UserLoginForm.js class. Let's set the layout manager, as shown in the following code snippet:
  2. _initLayout : function() {
    this.setLegend(this.tr("Login Form"));
    // setting a grid layout to the composite container
    this.setLayout(new qx.ui.layout.Grid(5,5));
    }

  3. Let's develop the widget for searching tweets. It should allow you to select the team, enter the search text, and search tweets. We also should have links for logging in and out. As this widget does not need any special features, such as, scroll, group box, and so on, the best container for this widget is the Composite container. As all the fields discussed above should appear horizontally, the best layout manager for this widget is HBox layout manager. Let's create the class and use the Composite container and set the HBox layout manager. Create the TweetSearchWidget.js file under C:\teamtwitter\source\ class\teamtwitter\ui and set the layout manager, as shown in the following code snippet:
  4. _initLayout : function() {
    // setting a grid layout to the composite container
    this.setLayout(new qx.ui.layout.HBox());
    }

  5. Let's set the layout manager to the tweetWidget class. In our Team Twitter application, for each tweet, we need to display the tweet text, user picture, tweet information, and so on. The best layout manager for this widget is the Grid layout manager. As we display multiple tweets in the tweet display area, it will be good to have a border, and optionally display the group title. The container which provides this functionality is called GroupBox. You can extend the qx.ui.groupbox.GroupBox class to use that container. Let's add the Grid layout for the tweetWidget. The following code just sets the Grid layout manager for the tweetWidget, located at \source\class\ teamtwitter\ui\TweetWidget.js:
  6. _initLayout : function() {
    // setting a grid layout to the composite container
    this.setLayout(new qx.ui.layout.Grid(5,5));
    }

  7. Let's develop the widget to display tags. In our Team Twitter application, the tags are dynamic content, and there are multiple tweets on the same tag. The best layout manager for the tags widget is the Flow layout manager. As the content is dynamic, we never know how many tags we need to display. So, it is better to use the Scroll container for the Tags panel and extend it from the Composite container. Let's develop the tags widget. As the widget should allow the selection and deselection of the tags, it is a good idea to allow the selection and deselection of all tags at once. This functionality is provided by the enhanced version of GroupBox, CheckGroupBox. Let's use the CheckGroupBox container for the outer panel. Create the TagsWidget.js class under C:\teamtwitter\source\class\teamtwitter\ui and set the layout manager, as shown in the following code snippet:
  8. _initLayout : function() {
    this.mainPanel = new qx.ui.groupbox.CheckGroupBox("Tags");
    this.mainPanel.addListener("changeValue", this.tagsClicked);
    // setting a Flow layout to the composite container
    this.mainPanel.setLayout(new qx.ui.layout.Flow(5,5));
    var scroll = new qx.ui.container.Scroll();
    scroll.set({
    allowShrinkY: false
    });
    scroll.add(this.mainPanel);
    this.add(scroll, {edge : "center"});
    }

  9. Let's develop the widget to display the team members. This widget should display the list of users in the team. It should allow you to select multiple users. As we display users in lists, vertically, the best layout manager is the VBox layout manager. It is a good idea to give a title and border; this functionality is provided by the GroupBox container. As the widget should allow the selection and deselection of the users, it is a good idea to allow the selection and deselection of all users at once. This functionality is provided by the enhanced version of GroupBox, CheckGroupBox. Let's use the CheckGroupBox container for this widget. Create the UsersListWidget.js file under C:\teamtwitter\source\class\ teamtwitter\ui and set the layout manager, as shown in the following code:
  10. qx.Class.define("teamtwitter.ui.UsersListWidget", {
    extend : qx.ui.groupbox.CheckGroupBox,
    construct : function(){
    this.base(arguments);
    this.setLayout(new qx.ui.layout.VBox());
    this._initLayout();
    this.addListener("changeValue", this.usersClicked);
    },
    members : {
    _initLayout : function() {
    this.setLegend(this.tr("Team Members"));
    },
    usersClicked : function(e) {
    // <TODO> select or unselect all the users
    },
    setTeamMembers : function(teamId) {
    // <TODO> get the members of the team and display
    }
    }
    });

  11. Let's develop the widget that first allows you to enter the tweet text, video ID, and tag, and then to submit the tweet. As this widget does not need any special features, such as, scroll, group box, and so on, the best container for this widget is the Composite container. As we need to display many widgets in rows and columns, the best layout manager for this widget is Grid layout manager. Let's create the class, use the Composite container, and set the Grid layout manager. Create the TweetInput.js file under C:\teamtwitter\source\class\ teamtwitter\ui and set the layout manager, as mentioned in the following code snippet:
  12. _initLayout : function() {
    // setting a grid layout to the composite container
    var g = new qx.ui.layout.Grid(4,5);
    g.set({
    spacingX : 10
    });
    this.setLayout(g);
    }

  13. Let's design TweetDisplayWidget to display the tweets. We have developed the tweet widget already. TweetDisplayWidget just displays multiple tweet widgets vertically. The best layout manager for this widget is VBox layout manager. It is a good idea to display a title and border for this widget. Therefore, we can use the GroupBox container for this widget. Create the TweetsDisplayWidget.js file under C:\teamtwitter\source\ class\teamtwitter\ui and set the layout shown in the following code snippet:
  14. _initLayout : function() {
    this.setLegend(this.tr("Tweets"));
    // setting a grid layout to the composite container
    this.setLayout(new qx.ui.layout.VBox());
    }

  15. We have written a few widgets and set the container and layout manager. Let's assemble these widgets to form MainWidget. Create the MainWidget.js file under C:\teamtwitter\source\class\ teamtwitter\ui and try to code for the same screen as the one shown in the screenshot that follows. To improve the usability and make use of AJAX in our application, we would like to display the login form overlapped on the home screen of the Team Twitter application, which helps to retain the context of the application. This is possible in the Canvas layout manager which allows you to position a widget relative to top, left, right, and bottom coordinates, or in percentages, and allows you to display overlapped content at any location. The Basic layout manager also supports overlapping of widgets, but the Canvas layout manager is an extended version of the Basic layout manager. So, we picked the Canvas layout manager over the Basic layout manager for the main widget. It is a good idea to display a title and set border for this widget. Therefore, we can use the GroupBox container for this widget. In the Canvas layout, add the TweetSearchWidget first, so that it is displayed on the top. Provide two percent space on the left hand side. Create an instance of the GroupBox container for the Content panel and set the Dock layout manager for the content panel, which supports adding the widgets on the four edges and the center of the container. Add the content panel next in the main canvas layout, leaving some space on the top for the TweetSearchWidget. If you do not leave space, the content panel will be rendered over the TweetSearchWidget, which was added earlier. In the Content panel, add the TweetDisplayWidget at the center of the Dock layout. As we'll display many tweets in this widget, add this widget into a scroll container and then add the scroll on the center of the Dock layout. Create a Composite container and set the VBox layout manager. Add TagsWidget first, and then add UsersListWidget. Add this container on the east of the Dock layout.
  16. Let's update our application class to remove the hello world button and add the main widget of the Team Twitter application. Edit the Application.js file under C:\teamtwitter\source\class\teamtwitter\ and update the code to add MainWidget into the application, as mentioned in the following code snippet:
  17. // Document is the application root
    var doc = this.getRoot();
    doc.add(new teamtwitter.ui.MainWidget(), {
    left : 0,
    top : 0
    });

  18. Now, try compiling your classes to identify any syntax errors in the code and fix them all. For this, use either of the following commands:
  19. C:/teamtwitter>generate.py build

    C:/teamtwitter-server>ant client.generate-build

  20. Generate the complete web application distribution by running the following command:
  21. C:/teamtwitter-server>ant dist

  22. Deploy the updated web application by running the following command:
  23. C:/teamtwitter-server>ant deploy

  24. Open the Team Twitter web application in the browser and check the appearance by entering the following URL:
    http://localhost:8080/teamtwitter/index.html

What just happened?

We have learnt how to select the right container and right layout manager based on the requirement.

From step 1 to step 7, we wrote a few classes for our Team Twitter application. For all those classes, we selected the right container, based on the requirement. We also selected the right layout manager for each class based on the requirement. In step 8, we assembled all the classes into a main widget. In step 9, we updated Application.js to display the main widget. In step 10, we built the client application. In step 11, we built the whole web application, including the server application. In step 12, we deployed the web application. In step 13, we checked the updated Team Twitter application from the web browser.

Summary

We covered the following:

  • We learnt about the base classes for the widgets.
  • We got an idea of different containers available in the qooxdoo framework.
  • We learnt about the layout manager and got a thorough understanding of different layout managers; this enables us to select the right layout manager for each container in the graphical user interface.

qooxdoo also supports the context menus that appear on the right-click action. We have applied the knowledge gained from this article to lay out the screens for our Team Twitter application. Now, we know how to select the right container and how to configure the right layout manager for the container.


Further resources on this subject:


qooxdoo Beginner's Guide Develop Rich Internet Applications (RIA) with qooxdoo book and ebook
Published: December 2011
eBook Price: £18.99
Book Price: £30.99
See more
Select your format and quantity:

About the Author :


Mohamed Raffi

Mohamed Raffi is an Enterprise Application specialist. His area of work includes Architecture, Design, Development, Training, and Mentoring. He has over thirteen years of product development experience in variety of java and javascript-based technologies and frameworks. You can find more about him at http://in.linkedin.com/in/raffimd and he writes his thoughts at http://thoughtstoblog.blogspot.com

Rajesh Kumar Bachu

Rajesh Kumar Bachu has over six years of experience in the design and development of Enterprise Applications and Mobile Games. He is good at programming in java and j2ee technologies. He has worked extensively in Qooxdoo application development and migrated an enterprise application to Qooxdoo. You can find more about him at http://in.linkedin.com/in/rajbachu

Books From Packt


jQuery 1.4 Reference Guide
jQuery 1.4 Reference Guide

Ext JS 4 First Look
Ext JS 4 First Look

Object-Oriented JavaScript
Object-Oriented JavaScript

Learning Ext JS 3.2
Learning Ext JS 3.2

Firebug 1.5: Editing, Debugging, and Monitoring Web Pages
Firebug 1.5: Editing, Debugging, and Monitoring Web Pages

YUI 2.8: Learning the Library
YUI 2.8: Learning the Library

OpenCart 1.4 Beginner's Guide
OpenCart 1.4 Beginner's Guide

Learning jQuery 1.3
Learning jQuery 1.3


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software