Table of Contents
Views are the basic visual element in OpenLaszlo applications. They allow you to specify how elements will interact with one another. In the OpenLaszlo Basics tutorial we've seen how to specify a top-to-bottom organization of text elements. In this tutorial you'll learn how to do more complex and powerful interactions among visual elements.
Here's the code from the previous tutorial:
Example 7.1. Simple window
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
>My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
We've added a button (My Button) just to remind us of how the
<simplelayout>
affected the sibling elements.
That button would look better if it were centered. There is an attribute that we could use to do this, but just to see better how LZX works, let's center the button programatically. This will give you a good look at how constraints and modifiers work, which will help you build more complex views.
A constraint is an object which takes responsibility for keeping a view property set to a certain value. Constraints are described in full in Chapter 27, Constraints, but here we'll just get a flavor of them because they are a key feature of LZX syntax. In order to show constraints, we'll also introduce the key concepts of "parent" and "immediateparent", which describe where views fit in different kinds of hierarchies.
Depending on the type of constraint, that can be 'the x position of the mouse' or 'the width of the parent view' or whatever. In this case, we will constrain a property to the width of the parent view.
Example 7.2. Constraining button position relative to window
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${immediateparent.width / 2}
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
What we've said here is "constrain the x position of the button to half the width of its parent". Actually we said "immediateparent". What's that about?
As explained in greater depth in Chapter 26, Views, "parent" is a term that refers to the lexical parent in the code, and "immediateparent" refers to the runtime parent of a view as the code is executed. Often they are the same thing, but it's important to understand when they're not. In particular, you generally need to use "immediateparent" when you create views by instantiating classes.
You can always use immediateparent
, instead of
parent
(you just have to type those extra 9 characters). In this case
the immediateparent
is the window's content area (the white bit). In
short we had to use immediateparent
here because
<window>
is a class, and when you
instantiate it and put contents inside of it, you must use the
immediateparent
reference to get the desired behavior.
You can perform operations on the value an attribute that you constrain to. The modifier in our example is the "divide by two" operator.
Notice that this code does not center the button. Rather, it constrains the position of the button to the middle of the window. The problem is that the position of a view is determined by its top-left corner. In other words, the top-left corner of the button is centered in the window, not the button itself. In order to center the button, we need to move it over by half of its own width. One way to do that would be to just give the button an explicit width, and offset the constraint by half of that.
Example 7.3. Centering the button
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
width
="160
" x
="${immediateparent.width / 2 - 80}
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
That works but it's not a general solution. We want the button to always be in the middle of the window even if it changes width. Here's how we do that:
Example 7.4. A button that stays centered
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${(immediateparent.width / 2) - (this.width / 2)}
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
This will center the button regardless of its size. Parenthesis have been added to clarify the execution order of the code. To prove that the button will remain centered, we'll add an onclick script to the button that will resize it.
For now, you don't need to understand how this works. Simply observe that when you click the button, its width grows. We'll revisit this topic in the Chapter 10, Introduction to Scripting.
Example 7.5. Growing button
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${(immediateparent.width / 2) - (this.width / 2)}
" onclick
="this.setAttribute('width', this.width + 10);
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Notice that as the button grows, it still stays centered.
What if now we wanted to have a row of buttons going across the top of our window? We can try adding a few buttons at the top:
Example 7.6. Vertically aligned buttons
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<button
>1
</button
>
<button
>2
</button
>
<button
>3
</button
>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${(immediateparent.width / 2) - (this.width / 2)}
" onclick
="this.setAttribute('width', this.width + 10);
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
We can't change the <simplelayout>
tag, because that
would make a mess of the other elements in the window. Instead we can put all three buttons in
their own view, and that view will then become a single element in the
window.
Then we can apply whatever kind of layout/positioning to the button view we want:
Example 7.7. Grouping buttons in a <view>
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<view
bgcolor
="#ff0000
">
<simplelayout
axis
="x
" spacing
="5
"/>
<button
>1
</button
>
<button
>2
</button
>
<button
>3
</button
>
</view
>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${(immediateparent.width / 2) - (this.width / 2)}
" onclick
="this.setAttribute('width', this.width + 10);
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
That's better. By using the attribute bgcolor
(background color) we can
see how big the view is; it's only as big as it needs to be. We haven't specified either a
height or width, so it is just large enough to accommodate the buttons.
What if we wanted the row to be like the toolbars at the top of your browser - a uniform color, that stretches from end to end?
We would constrain the width of the red view to the width of its parent.
Example 7.8. Constraining a width to a parent's width
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<view
bgcolor
="#ff0000
" width
="${immediateparent.width}
">
<simplelayout
axis
="x
" spacing
="5
"/>
<button
>1
</button
>
<button
>2
</button
>
<button
>3
</button
>
</view
>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${(immediateparent.width / 2) - (this.width / 2)}
" onclick
="this.setAttribute('width', this.width + 10);
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008, 2011 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Now the view stretches across, but if you look at the toolbars you'll notice that they are a little bit taller than the buttons they contain. To make our buttons look the same, we could set an absolute height, but let's make it dependent on one of the buttons:
Example 7.9. Constraining view to child's height
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<view
bgcolor
="#ff0000
" width
="${parent.width}
" height
="${this.refButton.height + 8}
">
<simplelayout
axis
="x
" spacing
="5
"/>
<button
name
="refButton
">1
</button
>
<button
>2
</button
>
<button
>3
</button
>
</view
>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${(immediateparent.width / 2) - (this.width / 2)}
" onclick
="this.setAttribute('width', this.width + 10);
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
In order to be able to reference a particular button, we had to give it a
name
attribute.
Now the buttons are top-aligned — they should be vertically aligned to the center of the red bar. Remember how earlier we said that there was an attribute to align stuff to the center? We're going to use it now:
Example 7.10. Using the 'valign' attribute
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<view
bgcolor
="#ff0000
" width
="${parent.width}
" height
="${this.refButton.height + 8}
">
<simplelayout
axis
="x
" spacing
="5
"/>
<button
name
="refButton
" valign
="middle
">
1
</button
>
<button
>2
</button
>
<button
>3
</button
>
</view
>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${(immediateparent.width / 2) - (this.width / 2)}
" onclick
="this.setAttribute('width', this.width + 10);
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
The valign
attribute aligns the view to the middle of its parent's
height. It can take a value of top
, middle
or
bottom
. There is an align
attribute that aligns views
to the x-axis. The only problem with using that here is that we'd have to give each button a
valign
attribute.
The solution is to wrap all of our buttons in a view. Then we could apply a
valign
attribute to all of them at once.
Example 7.11. Applying 'valign' to container view
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<view
bgcolor
="#ff0000
" width
="${parent.width}
" height
="${this.buttons.refButton.height + 8}
">
<simplelayout
axis
="x
" spacing
="5
"/>
<view
name
="buttons
" valign
="middle
">
<button
name
="refButton
">1
</button
>
<button
>2
</button
>
<button
>3
</button
>
</view
>
</view
>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${(immediateparent.width / 2) - (this.width / 2)}
" onclick
="this.setAttribute('width', this.width + 10);
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
OK, we seem to have lost buttons one and two, but let's come back to that. You'll notice
that we gave the new view a name: "buttons". We also had to change the address to the button's
height from this.refButton.height
to
this.buttons.refButton.height
. This was necessary because
refButton
is now inside buttons
, which is inside the
red view.
Now to get buttons one and two back! In the "buttons" view, there is nothing to tell the
OpenLaszlo Runtime that it should space them out. Why not? Because we forgot to transfer the
<simplelayout>
tag to the buttons
view.
Example 7.12. Using <simplelayout> to align buttons
<canvas
height
="300
" width
="100%
">
<window
x
="20
" y
="20
" width
="200
" height
="250
" title
="Simple Window
" resizable
="true
">
<simplelayout
axis
="y
" spacing
="10
"/>
<view
bgcolor
="#bdbdbd
" width
="${parent.width}
" height
="${this.buttons.refButton.height + 8}
">
<view
name
="buttons
" valign
="middle
">
<simplelayout
axis
="x
" spacing
="5
"/>
<button
name
="refButton
">1
</button
>
<button
>2
</button
>
<button
>3
</button
>
</view
>
</view
>
<text
>Here is some text.
</text
>
<text
>I could ramble for hours.
</text
>
<button
x
="${(immediateparent.width / 2) - (this.width / 2)}
" onclick
="this.setAttribute('width', this.width + 10);
">
My Button
</button
>
</window
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
We changed the color of the view to make it look better.
Copyright © 2002-2010 Laszlo Systems, Inc. All Rights Reserved. Unauthorized use, duplication or distribution is strictly prohibited. This is the proprietary information of Laszlo Systems, Inc. Use is subject to license terms.