Tips_tutorials   >   Studio104   >   Studio 104 (All Contents)

Introduction

Welcome to the Studio 104 tutorial.

This tutorial is provided to StudioTips Members only. If you are not currently a StudioTips Member please go to www.studiotips.net and click the link provided for becoming a StudioTips Member. The cost of membership is minimal and helps to cover the time and expense of creating these tutorials and maintaining the studiotips.net website.

This tutorial continues from where we left off in the Studio 103 tutorial. In this tutorial we will:

  1. Create a window with a headed list object.
  2. Learn about subwindow fields and how they work.
  3. Create a container window with two subwindows.
  4. Send messages to and from the subwindows.
This tutorial builds on the Studio 103 library. You must complete Studio 101, 102, and 103 prior to starting this tutorial.

Headed List Subwindow

The headed list object is one of my favorite list objects in Omnis Studio. In this section we will create a window which has a headed list object. The window will be generic in design, allowing it to be used as a subwindow to present different data lists.

List Object vs. List Variable

One thing we need to clarify when talking about lists is the difference between a list object and a list variable.

  1. List Variable - A variable with the variable type set to List. The list variable has columns and rows and holds data. The list variable does not present the data to the runtime user. In a window class you normally use an instance variable for any lists you want to display in a list object. For clarity, I normally refer to a list variable as a data list.
  2. List Object - A window field object that is used to display the contents of a list variable to the user. Omnis Studio has numerous list objects: kCheckList, kComplexGrid, kDataGrid, kDroplist, kHeadedListBox, kStringGrid

Create Headed List Window

To create the headed list window class:

  1. F2 Browser > select Contacts library > click New Class > click Window.
  2. Name the window class, wHeadedList.
  3. Right-click on the window class in the F2 Browser and select Methods... in the context menu.
  4. Add the following instance variables in the Variables pane:

    irDataList - Type - Item Reference - used to point the a list variable in the parent window
    irListObj - Type Item Reference - points to the headed list object in this window
    irParent - Type Item Reference - points to the parent window instance
  5. Add a $setParentRef method to the wHeadedList class methods.
  6. Add the parameter, pfrParent - Type - Field Reference to the $setParentRef method.
  7. Add the following code to the $setParentRef method.

    ; Register this window's parent for sending event messages.
    Set reference irParent to pfrParent.$ref
    Quit method kTrue



    Later in this tutorial when the wHeadedList is instantiated as a subwindow, the $setParentRef method will be used by the parent window to register itself as the parent of the child subwindow.
  8. Add a $:ListObjRef property method to the wHeadedList class methods.
  9. Add the following code to the $:ListObjRef method.

    ; Return a reference to the list object.
    Quit method irListObj

  10. Add a $setDataListRef property method to the wHeadedList class methods.
  11. Add the following code to the $setDataListRef method.

    ; Set ivar reference to the data list field.
    Set reference irDataList to pfDataList.$ref

  12. Press F3 to jump from the method editor to the window class editor of the wHeadedList window class.
  13. Press F3 again to open the Component Store palette window.
  14. Drag and drop the Headed List object from the Component Store to the wHeadedList window class.
  15. With the headed list field object selected press F6 to go to the field's properties.
  16. Set the headed field list properties as follows:

    General tab
    $name - HeadedListObj
    $dataname - irDataList
    $top - 20
    $left - 20

    Appearance tab
    $designcolumns - 1
  17. Double-click the headed list object to go to the object's methods.
  18. Add a $construct method to the headed list object and enter the following code in the method:

    ; Set ivar reference to the field.
    Set reference irListObj to $cfield

    ; Expand the field to fill the window class.
    Do $cfield.$edgefloat.$assign(kEFposnClient)



    The $construct window class method code will run when the window is instantiated, just prior to it becoming visible in the display.
  19. Select the $event method of the headed list object and replace the existing code with the following code in the method:

    ; Test to make sure the parent has a recipient method.
    If irParent.$event_HeadedListObj.$cando
       
       ; Forward the event message to the parent.
       Do irParent.$event_HeadedListObj
    End If



    All headed list events will be forwarded to the registered parent, provided that the parent window class has an $event_HeadedListObj method.

Parent Window

A parent window is a window class which contains one or more subwindow fields. The subwindow is considered a child window of the parent window.

A subwindow field is a special window object which allows you to instantiate a window class inside of another window class instance.

A child window knows nothing about the world outside of itself. The child window doesn't even know who its parent is. The parent is responsible to inform the child who its parent is.

Communication between parent and child window instances is accomplished by sending messages via the public class methods of the parent and child windows.

In this section we will create a parent window class with two subwindows. Each subwindow will be an instance of wHeadedList. One subwindow will display a list of the countries, the other subwindow class will display a list of states/provs for the selected country.

Create Parent Window

To create the parent window class:

  1. F2 Browser > select Contacts library > click New Class > click Window.
  2. Name the window class, wCountryStateprovContainer.
  3. Right-click on the window class in the F2 Browser and select Methods... in the context menu.
  4. Add the following instance variables in the Variables pane:

    iCountriesList - Type - List
    iStateprovsList - Type - List
    irswCountries - Type Item Reference - Countries subwindow field
    irswStateprovs - Type Item Reference - Stateprovs subwindow field
  5. Add a constructDefineLists method to the class methods.
  6. Add the following code to the constructDefineLists method.

    ; Define the list binding it to the table class.
    Do iCountriesList.$definefromsqlclass('tCountry')

    ; Set the session object in the list variable so that the SQL statements will be issued to that session's database.
    Do iCountriesList.$sessionobject.$assign($ctask.dbsessionobj)

    ; Define the list binding it to the table class.
    Do iStateprovsList.$definefromsqlclass('tStateprov')

    ; Set the session object in the list variable so that the SQL statements will be issued to that session's database.
    Do iStateprovsList.$sessionobject.$assign(dbsessionobj)

    Quit method kTrue

  7. Add a constructSubWin_Countries method to the class methods.
  8. Add the following code to the constructSubWin_Countries method.

    ; Register this window as the parent.
    Do irswCountries.$setParentRef($cinst) Returns FlagOK
    If FlagOK
       
       ; Set a reference to the data list variable.
       Do irswCountries.$setDataListRef(iCountriesList) Returns FlagOK
       If FlagOK
          
          ; Get a reference to the list object.
          Do irswCountries.$:ListObjRef() Returns rListObj
          
          ; Set the list object properties.
          Do rListObj.$name.$assign('CountriesList')
          Do rListObj.$colcount.$assign(1)
          Do rListObj.$columnnames.$assign('Country')
          Do rListObj.$calculation.$assign('irDataList.CountryName')
          
       End If
    End If
    Quit method FlagOK

  9. Add a constructSubWin_Stateprovs method to the class methods.
  10. Add the following code to the constructSubWin_Stateprovs method.

    ; Register this window as the parent.
    Do irswStateprovs.$setParentRef($cinst) Returns FlagOK
    If FlagOK
       
       ; Set a reference to the data list variable.
       Do irswStateprovs.$setDataListRef(iStateprovsList) Returns FlagOK
       If FlagOK
          
          ; Get a reference to the list object.
          Do irswStateprovs.$:ListObjRef() Returns rListObj
          
          ; Set the list object properties.
          Do rListObj.$name.$assign('StateprovsList')
          Do rListObj.$colcount.$assign(2)
          Do rListObj.$columnnames.$assign('State/Prov,Abbrev')
          Do rListObj.$calculation.$assign('con(irDataList.StateProvName,kTab,irDataList.StateProvAbbrev)')
          
       End If
    End If
    Quit method FlagOK

  11. Add a buildCountriesList method to the class methods.
  12. Add the following code to the buildCountriesList method.

    Do iCountriesList.$getAllRecords() Returns FlagOK
    Quit method FlagOK

  13. Add a buildStateprovsListForCurrCountry method to the class methods.
  14. Add the following code to the buildStateprovsListForCurrCountry method.

    If iCountriesList.$line
       
       ; Fetch the state/prov records linked to the selected country.
       Calculate SQLText as con("WHERE Country_fkey = ",iCountriesList.Country_pkey)
       Do iStateprovsList.$select(SQLText) Returns FlagOK
       If FlagOK
          Do iStateprovsList.$fetch(kFetchAll) Returns FlagOK
       End If
       
       ; Redraw the state/prov subwindow.
       Do irswStateprovs.$redraw()
       
    End If
    Quit method FlagOK

  15. Add the following code to the existing $construct class method.

    Do method constructDefineLists Returns FlagOK

    If FlagOK
       Do method constructSubWin_Countries Returns FlagOK
       
       If FlagOK
          Do method constructSubWin_Stateprovs Returns FlagOK
          
          If FlagOK
             Do method buildCountriesList Returns FlagOK
             
             If FlagOK
                Do method buildStateprovsListForCurrCountry Returns FlagOK
                
             End If
          End If
       End If
    End If
    If not(FlagOK)
       Do errhndlr.$promptonceLastError()
    End If
    Quit method FlagOK

  16. Add an $event_HeadedListObj method to the class methods.
  17. Add the following code to the $event_HeadedListObj method.

    Calculate FlagOK as kTrue ;; Preset flag to true

    Switch low($cobj().$name)
       Case 'countrieslist'
          
          If pEventCode=evClick
             Do method buildStateprovsListForCurrCountry Returns FlagOK
          End If
          
       Case 'stateprovslist'
          
          ; Do nothing.
          
    End Switch
    Quit method FlagOK

Add Subwindow Fields

We will now add the subwindow fields to the wCountryStateprovContainer window class.

  1. If you are still in the window methods editor, press F3 to switch to the window class editor, otherwise double-click on wCountryStateprovContainer in the F2 Browser.
  2. F3 Component Store > drag the Subwindow field onto the window class.
  3. With the subwindow field selected press F6 Property Manager and set the following properties:

    General tab
    $name - swCountries
    $classname - wHeadedList
    $height - 200
    $left - 10
    $top - 10
    $width - 400
  4. Dag another Subwindow field from the Component Store onto the window class.
  5. With the subwindow field selected press F6 Property Manager and set the following properties:

    General tab
    $name - swStateprov
    $classname - wHeadedList
    $height - 200
    $left - 10
    $top - 220
    $width - 400
  6. Double-click the swCountries subwindow field to get to its methods.
  7. Add a $construct method to the swCountries subwindow field and enter the following code:

    Set reference irswCountries to $cfield

  8. Add a $construct method to the swStateprovs subwindow field and enter the following code:

    Set reference irswStateprovs to $cfield

Main Menu

We are just about ready to test the wCountryStateprovContainer window.

In order to open and instance of the window class we will add a menu line to the main menu.

  1. F2 Browser > double-click mMainMenu.
  2. Add a menu line to mMainMenu and set its F6 properties as follows:

    $name - Countries, States/Provinces Browser
    $text - Countries, States/Provinces Browser
  3. Add the following code to the $event method of the menu line.

    ; Find and open an instance of the town/city list window class.
    Calculate ClassName as 'wCountryStateProvContainer'
    Do $clib.$windows.$findname(ClassName) Returns rClass
    If isnull(rClass)
       OK message [sys(85)] (Icon) {Unable to find the window class '[ClassName]'.}
    Else
       Do rClass.$openonce('*') Returns rWin
       If isnull(rWin)
          OK message [sys(85)] (Icon) {Unable to open an instance of the window class [ClassName].}
       End If
    End If
    Quit method rWin

  4. Close the menu class.
  5. Close and reopen the Startup_Task to reinstall the main menu. (F2 Browser > right-click Startup_Task > select Close Task, then right-click again and select Open Task.)

Testing the Parent Window

We are now ready to test the parent window.

  1. Contacts menu > select Counties, States/Provs Browser
  2. All going well and instance of the wCountyStateprovContainer window will be instantiated. The top subwindow will display a list of the countries and the bottom subwindow will display a list of states/provs for the selected country.
  3. If you select a different country, the list of states/provs will be rebuilt to display the states and provinces connected to the country.

Parent Window Sequence of Events

The following is an overview of the sequence of events that occur when the parent window is instantiated.

  1. When the wCountryStateprovContainer window begins to be instantiated, the two subwindow fields are first instantiated in order of the $order field property.
  2. The subwindows fields each open a separate instance of wHeadedList. When the window is instantiated the $construct methods of the window objects are first run. In this case the HeadedListObj $construct method expands the headed list object to fill the available area and sets the ivar irListObj to point to the headed list object.
  3. The $construct class method of wHeadedList runs next, but there isn't any code in the method.
  4. The $construct method of the subwindow fields in wCountryStateprovContainer set the ivars irswCountries and irswStateprovs to point to the respective subwindow fields.
  5. The $construct class method of wCountryStateprovContainer runs next. This method calls a series of private construct methods.
  6. constructDefineLists defines the data list variables iCountriesList and iStateprovsList of wCountryStateprovContainer.
  7. constructSubWin_Countries sends a $setParentRef($cinst) message to the swCountries subwindow field. The subwindow field automatically redirects the message to the window class instance of the subwindow field (wHeadedList). Redirecting messages to the window class instance is a feature of subwindow fields.
  8. The swCountries instance of wHeadedList sets its ivar irParent to point to the instance of wCountryStateprovContainer.
  9. constructSubWin_Countries sends a $setDataList(iCountriesList) message to the swCountries subwindow field which is redirected to its instance of wHeadedList.
  10. The swCountries instance of wHeadedList sets its ivar irDataList to point to the ivar iCountriesList of wCountryStateprovContainer.
  11. constructSubWin_Countries sends a $:ListObjRef message to the swCountries subwindow field which returns a reference to the headed list object.
  12. constructSubWin_Countries sets various properties of the headed list object. ($name, $colcount, $calculation, $columnnames) Additional properties could be set as needed.

    Note

    A better alternative would be to add a public method to wHeadedList for setting the headed list properties. e.g. $setListObjColumns(pDataListColNamesCSV,pColNamesCSV,pColAlignCSV) The method would then parse the CSV strings and set the $colcount, $columnnames, $calculation properties and set the alignment for each column.

  13. constructSubWin_Stateprovs repeats the steps completed by constructSubWin_Countries but for the swStateprovs subwindow field and the iStateprovsList variable.
  14. Finally the $construct class method of wCountryStateprovContainer calls the buildCountriesList method and then the buildStateprovsListForCurrCountry method.
  15. The parent window instance along with its two subwindow instances appears to the user.
  16. When the user clicks on a different country in the countries list, the $event method of wHeadedList sends an $event_HeadedListObj message to the registered parent.
  17. The instance of wCountryStateprovContainer receives the $event_HeadedListObj message, figures out that the message came from the countries list instance of wHeadedList and calls the buildStateprovsListForCurrCountry method which then rebuilds the lista and redraws the state/provs list subwindow.

Summary

Well that wraps up the Studio 104 tutorial.

I hope that this tutorial has helped you with:

  1. Seeing how subwindow fields can be used to open instances of other window classes within a parent window instance.
  2. Understanding how a parent window can send messages to the subwindow field's window instance.
  3. Learning how a subwindow field can store a reference to its parent window and then use that reference to send messages to the parent window.

If this tutorial has been helpful please send an emai to doug@vencor.ca. It's always encouraging to hear from developers who have benefited from these tutorials. Be sure to include any suggestions for improvements or additional topics you would like to see covered.

In the Studio 105 tutorial we will delve into the topic of Observers based on the Observer Design Pattern.

The Studio 105 tutorial is only available to StudioTips Members. Omnis Studio developers are encouraged to become StudioTips Members. The cost of membership is well worth the benefits of being a member.

Visit www.studiotips.net to find out more and to become a StudioTips Member. Your support is greatly appreciated!

Happy coding!

Doug Kuyvenhoven
Vencor Software