Hyderabad Jobs Book Website FREE PowerBuilder Training I Love Hyderabad Hyderabad Colleges
Home Business Emails Hyderabad Classifieds Contact Us
7 Wonders of Hyderabad Web Hosting Yellow Pages Our Network

 
Webpowerbuilder.hyderabad-colleges.com

Advanced PowerBuilder

HomePrevious Lesson: Creating a Standard User Object
Next Lesson: External User Objects

Custom User Objects

A custom user object is created by grouping more than one control. For example, in the first version of our "w_product_master" window, we had a series of CommandButtons and a DataWindow control, but by using a custom user object, we could group all of them together. Once we have an object like that, we can use it anywhere in the application.

While painting custom user objects, you can insert another user object, and infact other custom user objects also. This allows us to create any type of user object that we can think of, using objects offered by PowerBuilder, or any of the object that has been customized or inherited from the PowerBuilder parents.

In this session, let us create a custom user object using the CommandButton user object "uo_CommandButton" and user object "uo_DataWindow". The reason we are using the previously created user objects is that we added few functionality that we need to them.

In the above object, we can display items on the left hand side DataWindow and allow the user to select and put the selected items in the basket ( right hand side DataWindow ).

It is based on a simple idea. The user highlights the entries that (s)he is interested in and passes them over to the right hand side of the window. The user can also remove previous selections or pass all of the options from one side to the other at a click of a button. This is very useful because it allows you to include functionality that act upon the entries that appear in the list.

These type of windows are useful for multi-stage selections such as, when defining fields for a query or the sort order the query is supposed to use. You can also use this functionality to add addresses while creating the mail and so on.

Painting the Custom user object

We are going to paint a custom user object "uo_shuffle_rows_between_2_dws". Invoke the user object Painter and select icon and click OK button.

Insert an user object by selecting "Controls/user object" and selecting the user object "uo_DataWindow" from the list and click on the workspace. Name this as "dw_left". Follow the same steps and insert one more, and name it as "dw_right". Make sure that you place it to the right side of "dw_left".

Similarly insert the user object "uo_CommandButton" and place it between two DataWindow controls. Name this as "cb_transfer_to_right". Insert one more and place below the first one and name it "cb_transfer_to_left". Place one more below the "dw_left" DataWindow and name it as "cb_select_all". Place one more below the "dw_right" DataWindow and name it as "cb_deselect_all".

You can see that the ue_shiftclicked event is the ancestor script for the DataWindow control. This is object oriented design working in practice; when you placed uo_DataWindow control in the window, you are creating a new control which is inherited from the uo_DataWindow, that means the new DataWindow controls ( dw_left and dw_right ) gained all the functionality of the previously defined user object ( uo_DataWindow ). This means we don't have to write the same code over and over again.

Creating Functions for the Custom User Object

A function is basically a collection of PowerScript statements, which perform some processing. If you have series of statements that are expected to be used several times in the application then, it makes sense to put them in a function and call the function every time you want to execute those statements.

Functions consist of two distinct components: a function declaration and the actual code. A function declaration defines arguments the function is going to use as variables in the code. The code manipulates the arguments to achieve the required functionality.

We use several functions in this example:
1 f_copyrecord: This is used to copy records between controls.
2 uf_initialize: This is used to initialize the left and right DataWindow Controls and the headings.

We'll look briefly into each of these functions.

Global Function "f_copyrecord"

As with all functions, this function is defined in the Function Painter. Invoke the Function painter and select "New" from the "Select Function" dialog box. Declare the function, as shown in the following picture:

Write the following code:

String lColType
int li_ColCount, li_ColCounter
Long ll_CurrentRow
ll_CurrentRow = pm_destination_dw.InsertRow(0)
li_ColCount = integer( pm_source_dw.Describe( "datawindow.column.count"))
For li_ColCounter = 1 To li_ColCount
   lColType = pm_source_dw.Describe("#" + &
              String( li_ColCounter ) + ".ColType")
   Choose case upper( left( lColType,5))
      Case "CHAR("
           pm_destination_dw.SetItem( ll_CurrentRow, li_ColCounter, &
                 pm_source_dw.GetItemString( pm_row, li_ColCounter ))
      Case "NUMBE","DECIM"
           pm_destination_dw.SetItem( ll_CurrentRow, li_ColCounter, &
                 pm_source_dw.GetItemNumber( pm_row, li_ColCounter ))
      Case "DATE"
           pm_destination_dw.SetItem( ll_CurrentRow, li_ColCounter, &
                 pm_source_dw.GetItemDate( pm_row, li_ColCounter ))
      Case "DATET"
           pm_destination_dw.SetItem( ll_CurrentRow, li_ColCounter, &
                 pm_source_dw.GetItemDateTime( pm_row,li_ColCounter ))
      Case "TIME"
           pm_destination_dw.SetItem( ll_CurrentRow, li_ColCounter, &
                 pm_source_dw.GetItemTime( pm_row, li_ColCounter ))
   End Choose
Next
Return ll_CurrentRow

You can replace the above function with RowsCopy() DataWindow function, available from version 4.0 onwards. We still wrote this code, to expose you to more DataWindow related programming.

This function inserts the row made up from all the columns within the source DataWindow into the destination DataWindow. The arguments for the Describe() function return the total number of columns to the source DataWindow, while the FOR loop determines the data type of the columns. Finally the CASE statement simply calls the appropriate function, depending on the data type, to get the column value and then copies it to the destination DataWindow.
We use the first five characters of the data type to decide which case statement to execute, as it is the minimum number required to give unique values. If we use less than five, we wouldn't be able to distinguish between DATE and DATETIME.

While writing the code, if you want to change the function declaration, you can do so by selecting "Edit/Function Declaration..." from the menu.

We declare the access level as Public so that the function is available to all objects in the application. We don't need to return anything from this function, but we do need to pass three parameters to it, each by value.

You can send any number of parameters to a function, but you have to specify how they are passed; either by value or by reference. This completes the definition of f_copyrecord function.

user object Level Function "uf_initialize"

This is declared at the user object level. Select "Declare/user object Functions". Declare the function as shown below:

The difference between "f_copyrecord" and this function is that, the former one is Global ( available in all objects in the application ) and has "Public" access level. You can't define access level to a global function, it is always "Public". On the other hand, you have the freedom of declaring the access level to functions defined at the ( User ) object level.

We declared this function public because, we want all objects to use this function. This function allows initialization of the user object, which makes the user object more re-usable. we don't return anything from it, but we pass the function arguments by value.

st_left_heading.text = pm_heading_left
st_right_heading.text = pm_heading_right
dw_left.dataobject = pm_DataWindowObject
dw_right.dataobject = pm_DataWindowObject
dw_left.SetTransObject( pm_TransObject )
dw_right.SetTransObject( pm_TransObject )
dw_left.retrieve()

Since this is a reusable object, we neither specified any text for the StaticText controls nor assigned DataWindow objects to   dw_left and dw_right DataWindow controls. To set these controls, we write an initialization function. The function passes the transaction object as a parameter, which makes it flexible, if you are using more than one transaction in an application.

Code for the DataWindow Control

Write the following code for the clicked event of the "dw_left" control:

If Row > 0 Then
   cb_transfer_to_right.Enabled = TRUE
Else
   cb_transfer_to_right.Enabled = FALSE
End If

This simply checks if any rows are selected in the control and enables or disables the "cb_transfer_to_right" CommandButton accordingly. The logic for the other DataWindow control is exactly the same.
The script for both the DataWindows are identical, so, we can implement the script in a function and distinguish between them by passing relevant parameters and then call it from both the DataWindows.

Code for the CommandButton

Write the following code for the "cb_transfer_to_right" CommandButton`s clicked event:

/* Copies all the selected rows to the right side
DataWindow and deletes each row when copied. Later sorts
both the DataWindows on the first column */
Long ll_SelectedRow = 0
string ls_ColName
ll_SelectedRow = dw_left.GetSelectedRow( ll_SelectedRow )
If ll_SelectedRow = 0 Then Return
Do While ll_SelectedRow <> 0
   f_CopyRecord( dw_right, dw_left, ll_SelectedRow )
   dw_left.DeleteRow( ll_SelectedRow )
   ll_SelectedRow = ll_SelectedRow - 1
   ll_SelectedRow = dw_left.GetSelectedRow( ll_SelectedRow )
Loop
ls_ColName = dw_left.Describe("#1.Name")
dw_left.setsort( ls_ColName + " A" )
dw_left.Sort()
ls_ColName = dw_right.Describe("#1.Name")
dw_right.setsort( ls_ColName + " A" )
dw_right.Sort()
If dw_left.rowcount() = 0 Then
   cb_select_all.enabled = False
   cb_transfer_to_right.enabled = False
Else
   cb_select_all.enabled = True
   cb_transfer_to_right.enabled = True
End If
If dw_right.rowcount() = 0 Then
   cb_deselect_all.enabled = False
   cb_transfer_to_left.enabled = False
Else
   cb_deselect_all.enabled = True
   cb_transfer_to_left.enabled = True
End If

In our design, we have allowed the user to select more than one row using the Ctrl and Shift keys, so we have to take care to transfer all the selected rows. GetSelectedRow() gives the next highlighted row after the argument row number and once we know the selected row, we call the f_copy_record function to copy the specified row from the source DataWindow to the destination DataWindow.

Once the row has been copied over, we delete it from the source DataWindow and sort the destination DataWindow on the first column of the DataWindow. The arguments passed to the Describe() function returns the name of the first column in the DataWindow and we use the SetSort() function to specify the sort criteria, before performing the actual sort, using the Sort()function.
Note that, if you haven't specified a sort criteria when using SetSort() and moreover if you haven't set it before, PowerBuilder will prompt for a sort criteria.

Copy the script to the "cb_transfer_to_left" CommandButtons's clicked event. After copying, swap the words "dw_left" and "dw_right" in the code.

// Object: cb_select_all
// Event: Clicked
dw_left.SelectRow( 0, True )
// Object: cb_select_all
// Event: Clicked
dw_right.SelectRow( 0, True )

To test the custom user object, paint a window and place it in the new window. In the new window's open event, write the following code:

uo_1.uf_initialize("Available Products", &
"Selected Products ", "d_test", SQLCA )

We assume that you painted a test DataWindow with tabular presentation style and named it "d_test'. You can take the following data source for the "d_test" DataWindow.

SELECT product_description FROM product_master

Save the window as "w_shuffle_test". Open this window from the Application object's open event. Append the following line of code to the Open event code:

Open( w_shuffle_test )

Once you complete the testing, make sure to remove the code to open this window from the application object's open event.

Now, you can use this custom user object in any window you want, with just a single line of code. This has been a fairly complex example, but you can see that we've made most out of PowerBuilder's object oriented features, and reduced the amount of code we have to write. We've also tried to make the example as generic as possible, so that, you could easily manipulate them for your own applications. You only have to change the database to the one to which you log on and change the DataWindow assignment statements to match the new database.
HomePrevious Lesson: Creating a Standard User Object
Next Lesson: External User Objects

Copyright © 1996 - 2006 HamaraShehar.com Pvt. Ltd. All Rights Reserved.
Domain Registration, Website Design, Website Hosting by HamaraShehar.com