Tips   >   Lists   >   Lists

Lists

When you code in Omnis Studio, you should not use the Set current list, #L, #LN, and the other commands that require a current list. Global variables and global methods are not good for object-oriented programming. Code and values which depends on the current list will get you into trouble. This is espcially true with remote forms and multi-tasking.

With object-oriented programming what goes on inside your objects should not be affected by things happening outside of your objects. Set current list, #L, and #LN are global and therefore not a good thing for object-oriented programming.

In the List section I first give you the most common list operations grouped by the types of operations.

The List Notation section lists all the notational list commands in alphabetic order.

List Sendall and Row Sendall are special sections devoted to explaining and demonstration the use of $sendall for lists and rows.

Hope you find this Lists section helpful!

Note

Not all Omnis Studio developers are in agreement with the statements I make in the preceeding section.

There are developers far more experienced than me who state that the Omnis commands are easier to read in the code, faster to type, and execute quicker. (all true)

I admit that remembering and reading the parameters for $search is harder than clicking/reading the checkboxes in the Omnis command Search list. The downside with Search list is you have to first Set current list and doing so you have to be careful that you aren't affecting another method which is depending on the current list. This can be overcome with Begin reversible block and End reversible block ... but then that's 3 more lines of code to allow use of Search list.

The choice is yours. If you like using the Omnis commands, Omnis Studio graciously allows you to do so... but be warned, you are going against object-oriented programming principles if you do.

Define List

There are many ways to define a list in Studio.

The most common methods which I use are:

$definefromsqlclass

Do ListOrRow.$definefromsqlclass([LibName.] TableSchemaOrQueryClassName)
Do ListOrRow.$definefromsqlclass('t_author')
Do ListOrRow.$definefromsqlclass(SchemaOrTableRef)

The list is defined to match all the columns listed in the schema or query class.

Once I got into SQL, $definefromsqlclass became a favourite for me. Fast and easy, a very handy command. If you use table classes (and you should!), $definefromsqlclass binds an instance of the table class to the list/row variable, giving you direct access to all your table class methods from the variable. This is similar to object type variables where the object class is bound to the object type variable.

$cols.$add

Do ListRow.$cols.$add(variable|'ColName' [,kDataType,kDataSubtype,iMaxLen]) Returns ColRef

It took me a while to catch on to this one, but now I use it all the time. You can start with an undefined list or row variable and use $cols.$add to completely define the list.

I used to think figuring out the extra kConstants was too much of a hassle, but now that I found the F9 Catalog > Constants tab > Data type and Data subtypes, it's much quicker and easier to use.

Example: Define a 3 column list.

Do List.$cols.$add('name',kCharacter,kSimplechar,200)
Do List.$cols.$add('total',kInteger,kLongint)
Do List.$cols.$add('Active',kBoolean)

You can also use a variable which you've already defined. The column name becomes the variable name.

Do List.$cols.$add(VarName)

Warning

If you use a local variable, the column name is lost when you leave the scope of the class instance. Because of this, and the fact that I first have to declare the variable, I rarely use a variable with $cols.$add()

You can also use $addbefore, $addafter on $cols.

Do List.$cols.$addbefore(1,'Test',kBoolean)
Do List.$cols.$addafter(2,'Test2',kBoolean)

You can move a column to a new position using the $ident
Do List.$cols.1.$ident.$assign(3)

You can also use $cols.$remove(rCol).
Do List.$cols.$remove(rCol)

Note

Omnis Studio will not let you affect the original coulmns of a list or row defined using $definefromsqlclass. Omnis Studio will ignore $addbefore, $addafter, $ident.$assign, $name.$assign, or $remove if it affects the original columns of a list or row that has been defined using $definefromsqlclass. The reason for this is that SQL statements generated for you by Omnis Studio depend on the original set of columns that are mapped to the schema or query class.

Calculate List1 as List2

This copies the list definition and data from one list to another

You can copy the current row in a list to a row variable.
Calculate Row as List

Warning

If the list is large, Calculate Row as List, is very slow. You are better to Calculate Row as List when the list is empty, and then use Row.$assignrow(List) in your loop.

I use the Calculate Row as List a lot immediately after Do List.$definefromsqlclass('TableClassName'). The Row is also bound to the table class, just the same as the List.

Looping through a list

There are several methods for looping through a list of records using notation. The best ones I've found are listed below.

For looping through all of the lines in a list:

For List.$line from 1 to List.$linecount step 1
  ; The current line is automatically set by the For loop
End For

For looping through the selected lines in a list use $first and $next with the appropriate parameters:

Do List.$first([bOnlySelectedNY,bBackwardsNY])
Do List.$next(LineN,[bOnlySelectedNY,bBackwardsNY])

Do List.$first(kTrue) ;; Only selected lines
While List.$line
  ; The current line is automatically set by $first, then $next
  Do List.$next(0,kTrue) ;; 0=starting with the current line, kTrue=next selected line
End While

You could use $first and $next to loop through all the lines in a list but it is not as fast or as simple as For List.$line from 1 to List.$linecount step 1.

Tip

The Omnis command For each line in list... is still the fastest. If you have a large list (100,000+ lines) and speed is critical you may want to use the Omnis command Set current list in a reversible block and the Omnis command For each line in list to loop through the list.

If you click the Run Demo button in the StudioTips Browser you can compare the performance of the above loops. On my computer the results for looping through the 100,000 line list are as follows:


  • 0.30 seconds - For List.$line
  • 0.45 seconds - $first and $next
  • 0.08 seconds - For each line in list


All of the 100,000 line loops come in under 1 second, so I'm not sure that the end user will notice if you use For List.$line vs. For each line in list.

Moving Lines

Moving a line in the same list can be tricky because the line number of the line your are moving will change if you insert the line higher up the list. Or if you insert the line lower in the list, the position you are moving the line to will be reduce by one after you remove the old line.

The following code could be put into a $moveLineInList method with the appropriate parameters.

; If the "ToLineNum" is less than or equal to the "FromLineNum", then "ToLineNum" must be incremented.
If ToLineNum>=FromLineNum
   Calculate ToLineNum as ToLineNum+1
End If

; If the "FromLineNum" is greater than or equal to the "ToLineNum", then "FromLineNum" must be incremented.
If FromLineNum>=ToLineNum
   Calculate FromLineNum as FromLineNum+1
End If

; Add a line before the "ToLineNum" and immediately assign the "LineFrom" values to the new line.
Do List.$addbefore(ToLineNum).$assignrow(List.[FromLineNum])

; Remove the "FromLineNum" line.
Do List.$remove(FromLineNum)

Set current line

You can set the current line using $line, $search, $first, or $next

Remember that the selected line and the current line are not the same thing, they can be different. You can have 50 lines selected in a list and no current line. You can have a current line and no lines selected.

You can set and get a value from a column in a list without setting the current line, but then you must specify the line number in your calculation.

Calculate Value as List.[LineNum].ColName

If the current line is set, you do not need to specify the line number.

Calculate Value as List.ColName

Be sure to always set the current line before you try to set or get column values. This is an easy mistake to make when you are first learning to use Omnis Studio.

For row variable the one and only row is always the current row, you never need to set the current line for a row variable.

Calculate Value as Row.ColName

$line tells you the current line number in the list. Using $assign you can set the current line.

; Set the current line to the value of LineNum, provided LineNum is between 1 and List.$linecount.
Do List.$line.$assign(LineNum)

; Set the current line to zero. No line selected.
Do List.$line.$assign(0)

; Set the current line to the last line in the list.
Do List.$line.$assign($ref.$linecount)

; Either of the following will tell you the current line.
Calculate %L as List.$line
Do List.$line Returns %L

The $search method with the parameters 1,0,0,0 will set the current line.

; Set the current line to the first line which matches the search criteria.
Do List.$search($ref.ColName=Value,1,0,0,0)

See the topic for $search or Search to Select/Deselect for more information.

The $first method can be used to set the current line in a list.

Do List.$first([kOnlySelectedNY,kBackwardsNY])

; Set current line to the first line in the list.
Do List.$first()

; Set current line to the first selected line in the list.
Do List.$first(kTrue)

; Set current line to the last line in the list.
Do List.$first(kFalse,kTrue)

; Set current line to the last selected line in the list.
Do List.$first(kTrue,kTrue)

The $next method can be used to set the current line in a list.

Do List.$next(LineN,[kOnlySelectedNY,kBackwardsNY])

; Set current line to the next line in the list, starting from the current line
Do List.$next(0)

; Set current line to the next selected line in the list.
Do List.$next(0,kTrue) ;; (From current line, Selected lines)

; Set current line to the next lines in the list, going backwards.
Do List.$next(0,kFalse,kTrue) ;; (From current line, Selected lines, Backwards)

; Set current line to the next selected line in the list, going backwards.
Do List.$next(0,kTrue,kTrue) ;; (From current line, Selected lines, Backwards)


Totals

There are a number of notational commands for totaling columns in a list: $total, $average, $maximum, $minimum

; Total of the values in a column of the list.
Calculate Total as List.$cols.ColName.$total()

; Average of the values in a column of the list.
Calculate Average as List.$cols.ColName.$average()

; Maximum of the values in a column of the list.
Calculate Maximum as List.$cols.ColName.$maximum()

; Minimum of the values in a column of the list.
Calculate Minimum as List.$cols.ColName.$minimum()

; Count the number of non-null values in a column of the list.
Calculate Count as List.$cols.ColName.$count()

; You can add the parameter kTrue to any of the above to include selected lines only.

; Total value of the values in a column of the list, selected lines only.
Calculate Total as List.$cols.ColName.$total(kTrue) ;; (Selected lines)

; Count the number of non-null values in a column of the list, selected lines only.
Calculate Count as List.$cols.ColName.$count(kTrue) ;; (Selected lines)

Use $totc to find the total number of selected lines in list.

; Number of selected lines in a list.
Calculate %N as List.$totc(#LSEL)

Working Message

The Omnis Studio built in Working Message has a number of parameters which allow you to show a progress bar when looping through a list. To show a progress bar in a loop do the following:

  1. On a new line in the method editor, type: Wor, Omnis completes the line for you selecting Working message in the Omnis commands list.
  2. Click the Configure button, this opens a dialog window were you can set various Title properties for your working message.
  3. Click the OK button to accept the default settings. Omnis will enter the default settings in the working message's Title field.

    Working/-1073735824,-1073735820;50;0;60
  4. The syntax for the Title field is as follows:

    Title text/start id,end id;speed;progress bar range;display delay
  5. The F1 Help defines each Title field parameters as follows:
    • start id and end id specify a range of icon ids, which identify the icons drawn in the alternating sequence on the working message window. These are usually negative numbers, as each id is the sum of the icon id and the value of the constant k16x16, k32x32 or k48x48, to indicate the size of the icon. These icons can come from #ICONS for the library, or OmnisPic or UserPic.
    • speed indicates the time, in 1/60th second units, that an icon in the alternating sequence is displayed.
    • progress bar range specifies the range of a progress bar. If you specify a non-zero value, then the working message window displays a progress bar, and each call to the Working message command increases the length of the bar until it reaches the range.
    • display delay specifies the time in 1/60th second units, that must elapse before the working message window becomes visible. This allows you to use the Working message command in situations where the processing is sometimes very rapid, and in that case avoid the message displaying and disappearing almost immediately.
  6. When putting the Working message in a loop, I normally calculate the List.$linecount to a local variable %LN, and the use [%LN] as the progress bar range parameter. (See the sample code in the demo below)
Tip

Note

: You need to include Redraw working message in the loop if you have a variable in the Message field that changes for each cycle through the loop.

Warning

Redraw working message slightly affects performance in a large loop (100,000+ lines). If you evaluated a variable in the working message text it severely affects performance. (as of Omnis Studio 4.2) Click the Run Demo button in the StudioTips Browser to see the speed differences.