Friday, March 25, 2011

Creating dynamically user interfaces with the cWidgets widget

This post will show you: how to create dynamically user's interfaces using the cWidgets widget. This widget will let you create various different widgets like text inputs, buttons, combo boxes , check boxes, option buttons, radio buttons, etc.


The first step to use the cWidgets widget is ensure it is in the HB server. for more info about this read the post titled 'accessing databases with Hummingbird and scripting, part I', section 'uploading a widget to the hummingbird server'.
The cWidgets is visible only at design time.
On this case the page we are working on has the name database4. following is at design time:



database4_1 corresponds to the cWidget and database4_2 is a panel component. The code for the different events next:

imports event:

import mx.collections.ArrayCollection; // we need this to use ArrayCollections
import mx.controls.Alert; // needed if we want to show messages alerts

/*
we will use the next variable to syncronize the creation of
the widget cWidget in database4_1 with the creation of
the panel database4_2
*/
global.flag=0; // this variable will allow us to detect when the widget and the panel are created


// The next are needed for communication with the midleware
import Connection; // needed to connect with the midleware
/*
next we create an connection object and stored it in a global variable (con)
for later use
*/
global.con=page.newConnection();
// loading of the loadPolicy file in order to have acces to the remote call procedures
global.con.loadPolicyFile("http://alex.cl/WebServPortalFlex/crossdomain.xml");
// open the connection to the midleware (made with asp.net)
global.con.openConnection("http://alex.cl/WebServPortalFlex/Gateway.aspx");


database4_1_ready event:

global.flag++;
if (global.flag==2) // the widget and the panel are ready, so we create our interface
create_interface();

database4_2_onCreated event:

global.flag++;
if (global.flag==2) // the widget and the panel are ready, so we create our interface
create_interface();

functions event:

function create_interface()
{
/*
this function create our interface dynamically
*/

// get a reference to the cWidget
var o=page.findObject2("/database4_1");
if (o!=null)
{
// use the cWidget reference to create some objects

// create label 'name' and a textInput
var l1=o.content.application.new_label();
l1.text='Name';l1.x=10;l1.y=10;

var t1=o.content.application.new_textInput();
t1.x=60;t1.y=10;t1.width=150;

// create label 'email' and a textInput
var l2=o.content.application.new_label();
l2.text='Email';l2.x=10;l2.y=40;

var t2=o.content.application.new_textInput();
t2.x=60;t2.y=40;t2.width=150;

// create label 'subject' and a textInput
var l3=o.content.application.new_label();
l3.text='Subject';l3.x=10;l3.y=70;

var t3=o.content.application.new_textInput();
t3.x=60;t3.y=70;t3.width=150;

// create label 'recipient' and a comboBox
var l4=o.content.application.new_label();
l4.text="Recipient";l4.x=10;l4.y=110;

var c1=o.content.application.new_comboBox();
c1.editable=false;
c1.x=70;c1.y=110
var dataP=new ArrayCollection();
dataP.addItem({label:'General',data:'0'});
dataP.addItem({label:'Clients',data:'1'});
dataP.addItem({label:'IT dept.',data:'2'});
c1.dataProvider=dataP;
c1.addEvents("change");
c1.toolTip='select the recipient';
c1.height=20;
// apply some styles to the combo

c1.setStyle("cornerRadius", 4);
c1.setStyle("selectionColor", 0xffcc99);
c1.setStyle("rollOverColor", 0xffcc66);


//pa.addChild(o.content.application.new_checkBox());

// create textArea for the message
var t4=o.content.application.new_textArea();
t4.x=10;t4.y=140;t4.width=200;t4.height=100;

// create a 'send' button
var b1=o.content.application.new_button();
b1.label="Send";
b1.x=10;b1.y=260;
b1.toolTip='press this button to send the message';
b1.id="send";
b1.addEvents("click");

// create a 'clear' button
var b2=o.content.application.new_button();
b2.label="Clear";
b2.x=100;b2.y=260;
b2.toolTip='press this button to clear all the data';
b2.id="clear";
b2.addEvents("click");

// we will add the above objects inside a panel
// we get a reference to the panel
var pa=page.findObject2("/database4_2");
if (pa!=null)
{
// now we add the just created objects to the panel
pa.addChild(l1);
pa.addChild(l2);
pa.addChild(l3);

pa.addChild(t1);
pa.addChild(t2);
pa.addChild(t3);
pa.addChild(l4);
pa.addChild(c1);
pa.addChild(t4);


pa.addChild(b1);
pa.addChild(b2);

/*
save references to texinputs, combobox and textarea into
global variables for use in others events
*/
global.t1=t1;
global.t2=t2;
global.t3=t3;
global.c1=c1;
global.t4=t4;

}

}


} // end of function create_interface


On the above script you must notice the line where i put an id to the buttons and the line using the addEvents method. These lines will allow us work with the click events of the both buttons in order to detect when the user click the 'send' or 'clear' button, like you will see later.

These are all our events for the moment. you can see them on the scripts window next:






At this point you will have the interface, but it don't make anything when the user press the buttons, for that you will need add the next event:

database4_1_buttonClick event:

/*
this event script will be called for all the click events of the
buttons created with the cWidget database4_1
you can identify every button for its id property like showed below
*/

switch(me.id)
{
case 'send':
// send button pressed

var name=global.t1.text;
var email=global.t2.text;
var subject=global.t3.text;
var recipient=global.c1.selectedLabel;
var message=global.t4.text;

// you must validate the data according some criteria

// after validation you proceed to send the message
global.con.call("WebServPortalFlex.servicios.sendMail","serverResponse","serverError",name,email,subject,recipient,message);
break;
case 'clear':
// clear button pressed
global.t1.text="";
global.t2.text="";
global.t3.text=""
global.c1.selectedIndex=0;
global.t4.text="";
break;
}

serverResponse event:

Alert.message("your message was sended");

serverError event:

Alert.message("there was an error trying to send your message");


On the sample showed on this post you must create the midleware code that receive the data from the HB page and send the email, using (on this case) asp.net. if you need more info about creating the midleware layer with asp.net read the post titled "Accessing databases with hummingbird and scripting part II".
A nice thing about locate the interface inside the panel is that you can move the panel with the mouse on the designer, in order to locate all the interface inside it where you want. :)


Wednesday, March 9, 2011

Creating menus with the hb_menuBar widget

This post will show you: how to create dinamically menus using the hb_menuBar widget like showed on the next picture:


The hb_menuBar widget let you create menu bars which contains drop down menus. This menus are defined using a simple xml syntax, and you can control the appearance of the menu using styles.
You can create as many menuBars like you need using the same hb_menuBar widget.

The first step is upload the hb_menuBar widget to the HB server, for an explanation about how to upload a widget read the post entitled 'Accessing databases with Hummingbird and scripting part I' and the section entitled 'Uploading a widget to the Hummingbird server'.

Once you have upload the hb_menuBar widget to the HB server. you must put the widget onto a HB page, like showed on this picture:


On the above image you can see the widget on the upper right corner. This widget is only visible at design time.
The steps to create a menuBar using the hb_menuBar widget:
- get access to the instance of hb_menuBar widget.
- create a new instance of a menu using the instance of the hb_menuBar.
- set the options of the menu with xml using the setXml method of the widget.
- set some properties like the width, height, etc.
- set some styles for the menu in order to change its appearance.
- add the menu instance to a container (using the addChild method) in order to make it visible to the user. this container could be the page object (page.content.addChild) or a panel object that is visible to the user.

following is the code corresponding to every step described:

// get access to the menuBar widget instance
var mb=page.findObject2("/database2_2");
// create a new menu using the hb_menuBar instance
var m=mb.content.application.new_menu();
/*
set the options of the menu into a string variable with xml
in the xml string the 'label' attribute is the text for the menu's option and the 'data' attribute is used to identify the option selected for the user
*/
var menus=''+
' <root>'+
' <menuitem label="Home" data="1"/>'+
' <menuitem label="Products" data="0">'+
' <menuitem label="Cms software" data="2"/>'+
' <menuitem label="CMR" data="3"/>'+
' </menuitem>'+
' <menuitem label="About us" data="0">'+
' <menuitem label="Who we are" data="4"/>'+
' <menuitem label="Clients" data="5"/>'+
' <menuitem label="Partners" data="6"/>'+
' </menuitem>'+
' <menuitem label="Contact" data="0"> '+
' <menuitem label="Send us a message" data="7"/>'+
' <menuitem label="Address" data="8"/>'+
' </menuitem>'+
' </root>';


m.setXml(menus); // pass the xml with the options to the widget

// set the width of the menu to 100 percent of its container
m.percentWidth='100';
//m.height=30; // set the height of the menu

// set some styles for the menu
m.setStyle('cornerRadius', 0);
m.setStyle('letterSpacing', 1);
m.setStyle('fillColors',[0x3333ff, 0x0066ff]);
m.setStyle('rollOverColor',0x0033cc);
m.setStyle('color', 0xffffff);
m.setStyle('textRollOverColor', 0xffffff);
m.setStyle('themeColor', 0x0066ff);
m.setStyle('fontFamily', 'Times New Roman');;
m.setStyle('fontSize', 20);
m.setStyle('fontWeight', 'normal');
m.setStyle('fontStyle', 'italic');
m.setStyle('textIndent', 0);
m.setStyle('borderColor', 0x333399);
m.setStyle('borderStyle','none');
m.setStyle('fillAlphas',[1, 1]);
// we set the background color for the dropdown menus
var ms=new CSSStyleDeclaration(".myMenuBar"); // we create a CSS
ms.setStyle("backgroundColor",0x000000);
//ms.setStyle("backgroundAlpha",0.5);
m.setStyle('menuStyleName',"myMenuBar");


/*
add the menu to a panel, remember that the menu width
will be 100 percent of the width of its container, on this case
the container is the panel
*/
var o=page.findObject2("/database2_3"); // get a reference to the panel
if (o!=null)
{
// if you need center the menu onto the page uncomment the next line
//o.parent.x=page.content.width/2-o.parent.width/2;
o.addChild(m); // add the menuBar to the panel

}


we write the above code in the ready event of the hb_menuBar widget, like showed here:


The reason why we put the above code on the ready event of the widget is this:
Every widget triggers a 'ready' event when is initialized, let say when is just created, so this event is the ideal place to put our code in order to create a widget's instance when the page is just loaded into the user's browser, because that will be the moment when our widget will be created and the 'ready' event will be triggered. You must take into account that the video, the text, the panel and the picture are not widgets, they are built-in components and they don't trigger a 'ready' event, but if you need to execute some code when these built-in components are just created you can use the 'onCreated' event of the built-in component.

after follow the steps described above you will have a nice menuBar on your HB page. But there is a question for resolve and is ¿ how do you execute an action when the user selects an option ?.
This is simple: when the user selects an option the widget will trigger and event called 'menuClick' and it passes to the event a parameter called 'data' which corresponds to the 'data' attribute defined for you on the xml string for the menu. watch the following code located in the menuClick event of the hb_menuBar widget:

/*
this event is triggered when a user makes click on some option
of the menu, every option must have a data property which is passed
to this event in the info.data parameter, so you will know what option
was clicked by watching for this data
*/

if (info.data==0)
return;
// show a little message with the data attribute of the option selected
Alert.show("option choosed:"+info.data);
// now you must exec some action in response to the selected option
switch (info.data)
{
case '1': // home

break;
case '2': // cms software

break;
case '3': // cmr

break;
case '4': // who we are

break;
default: // others options

break;
};

you will see the above code on this picture:


That is, now you have completed all the steps to have a nice menuBar on your page. :)

a nice feature about the menuBar widget is that you can change the options of the menu at runtime, lets say you can add, replace o remove any option of the menu to adapt the menu according some criteria, like for example the perfil of the user that visits the page. You can disable an option using the 'enabled' attribute with a value of false.
On the next picture you can see how using a button labeled 'change menu' we change the options of the menu when the visitor click on the button:


On the above picture you see how we added a last line of code to the 'ready' event of the hb_menuBar widget (database2_2_ready) in order to store a reference to the menu. this reference will allow us modify the menu in other events. On this case we will change the menu's options in the click event of the button 'database2_4' . you can see the code of the event on the next picture:



On the image you can see that using the setXml method of the menuBar with a new set of options the menu is refreshed automatically on the page. watch that we are using the 'enabled' attribute with a value of false to disable the option labeled 'CMR'.
On the next image you can see the menu with the new options set, just after we clicked the 'change menu' button:


A last note above the hb_menuBar widget: you can control the transparency level of the drop down menus, like you see on this picture:



nice :)