![]() |
|
Published 1998-05-01 Printer-friendly version
TopSpeed offers a curriculum of three classes for Clarion: Fundamentals, Essentials, and Mastery. The Fundamentals class shows how to use Clarion to generate systems with little or no coding. Topics covered include creating a dictionary, using the various wizards, and options within the development environment. In a very short time an operational program can be created. The Essentials class builds upon these fundamentals and addresses how to expand the look and feel and functionality of the program. Much of this involves writing code fragments into embed points. Additional topics include DLL development, creating reports, batch processing, using the Windows API, drag and drop, DDE, using OLE and OCX controls, and the debuggers. As one adds more and more embedded code into a system, the time it takes to create a system increases, but the end product can have much more functionality and a more professional look and feel. The Mastery class covers writing your own ABC classes, writing templates, ODBC, Internet Connect and other more advanced topics. One of the goals of this class is to give to developers the speed of Fundamental development with the functionality available through Essentials techniques. This is done through templates.
At a recent Essentials class taught in Detroit we spent a fair amount of time learning which embed points to use and how to change the functionality of the programs we were writing. Towards the end of class, many class members wanted to learn more about templates. Although this is a Mastery class topic, there is an appendix in the Essentials class manual which talks about templates. I asked the class members if they would like me to show them an example. They did. Having received this homework assignment from the students I converted an existing CW2.003 template into an ABC template. The next day I shared it with the class.
#TEMPLATE(WCCG2003,'WCCG Template Fragment 2.003')
#!
#! Written by Don W. Reynolds, World-class Consulting Group
#! Feel free to modify this template, use in your applications
#! but do not sell the template.
#!
#! Template is provided as is.
#! However, under no circumstances should Don W. Reynolds,
#! World-class Consulting Group, or TopSpeed Corporation
#! be held liable for any damages from its use.
#!
#CONTROL(LookupButton2,'Lookup2 coded value'), |
DESCRIPTION('Lookup2 Button for: ' |
& %ExternalKeyField), |
MULTI,WINDOW
#DISPLAY('This is used to set an external key on a child record')
#PROMPT('Select Lookup File',FILE),%LookupFile,REQ
#PROMPT('Select Text Field in Lookup',FIELD(%LookupFile)),|
%LookupTextField,REQ
#PROMPT('Require Entry',Check),%LookupRequire)
#PROMPT('Lookup Procedure',PROCEDURE),%LookupProcedure
#PROMPT('Select Child File',FILE),%ChildFile,REQ
#PROMPT('Select External Key Field',FIELD(%ChildFile)),|
%ExternalKeyField,REQ
#PROMPT('Select Loc Field',FROM(%LocalData)),%LocField,REQ
#PROMPT('Action before lookup',@S255),%ActionBeforeLookup
#PROMPT('Action after lookup',@S255),%ActionAfterLookup
CONTROLS
BUTTON('...'),AT(,,12,12),USE(?FlookupButton),|
MSG('Lookup %LocField')
END
#ATSTART
#DECLARE(%FLookupButton)
#FOR(%Control),|
WHERE(%ControlInstance=%ActiveTemplateInstance)
#SET(%FLookupButton,%Control)
#ENDFOR
#FIX(%Control,%LocField)
#ENDAT
#AT(%AfterWindowOpening)
#COMMENT(46)
IF LocalRequest = ChangeRecord OR |
LocalRequest = DeleteRecord
#FIX(%File,%LookupFile) #! See note 1
#For(%Key),WHERE(%KeyPrimary) #! See note 2
#SELECT(%KeyField,1)
%KeyField = %ExternalKeyField #<! Prime primary key field
#ENDFOR
%ActionBeforeLookup
#IF(%LookupKey)
GET(%LookupFile,%LookupKey)
#ELSE
GET(%LookupFile,%FilePrimaryKey) #<! Get using primary key
#END
IF ERRORCODE()
%LocField = ''
ELSE
%LocField = %LookupTextField
%ActionAfterLookup
END !If
END !If
#ENDAT
#AT(%ControlEventHandling,%FLookupButton,'Accepted')
#INSERT(%LookupCode)
#ENDAT
#AT(%ControlPreEventHandling,'?OK','Accepted')
#IF(%LookupRequired)
IF %LocField = ''
MESSAGE('Missing Required Entry for ' & '%ExternalKeyField')
SELECT(%FLookupButton)
CYCLE
END
#ENDIF
#ENDAT
#GROUP(%Lookupcode)
#COMMENT(46)
GlobalRequest = SelectRecord #<!Set Browse to Select
%ActionBeforeLookup
#FIX(%File,%LookupFile) #! See note1
LU_%File #<!Call Browse as Lookup
%ActionAfterLookup
LocalResponse = GlobalResponse #<!Was Lookup Successful?
IFf LocalResponse = RequestCompleted #<!Yes
#For(%Key),WHERE(%KeyPrimary) #! See note 2
#SELECT(%KeyField,1)
%ExternalKeyField = %KeyField #<! Set external field
#ENDFOR
%LocField = %LookupTextField #<!Set Local field
DISPLAY(?%LocField) #<!Display local field
END
ForceRefresh = True #<!Force Refresh
DO RefreshWindow #<!of Window
#!--------------------------------------------------
#!Notes
#!
#! Note 1 Sets multivalued file to single occurrence
#! identified by LookupFile
#!
#! Note 2 Sets value of keyfield to the first field
#! of the primary key
#!
#! Note 3 Get of file using primary key
#!
#! In order for this template to work, the file must
#! have a primary key
#!
#!--------------------------------------------------
This is a control template usually used on a form. The control, a lookup button with on it, is used when looking up a value from a secondary code file. Usually Clarion restricts relationships between two files to just one relationship. File aliases can provide more. This template is an alternative to multiple aliased files. No relationship between the files needs to be defined in the dictionary, although there is a relationship. The relationship is being managed by the programmer .through this template.
We use this template when we store multiple codes in a single file. The functionality desired is to save the code in the file, but display to the end user the meaning of the code. This keeps the internal codes hidden from the end user. The system appears as if the full text is selected.
When the button is pressed, a previously defined lookup procedure is called. This is usually a browse procedure with a Select button on it. When an entry has been selected, we want to store the description of the code in the local variable were displaying on the screen and store the key value in the file.
We can also specify whether this field is required or not, and add some additional code of our own before and after the call to the lookup procedure. The important thing for this article is not so much what the template does as it is what was required to change the template to be C4 compliant.
#TEMPLATE(Detroit,'Detroit Essentials Template'),FAMILY('ABC')
#!
#! Written by Don W. Reynolds, World-class Consulting Group
#! Feel free to modify this template, use in your applications
#! but do not sell the template.
#!
#! Template is provided as is.
#! However, under no circumstances should Don W. Reynolds,
#! World-class Consulting Group, TopSpeed Corporation
#! be held liable for any damages from its use.
#!
#CONTROL(LookupButton2,'Lookup2 coded value'), |
DESCRIPTION('Lookup2 Button for: ' & %ExternalKeyField),
MULTI,WINDOW
#DISPLAY('This is used to set an external key on a child record')
#PROMPT('Select Lookup File',FILE),%LookupFile,REQ
#PROMPT('Select Text Field in Lookup',FIELD(%LookupFile)),|
%LookupTextField,REQ
#PROMPT('Require Entry',Check),%LookupRequired
#PROMPT('Lookup Procedure',PROCEDURE),%LookupProcedure
#PROMPT('Select Child File',FILE),%ChildFile,REQ
#PROMPT('Select External Key Field',FIELD(%ChildFile)),|
%ExternalKeyField,REQ
#PROMPT('Select Loc Field',FROM(%LocalData)),%LocField,REQ
#PROMPT('Action before lookup',@S255),%ActionBeforeLookup
#PROMPT('Action after lookup',@S255),%ActionAfterLookup
CONTROLS
BUTTON('...'),AT(,,12,12),USE(?FlookupButton),|
MSG('Lookup %LocField')
END
#ATSTART
#DECLARE(%FLookupButton)
#FOR(%Control),|
WHERE(%ControlInstance=%ActiveTemplateInstance)
#SET(%FLookupButton,%Control)
#ENDFOR
#FIX(%Control,%LocField)
#ENDAT
#AT(%WindowManagerMethodCodeSection, 'INIT, (),BYTE')
#COMMENT(46)
IF ThisWindow.Request = ChangeRecord |
OR ThisWindow.Request = DeleteRecord
#FIX(%File,%LookupFile) #! See note 1
#FOR(%Key),WHERE(%KeyPrimary) #! See note 2
#SELECT(%KeyField,1)
%KeyField = %ExternalKeyField #<! Prime primary key field
#ENDFOR
%ActionBeforeLookup
#IF(%LookupKey)
GET(%LookupFile,%LookupKey)
#ELSE
GET(%LookupFile,%FilePrimaryKey) #<! Get using primary key
#END
IF ERRORCODE()
%LocField = ''
ELSE
%LocField = %LookupTextField
%ActionAfterLookup
END !If
END !If
#ENDAT
#AT(%ControlEventHandling,%FLookupButton,'Accepted')
#INSERT(%LookupCode)
#ENDAT
#AT(%ControlPreEventHandling,'?OK','Accepted')
#IF(%LookupRequired)
IF %LocField = ''
MESSAGE('Missing Required Entry for ' |
& '%ExternalKeyField')
SELECT(%FLookupButton)
CYCLE
END
#ENDIF
#ENDAT
#GROUP(%Lookupcode)
#COMMENT(46)
GlobalRequest = SelectRecord #<!Set Browse to Select
%ActionBeforeLookup
#FIX(%File,%LookupFile) #! See note1
%LookupProcedure #<!Call Browse as Lookup
%ActionAfterLookup
ThisWindow.Response = GlobalResponse #<!Was Lookup OK?
IF ThisWindow.Response = RequestCompleted #<!Yes
#FOR(%Key),WHERE(%KeyPrimary) #! See note 2
#SELECT(%KeyField,1)
%ExternalKeyField = %KeyField #<! Set external field
#ENDFOR
%LocField = %LookupTextField #<!Set Local field
DISPLAY(%LocField) #<!Display local field
END !If
ThisWindow.Reset(True) #<!of Window
#!--------------------------------------------------
#!Notes
#!
#! Note 1 Sets multivalued file to single occurrence
#| identified by LookupFile
#!
#! Note 2 Sets value of keyfield to the first field
#| of the primary key
#!
#! Note 3 Get of file using primary key
#!
#! In order for this template to work, the file must
#| have a primary key
#!
#!--------------------------------------------------
#TEMPLATE(Detroit,'Detroit Essentials Template'),FAMILY('ABC')
FAMILY(ABC) now arms this template for use in the ABC template chain.
#AT(%WindowManagerMethodCodeSection, 'INIT, (),BYTE')
#AT(%AfterWindowOpening) in 2.003 changes to #AT(%WindowManagerMethodCodeSection, 'INIT, (),BYTE') in C4
IF ThisWindow.Request = ChangeRecord | OR ThisWindow.Request = DeleteRecord
Localrequest in 2.003 changes to ThisWindow.Request in C4
ThisWindow.Response = GlobalResponse #<!Was Lookup Successful? If ThisWindow.Response = RequestCompleted #<!Yes
LocalResponse in 2.003 changes to ThisWindow.Response in C4
ThisWindow.Reset(True) #<!of Window
ForceRefresh = True in 2.003 changes to ThisWindow.Reset(True)
The above changes involved two types of changes:
Both can be solved with a little effort. Since templates generate code and the code generated by C4 may be different than the code generated from CW2.003 we can use the application converter to do the work for us:
This usually involves the following steps:
WindowManager Method Executable Code Section INIT() ,BYTE
should become
#AT(%WindowManagerMethodExecutableCodeSection, 'INIT, (),BYTE')
However, embed points have an internal name and an external name. The external name is what displays in the embed tree window. Sometimes the internal name and external name are the same, sometimes they are different. In the above case they are different, so I scan through the template sets looking for "WindowManager Method Executable Code Section". I find at line 796 in the ABWindow.tps the following line (all one line in the template code):
#EMBED(%WindowManagerMethodCodeSection,
'WindowManager Method Executable Code Section'),
%pClassMethod,
%pClassMethodPrototype,
WHERE(%MethodEmbedPointValid()),
PREPARE(%FixClassName(%FixBaseClassToUse('Default')))
WindowManager Method Executable Code Section is the external name. WindowManagerMethodCodeSection is the internal name and will be the name I now use for my #AT statement.
#AT(%WindowManagerMethodCodeSection, 'INIT, (),BYTE')
Simple CW2.003 templates can be converted to C4 ABC templates with a little bit of effort. Tools exist to help make these conversions.
Copyright © 1999-2008 by CoveComm Inc. All Rights Reserved. Reproduction in any form without the express written consent of CoveComm Inc., except as described in the subscription agreement, is prohibited.
Clarion Magazine ISSN 1718-9942
One year: $184
(includes all back issues since '99)
Renewals from $134
Two years: $274
Renewals from $224