Tips_gui   >   Misc   >   Misc (All Contents)

Misc

This section is the catchall for topics which don't fit under the other StudioTips - GUI sections.

$hscroll & $vscroll

Various window objects allow you to show a vertical and/or horizontal scrollbar. The properties associated with this capability are $horzscroll and $vertscroll. Setting them to kTrue or kFalse shows or hides the particular scrollbar.

If the user scrolls the object an evHScroll or evVScroll $event message is sent to the object.

The $hscroll and $vscroll properties return an integer value telling you how far the user has scrolled. The integer value is a ratio of 1:8 pixel units. To convert the $hscroll or $vscroll property to pixels use the following calculation:

Calculate Pixels as 8*(ScrollableObjRef.$hscroll-1)
Calculate Pixels as 8*(ScrollableObjRef.$vscroll-1)

Cross-Platform Modifier Keys

Modifier keys

Display ASCII Characters

The chr() function converts an ASCII value to a character. To see a list of all the ASCII characters go to StudioTips > Functions > String Functions > chr() - characters.

Fonts, Field Styles, #STYLES

If you look in the System Classes folder of any libary you will see a #STYLES class and a series of #W*FONTS and #M*FONTS classes.

The Omnis Studio help states that #STYLES supercedes #W*FONTS, #M*FONTS. #STYLES is better because it not only allows you to specify different fonts for different platforms, but it also gives you full control over font size, font style, etc.

Once a style is declared and used in your library, any text which is assigned $fieldstyle is mapped to the row # in the #STYLES table, not the style name! If you change a style name in the table, the style name of all the text in your library which is mapped to that row will immediately change its $fieldstyle name to match the #STYLES style name. (Try it, it's harmless to do, just be sure to change it back.)

If a text related object with a $fieldstyle is copied into your library, Omnis Studio tries to match its name to the existing styles in the #STYLES table, if it finds a match, the $fieldstyle is then mapped to that row. If it doesn't find a matching style, Omnis Studio automatically adds the new style to the next available line in the #STYLES table.

Warning

If you don't have any styles in your library, your styles table will be built in the order that you drag components in. For example if you have an empty #STYLES tables in Library A and B. In Libary A and you first drag in a button object, #STYLES row 1 will be CtrlPushButton. In Library B you drag in an entry field first, row 1 will be CtrlEditText. As you can see, that can get messy if you decide later decide you want the same #STYLES table in all your libraries and you drag a brand new #STYLES class table into your library. If you drag #STYLES from Library A to Library B, the field styles which were mapped to #STYLE row 1, will still be mapped to #STYLE row 1. The $fieldstyles in your library are mapped to the row #, not the name!

To set up custom field styles:

  1. F2 Browser and select the System Classes folder of a library.
  2. Double-click on the #STYLES class to open the Styles window.
  3. The interface is intuitive and the Omnis documentation is clear, so I won't get into more detail.

For each style you can control the properties for All platforms, kMSWindow, kMacintosh (OS9), kUnix (Linux), and kMacOSX.

For any $has... property you set to kTrue in All platforms, the specified property can not be changed at the field level. If the styles says the $textcolor is kBlue and the $hastextcolor setting is set to kTrue, you won't be able to change the $textcolor property for that $fieldstyle at the field level. Change $hastextcolor to kFalse in the #STYLES class for the style, will allow you to change the default $textcolor at the field level.

I recommend that you create your own field styles in the #STYLES class for any special text you want to consistent cross-platform control of the font size and style. Here are some hints when you are doing this:

  1. Think through and set up your #STYLES table very early in developing your application. Otherwise you'll be going back doing a lot of extra clean up work later on.
  2. Don't use font names for your style names.
  3. Set up separate styles for window classes and for report classes. Fonts that work well for window classes, don't necessarily work well for reports, so keep them separate.
  4. Don't get carried away and declare more styles than you need.
  5. Only enforce color or justification on a style if you are sure about the need to control the color or justification.
  6. Use a consistent prefixes for your custom styles. e.g. Prefix all report styles with rprt. This makes it easier to enter the $fieldstyle in design mode with the notation helper.

Here are some field styles to consider for reports:

  1. rprtText - regular report text (Mac/Win:Helvetica 10)
  2. rprtCorrespText - report text for correspondence (Mac/Win:Times New Roman 12)
  3. rprtSmallText - report text for tiny header or footer text (Mac/Win:Helvetica 6)
  4. rprtTitle - report text for report titles (Mac/Win:Helvetica 12 Bold)
  5. rprtSubtitle - report text for for the subtitles (Mac/Win:Helvetica 10)
  6. rprtCompanyName - report text in the style that best suits the company (Mac/Win:Helvetica 12 Bold?)
  7. rprtSpacer - red report spacer (Red color makes spacer fields stand out on the report)
  8. rprtMicroSpacer - red report spacer (Mac/Win:Helvetica 3)

Multiple Monitors

Getting a window to reopen in the same position with multiple monitors on the Mac platforms is a bit tricky.

$modes.$width and $modes.$height returns the width and height of the main monitor (the one with the applications menu bar), ignoring additional monitors.

$modes.$height is the height not including the 22 pixels used by the applications menu bar. For a monitor set to 1200 pixels high, $modes.$height is 1178 pixels.

sys(104) and sys(105) return the overall total width and overall height of all the monitors provided that the main monitor is the left most monitor in your System Preferences > Displays > Arrangement window and the tops of the extra monitors are not above the top of the main monitor.

If a monitor is located to the left of the main monitor is will not be included in the sys(104) width calculation.
If a monitor goes higher than the top of the main monitor the portion above the main monitor will not be included in the sys(105) height calculation.

Tip

You can move the applications menu bar from one monitor to another by dragging it to the other monitor in System Preferences > Displays > Arrangement

If the resolution is different on the 2 monitors (one is 1200 pixels high, the other is 1024 pixels high) it becomes a bit of a guessing game outside of the main monitor where the top and bottom of the additional monitor really is.

If you have a dual monitor setup you can click the Run Demo button in the StudioTips Browser window to find out the current $modes.$width, $modes.$height, sys(104), and sys(105), for your current monitor arrangement. Move the StudioTips Browser window to each of the monitors. The demo will also tell you the top, left, bottom, and right pixel location of the StudioTips Browser window.

In my applications I store the last size and position of each window instance for each user when they close the window. The next time they open the same window instance I restore it to the last size and position. If the user is on a different work station or goes from a multiple monitor setup to a single monitor the window instance may need to be resized and repositioned to fit on the available monitor space.

The sample code that follows checks the size and location of a window instance to make sure the window instance fits within the available monitor(s) and if not, resizes and repositions the window to fit within the available space. You are free to copy the code to your own application.

checkSizeAndFit

The checkSizeAndFit method simply has a switch/case that checks the platform and call the respective checkSizeAndFit submethod.

; Parameter 1: prWinInst - Item Reference - reference to the window instance.

; Check and Size to the window to fit the available screen area.
Switch sys(6)
   Case 'M','X'
      Do method checkSizeAndFit_MacOS (prWinInst) Returns FlagOK
   Default
      Do method checkSizeAndFit_Default (prWinInst) Returns FlagOK
End Switch

Quit method FlagOK

checkSizeAndFit_Default

The checkSizeAndFit_Default method is used for non-Mac platforms. For non-Mac platforms all Omnis window instances exist within the Omnis application space ($modes) so the method does not need to worry about the size and location of multiple monitors.

; Parameter 1: prWinInst - Item Reference - reference to the window instance.

; On Windows and Linux the Omnis application window is the max space.
Calculate AvailWidth as $modes.$width
Calculate AvailHeight as $modes.$height

Set reference rTopLevelFrame to prWinInst.$toplevelhwnd.$ref

; Adjust window size if it doesn't fit the available space.
If rTopLevelFrame.$width>AvailWidth
   Calculate rTopLevelFrame.$width as AvailWidth
End If
If rTopLevelFrame.$height>AvailHeight
   Calculate rTopLevelFrame.$height as AvailHeight
End If

; Reposition window if it is outside the available width.
If rTopLevelFrame.$left+rTopLevelFrame.$width>AvailWidth
   Calculate rTopLevelFrame.$left as AvailWidth-rTopLevelFrame.$width
End If

; If the window is below the available height, move it up.
If rTopLevelFrame.$top+rTopLevelFrame.$height>AvailHeight
   Calculate rTopLevelFrame.$top as AvailHeight-rTopLevelFrame.$height
End If

; Check to make sure the window is not off the top of the main monitor window.
If rTopLevelFrame.$top<0
   Calculate rTopLevelFrame.$top as 0
End If

; Check to make sure the window is not off the left of the main monitor window.
If rTopLevelFrame.$left<0
   Calculate rTopLevelFrame.$left as 0
End If

Quit method kTrue

checkSizeAndFit_MacOS

The checkSizeAndFit_MacOS method is used for the Mac platform. On the Mac platform the Omnis window instances can exist outside of $modes space so the method needs to find out the size and location of external monitors using AppleScript then size and locate the window instance accordinly.

; Parameter 1: prWinInst - Item Reference - reference to the window instance.

; Overall Omnis application space on the Mac platform
; includes extra monitors to the left of the main monitor.

Calculate Width_MainMonitor as $modes.$width
; Note : main monitor height excludes the system bar (53 pixels)
Calculate Height_MainMonitor as $modes.$height

; Get the right bounds of the screen. May not be the whole deal if external on the left !
Calculate AScript as con('tell Application ',chr(34),'Finder',chr(34),chr(13),' set screensize to bounds of window of desktop',chr(13),' set returnval to item 3 of screensize',chr(13),' result',chr(13),'end tell')
Do $runapplescript(AScript,ScriptResult)
Calculate Width_Overall as ScriptResult

; Get the leftmost coordinate. Tells us if the external monitor is on the left (if negative).
Calculate AScript as con('tell Application ',chr(34),'Finder',chr(34),chr(13),' set screensize to bounds of window of desktop',chr(13),' set returnval to item 1 of screensize',chr(13),' result',chr(13),'end tell')
Do $runapplescript(AScript,ScriptResult)

; This takes account of having an external monitor on the left - if it is on the right then leftmost value is 0
Calculate Width_Overall as Width_Overall-ScriptResult

; If the main monitor width is the same as the overall width, we have no external monitor or its
; the same width and exactly on top or underneath - otherwise calculate the left of the external
Calculate ExternalMonitor_Left as pick(Width_MainMonitor<>Width_Overall,0,pick(ScriptResult=0,ScriptResult,Width_MainMonitor+1))
Calculate ExternalMonitor_Width as pick(Width_MainMonitor<>Width_Overall,Width_MainMonitor,pick(ScriptResult=0,-ScriptResult,Width_Overall-Width_MainMonitor))

; Get the height bounds of the screen.
Calculate AScript as con('tell Application ',chr(34),'Finder',chr(34),chr(13),' set screensize to bounds of window of desktop',chr(13),' set returnval to item 4 of screensize',chr(13),' result',chr(13),'end tell')
Do $runapplescript(AScript,ScriptResult)
; Note : if the external monitor is lower then this gives overall height, if higher then this is only the main mon height.
Calculate Height_Overall as ScriptResult

Calculate AScript as con('tell Application ',chr(34),'Finder',chr(34),chr(13),' set screensize to bounds of window of desktop',chr(13),' set returnval to item 2 of screensize',chr(13),' result',chr(13),'end tell')
Do $runapplescript(AScript,ScriptResult)
; Note : we have no way of knowing if the external monitor opens lower down than the main monitor, only if higher (so top is negative).
Calculate ExternalMonitor_Top as pick(Height_MainMonitor<>Height_Overall,0,ScriptResult)

; Note Omnis takes 53 off any value less than 0 but if we are on an external monitor we can put it back as we don't have the system bar!!
If ExternalMonitor_Top<0
   
   ; This corrects the height_overall where external is higher than main monitor
   Calculate Height_Overall as Height_Overall-ExternalMonitor_Top
   Calculate ExternalMonitor_Top as ExternalMonitor_Top-53
   
End If

; Note - we have no way of knowing if the external monitor is less height than the main monitor - only if it is taller
Calculate ExternalMonitor_Height as pick(Height_MainMonitor<>Height_Overall,Height_MainMonitor,Height_Overall)

; Note : the toolbar can be relevant to either main monitor.

Set reference rTopLevelFrame to prWinInst.$toplevelhwnd.$ref

; Make sure that the window's width is no greater than the overal monitor width
If rTopLevelFrame.$width>Width_Overall
   Calculate rTopLevelFrame.$width as Width_Overall
End If

; Make sure that the window's height is no greater than the overal monitor height less the toolbar
If rTopLevelFrame.$height>Height_Overall-Toolbar_Height
   Calculate rTopLevelFrame.$height as Width_Overall
End If

; If the window's left edge is inside the main monitor, use the main monitor as the available height.
If rTopLevelFrame.$left<=Width_MainMonitor&rTopLevelFrame.$left=0
   
   ; Note : the toolbar can be relevant to either main monitor.
   
   If rTopLevelFrame.$height>Height_MainMonitor
      Calculate rTopLevelFrame.$height as Height_MainMonitor
   End If
   
   ; Make sure the top of the window is not off the top of the main window.
   If rTopLevelFrame.$top<Toolbar_Height
      Calculate rTopLevelFrame.$top as Toolbar_Height
   End If
   
   ; Make sure the bottom of the window is not past the bottom edge of the main monitor.
   If rTopLevelFrame.$top+rTopLevelFrame.$height>Height_MainMonitor-Toolbar_Height
      If Height_MainMonitor-Toolbar_Height>rTopLevelFrame.$height
         Calculate rTopLevelFrame.$top as Height_MainMonitor-Toolbar_Height-rTopLevelFrame.$height
      Else
         Calculate rTopLevelFrame.$top as Toolbar_Height
         Calculate rTopLevelFrame.$height as Height_MainMonitor-Toolbar_Height
      End If
   End If
   
Else
   ; The window's left edge is outside of the main monitor, use ExternalMonitor_Height as the available height.
   
   If rTopLevelFrame.$height>ExternalMonitor_Height
      Calculate rTopLevelFrame.$height as ExternalMonitor_Height
   End If
   
   ; Make sure the top of the window is not off the top of the external window.
   If rTopLevelFrame.$top<ExternalMonitor_Top+Toolbar_Height
      Calculate rTopLevelFrame.$top as ExternalMonitor_Top+Toolbar_Height
   End If
   
   ; Make sure the bottom of the window is not off the bottom edge of the available space.
   If rTopLevelFrame.$top+rTopLevelFrame.$height>ExternalMonitor_Height
      If rTopLevelFrame.$height<(ExternalMonitor_Height-Toolbar_Height)
         Calculate rTopLevelFrame.$top as ExternalMonitor_Height-rTopLevelFrame.$height
      Else
         ; The window is larger than the available space, size it to fit.
         Calculate rTopLevelFrame.$top as Toolbar_Height
         Calculate rTopLevelFrame.$height as ExternalMonitor_Height-Toolbar_Height
      End If
      ; If the extra monitor is smaller than the main monitor it could still be off the bottom of the extra monitor
   End If
   
End If

; Make sure the right edge of the window is within the overall width.
Calculate Right as rTopLevelFrame.$left+rTopLevelFrame.$width
; If rTopLevelFrame.$left+rTopLevelFrame.$width>pick(ExternalMonitor_Left<0,Width_Overall,Width_MainMonitor)

If rTopLevelFrame.$left+rTopLevelFrame.$width>pick(ExternalMonitor_Left<0,Width_Overall,Width_MainMonitor)
   Calculate rTopLevelFrame.$left as pick(ExternalMonitor_Left<0,Width_Overall,Width_MainMonitor)-rTopLevelFrame.$width
End If

; Make sure the left of the window is not off the left edge of the available space.
; ExternalMonitor_Left can be less than zero - if it is greater than 0 then 0 is our low point
If rTopLevelFrame.$left<min(0,ExternalMonitor_Left)
   Calculate rTopLevelFrame.$left as min(0,ExternalMonitor_Left)
End If

Quit method kTrue

String Tables

String tables can be used to support multiple languages. String tables are a good discipline to follow, even if you are supporting only one language.

Books on GUI recommend that developers use some sort of a common phrase dictionary for all the labels, titles, prompts, and messages throughout the application. By using a centralized phrase dictionary you are better assured that the same terminology is used for the same things throughout your application. This is especially critical for applications being developed by multiple programmers. The user becomes confused when in one window you refer to the a certain menu as the Application Menu and in another window you refer to it as Main Menu.

String tables could also be used for operating system sensitive terminlogy.
e.g. Mac vs. Win vs. Unix. Ctrl-Click vs. Right-Click

At the time of writing this section in StudioTips, finding the information on String Tables took some effort. Eventually I found a Tech Note on the Omnis web site at: www.omnis.net/develop/resources/notes/technotes.html

You can also download two string table demo libraries from Omnis: strtest.lbs and Table.lbs

This section of StudioTips goes through the information provided in the Tech Note giving demos and suggestion of how to implement String Tables. Each String Table function is listed and explained.

String Table Editor

The String Table Editor is a window interface which Omnis has created to assist developers in creating, editting, and saving String Tables.

To open the String Table Editor look under the Tools menu > Add-Ons > String Table Editor... Look through the File and Tools menus. Hold your mouse of the toolbar buttons to review all the String Table Editor functions that Omnis has provided for you to use.

When you Save a string table, Omnis sorts the table on the ID column just prior to saving it. This is done to speed lookups when the string table is being used.

For editing an existing string table, you have the option of exporting it, editing it in Excel and then importing it. You might find it easier to create your string table in Excel and then import it.

Tip

If you aren't happy with the String Table Editor you can roll your own. Click the Run Demo button in the StudioTips Browser to open the StudioTips custom String Table Editor.

Using String Tables

So, how do you go about using string tables in your own application? Well, as usual there are many ways. Some developers choose to create and store the string tables as lists which are stored in the data file, rather than using actual string table files stored on disk. In that case you would use $loadtablefromlist instead of $loadstringtable.

My own preference at this stage is to save and load the string tables as files.

To keep your string tables manageable, it is recommended that you have separate string tables for various categories. For example you can have separate string tables for:

You should store all the string table files in a separate directory below the main library of your application. For StudioTips I created a string_tables folder located inside the demos folder.

Even if you are currently only developing your application in one language, the use of string tables can be a good discipline for keeping your terminology consistent throughout your application.

String Tables Mapped to Schema Columns

As I was adding labels to the entry fields on a window the idea occurred to me to create a string table for each server table and to use the server table column name as the string table ID column. Every colum in my database would be mapped to a unique string table row.

I have embarked on a mission to create a string table for every SQL table that has data which is displayed on a window or report.

  1. The string table file name is the server table name.
  2. The ID column of the string table is the SQL table column names,
  3. The different language columns contain the exact label wording as I want it displayed in window labels for that column name.

For example, a server table column name of ChequeNumber in the en-US (English-US) column will say Check Number and in the en-GB (English-British) column will say Cheque Number.

In your windows and report instead of entering the actual field label text, you can use a kText field and put the following square bracket notation:

[StringTable.$gettext('SQLTable.ColumnName')]

No further thinking or coding is required! When the window opens the labels will display the correct label text for the language column that was set when the library was opened. If I or my client want to change the label for the server table column LastName from Last Name to Surname ... no problem. Change it in the string table and every place LastName is displayed will be changed from Last Name to Surname.

To speed up creation of string tables which match existing schema classes, I created a String Table Editor which allows you to select a schema class and then using a context menu call a method which builds a string table list with the ID and 1st language column already filled in. You can then edit and save the string table as a file.

StudioTips includes the custom String Tables Editor with the Create String Table from Schema Class feature. Click the Run Demo button in the StudioTips Browser to open the StudioTips custom String Tables Editor.

String Table Labels

Omnis provides a handy String Table Label external component which works well with string tables. You will find the String Table Label in the Component Store under Background Components.

The String Table Label has a property $rowid under the Custom tab where you enter TableName.ID

One alternative is to use "text" background objects and enclose the $gettext function in [square brackets].
Example: [StringTable.$gettext('TableName.ID')]

String Table Column Names

If you are using string tables for supporting various languages, you may want to use the same language abbreviations used by the web browsers. Why bother figuring out codes for the various languages, when there is already a standard being used.

To find out the code, open the Preferences in your web brower and click on the Languages preferences setting. Click on the Add... button, and you will be prompted with a list of languages and their abbreviations.

Warning

Don't include parenthesis () in your string table column names ... the brackets will mess up your notation.

Headed List Column Headings

The headed list $columnnames property doesn't evaluate [] square bracket $gettext notation. One workaround is to build the $columnnames string in the $construct method of the headed list.

Click Run Demo to see how this can be done.

$colcnt

Do StringTable.$colcnt([TableName])

Returns the column count for TableName.

$getcolumnname

Do StringTable.$getcolumnname(TableName)

Gets the column name for the current column.

$getcolumnnumber

Do StringTable.$getcolumnnumber(TableName)

Gets the column number for the current column.

$gettext

Do StringTable.$gettext('[TableName.]ID') Returns Text

Gets the text in the current column of the specified String Table for the row matching ID.

You can use square brackets in a kText label:

[StringTable.$gettext('TableName.ID')]

$loadcolumn

Do StringTable.$loadcolumn(ColumnName,TableName,Path)

Creates a string table file using a single column of an existing string table.

$loadlistfromtable

Do StringTable.$loadlistfromtable(TableName) Returns List

Loads a string table already in memory to a list variable.

$loadstringtable

Do StringTable.$loadstringtable(TableName,Path)

Loads an existing string table into memory from an existing string table file.

Note: If the string table has already been loaded, you must first $unloadstringtable. Trying to load the same string table will result in an error.

$loadtablefromlist

Do StringTable.$loadtablefromlist(TableName,Path,List) Returns ErrCode

Creates a string table from a list variable. It should be noted that the table is created in memory at this point. To save the table, use $savestringtable.

Although this command requires a path, it doesn't actually create the file until you issue the $savestringtable.

If the String Table has already been loaded, you must first $unloadstringtable. Trying to load the same string table will result in an error.

$redraw

Do StringTable.$redraw(WindowInstanceRef.$hwnd)

Redraws the string table labels on an entire window.

Warning

Not including the .$hwnd will cause Omnis Studio to crash. (I know from experience!)

$redrawAll

Redraw all windows after selecting a new string table.

This is not a string table function. This is a method you can create/use for redrawing all the string table labels in all the open windows.

$removestringtable

Do StringTable.$removestringtable(Path)

Deletes a string table stored on disk.

Warning

This function really does delete the string table file!

$rowcnt

Do StringTable.$rowcnt([TableName])

Returns the row count for TableName.

$savestringtable

Do StringTable.$savestringtable(TableName)

Saves a string table which has been previously created.

Note: A path name is not required when saving. Pathnames are only specified when creating string tables.

If you had a new string table in a list, the process of creating the new string table file on disk would be as follows:

; Saving a string table to disk.

; First unload the String Table if it has already been loaded.
Do StringTable.$unloadstringtable(TableName)

; Load the list and path into the String Table to be held in memory.
Do StringTable.$loadtablefromlist(TableName,Path,List)

; The path was loaded into the String Table, so it's already there when you $savestringtable().
Do StringTable.$savestringtable(TableName)

$setcolumn

Do StringTable.$setcolumn([StringTableName.]ColumnName)

Sets the current column to ColumnName. This may be either a name or a number.

Note: ColumnName is case sensitive. If multiple string tables are being used then the format needs to be TableName.ColumnName

Do StringTable.$setcolumn("Table1.French")

or

Do StringTable.$setcolumn("Table1.3")

$unloadall

Do StringTable.$unloadall()

Unloads all string tables from memory.

This function is optional, as all String Tables are automatically unloaded when Omnis quits.

$unloadstringtable

Do StringTable.$unloadstringtable(TableName)

Unloads a string table from memory.

This function is optional, as all string tables are automatically unloaded when Omnis quits.