Sw4   >   Windows   >   Windows (All Contents)
All window instances in StudioWorks must included in the oWindows master list before you can open an instance of the window. Each module adds their own window instances to the master list. The window instances lists are returned by the $:WindowInstancesList property method of the oWindowList objects.
StudioWorks automatically declares a default list and edit window instance for each schema class in your application. For example if you have a schema class named sAuthor with a server table name Author, StudioWorks will automatically declare the window instances AuthorList and AuthorEdit for you. Each window instance is called a wininstid and must be unique across all modules.
For each default window instance StudioWorks automatically sets its sqlclassname property by searching for a query or schema class based on naming conventions. The following example is for the AuthorList window instance:
You add/modify/delete window instances using the
Tooltips are provided for the various fields (window instance properties) of the located under a tab of the . Instruction are provided in the editor window. If you change any of the properties of a default wininstid you become responsible for all further changes. .attachChangeRecordObserverYou can set default commands to be excecuted when an evOK or evCancel is received by the wShell window.
The wShell window's $event method traps On evOK and On evCancel and sends a $doCmnd(pCmnd) message to the current subwindow. The pCmnd parameter is set as follows:
The $doCmnd method, checks for pCmnd = to 'defaultokay' or 'defaultcancel' and changes the parameter value to the return value of $:DefaultCmnd_evOK or $:DefaultCmnd_evCancel as applicable.
The base window defaults have been set to the following:
You should place your edit fields for any edit type subwindow inside of a kScrollbox object named MainScrollbox. (The exact name and case is important.)
The reason for doing this is to allow the edit fields to scroll independent of the swToolbar subwindow field which is normally at the top of an edit type subwindow.
If we were to set the entire edit subwindow field to scroll, the swToolbar would scroll off the top if user scrolled down the subwindow field. The solution was to put all of the edit fields inside of a kScrollbox field, thereby allowing the user to scroll down the MainScrollbox field without affecting the swToolbar field.
When you wEdit_autoconfig window, StudioWorks automatically adds the MainScrollbox for you and puts the edit fields inside the scrollbox.
aIf you have an edit subwindow that does not scroll when it should, you likely need to add a MainScrollbox field to the subwindow. Here's what to do:
There are several shared module libraries that are included with StudioWorks. You set whether or not to include each library in the $:AppLibsList method of oConstants. (See Configuration > App Libraries List)
When you include a library, the window instances declared by the library's oWindowList object are automatically added to your application's windows list and navigation menus.
You may have a situation where you want to modify or replace a window instance declared by a StudioWorks shared library. Making the change directly in the shared library would be a problem because StudioWorks updates would wipe out your changes.
One technique you can use is to add the exact same WinInstID to the oWindowsList object in your main library or one of your module libraries. For the WinInstID which you add, you would point it to your custom window class.
You then need to remove the shared library WinInstID from the master windows list. You can accomplish this as follows:
; Superclass builds the list of all WinInstIDs.
Do inherited Returns FlagOK
If FlagOK
; Find and remove the shared library WinInstID that is being replaced by a custom WinInstID.
Calculate HomeLibName as 'swContacts4'
Calculate WinInstID as 'PersonEdit'
If iWindowsList.$search($ref.homelibname=HomeLibName&$ref.wininstid=WinInstID,1,0,0,0)
Do iWindowsList.$remove(kListDeleteSelected)
End If
End If
Quit method FlagOK
The StudioWorks field handling classes provides you with the following benefits:
A new field handler structure and classes was introduced in the 2008-03 release of StudioWorks. The new field handling structure and classes make it easier for StudioWorks developers to override and customize field handling. The field handler classes are located in the Field Handling folder of swGui4.
has a module with simple windows that demonstrate various aspects of the field handler. You can shift+click on buttons in the demo windows to look at the code behind the window and step through the field handler code.
The easiest way to control field handling is by setting the
under the section of the .The decorator types supported in StudioWorks are:
The decorator type values can each field are listed in the decoratortype column of the SQL lists columns list. You can get the columns list from a StudioWorks SQL defined list from the $:ColsList property method.
The FieldHandlersFactory_Task provides oFieldHandlerController with a $:TypesList. The list has 4 columns:
For example a clickedit decorator type would have the following values:
The field properties list is a list of all the fields in a window instance which the field handler could be involved with.
The field properties list is defined from sFieldHandlerProperties_listdef. It has the following columns:
A window class can include a field properties list with the $initialize message it sends to oFieldHandlerController. To improve performance oConcretizer builds and stores a field properties list in the $userinfo property of a runtimized window class when it creates it.
If the field properties list is not supplied, oFieldHandlerController builds a list on-the-fly by sending a $retFieldPropertiesList message to the oFieldHandlerPropertiesList object.
If the data list of a window is based on a query class that joins multiple tables any field which is not part of the base schema of the query class is automatically assigned a decoratortype as follows:
When oFieldHandlerController receives an $event message, is searches the field properties list for a matching objident, then based on the current mode, it sends a message to the appropriate field handler object.
You can change the decoratortype for any field, add new fields, or add complex grid exceptions to the field properties list, using the $addsetFieldDecoratorType method of oFieldHandlerController.
You can modify the field properties list by getting it from the field handler controller, modifying the list, and then setting it back to the controller.
See the section on for more details.The current mode affects which field handler object is called to handle a field's events. The handler_new, handler_edit, handler_view columns in the properties list specify which field handler object to use for the appropriate mode.
For a clickedit decorator type the handler_[mode] column values would be as follows:
Each time the mode is set in the window class, the window must send a $setMode(pMode) message to the oFieldHandlerController.
If the value of pMode is different than the controller's current mode, the controller sets its internal iMode state to the specified mode, and then loops through the field properties list sending a $setField message to the appropriate field handler specified in the handler_[iMode] column.
When an $event message is passed to oFieldHandlerController it searches for the current field in the field properties list, and then forwards the message to the field handler type specified in the appropriate handler_[iMode] column.
With the clickedit decorator type example above the oFieldHandlerController will send messages to the following field handlers for the specified modes:
The oFieldHandlerController delegates most of the field handling to field handler objects.
The field handler object naming syntax is: oFieldHandler_type
The following field handler objects can be found in swGui4.
The field handler objects delegate field decoration to field decorator objects.
The field decorator object naming syntax is: oFieldDecorator_type
The following field decorator objects can be found in swGui4.
Normally a field is decorated by setting its $fieldstyle property. There are a series of StudioWorks field styles which you must have in the #STYLES class of your library in order for field decoration to work. The StudioWorks field styles are:
You can use the StudioTips swGui4 to your library's #STYLES class.
utilities to copy the StudioWorks field styles fromComplex grids add a wrinkle to field decoration because you can not set the $fieldstyle for an individual cell. For complex grids we have to set each property separately to change the field decoration of each field. The StudioWorks field styles for complex grids are:
The FieldHandlersFactory_Task is a task class which is used to reduce memory use and improve performance. The StudioWorks field handling structure is based on the flyweight design pattern.
When oFieldHandlerController is initialized it checks for a task instance of the FieldHandlersFactory_Task. If found it uses the existing instance. If not found, it opens an instance.
The FieldHandlersFactory_Task finds and creates a single instance of each oFieldHandler_type object class and a single instance of each oFieldDecorator_type object class. Object reference datatypes are used to ensure that just one instance of each of these object classes is created. The object reference to each of these instances are stored in an iHandlersRow and an iDecoratorsRow in the FieldHandlersFactory_Task.
The handler and decorator type suffix is used for the row column name.
iHandlersRow would have columns named: click, displayonly, lookup, notes, notesdisplay
iDecoratorsRow would have columns named: click, displayonly, hasfocus, normal, notes
When oFieldHandlerController is initialized it gets these rows from the FieldHandlersFactory_Task by sending it a $:HandlersRow message and a $:DecoratorsRow message. Each column in the row has a pointer to the single instance of the respective handler or decorator. All instances of oFieldHandlerController point to the exact same instance of each handler and decorator.
Developers can create their own oFieldHandler_type and oFieldDecorator_type classes in their main library. Handlers and decorators found in the main library take priority over ones by the same name in swGui4. As long as your handler has the same methods and parameters at those found in swGui4 you are free to tweak your handler or decorator code to suit your application's needs.
One potential design flaw in the FieldHandlersFactory_Task is that a single task instance of the factory is used for all StudioWorks applications open under the same instance of Omnis Studio. When a second StudioWorks app is opened it finds and uses the existing task instance of the factory. If the second StudioWorks app has custom field handlers or decorators they will be ignored. The solution is to have each StudioWorks app open its own task instance of the factory. This is relatively easy to implement, but it uses more memory, and will likely never be an issue for 99% of StudioWorks developers.
If you add custom handlers or decorators you need to quit Omnis Studio and reopen it in order to destroy the factory task instance. Just closing and reopening the StudioWorks app won't destroy the factory task instance.
StudioWorks normally decorates fields by changing the $fieldstyle of the field to the appropriate type.
For a click field, the $fieldstyle is set to swFieldNoFocus_click, until the user clicks on the field as which time the $fieldstyle is set to swFieldFocus
Complex grids increase the complexity of field handling because you can not set the $fieldstyle for individual cells of a complex grid. To decorate a field in a cell of complex grid we must set each field property individually, and we must specify the row number in the complex grid for each property we set.
The oFieldHandler_type and oFieldDecorator_type series objects check if the specified field is inside a complex grid and if so, executes complex grid friendly handler and decorator code.
One advantage of the StudioWorks field handling structure is that lookups and notes decorator type fields automatically work in complex grids. This is a big benefit!
The field handler classes are located in the Field Handling folder of swGui4.
The oFieldHandlerController object is instantiated by the ivar ifld in the window instance. There will be one instance of oFieldHandlerController for each window (subwindow) instance.
When the window is instantiated the following sequence of events relating to field handling normally takes place:
Runtimized window have the field properties list stored in the $userinfo property of the runtimized window class.
Note: If you have an On evBefore in the field $event method, the event will not pass to the window's $control method. If you want StudioWorks field handling for the field you must either remove the On evBefore or end it with Quit event handler (Pass to next handler). The same goes for evAfter, evClick, and evKey. For evKey the field or library's $keyevents property must be set to kTrue.
Overriding field handling and decorating is relatively easy. Knowing the sequence of events, you can decide where to best intercept and modify the field handling.
; Set the OrderID field in row 2 of the complex grid to 'displayonly'
; (prField,pDecoratorType,pRowNum_opt)
Do ioFieldHandlerController.$addsetFieldDecoratorType($cinst.$objs.OrderID,'displayonly',2)
; Add a displayonly Status field.
; (prField,pDecoratorType,pRowNum_opt)
Do ioFieldHandlerController.$addsetFieldDecoratorType($cinst.$objs.Status,'displayonly')
; Get the field properties list and add a special 'approved' mode.
Do ioFieldHandlerController.$:FieldPropertiesList() Returns List
Do List.$cols.$add('handler_approved',kCharacter,kSimplechar,50)
; Set the handler to click for any displayonly fields.
Do List.$sendall($ref.handler_approved.$assign('click'),List.handler_edit='displayonly')
; Assign the modified field properties list back to the field handler controller.
Do ioFieldHandlerController.$:FieldPropertiesList.$assign(List)
You can also create additional field handlers and decorators. As long as you following the naming convention syntax for field handlers and decorators, the FieldHandlersFactory_Task will find and add them to the handlers row and the decorators row. If you get to this level of overriding StudioWorks field handling you will likely need to also take over the FieldHandlersFactory_Task. Ask questions via the StudioWorks members list if you get to this stage.
has a module with simple windows that demonstrate various aspects of the field handler. You can shift+click on windows in the demo to look at the code behind the window and step through the field handler code
In a relational database you reduce data duplication by putting similar data into separate tables and linking the data with foreign keys. Rather than storing the same CountryName over and over in the Address table, we store the all the countries in a Country table and then save the primary key of the correct Country record in each record of the Address table.
When the user creates a new Address record and they get to the CountryName field it is helps to provide the user with a list of countries from the Country table. If they type the letter U they appreciate it if you open a droplist of all the countries in the Country table that begin with the letter U. After they select a country, the Country_fkey field needs to be set in the Address record to the primary key of the selected country.
Based on the SQL meta-data the StudioWorks framework can automate all of the above. The StudioWorks tutorial takes you through the basics of setting this up. This section dives into the details of controlling lookups in StudioWorks.
Refs Lookups, a non-linking variation of the above, is also covered in this section.The following meta-data properties are used to control lookups:
There are 3 different locations in the
where you can set lookup meta-data:Lookup fields help the user join a record in the main table to a record in the lookup table. e.g. Address to a Country.
To use the StudioWorks framework lookups you will need an edit query class which joins the main table to the lookup table and includes at least one includeinprompts column from the lookup table. e.g. qAddressEdit which includes all the Address table fields plus the CountryName from the Country table.
When the field handler generates the field properties list is detects any lookup columns in the query class and sets the lookup... properties based on the meta-data.
When the lookup field gets the focus (evBefore) the field handler detects that it is a lookup field and the oFieldHandlerLookupTypeAhead object is asked to handle the field events.
Based on the lookup meta-data the field handler will suggest to the user possible lookup records to choose from based on the characters they type into the lookup field.
There are some special power user tricks built into the lookup field handler:
The developer can intercept the lookup field handler at several locations:
The lookup list is actually a window class, wLookupList, which is positioned directly below the lookup field and made to appear as a droplist.
The oFieldHandlerLookupTypeAhead controls the lookup list.
The lookupsqlclass is used to define and fetch the lookup records list. Only the includeinprompts columns are displayed in the lookup list.The Refs table can be used for non-relational lookups. These would be lookups where you want to copy the lookup list value to the record. You may want to give the user a list of suggested job titles or give the user 3 possible choices to enter for the person's gender. (F=Female, M=Male, Blank=Unknown)
To use the Refs table for lookups you need to create a set of Refs records with the RefsType set to lookup.
The following schema class columns meta-data properties are used to point to the Refs table lookup records which you create:
The RefsSortOrder can be used to controlling the order of the lookup records in the list. The RefsDisplayText and RefsDesc will appear in the lookup list. (If they match, only the RefsDisplayText will appear in the lookup list). The RefsDisplayText will be copied to the actual lookup field.
If you want to permit the user to leave the field empty you need to create a Refs lookup record in your group/subgroup that has the value set to blank.There are several common problems that will stop the lookup field handling from working.
On evBefore
; This traps the evBefore event but fails to pass it to the field handler.
On evAfter
; This traps the evAfter event but fails to pass it to the field handler.
On evBefore
; Do my special custom code.
; Always end with this next line, unless you don't want the field handler to process the event.
Quit event handler (Pass to next handler)
StudioWorks has a field handler object, oFieldHandler, which is responsible for field decoration, enabling and disabling fields, and type-ahead lookups.
The type-ahead lookups field handling is delegated to oFieldHandlerLookupTypeAhead and are discussed under the topic, .
The default field handling for entry fields in StudioWorks is as follows:
Non-standard field handling is accomplished by setting the Display Properties - Decorator Type in the SQL Meta-Data Editor. The decorator types supported are:
The oFieldHandler object is instantiated by the ivar ifld in the window instance which makes use of the field handler. There is one instance of oFieldHandler in each window (subwindow) instance.
When the window is instantiated at the end of the $construct method a $runtimeWinInst message is sent to oConcretizer.
Do conc.$runtimizeWinInst($cinst,iSQLClassName,iWinInstID)
One of the things the concretizer does is generate a list of the fields in the window and the properties for each field based on the SQL meta-data of the SQL class defined from that window. It is a fairly complex operation with the end result of a field properties list that is defined using sFieldProperties_listdef. The field properties list is cached in the $userinfo property of the window instance (or window class for when the window is runtimized)
The field properties list is what drives the field handling behavior.
When the window receives $_setMode message, the $_setMode method sends an $initializeFields message to oFieldHandler.
Do ifld.$initializeFields($cinst,pMode,pSQLClassName,pExtraFieldsList_opt)
The $initializeFields method gets the fields list from $userinfo, if it hasn't already been fetched for the instance, and then proceeds to set the properties of each field in the window for the specified mode.
Each $_setMode message initializes the fields for the specified mode.
When the user enters a field, Omnis Studio sends a $event message to the field. The $event message passes to the $control method of the window class where you will see code which forwards the message to the field handler.
Do ifld.$control($cobj,$cinst,iMode)You can override the field handler properties, or add fields to the field handler. This can be accomplished through the pExtraFieldsList_opt parameter.
The $_setMode methods sends an $initializeFields message to the field handler each time the mode is set.
Do ifld.$initializeFields($cinst,pMode,pSQLClassName,pExtraFieldsList_opt)
You can get an empty fields properties list from the field handler using the $:EmptyFieldPropertiesList method.
The following $_setMode method sample code adds an extra field to the field handler. The field is one from the sSecurityInfoRow_listdef schema class which has added to the wUsrEdit window class.
; Set the mode var.
Calculate $cinst.iMode as pMode
; Add extra fields from the security row.
If iExtraFieldsList.$colcount=0
; Define the field handler extra fields list.
Do ifld.$:EmptyFieldPropertiesList Returns iExtraFieldsList
; Add the 'securitytimeoutminutes' field as a 'clickalways' field.
Do iExtraFieldsList.$add()
Do iExtraFieldsList.$line.$assign($ref.$linecount)
Do $cinst.$objs.$findname('securitytimeoutminutes') Returns rObj
Calculate iExtraFieldsList.objident as rObj.$ident
Calculate iExtraFieldsList.objtype as rObj.$objtype
Calculate Suffix as mid(rObj().$fullname,len($cinst().$fullname)+2)
Calculate iExtraFieldsList.refsuffix as Suffix
Calculate iExtraFieldsList.visible as kTrue
Calculate iExtraFieldsList.focusfieldstyle as 'swFieldFocus'
Calculate iExtraFieldsList.nofocusfieldstyle as 'swFieldNoFocus_click'
Calculate iExtraFieldsList.active as kTrue
Calculate iExtraFieldsList.click as kTrue
Calculate iExtraFieldsList.focusfieldstyle_new as 'swFieldFocus'
Calculate iExtraFieldsList.nofocusfieldstyle_new as 'swFieldNoFocus_click'
Calculate iExtraFieldsList.active_new as kTrue
Calculate iExtraFieldsList.click_new as kTrue
Calculate iExtraFieldsList.focusfieldstyle_view as 'swFieldFocus'
Calculate iExtraFieldsList.nofocusfieldstyle_view as 'swFieldNoFocus_click'
Calculate iExtraFieldsList.active_view as kTrue
Calculate iExtraFieldsList.click_view as kTrue
End If
; Send an $initialFields message to the field handler, to update all the field objects to the new mode.
Do ifld.$initializeFields($cinst,pMode,iExtraFieldsList) Returns FlagOK
If FlagOK
; Update the button menu bar
Do $cinst.$updateActiveCmnds() Returns FlagOK
End If
Quit method FlagOK
The first time the $_setMode method is run it builds the iExtraFieldsList. Each subsequent time it skips directly to sending the $initializeFields message to the field handler.
You can view all of the swField... styles in the #STYLES class of swGui4.
You can view all of the extra fields list columns in the swGui4 > . Hovering of a columm gives you a tooltip with more information.
If you put a breakpoint in the > > $initializeFields method of oFieldHandler you can look at the contents of the iFieldsList to get a sense for what the various properties can be set to.