Comments
bruce.armstrong wrote: Somebody just said it better than I did, and with more chops to say it: Open Letter to Mark Zuckerberg, Sheryl Sandberg & Facebook Mobile
Cloud Computing
Conference & Expo
November 2-4, 2009 NYC
Register Today and SAVE !..
SYS-CON.TV
Today's Top SOA Links


Organize Your GUI with Layout Managers
Getting control over your windows

PowerBuilder novices know the problem as well as seasoned PowerBuilder developers. You build a window in the window painter. You arrange the controls on the window and the layout looks fine.

Your users start the window and size it. It doesn't look fine any more because the components in the window don't fit the workspace. PowerBuilder doesn't resize automatically, so you have to build a resize service. The PowerBuilder window object delivers an event that resizes and positions the controls perfectly whenever the user resizes the window. But you have to code it yourself and adding controls expands the script in the resize event. Sure, you can implement it separately in functions, but you have to code it in all the windows you're using in your application. Copy and pasting is helpful, but a better way is to inherit the windows from a base window with a resize service implemented. To do this you have to program a generic resize service in the ancestor window. But not all your windows look the same, so you have to build different ancestors for different layouts. Another problem is how to change the layout without building a whole new window.

Let's have a look how other programming languages or frameworks solve this problem. Let's adapt some of ideas from Java or C# and build some layout managers.

What Is a Layout Manager?
The Java 2 Platform Specification says a layout manager "defines the interface for classes that know how to lay out containers." In other words, it's simply an object that does the resizing work for you. You tell the object which controls to lay out and start the layout process with a function. The way the objects are laid out depends on the layout style you specify in the manager. "Border," "grid," or "tab" are some of them and will be explained below. Layout managers can be used for different types of graphic objects like windows, tab folders, or custom visual user objects. The layout for an object can be done by changing the definition of the container in the constructor without building a new inheritance or changing the resize event. But unlike the resize service in the PFC where we have to define the resize behaviour of every object we register, with a layout manager we only have to register the objects. The layout is defined by the type of layout manager that we use. So setting up a layout is less work with layout managers.

Building a Layout Manager for PowerBuilder
Think of a PowerBuilder layout manager as a service class similar to those in the PFC. "All" we have to do with this service is to register the objects we want to resize automatically and specify the layout style. The different layout styles are based on different layout managers. So we have a kind of service-based architecture (SBA) instead of inheritance-based architecture.

That doesn't mean there's no inheritance in the layout manager architecture. All the objects for the special layout styles have common functionality that's implemented in a common base object.

We need an ancestor object for all layout managers that defines the base functionality as shown in Figure 1.


n_cst_layoutmanager inherited from nonvisualobject

The whole idea is to lay out the controls in a window or user object. So we need a function to do this. The function has to lay out the container and arranges the controls. The container could be a window or another control like a tab page. Both are descendents from the graphic object type, so my first thought was to use this class for the common function for all graphic objects. But I am afraid we can't use this class because a graphic object doesn't have information about the position and size of the object. So we have to write two different functions, one for the class window and one for drag objects. The drag object is the ancestor class of all the controls in a window that can be containers for other controls (group boxes or user objects, for example). If you want to use a layout manager to draw objects like rectangles and ovals you have to build more functions in the ancestor class for the draw object type and perhaps for the mdiclient too.

I chose to implement different functions for each container type to be sure that no wrong function calls are implemented because the compiler wouldn't accept them.

Let's have a look on how it's defined for a drag object:


public function of_LayoutContainer(readonly dragobject ado_parent)

If you've got two or more functions to lay out different types of visual objects, as described above, you can consolidate your work by implementing a protected function of_layout(readonly graphicobject ago_parent), which will do the layout work. This function will be internally called by the different of_layoutcontainer functions (maybe four as described above). Here is the implementation for the window:


public subroutine of_layoutcontainer (readonly window aw_parent);
this.of_layout(aw_parent)
end subroutine

This is done this way to be sure that no wrong function calls are implemented, because the compiler won't accept them and you only have to implement the functionality once per layout manager.

Notice that the function (of_layout) is a kind of virtual function in the n_cst_layoutmanager object, because all the layout managers we use are ultimately inherited from this base object. The function is coded in the descendants because this is the main function of the layout process and differs by type of layout manager.

It's now time to think about telling the object which components to arrange. We can do this, for example, in the constructor event of the container with a function like this:


public function of_addLayoutComponent
(string as_name, ref dragobject ado_component)

We store the components in an instance array (n_cst_component invo_component[]). To create this array we have to define the class for n_cst_component (see Figure 1) and a set of functions to make it work:

  • of_setComponent(ref dragobject ado_component): Defines a reference to the component that is treated as a private instance variable ido_component in the object.
  • of_setName(string as_name): Gives the component a corresponding speaking name treated as a private instance variable is_name in the object.
  • dragobject of_getcomponent(): To get a reference to the component from the instance variable ido_component.
  • string of_getname(): To get the name of the component from the instance variable is_name.
  • of_reset(): To delete all instance variables in the whole component.
The function of_addLayoutComponent should be implemented as follows:

long ll_counter

// Get the Maximum of the componentlist
ll_counter = upperbound(invo_component)

// and create a new component at the end
ll_counter++
invo_component[ll_counter] = create n_cst_component
invo_component[ll_counter].of_setname( as_name )
invo_component[ll_counter].of_setcomponent( ado_component )

To remove a component from the list you have to implement the this function:


//of_removeLayoutComponent(ref dragobject ado_component)
long ll_index, & ll_max
// search the component in the componentenarray
ll_max = upperbound(invo_component)
for ll_index = 1 to ll_max
if ado_component = invo_component[ll_index].of_getcomponent() then
// set the component to null
invo_component[ll_index].of_reset()
end if
next

This is the base functionality of a layout manager, but it doesn't lay out anything yet. You can tell it which components it should lay out for which container. The defined function of_Layout is only a virtual function. You have to implement it in the specific layout manager type.


About Christoph Menken
Christoph Menken is a senior developer and consultant on Power People (www.powerpeople.de) and a frequent speaker at the PowerBuilder User Group Germany (www.pbugg.de). He has been using PowerBuilder since version 5.0 and PocketBuilder since version 1.5.

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON Featured Whitepapers
ADS BY GOOGLE