Tips_gui   >   Headedlists   >   Headed Lists (All Contents)

Headed Lists

Of the available list objects in the Component Store the Headed List Object is the favorite of most developers.

The headed list box header buttons are clickable (if you enable them), so you can sort the list by the column heading which the user clicks on. See the Sort Column on Header Click topic for a generic sort list method which you can use on any headed list.

You can display whatever list variable column(s) you want in the headed list box, in whatever order you specify. You do not have to create a special list in the correct column order to match what you want to display.

One thing you must clearly understand when working with the headed list object is the difference between the list object and the list variable.

The list object displays to the user data that is stored in the list variable.

In some cases the list object and the list variable are quite tightly tied together. If the user clicks on a line in the headed list object, Omnis Studio immediately sets the current line in the list variable to the same line which the user clicked on in the headed list object. If $multipleselect is set to kTrue when the user selects lines in the headed list object, Omnis Studio immediately set the selected status of the lines in the list variable to match the selected lines in the headed list object.

However, if $multipleselect is set to kFalse, clicking on a line in the headed list object does not changed the selected line(s) in the list variable.

In other cases the list object and the list variable are not tightly tied together. If the user edits text in the headed list object, you the developer have to write code that traps the evHeadedListEditFinished event and copy the pNewText to the correct cell in the list variable.

You must clearly understand the difference between the list object and the list variable when working with headed lists and other list display objects. (Data grid, string grid, complex grid, etc.)

Headed List Runtime Properties

There are a number of headed list object features which can only be set during runtime, that is the list has been or is in the process of being instantiated.

The runtime properties of the headed list are shown in green text in the F6 Property Manager.

To view the runtime properties be sure to have Show runtime properties turned on in the Property Manager. To do so, right-click on the Property Manager window and make sure Show runtime properties has a check mark beside it. Make sure Help tips is checked on as well.

In developer mode, when you click on a headed list object, press F6 to view the Property Manager, select the Methods tab (and others) and note the properties listed in green text. They are the runtime properties. e.g. $setcolumnalign and $columwiths.

Be sure to review the topic Construct Headed List using Notation, it has saved me a lot of time and cut way back on the number of windows in my application.

Headed Lists ... a great feature of Studio!

Columns Displayed

If you have a list variable defined with exactly the columns you want to displayed, in the right order you simply need to enter the list variable name in the $dataname property of the headed list object.

Since that is rarely the case, you would additionally use the $calculation property to specify the columns you want displays and the order you want them displayed by the headed list object.

The $calculation property accepts a tab delimited string of columns. An example might be:

con(iList.Qty,kTab,iList.Desc,kTab,iList.CostPer,...)

Calculated Columns

Headed lists can have calculated columns. If you have a headed list with a Qty column and a CostPer column, you can display a ExtPrice column which is Qty*CostPer. The ExtPrice column does not exist in the list variable, only in the headed list object display. The $calculation property of the list might look like this:

; Set the $calculation property for the list object.
; The 5th column is a calculated column which is not in the list variable.
; Use the jst() function to set the 5th column to display 2dp.
Do irListObj.$calculation.$assign("con(iList.Qty,kTab,iList.Desc,kTab,iList.CostPer,ktab,iList.UM,ktab,jst(iList.Qty*iList.CostPer,'N2'))")
Do $cinst.$redraw()

If we want to sort the list by the calculated ExtPrice column, how do we sort the list? The column doesn't exist in the real list, it is only in the headed list display. Much to my amazement I discovered that OMST's $sort method accepts calculations!

Do iList.$sort(iList.Qty:*iList.CostPer)

Way to go OMST!

Column Alignment

Headed list columns are left justified by default. You can change the column alignment using notation.

Do ListObjRef.$setcolumnalign(ColumnNumber,kAlignment)

kJustify can be:

The alignment constants can be found in the F9 Catalog > Constants tab > Alignment. (kCenterJst, kRightJst, kLeftJst )

If you have a series of columns to set the alignment you can do it in a loop. A handy place to set the column alignment is in the $construct of the headed list object.

; If you have a series of columns to $setcolumnalign, you can do it in a loop.
For %N from 3 to 6 step 1
   Do irListObj.$setcolumnalign(%N,kRightJst)
End For

Column Widths

The column widths are a runtime property which can be set using notation.

Do irListObj.$columnwidths.$assign('50,100,40')

The column widths are in pixels.

You can adjust column widths manually in design mode or you can set the widths in runtime using notation.

Tip

In my applications I save the $columnwidths property for each headed list in each window instance to the user's profile in the database. When the user reopens a window instance the headed list $columnwidths are restored from their user profile.

Multiple Select

In the headed list properties, under the Action tab, there is a property called $multipleselect.

If you set it to kTrue, the user can Shift+click or Ctrl/Cmnd+click on the headed list to select multiple lines.

Warning

When $multipleselect is kFalse, clicking on different lines in the list object does not set or affect the selected lines in the list variable, it only changes the current line in the list variable. This can be confusing for the developer, because even though the current line looks as though it is the selected line in the list, the reality is that a totally different line may or may not be selected in the list variable. To keep things simple I include the following code in the $event method of my headed list object to keep th selected lines in the list variable in sync with the headed list object selected lines.

On evClick
; Multiple select headed list automatically sets the current and selected list line.
; Non-multiple select headed list does not set the current line to selected. This causes
; confusion because the current line looks like it is selected in the headed list object.

; If the list is not $multipleselect, deselect all the list lines, then selected the clicked line.
If not(irListObj.$multipleselect)
   Do iList.$search(kFalse)
   Do iList.[pLineNumber].$selected.$assign(kTrue)
End If

; If there are no lines selected, select the current line.
If iList.$totc(#LSEL)=0
   Do iList.[pLineNumber].$selected.$assign(kTrue)
   Do $cobj.$redraw()
End If

Tip

If the user clicks below the last line in the headed list object, pLineNumber will be the current line in the list.

Show/Hide Columns

The $columnscontextmenu property is a runtime property which can be set using notation. It is a comma separated string of the columns that you wish to allow the user to show/hide by way of a context menu which they can open by right-clicking on any of the column headers.

; Enable the columns context menu for columns 1, 3, & 5.
Do irListObj.$columnscontextmenu.$assign('1,3,5')

If you want to enable the columns context menu for all of the columns you can do a loop for $colcount.

; Enable the columns context menu for all of the columns.
For Count from 1 to irListObj.$colcount step 1
   Calculate CSVString as con(CSVString,',',Count)
End For
Calculate CSVString as trim(CSVString,kTrue,kTrue,',')
Do irListObj.$columnscontextmenu.$assign(CSVString)

The $columnsvisible property is a comma separated string of the currently visible columns. If you want to save and restore the visible columns in the user's profile this is the property you will need to save on $destruct and set on $construct of the headed list object.

Set Sort Column

$setsortcolumn(iColumnnumber,bDescending)

Sets the sort column for the headed list,and whether the direction is ascending or descending. This controls the drawing of the sort arrow. To clear the sort column, pass zero in iColumnnumber.

It appears that only one column can hav the sort arrow, so you can't use this to communicate multi-column sorting.

There doesn't appear to be a property to let you know which column has the sort arrow and whether the arrow is ascending or descending, so if you use the $setsortcolumn method you will need to keep track of the current state of ascending or descending.

Use the evHeaderClick event to trap when the user clicks on the header and pColumnNumber to set the sort column.

; Set the sort column when the user clicks the header.
On evHeaderClick
Do irListObj.$setsortcolumn(pColumnNumber,kFalse) ;; (,Descending)

Be sure to enable the header for the headed list object.

; Enable the columns header.
Do irListObj.$enableheader.$assign(kTrue)

Sort List on Header Click

Outlook Express (and I expect other programs) have the following behavior for headed list column heading clicks:

  1. The list is resorted by the clicked column heading.
  2. The line selected before sorting the list remains the line selected after sorting the list.
  3. If the user clicks twice in a row on a column header the ascending/descending sorting is toggled and the list is resorted.
  4. If the user clicks on a column other than the current sort column, the ascending/descending default for the new column will be the same as the previous column.

The oHeadedList_sort object class has been created to mimic the above behavior for headed lists in Omnis Studio.

Multiple List Sorting

You may want to allow users to do multiple column sorting on headed lists. The user would click one column heading, then click a second column heading, etc. The last column clicked would be the 1st column sort, the 2nd last column clicked the 2nd column sort, etc.

The oHeadedList_sort object supports 3 levels of multiple column sorting.

Communicating to the user multiple column sorting is difficult. Using icons and text the oHeadedList_sort object returns a text string which can be displayed to the user in a headed list footer.

Total, Selected, and Non-Selected Records

Users like to know the total number of records in a list. Sometimes if they selected multiple records in a list, it is nice to know then number of selected and non-selected records.

The oHeadedList_sort object also returns the total, selected, and non-selected records for display in the footer. If there is just 1 record in the list, the text is left blank. If there is just 1 record selected, only the number of records in the list is returned.

Click the Run Demo button in the StudioTips Browser to see a headed list which uses oHeadedList_sort object class.

After you have tested the demo:

  1. Copy the object class oHeadedList_sort to your library.
  2. Copy the headed list and footer message in the demo to a window in your library.
  3. Set the $dataname, $calculation, and other headed list properties for you window class.
Note: If you have more than one headed list in a window class you will need a separate ioHeadedList_sorts instance variable for each headed list. Each instance of oHeadedList_sort can only be used for one headed list.

Edit Text

It is possible to edit the text in a headed list object. In order to use this feature you have to set the $maxeditchars property to a value greater than zero. You either do this under the General tab of the list properties, or you can do it with notation.

; Set the maximum edit characters to allow list text to be edited.
Do irListObj.$maxeditchars.$assign(1000)

Once you have set the $maxeditchars to a value greater than zero the user can click on a line, then click again on a cell. The text in the cell will then become editable.

There are several $event messages which get sent to the headed list object when the user edits a cell. In all of these events pColumnNumber indicates the list object column number, and pLineNumber indicates the list object line number. The events occur in the following order.

  1. evHeadedListEditStarting - The user has started editing a cell. pColumnNumber indicates which column is being edited. You can prevent editing certain columns by discarding the event.

    On evHeadedListEditStarting
    ; Don't allow the user to edit columns 3 or 5.
    If pColumnNumber=3|pColumnNumber=5
       Quit event handler (Discard event)
    End If

  2. evHeadedListEditFinishing - Sent to a headed list box when new text is ready to be stored in the list. The event parameter pNewText is the text entered by the user. You must trap this event and copy the new text to the list variable and redraw the list object if you want the text entered by the user to be saved. This also gives you an opportunity to validate the text entered by the user.

    On evHeadedListEditFinishing
    ; Copy the new text to the list variable and redraw the list object.
    ; The following calculation ONLY works if the list object column numbers
    ; match the list variable column numbers. If not, you need code to map them.
    Calculate iList.C[pColumnNumber] as pNewText
    Do $cobj.$redraw()

  3. evHeadedListEditFinished - Sent to a headed list box when the edit field has been closed.

Construct Headed List Using Notation

I find it a tedious job to tinker around with my mouse and the property manager fine tuning headed lists. You can skip all that by using notation to set everything on the headed list.

In my applications, I have a window class method called $constructHeadedList which is called from the $construct method of the window.

If I want to change anything in the headed list, I simply go to the method $constructHeadedList change the code, and the next time the window is instantiated the change is done. I find that a lot faster than setting the properties in the F6 Property Manager. It also makes it easer to maintain the application later on.

The following sample code give you some ideas on the code you can include in the $constructHeadedList method.

; Set the number of columns
Do irListObj.$colcount.$assign(7)

; Set the column header text
Do irListObj.$columnnames.$assign('Qty,Desc,Cost Per,UM,Ext Price')
Do irListObj.$columnwidths.$assign('75,125,90,65,125') ;; Set the column widths

; Set the column alignment
Do irListObj.$setcolumnalign(1,kRightJst)
Do irListObj.$setcolumnalign(3,kRightJst)
Do irListObj.$setcolumnalign(4,kCenterJst)
Do irListObj.$setcolumnalign(5,kRightJst)

; Set the $calculation property to the correct column names
Calculate String as "con(iList.Qty,kTab,iList.Desc,kTab,iList.CostPer,ktab,iList.UM,ktab,jst(iList.Qty*iList.CostPer,'N2'))"
Do irListObj.$calculation.$assign(String)

; Allow multiple select.
Do irListObj.$multipleselect.$assign(kTrue)

Quit method kTrue

Adding styles() to Headed Lists

The following information is adapted from the Omnis Technical Note TNGI0002 by Nicky Mason.

Styles are used within lists to change the appearance of any cell in one of the Omnis list objects. The objects that can use styles are:

Headed List Boxes, Check List Boxes, List Boxes, Tree Lists

You can change the font style of a particular cell to be bold, italic or underlined on Windows platforms, or set any of the Mac styles, eg. Shadow or outline for Mac platforms. You can change the color of the text and you can even add an icon to the text.

Examples of how to use styles follow, basically the style is embedded within the text, so to add a line to a list, with the first column a normal number and the second with green coloured text, you would use the following code:

Do List.$add(5,con(style(kEscColor,kGreen),'Hello'))

To add an blue dot icon just before the text, you would use the following code:

Do List.$add(5,con(style(kEscBmp,1756),'Hello'))

To change the style of the text, you would use the following :

Do List.$add(5,con(style(kEscStyle,kBold),'Hello'))

To add multiple different styles to some text, you would use the following:

Do List.$add(5,con(style(kEscStyle,kBold),style(kEscBmp,1750),style(kEscColor,kMagenta),'Hello'))

If you wanted to change a line in the list based on a users action, then you could do the
following:

On evDoubleClick
  Calculate List.ColName as con(style(kEscColor,kRed),List.ColName)

Warning


  1. You can only apply styles to kCharacter columns and the number of characters must accomodate the additional style() function characters.

  2. The numeric list has the same style code behind the list, but when a style is applied value changes to zero.

  3. Sorting a list after applying styles doesn't work very well because the style() information is prefixed to the actual data in the list.

  4. Removing styles after they have been applied is not simple because previous style information has to be parsed out.

One solution is to create a display list variable (e.g. iDisplayList') which has the same columns as the real list variable, but all of the columns are kCharacter, then merge the data from the real list variable. Point the list object to the display list variable. Styles can be applied to the display list, leaving the original data list values alone.

Personally, I don't think using styles with the headed list object is a good idea. In my opinion you are better off to use the complex grid object.