FAQsTipsTricks
FAQsTipsTricks
www.softvelocity.com
Trademark Acknowledgements:
ii
Table Of Contents
Table of Contents
Common IDE FAQs..............................................................................................................1
Installation and Configuration ........................................................................................................................1
Dictionaries How to... .....................................................................................................................................2
How to Create a Data Dictionary .............................................................................................................2
How to Create a Dictionary (.DCT) File ...................................................................................................3
How to Add Tables to a Dictionary ..........................................................................................................4
How to Add a Table Alias to the Dictionary .............................................................................................4
How to Add Columns to Data Dictionary Tables .....................................................................................5
How to add a column to the end of a GROUP ........................................................................................5
How to Create a Key ...............................................................................................................................6
How to Define Table Relationships and Referential Integrity ..................................................................7
An Alternative Way to do All of the Above ...............................................................................................8
How to Import a File Definition From an Existing Data File .....................................................................9
How to Reorder Dictionary Elements in the Dictionary Editor .................................................................9
Applications - How to.. ................................................................................................................................ 10
How to Create a New Application File .................................................................................................. 10
Converting Applications from Clarion 6 ................................................................................................ 11
Resolving Conversion Issues from C6 to C7 Applications ................................................................... 12
Adding Applications to an Existing Solution ......................................................................................... 14
Project System FAQ ..........................................................................................................15
Project System Quick Start ......................................................................................................................... 15
Converting Topspeed Project Files to MSBuild projects ............................................................................. 16
FAQs 17
Troubleshooting .......................................................................................................................................... 17
General Information .................................................................................................................................... 18
Clarion--Common Questions .................................................................. Error! Bookmark not defined.
Adding Procedure Extensions .............................................................................................................. 18
ActiveX Controls, License Files, and Compound Storage Files ........................................................... 19
Font Support Quick Summary .............................................................................................................. 20
How the Print Engine Processes Report Sections at Runtime ............................................................. 21
Request and Response ........................................................................................................................ 23
How to... ...................................................................................................................................................... 25
Multiple Version Support ...................................................................................................................... 25
Adding Control Templates .................................................................................................................... 25
How to add a reverse sort order to a browse ....................................................................................... 26
How to Add a Toolbar ........................................................................................................................... 27
How to add Column Tool Tips to a List Box ......................................................................................... 30
How to add Drag and Drop to a List Box .............................................................................................. 31
How to Add Embedded Source Code .................................................................................................. 33
How to Add Hot Key Display to a Menu Item ....................................................................................... 37
How to Assign an Image to Display at Runtime ................................................................................... 37
How to Autosize all Columns in a Browse Box when the Window Opens ........................................... 38
How to change the printer device without calling PRINTERDIALOG ................................................... 39
How to Change Your Application's Dictionary ...................................................................................... 40
How to Choose Data Types .................................................................................................................. 41
How to Clip and Concatenate Name Fields ......................................................................................... 42
How to Complete an Entry Field when the Last Character is Entered ................................................. 44
How to Control Page Breaks ................................................................................................................ 45
How to Control the Update Buttons of the Browse Box template ......................................................... 47
How to Convert a File--Generate Source ............................................................................................. 48
How to Convert a File (without generating source) .............................................................................. 50
How to Create a Complex Assignment Expression .............................................................................. 51
iii
FAQs, Tips & Tricks
iv
Table Of Contents
v
Common IDE FAQs
1
Tips, Tricks & FAQs
2
Common IDE FAQs
After either method, above the Dictionary dialog appears. At this time, you can optionally set up the Dictionary Properties
as follows.
1. In the DCT Explorer, press the Dictionary Properties toolbar button located in the DCT Explorer toolbar.
2. On the Comments tab, type the description in the space provided.
The description is solely for your convenience, and has no effect on the application. It is useful when other programmers
take over your project, or for when you return to the project after a long absence.
Your data dictionary file is created. At this point the dictionary is an empty shell. Use the Dictionary dialog to add files,
fields, keys, and file relationships.
3
Tips, Tricks & FAQs
You can also add a new table from the DCT Explorer toolbar if any existing table is selected and you press the Add
button
When using aliases it is best to use a database driver that stores keys internally, such as TopSpeed or Btrieve, to
conserve file handles.
For example, let's say your hospital application has a patient table and a doctor table. A patient has several doctors: an
admitting doctor, a primary doctor, and a surgeon. In database terms, the patient record has three different fields
containing doctor IDs, and all three are linking fields to the doctor table (thus, three relationships between the same two
tables). If you want to automatically display all the patient's doctors on the same window, you need a record buffer for
each link, otherwise, you can show only one doctor at a time--the last one retrieved.
By defining aliases for the doctor table, you can supply additional buffers to hold more than one doctor record at a time.
Do not confuse this with the THREAD attribute for a table. The THREAD attribute provides for a separate record buffer for
each different thread, whereas an alias provides an additional record buffer on the same thread.
When using aliases, you must open the table for shared access.
You can edit the fields and keys for the Alias by pressing the Edit button in the Field or Keys list. The Field and Key Pads
lists the fields and keys for the original table; any changes you make will update the originals.
4
Common IDE FAQs
If you click on the drop down, you can select to add a field to the group or the parent. In the case where the field is at the
end of a group which is itself at the end of a group you have the option to add to the group, the parent group or the parent
of the parent group. The list of options grows as you have more nested groups.
You can also add a field after a group by right clicking on the field at the end of the group.
5
Tips, Tricks & FAQs
6
Common IDE FAQs
7
Tips, Tricks & FAQs
8
Common IDE FAQs
9
Tips, Tricks & FAQs
10
Common IDE FAQs
11
Tips, Tricks & FAQs
This indicates that some WINDOW or REPORT structures may have syntax errors that need to be manually corrected in
the new C7 Application Generator environment. The process is fairly simple.
First, identify the problem procedure. They are clearly marked with the following procedure icon:
Next, access the Window or Report as needed. Highlight the target procedure and press the Window or Report button. If
the Window or Report has a syntax problem, the Designer will not auto-load, and you will be in the appropriate Window or
Report Editor
The Designer button will be disabled. Press the Edit as Text button to correct the converted target structure.
Here is a sample REPORT structure, where the Report Date, Report Time, and Report Page control templates contain an
extraneous USE variable attribute. For example, look at the following structure.
The items highlighted in yellow need to be removed. After doing so, press the Accept button to save and write your
changes:
12
Common IDE FAQs
At this point, the Designer button is now enabled, and you are now ready to access the Window or Report Designers as
needed.
The conversion errors for REPORTs are generally caused by the Report Date, Report Time, and Report Page control
templates. After correcting the structure once, you can copy and paste your corrections to the other similar report
procedures and save time.
In addition after the procedure is saved, you are now able to re-enter the Window Editor or Designer and change the USE
variable field equates as needed.
13
Tips, Tricks & FAQs
14
Common IDE FAQs
For your convenience, we also have included the project system documentation for the versions of Clarion prior to Version
7.
15
Tips, Tricks & FAQs
These messages will then be reported as errors and appear as errors in the error pad within the IDE or as error messages
on the command line if using MSBuild.exe or in the appropriate error place if using any other MSBuild compliant tool to
build the project.
16
FAQs
Troubleshooting
This topic contains some common issues that users may encounter.
Application Generator
Q. When I do a "Generate All" I see the following errors:
ASSERT: %FixClassName: Cannot find class RelationManager
ASSERT: %FixClassName: Cannot find class ViewManager
ASSERT: %FixClassName: Cannot find class FileManager
A. That implies the system is having trouble finding the ABC classes.
Look in Tools->Options->Clarion->Clarion for Windows->Versions
The Directories scanned for ABC Classes dialog lists the directories that the ABC Class reader looks in to find ABC
compliant classes. In previous versions of Clarion, the ABC reader only read the LIBSRC directory. As of Clarion 7, the
ABC reader supports multiple directory locations.
A. You have probably not Generated source yet. Press CTRL + M to Generate and Make(Build) the application.
17
Tips, Tricks & FAQs
General Information
Only Extension templates may be added and deleted using the Extensions button. Control templates may not be added or
deleted, but may be modified. Control templates may be added or deleted from the Window Designer through the
Controls Pad.
18
Clarion 7 FAQs
19
Tips, Tricks & FAQs
title A string constant or variable containing the title to place on the font choice dialog.
If omitted, a default title is supplied by Windows.
control A field number or field equate label for the control to affect. If control is zero (0), it
specifies the WINDOW.
typeface A string constant or variable containing the name of the font. If omitted, the system
font is used.
size A SREAL constant or variable containing the size (in points) of the font. If omitted,
the system default font size is used.
color A SIGNED integer constant or variable containing the red, green, and blue values
for the color of the font in the low-order three bytes, or an EQUATE for a standard
Windows color value. If omitted, black is used.
added An integer constant or variable that specifies adding screen or printer fonts, or
both, to the list of available fonts. Zero (0) adds screen fonts, one (1) adds printer
fonts, and two (2) adds both. If omitted, only Windows registered fonts are listed.
20
Clarion 7 FAQs
Of course, if you're using the Application Generator, you don't even have to write that much! In the example above, the
PRINT statement prints a DETAIL structure for each record in the file retrieved with the NEXT statement inside the LOOP
.
The REPORT data structure contains the items that belong on the page, plus the attributes that determine how they
appear there. Since you visually design these in the Report Designer, the code example above really is all you have to do
to print the report.
The PRINT statement automatically initiates the page overflow handling. This means that when the LOOP goes through
enough records to fill up the page, it automatically generates any other structures on the page--the FOOTER, for example.
Then it sends the entire page to the print spooler.
Order
The parts are wholly contained and managed within the REPORT data structure. The parts of the data structure are the
FORM, PAGE, HEADER, DETAIL, and page FOOTER; their functions are fully described below. The REPORT data
structure may also contain group BREAK structures. Each group BREAK structure can contain its own group HEADER,
DETAIL, and FOOTER.
Normally, you want to design reports with only one DETAIL. When you generate reports using the Application Generator,
they will probably have only one. This usually is the one inside the group BREAK structure. The Report Designer adds a
DETAIL for each BREAK, for flexibility. You can delete the ones not used.
Once you know the order in which the parts generate at print time, you can understand how to use them better. For the
following example, assume a report utilizing all the parts listed above, containing one group structure, with a DETAIL
inside. Immediately upon the PRINT command:
1. The print engine composes the FORM, but does not send it to the print spooler yet. The FORM generates only
once; the application repeats the FORM and does not recompose it for additional pages.
2. The print engine composes the page HEADER.
3. The print engine processes the group HEADER.
21
Tips, Tricks & FAQs
4. The application generates the DETAIL section (within the BREAK) for as many times as will fill the first page,
continuously checking for group BREAKs.
If a BREAK occurs on the page:
5. The print engine composes the group FOOTER for the first group.
6. The print engine composes the group HEADER for the next group.
7. The application generates the DETAIL section for the next group of records, continuously checking for further
group BREAKs.
At the bottom of the page:
8. The print engine checks for widows, increments the page count, and checks the next page for orphans.
9. The print engine composes the page FOOTER.
10. The print engine sends the entire first page to the print spooler.
11. For page two, since the FORM was composed already, it does not get regenerated, though it will print on the
page. The application proceeds directly to the page HEADER.
12. The application repeats the procedures above for this and any additional pages.
Flexibility
The page-oriented nature of the Report Designer is the key to its flexibility. The print engine composes each page in its
entirety before sending it to the printer. This means you may arrange the parts of the report into any page layout you wish.
You can place the FORM, page HEADER, and page FOOTER structures anywhere on the page, within certain limitations.
Their placement does not affect the order that the application generates the parts.
That means you can physically place a page FOOTER above a page HEADER. Since the FOOTER generates only after
the report processes all the records on the page, this allows you, for example, to place a page total above the records on
the page.
You set the position and size of the DETAIL structure as an offset vs. the last DETAIL printed. The print engine prints
each DETAIL from page top to page bottom. If the DETAIL is narrow enough so that more than one fits across the width
of the page, they print in order left to right, top to bottom.
Group BREAK structures--group HEADER, group DETAIL and group FOOTER--all print as offsets within the DETAIL
area, one after the other.
You can do some fancy footwork in cooperation with the print engine. For example, because the DETAIL structure must
be printed with the PRINT statement, you can utilize embedded source to place conditional statements within your
executable code, to print one DETAIL upon one condition, and another upon a different condition.
As long as you remember the order in which the application generates each section, which determines the current record
and the values of the totals, tallies and other operations on the fields in each structure, you can build in a great deal of
flexibility within the REPORT data structure, and let the print engine worry about fitting it all onto the page at runtime.
22
Clarion 7 FAQs
If you are creating an application that consists of more than one AppGen created DLL, you MUST check the "Generate
Internal Global Data as EXTERNAL" check box for all DLLs except one. Likewise, you MUST check the "Generate
Internal Global Data as EXTERNAL" check box for each APP creating an .EXE.
23
Tips, Tricks & FAQs
Enumerated These are primarily to increase readability of the code. The actual
EQUATEs: numbers themselves are inconsequential, with one exception; Request
values less than 0 are reserved for use in multi-page systems.
24
Clarion 7 FAQs
How to...
25
Tips, Tricks & FAQs
To implement a reverse sort order to a template-generated listbox is a simple process of populating a tab, and setting the
conditional behavior using the Additional Sort order option.
26
Clarion 7 FAQs
You may add a toolbar to any window with a simple command in the Window Designer: drag the Toolbar from the
Controls Toolbox. You may place any control on a toolbar, but the ones you will probably use the most are command
buttons, check boxes, radio buttons, and drop down list boxes. As with menus, Clarion will automatically merge toolbars in
certain situations.
Adding a Command Button
The following describes how to add a toolbar with a command button to a window. The starting point is the Window
Designer, open to an empty window:
1. From the Controls Toolbox, drag the Toolbar item to the window area, Releasing the mouse automatically
positions the ToolBar.
A rectangular area appears at the top of the window. This is the toolbar. At runtime, it appears dark gray.
2. Drag the Button in the Controls toolbox, then CLICK inside the new toolbar in the sample window.
A button control appears.
3. RIGHT-CLICK on the button and select Properties from the popup menu, or choose View Properties (or press
the F4 key).
The Properties Pad dialog for the new button appears and is selected.
4. Delete the default text in the Text property.
This allows you to create a picture button without text.
5. Type a descriptive Field Equate Label in the Use property.
For a File/Open button, for example, you might type ?OpenButton. The Field Equate Label will appear in the Embedded
Source dialog, making it easy to identify where to embed source.
6. In the Icon property, choose an icon from the Icon drop down list, or type the name of an icon file (*.ICO) of your
own.
The icon list contains a number of default icons for such standard actions as File/Open, or Cut, Copy, and Paste.
7. Add additional functionality to the button. Modify the STD property and select an STD ID from the drop down list,
or click on the Actions link and embed source code, call a procedure or run a program.
Clarion's . ICO files are 32 x 32 pixels . Most toolbar buttons will be smaller--for example, 16 x 18 pixels. By using these
larger files, we can create the "disabled" icon from the same file, rather than requiring a separate file. When creating a
custom .ICO file for a toolbar button, place the image in the center of the icon file. Clarion automatically crops the image to
fit the button size.
4. In the Select Column dialog, highlight Local Data, then press the New button.
The New Column Properties dialog appears.
5. In the Column Name field, type a name, then choose BYTE from the data type drop down list. Press OK to
accept the new data and return to the Properties Pad.
A button created from a check box control has two modes: on or off. When the check box is 'on' (the button appears
'pushed in'), and the value of its USE variable is one. When the check box is 'off' (the button appears raised), and the
value of its USE variable is zero.
6. From the Icon property, choose an icon from the Icon drop down list, or type the name of an icon file (*.ICO) of
your own.
This is what makes it a "latched button" - placing an ICON on a CHECK control.
7. Clear the Text property if desired, or set the Justification property to LEFT or RIGHT as needed.
The button is complete; you need only adjust its position by dragging its center, if necessary.
28
Clarion 7 FAQs
Adding an icon causes the radio button to look like a command button.
The first button is complete; you need only adjust its position by dragging its center.
10. Repeat steps 5 through 9 for the "center" and "right" buttons.
13. Press CTRL + Q or press from the Window Designer menu to save your window.
Toolbar Merging
Global and Local Tools
The TOOLBAR structure declares the tools displayed for a window. On an APPLICATION window, the TOOLBAR defines
Global tools available to all the windows in the application. However, if the NOMERGE attribute is specified on the
APPLICATION's TOOLBAR, the tools are local and are displayed only when no MDI child windows are open; there are no
global tools. Global tools are active and available on all MDI child windows unless an MDI child window's TOOLBAR
structure has the NOMERGE attribute.
MDI Windows
On an MDI child window, the TOOLBAR defines local tools that are automatically merged onto the Global toolbar. Both
the Global and the local tools are then active while the MDI "child" window has input focus. Once the window loses focus,
its specific tools are removed from the Global toolbar. If the NOMERGE attribute is specified on an MDI child window's
TOOLBAR, the local toolbar replaces the Global toolbar.
Non-MDI Windows
On a non-MDI WINDOW, the TOOLBAR is never merged with the Global menu. A TOOLBAR on a non-MDI window
always appears in the window, not on any parent window which may have been previously opened.
Merging Order
When an MDI window's local TOOLBAR is merged into an application's global TOOLBAR, the global tools appear first,
followed by the local tools. The toolbars are merged so that the tools in the local toolbar begin just right of the position
specified by the value of the width parameter of the global TOOLBAR's AT attribute. The height of the displayed toolbar is
the maximum height of the "tallest" tool, whether global or local. If any part of a control falls below the bottom, the height is
increased accordingly.
To merge toolbars, the global toolbar's AT width must be less than the APPLICATION's frame width.
29
Tips, Tricks & FAQs
The List Box Formatter includes support for column field numbers and individual column (or cell) tool tips.. The
AutoFieldNumber property designates that the field numbering of the selected column will be "standard", based on the
order that it appears in the list box. Setting this property to FALSE allows the field numbering to be modified.
The Tooltip property is used to activate a specific tooltip for the selected column.
Before you can activate individual column tooltips, make sure that you have a tooltip defined for the listbox control. This is
located in the Tip property of the Properties Pad of the selected list box control.
A DefaultColumnTip property, shown on the list box Formatter’s column property pad, is used to designate default text to
be used for the selected column’s tool tip.
It is not necessary to be concerned with the precise syntax of the List Box Format String. Always use the List Box
Formatter to build the string for you. If you are using PROP:FORMAT in your embedded source, you can always cut and
paste your format string from the Formatter as needed.
Associated New Template Symbols
As a result of the new IDE support for List Box Column Tool Tips, the following template symbols have been added.
%ControlHasTip
Similar to symbols like %ControlHasIcon but for per-cell (list box column) tooltip (P modifier)
%ControlFieldHasTip
Similar to symbols like %ControlFieldHasIcon but for per-cell (list box column) tooltip (P modifier)
%ControlFieldDefaultTip
A string value that contains value of the column default tip if it is given, or an empty string otherwise.
30
Clarion 7 FAQs
Drag and Drop capability for lists means the user can select an item in a list box, hold down the left mouse button, "drag"
the item to another control, release the mouse button to "drop" the item on the control, which can look at the data that was
"dropped" on it, and then do something with it.
Adding Drag and Drop to a Clarion list box is a simple operation. This section provides an example of dragging an item
from one list box to another, within the same application. You can also "Drag and Drop" to or from another application--for
example, File Manager.
To implement Drag and Drop, you must add the DRAGID and DROPID attributes to the controls. You can add either or
both to a control. The simplest, quickest way to do this is with Property Syntax statements. Assume for this example that
the field equate labels for the two list boxes are ?FromList and ?ToList. Assume you want the end user to be able to drag
from ?FromList to ?ToList.
Set up ?FromList as a drag host:
1. RIGHT-CLICK on the list control and choose Properties from the popup menu. The Properties Pad is selected.
2. In the DragID property, type FromList
This sets the Drag ID signature which identifies "FromList" as the source of any "drag" operation from this control.
Add drag functionality to the drag host, that is, detect a drag event and provide something to drag and drop:
1. RIGHT-CLICK on the FromList control and choose Embeds from the popup menu.
2. Locate the "Control Event Handling--?Browse:1--Drag" embed point (Clarion Chain) or Control Events – Drag
(ABC Chain) and embed the following code:
This code detects a drag event--at the time the user releases the mouse button over a valid drop target--and places a
string to drag with the SETDROPID function.
You can just as easily use the CHOICE() and GET() functions to retrieve an item from the local QUEUE for the first list
box, then place the item in a global QUEUE. Then, upon detecting a drop event in the second list box, you could ADD
from the global QUEUE to the local QUEUE for the second list box.
Add drop functionality to the drop target, that is, detect a drop event and retrieve whatever was dropped:
3. Set the Priority to 1.
31
Tips, Tricks & FAQs
1. RIGHT-CLICK on the ToList control and choose Embeds from the popup menu.
2. Locate the "Control Event Handling--?Browse:1--Drop embed point (Clarion Chain) or Control Events – Drop
(ABC Chain) and embed the following code:
MyField = DROPID() ! Retrieve the passed string
CallMyProcedure ! Handle the rest in procedure
32
Clarion 7 FAQs
33
Tips, Tricks & FAQs
You may configure the Embeditor's temporary source file with the Application and Editor tabs of the Application Options
dialog. Choose Tools Application Options.
The Embeditor is the Text Editor opened in a special mode which allows you to not only edit all the embed points in your
procedure, but to edit them within the context of template-generated code. The Embeditor displays all possible embed
points for the procedure within the context of all the possible code that may be generated for the procedure. Notice the
distinction here--Embeditor does not show you the code that will be generated, but all the code which could be
generated, if you placed code into every available embed point.
scrolls to the previous embed point; scrolls to the next filled embed point; scrolls to the previous filled embed
point.
3. Place the insertion point in the unshaded area, then type your source code.
The full power of the Text Editor is at your disposal. See the Text Editor help topic for more information.
The Embeditor automatically indents your source code at least as far as the embed point comments. You may indent
farther (to the right), but you may not indent less (to the left).
You may sort the embed points in alphabetical order or in logical order with the Application tab of the Application Options
dialog. Choose Setup Application Options from the menu.
Filter the embed points list by choosing from all available embeds or only "filled" embeds. Locate an embed point by
typing its name in the locator field near the top of the dialog.
You may configure the available list of embed points with the Application tab of the Application Options dialog. Choose
Tools Application Options.
To embed code associated with a specific control, open the Window Designer, RIGHT-CLICK the control and choose
Embeds from the popup menu. Only those embed points associated with the selected control are listed.
2. Select an embed point then press the Insert button.
34
Clarion 7 FAQs
This opens the Select Embed Type dialog. There are three ways to create the embedded source code: hand-coding with
the text editor, calling another procedure, or embedding a Code template.
You may combine one or more of these three methods at a single embed point--that is, a single embed point accepts
multiple "blocks" of embedded code. You can control the execution sequence of each block of code relative to any other
code in the embed point by setting its priority. Lower priority numbers execute before higher priority numbers.
The Embedded Source dialog displays the embedded source in the order it generates and executes.
Don't forget to use the on-line help for explanations and examples of Clarion Language syntax and techniques. Copy and
paste directly from the help examples!
Call a Procedure
1. Select Call a Procedure in the Select Embed Type dialog.
A dialog named for the embed point opens to accept the name of the procedure to call.
2. In the Procedure to Call field, type a name for the procedure or choose an existing procedure from the drop-
down list.
Typing a new name tells the Application Generator to add the procedure to the Application Tree as a "To Do" item. If
another procedure with the same name already exists, the Application Generator generates code to call it.
You define the functionality of the other procedure separately.
3. Press the OK button to close the dialog.
Use a Code template to generate the embedded code
1. In the Select Embed Type dialog, select a Code template then press the Select button.
Code templates are the items indented beneath the Class folders.
This displays a Prompts for... dialog box.
2. Read the instructions and explanations in the dialog.
Each code template includes explanatory text on its proper use and how to fill in the necessary options.
3. Fill in or choose from the options in the Prompts for... dialog.
4. Press the OK button to close the dialog.
35
Tips, Tricks & FAQs
36
Clarion 7 FAQs
The Menu Editor now has built-in support for the following technique.
Many programs have "direct action" Hot Keys assigned to commonly used menu items. The usual way to display these is
aligned to the right in the item's text. Here's the "secret" to aligning the hot keys -- the ASCII tab character (ASCII 9).
Make your menu text look like this:
ITEM('&Customers<9>Alt+F3'),USE(?ViewCustomers),KEY(AltF3)
You can now add this directly to the Menu Editor through the Text property.
The parameter for an IMAGE control cannot accept a variable; however, you can reassign the image to display a runtime
using a property assignment statement.
Insert the following line of source code in the embed point where the assignment will take place.
?Image{PROP:Text} = FileName
Optionally, you can use the DosFileLookup control template to allow a user to select the graphic image from a standard
File Dialog.
37
Tips, Tricks & FAQs
How to Autosize all Columns in a Browse Box when the Window Opens
Auto-sizing of Browse Box columns available from the Global Properties App Settings tab control. At runtime, double-
clicking on a column auto sizes the column to fit the data contents.
There is a simple way to extended this feature and get all the columns in a browse box to autosize when the window
opens.
Set the following property after the browse box is initialized, and after the list box has been populated:
BRWx::AutoSizeColumn.ResizeAll()
where BRWx is equal to the instance of the browse object. A good embed point is the very last embed point provided by
the Window Manager’s Init method:
BRW1::AutoSizeColumn.Init()
BRW1::AutoSizeColumn.AddListBox(?Browse:1,Queue:Browse:1)
! [Priority 9550]
BRW1::AutoSizeColumn.ResizeAll()
! End of "WindowManager Method Executable Code Section"
RETURN ReturnValue
38
Clarion 7 FAQs
To include PRNPROP.CLW:
1. Click on the Global Embeds tab on the Application Tree.
2. Select the After Global INCLUDEs embed point and add the following embedded source code:
include('prnprop.clw')
The device property takes the name of the printer device. This can be found by looking in windows print manager. The
device is the actual printer name. The device property string is case insensitive.
At the end of the report, restore the original default printer:
1. From the Application Tree, select your report procedure and press the Embeds button.
2. Select the ProcessManager Method Executable Code--Close (Priority:7500) embed point and add the following
embedded source code:
PRINTER{PROPPRINT:Device} = sav::printer
39
Tips, Tricks & FAQs
40
Clarion 7 FAQs
ZIP Codes
The DECIMAL data type is very good for zip codes because it's a packed decimal format -- a 9 digit ZIP+4 in a DECIMAL
is 5 bytes of storage while 9 digit zip in a STRING is 10 bytes. This kind of storage savings is a real consideration when
you're setting up a large database. Since there is no math to perform on ZIP codes, storage is generally a larger
consideration than performance.
Phone Numbers
The DECIMAL data type is also very good for non-international phone numbers, for the same reasons as ZIP codes.
Since you're dealing only with phone numbers in your own country, you should be able to define the exact number of
digits and format to display. For U.S. numbers, you can store the area code separately from the phone number -- use a
SHORT for the area code (3 digits in 2 bytes) and a LONG for the phone number (7 digits in 4 bytes) -- and achieve the
same storage as a single DECIMAL(10,0) (10 digits in 6 bytes).
If your program must deal with international phone numbers, the best data type is a STRING, because the most common
method of indicating the country code is with a plus sign (+). For example, +44 (0)800 555 1212 indicates country code 44
(the United Kingdom). You should make the STRING at least 19 characters, since the number of digits in the number can
vary from country to country, and even within separate sections of the same country.
"Customer" Numbers
"Customer" Number is defined for this discussion as: any internal number in your program used primarily as the linking
field between Parent and Child files.
LONG is the most common data type used for internal numbering for linking purposes. It is very efficient for both storage
(4 bytes) and execution (it is one of the base data types used internally by the Clarion libraries – see Base Types in the
Language Reference). Any KEY based on a single LONG field is very efficient and small on the disk, since it will require
fewer key node splits than a KEY based on a longer STRING (like the "customer" name).
Money
The best data type for any field that will store money values is DECIMAL. Using DECIMAL provides the most efficient
storage, since it is a packed-decimal format. It also provides Binary Coded Decimal (BCD) math functionality, which
means that calculations are executed in Base 10 instead of Binary (as it would if you use REAL). Using BCD math
eliminates the rounding and significant digit problems that you can encounter when you use any of the floating point data
types (REAL, SREAL, BFLOAT4, BFLOAT 8).
41
Tips, Tricks & FAQs
& ', ' & CLIP(FirstNameField) & ' ' & (MiddleInitialField) & '.'
42
Clarion 7 FAQs
Where FirstNameField is the first name field in your report file, and MiddleInitialField is the initial field in your report file.
Steps 5 - 7 show how you may type your expression, or use the Formula Editor buttons to choose valid operands and
operators.
9. Press the Check button to check your expression syntax.
A green check appears if syntax is correct, otherwise a red X appears.
10. Press to exit the Formula Editor, and again in the Procedure Properties to return to the Application Tree.
43
Tips, Tricks & FAQs
In Clarion's older DOS products, an entry field with the immediate attribute (IMM) was automatically completed when the
last character was typed. In Clarion, the IMM attribute behaves differently. In Clarion, an entry field with the IMM attribute
generates an Event:NewSelection as each character is typed.
To mimic the behavior of the Clarion DOS products, a few lines of embedded source code are needed.
In the Window Designer:
1. RIGHT-CLICK on the control, then select Properties to open the Properties Pad.
2. Set the Immediate property to TRUE.
3. RIGHT-CLICK on the control and select Embeds to access the Embedded Source dialog.
4. Select the Control Event Handling--Event:NewSelection embed point for the control, then press the Insert button.
This embed point will only appear after you have checked the Immediate box.
5. Select SOURCE and type one of the following code segments in the Embedded Source Code Point:
Use this code if the field is a string:
UPDATE(?PRE:FieldName)
IF LEN(CLIP(PRE:FieldName)) = SIZE(PRE:FieldName) AND KEYCODE()<> MouseLeft
! use size of -1 with CSTRING or PSTRING
SELECT(?+1)
END !IF
Use this code if the field is any non-string numeric data type:
UPDATE(?PRE:FieldName)
Str" = PRE:FieldName
IF LEN(CLIP(Str") = 5 AND KEYCODE() <> MouseLeft
SELECT(?+1)
END !IF
In this example the value of the field is assigned to an implicit string variable (Str") so that its length can be determined. Its
length is compared to a constant number (in this case 5) instead of using the SIZE function. Since SIZE() returns the
number of BYTES in the Use variable, it is not a valid comparison for numeric data types.
6. Set the Priority to 2500.
This example does not handle leading zeros. If your data can contains leading zeros, you will have to modify the
embedded source code to handle them.
44
Clarion 7 FAQs
PAGEAFTER
To print the DETAIL, then force a new page, highlight the Detail, and type a value in the PageAfter property in the
Properties Pad dialog. This sets the PAGEAFTER attribute. This prints the DETAIL, then prints the page FOOTER, then
begins a new page.
To print a separate page for each record, place the variable strings and/or controls you wish in the DETAIL, and specify
the PAGEAFTER attribute in the Detail Properties dialog.
The page number automatically increments, unless you reset it. To reset the page number to a value you specify, type it
in the PageAfter property in the Detail’s Properties Pad dialog.
PAGEBEFORE
To print the DETAIL structure on a new page, highlight the Detail, and type a value in the PageBefore property in the
Properties Pad dialog. This sets the PAGEBEFORE attribute. The report prints the full DETAIL starting at the top of the
next page. The report FOOTER, however, prints on the first page.
The page number automatically increments, unless you reset it. To reset the page number to a value you specify, type it
in the PageBefore property in the Detail’s Properties Pad dialog.
WITHNEXT
To prevent 'widow' elements in a printout, type a value in the KeepNext property in the Properties Pad dialog. This
sets the WITHNEXT attribute. A 'widowed' print element is one which prints, but then is separated from the succeeding
elements by a page break.
The value specifies the number of succeeding elements to print--a value of '1,' for examples, specifies that the next
element must print on the same page, else page overflow puts them on the next.
WITHPRIOR
To prevent 'orphan' elements in a printout, type a value in the KeepPrior property in the Properties Pad dialog. This sets
the WITHPRIOR attribute. An 'orphaned' print element is one which prints on a following page, separated from its related
items.
The value specifies the number of preceding elements to print--a value of "1," for example, specifies that the previous
element must print on the same page.
45
Tips, Tricks & FAQs
When placing subtotals or totals in a DETAIL, use the WITHPRIOR attribute to insure they print with at least one member
of the column above it when a page break occurs.
46
Clarion 7 FAQs
Using the Application Generator, applications frequently use the Browse Box template. Another control template, the
BrowseUpdateButtons control template, is used to call an appropriate update procedure from the Browse Box.
In the ABC template set, these templates use the BrowseClass to manage the state of these buttons. For example, you
would only want the Insert button to be enabled if there were no records displayed in the list box.
There may be other situations where you need to manually control the state of these buttons and override the Class
behavior. The solution to this is to add the following three lines of embedded code in the Init procedure of the target
Browse object:
BrwX.InsertControl = 0
BrwX.ChangeControl = 0
BrwX.DeleteControl = 0
Where BrwX is the name of the browse class instance that you are trying to affect. You probably will use this to
conditionally grant access to a particular update operation, like the following example:
IF User:Access < Rights:Delete !If the user does not have delete clearance
Brw1.DeleteControl = 0 !Override class control
DISABLE(?DeleteButton)
END
47
Tips, Tricks & FAQs
You can specify a table to convert from three different sources. The target can be directly on disk (using Data File), a table
definition in the current dictionary (using Table Definition), or a table definition in another dictionary (using Table Definition
from another DCT). We have chosen a table from our current dictionary.
If you have Clarion.NET installed, you also have the option of generating a conversion program in standard Clarion
language format or Clarion# to generate a conversion program that runs with the .NET Framework.
The table that you select first in the conversion program process is always the target. In our example, the CUSTOMER
table is the target.
5. In the Select a Table dialog, highlight CUSTOMER and press the Select button.
6. The Select New Project File dialog appears. Accept the default name (convert.cwproj), and the default
LearningClarion folder name, by pressing the Save button.
Project files determine what source file to compile, and how to build (link) it. The default extension of project files is
*.cwproj.
When you press the Save button, this will generate all the Clarion source code necessary to take the data in the Source
Filename, and copy it into a new Target Filename, using the file format specified by the Target Structure.
7. The Select Destination Data File dialog appears. Highlight the CUSTOMER.TPS file located in the Learning
Clarion folder, and press the Open button.
8. Another dialog pops up that asks you if you would like to load the data conversion program. Press the Yes
button.
The best reason to generate Clarion source code for the data conversion is to provide you the opportunity to modify the
code before you compile and execute it to handle any special data conversion needs you may have. This makes the
conversion process completely flexible to handle any situation that can occur.
9. Choose View Solution Explorer (or press CTRL+ALT+L).
Expand the Convert project node, and highlight the Convert.clw file, then press the Open button in the Solution Explorer
toolbar, or you can right-click and select Open from the popup menu, or simply double-click on the file to open it.
Clarion’s Text Editor appears with the file loaded, ready to edit.
10. Edit the source code as required to make the field assignments.
See Editing Source Code to Make Field Assignments
48
Clarion 7 FAQs
49
Tips, Tricks & FAQs
It is always a good idea to make backup copies of your files before running any conversion process.
If you change the name of a field, you must generate source code, and edit the source code to make the field
assignments. Otherwise, your data will be lost.
1. Open (load) the dictionary that contains the file to be modified.
2. Modify the data file definition as desired (add fields or keys, etc.).
3. With the modified file highlighted in the DCT Explorer, press the button to load the data file in the Database
Browser.
A dialog appears, giving you different options to convert the table..
4. Select an option, and press the OK button to convert the file.
The conversion process is now complete!
50
Clarion 7 FAQs
Complex Expressions - IF
Use an IF structure to assign one of two values to the Result field depending on a condition. Nesting IF structures allows
more complex alternative assignments.
To create an IF conditional formula (from the Application Tree):
1. Press the Formulas button.
2. Highlight a Formula type in the list, and press the Insert button. The Formula Editor dialog appears.
3. In the Name field, type a name for the formula.
4. Verify the Class field in the Formula Class drop list.
A formula class determines where in the generated source code its calculation is performed. Each Clarion procedure
template has its own set of formula classes. For example, in the Form Template there is a class called "After Lookups"
which tells the Application Generator to compute the formula after all lookups to secondary files are completed for the
procedure.
5. In the Description field, type a description of the formula.
6. In the Result field, type the variable to which the result of the expression is assigned, or press the ellipsis (...)
button to choose a variable from the Select Field dialog.
You can choose a local, module, or global variable, or a data dictionary field.
In the Statement dialog, enter a valid expression that you nees to test. For example, if the condition will be:
IF Date > TODAY( )
7. Simply enter "Date > TODAY( )" in the Statement dialog.
8. Press the IF..THEN button.
The IF structure appears in the Structure window.
9. On the Statement line, enter the IF condition to evaluate.
You can type the expression, or you can use the Operators and Operands buttons to select expression components, or
you can do both.
10. Press the Check button to check your syntax.
11. Press the Accept button to insert your expression into the structure.
12. Highlight the line below the IF line in the Structure window.
This is where the "True" assignment expression goes.
13. On the Statement line, enter the "True" assignment expression.
Again, you can type the expression, or you can use the Operators and Operands buttons to select expression
components, or you can do both. If the IF condition is true, this expression is evaluated and the resulting value is assigned
to the Result variable.
A "true" assignment expression is not required. If no assignment is entered, then no assignment is made.
14. Press the Check button to check your syntax.
51
Tips, Tricks & FAQs
15. Press the Accept button to enter your expression into the structure.
16. Highlight the line below the ELSE line in the Structure window
This is where the "False" assignment expression goes.
17. On the Statement line, insert the "False" assignment expression.
Again, you can type the expression, or you can use the Operators and Operands buttons to select expression
components, or you can do both. If the IF condition is false, this expression is evaluated and the resulting value is
assigned to the Result variable.
A "false" assignment expression is not required. If no assignment is entered, then no assignment is made.
18. Press the Check button to check your syntax.
19. Press the Accept button to insert your expression into the structure.
To add a nested control structure:
20. Highlight one of the assignment lines in the Structure window.
21. Press either the CASE..OF or IF..THEN button.
A new nested structure appears in the Structure window.
22. Insert expressions on the appropriate lines as described above.
Again, you can type the expression, or you can use the Operators and Operands buttons to select expression
components, or you can do both
23. When your control structure is complete, press the OK buttons in the Conditionals, Formula Editor, and
Formulas dialogs.
52
Clarion 7 FAQs
9. On the Statement line, enter the CASE expression that is compared to the multiple OF expressions.
You can type the expression, or you can use the Operators and Operands buttons to select expression components, or
you can do both.
10. Press the Check button to check your syntax.
11. Press the Accept button to insert your expression into the structure.
12. Highlight the OF line below the CASE line in the Structure window.
This is where the first OF comparison expression goes.
13. On the Statement line, enter the OF comparison expression.
Again, you can type the expression, or you can use the Operators and Operands buttons to select expression
components, or you can do both. At runtime, if the CASE expression equals this OF expression, then the subsequent
assignment expression is evaluated and the resulting value is assigned to the Result variable.
14. Press the Check button to check your syntax.
15. Press the Accept button to insert your expression into the structure.
16. Highlight the line below the OF line in the Structure window.
This is where the first OF assignment expression goes.
17. On the Statement line, insert the OF assignment expression.
Again, you can type the expression, or you can use the Operators and Operands buttons to select expression
components, or you can do both. At runtime, if the CASE expression equals the above OF expression, then this
assignment expression is evaluated and the resulting value is assigned to the Result variable.
18. Press the Check button to check your syntax.
19. Press the Accept button to insert your expression into the structure.
To add additional OF statements:
20. Highlight an OF line in the Structure window.
21. Press the Case..OF button
22. Insert your expressions in the same manner described above.
To add a nested control structure:
23. Highlight an assignment line in the Structure window.
24. Press either the CASE..OF or IF..THEN button
25. Insert expressions on the appropriate lines following the instructions in the previous sections.
Again, you can type the expression, or you can use the Operators and Operands buttons to select expression
components, or you can do both.
26. When your control structure is complete, press the OK buttons in the Conditionals, Formula Editor, and
Formulas dialogs.
53
Tips, Tricks & FAQs
This section describes the steps to create a program using one main application and several sub-applications compiled
and linked as external.DLLs. It is written with Team Development in mind, so it describes some of the aspects of working
in a multi-developer environment. Dividing a large project into multiple .DLLs provides many benefits:
Each sub-application can be modified and tested independently.
Developers can work on their portion of the project without interfering with others on the development team.
Each sub-application can be compiled as a DLL and tested in the main program without recompiling the entire
project. This reduces compile and link time.
Future updates can be deployed by shipping a new .DLL, reducing shipping costs.
With this approach, each Team Member creates a separate .DLL that is called by a "master" application. This requires
splitting the application into a "Main" executable and "secondary" .DLLs. The individual team members maintain separate
application files for each component. The Team Leader creates a master application that calls the sub-applications and a
"data" application that contains (and exports) all the File definitions and Global variables. Optionally, members can call
procedures from another member's .DLL.
This method also requires extensive pre-planning of the "division of labor" between the various target files created by the
application.
The following outlines a possible implementation of this strategy:
1. Create the data dictionary and set up the workstations as described above.
2. Create a "dummy" application to store and export all data declarations. All Global variables or structures and all
file definitions are defined (and exported) in this application. Use the following settings:
54
Clarion 7 FAQs
Changing the Target Type enables procedures to be exported. Make sure that every procedure that is called by the
master application or another .DLL has the Export Procedure check box in the Procedure Properties checked (the check
box is only available after changing the target type).
4. Team members synchronize their local directory with an equivalent on the network at the end of each day.
5. Team Members release their compiled and linked .DLLs to the Team Leader.
Each sub-application has a "dummy" frame (not exported) that calls the sub-application's procedures so the Team
Member can test the sub-application by compiling it as an .EXE. Once it passes testing, the member compiles it to a .DLL
by changing the Application Properties' Target File type to .DLL and releases the file to the Team Leader.
6. The Team Leader copies the released .DLLs into the master directory and creates a master .APP file which calls
the entry point procedures in the .DLLs.
The Master .APP is typically just a bare bones application with just a splash screen and a main frame with a menu and
toolbar. The .DLLs are called at runtime so you don't need to compile a large Master .EXE. The Master .APP should have
the same settings as the sub-applications except that it is always compiled as an .EXE.
The master .APP should have these settings:
In the Application Properties:
55
Tips, Tricks & FAQs
Dictionary File:
The master dictionary residing on the network.
Target Type:
EXE
In the Application's Global Properties:
Generate Global Data as External:
ON
File Control Flags
Generate All File declarations:
OFF
External:
ALL EXTERNAL
All Files declared in another .App:
ON
Declaring Module:
Leave this blank
56
Clarion 7 FAQs
This specifies no parameters and a return data type of LONG. The data type may be any valid Clarion language data
type.
2. Press the Actions button to open the Procedure Properties sub-dialog.
This enables the Return Value field.
3. In the Return Value field, press the ellipsis button (...) to select or define a variable to receive the return value for
your function.
You should embed code to assign the appropriate value to the returned variable.
Receiving Return Values from Procedures
Although you may call a function with Call a Procedure from the Actions dialog from a button or method, this method
does not allow you to receive return values. Therefore, you should generally use embedded source or hand code to
receive a return value from a function. Following is one way to call a function from a control; however, you may call a
function in many ways.
1. Right-click on the button control, and select the Embeds option.
2. In the Embedded Source dialog, choose the Accepted embed point for Control Event Handling, after generated
code, then press Insert.
3. In the Select Embed Type dialog, select SOURCE.
4. In the Text Editor, type your function call, for example:
ValueFromFunction = MyFunction()
where ValueFromFunction is a local, module, or global variable that receives the value returned by the function.
5. Press the Save and Close button from the menu, then save your embedded source when prompted.
57
Tips, Tricks & FAQs
58
Clarion 7 FAQs
Here are the steps for creating a menu starting from an empty window within the Window Designer.
1. Choose the MENUBAR from the Control Toolbox. Drag the item to the target window.
2. Right-Click on the Menu, and select Properties from the popup menu.
3. In the Properties toolbox you will notice a link near the bottom. Click on the Edit Menu link. The Menu Editor
dialog appears. Only the MENUBAR statement is present.
You can also simply DOUBLE-CLICK on the Menu to open the Menu Editor.
When using the Application Generator, each ITEM you place on a MENU or MENUBAR automatically adds an embed
point to the control event handling tree in the Embedded Source dialog. This allows you to easily attach functionality to
your ITEMs.
8. In the Text field, type the text you want to display for this menu ITEM.
For example, type &OPEN, so the end user sees Open. The ampersand within the ITEM name signifies the character
following the ampersand is the accelerator key.
9. In the Use field, type a Field Equate Label.
A Field Equate Label has a leading question mark ( ? ), and you should make it descriptive. For example ?FileOpen
shows at a glance the intended purpose of this ITEM: to open a file.
10. In the Message field, type the MSG attribute contents.
This message text displays in the status bar (if enabled) when the user highlights this MENU or ITEM.
11. In the HelpID field, type either a help keyword or a context string present in a .HLP file.
If you fill in the HelpID for a MENU or an ITEM, when the user highlights the MENU or ITEM and presses F1, the help file
opens to the referenced topic. If more than one topic matches a keyword, the search dialog appears.
A Help keyword is a word or phrase indexed so that the user may search for it in the Help Search dialog. When
referencing a context string in the HelpID field, you must identify it with a leading tilde (~).
12. Right-click on the menu item and select Actions. In the Actions dialog, choose Call a Procedure from the When
Pressed drop down list.
59
Tips, Tricks & FAQs
The procedure you specify executes when the user selects this ITEM. You may specify parameters to pass and standard
file actions (insert, change, delete, or select) if applicable, or you may initiate a new thread. The procedure appears as a
"ToDo" item in your Application Tree (unless you named a procedure that already exists).
This is one way to add functionality to your ITEM. You may also add functionality by Run a Program from the drop down
list, by embedding source code, or by typing an STD ID in the STD ID field.
After following these steps, you have a single MENU called File, with a single ITEM called Open. To add other ITEMS to
the MENU, repeat steps 7 through 12. To add a second MENU, select the END statement and press the Menu button. To
add a subMENU, select a MENU or ITEM statement and press the Menu button.
13. To finish the menu and return to the Window Designer, press the Save and Close button.
60
Clarion 7 FAQs
GLO:ReportQueryResult STRING(1024)
!Note this can be as much as 5k chars)
2. Press the OK button to save the new global variable, then press the Cancel button when the New Column
Properties dialog appears again.
This enables a query on the browse and saves the filter expression we will pass to the report.
GLO:ReportQueryResult = QBEn.GetFilter()
Replace n with the appropriate number of the QBE object which you noted earlier.
61
Tips, Tricks & FAQs
The report MUST use the same key and filter as the browse!
3. Press the Save and Close button to return to the Application Tree.
4. Press the Embeds button, and navigate to the ThisReport.Open in the LocalObjects branch of the embed tree.
Embed the following code in the CODE section at a Priority of 5000:
IF GLO:ReportQueryResult
ThisReport.SetFilter(GLO:ReportQueryResult)
ThisReport.ApplyFilter()
GLO:ReportQueryResult = '' !Clear the var
END
Exit back to the Application tree saving your work when prompted.
62
Clarion 7 FAQs
63
Tips, Tricks & FAQs
A wizard is a window with a "tabless" SHEET control containing one or more TABS. You'll need to write the code to
handle the "turning of the pages".
This topic explains one method of creating a wizard using <<Back and Next>> buttons.
1. Create a procedure using the Window Template.
2. Create two Local Variables (by pressing the Data Button on the Procedure properties dialog).
TabNumber Byte 1
Use Text
?Back <<Back
?Next Next>>
8. Place a third button control under the SHEET control using either a standard button, a Save Button Control template,
or a Close Button control template.
Use Text
?Finish Finish
The type of control will depend on the task you intend the wizard to perform. If you are using a Save Button control
template, you will need to either call the wizard from a browse or set GlobalRequest=InsertRecord in the WindowManager
Method Executable Code -- INIT [Priority First] embed point.
9. In the point after WindowManager Method Executable Code -- INIT--Open The Window (Priority 8250)
HIDE(?Finish)
Select(?sheet1,TabNumber)
Disable(?Back)
64
Clarion 7 FAQs
This hides the Finish button and disables the <<Back button when the window opens.
10. In the Control Event Handling--?Back, Accepted embed point, add this code and set the Priority to 2500:
TabNumber -=1
CASE TabNumber
OF 1
HIDE(?Finish)
DISABLE(?Back)
SELECT(?SHEET1,TabNumber)
OF MaxTabs
UNHIDE(?Finish)
DISABLE(?Next)
SELECT(?SHEET1,TabNumber)
ELSE
HIDE(?Finish)
ENABLE(?Back)
ENABLE(?Next)
SELECT(?SHEET1,TabNumber)
END
This code decrements TabNumber, disables inappropriate buttons, and keeps the Finish button hidden until the final TAB.
11. In the Control Event Handling--?Next, Accepted embed point, add this code and set the Priority to 2500:
TabNumber +=1
CASE TabNumber
OF 1
HIDE(?Finish)
DISABLE(?Back)
SELECT(?SHEET1,TabNumber)
OF MaxTabs
UNHIDE(?Finish)
DISABLE(?Next)
SELECT(?SHEET1,TabNumber)
ELSE
HIDE(?Finish)
ENABLE(?Back)
ENABLE(?Next)
SELECT(?SHEET1,TabNumber)
END
This code increments TabNumber, disables inappropriate buttons, and keeps the Finish button hidden until the final TAB.
12. Write the code for the Finish button to accomplish the desired tasks and close the window.
65
Tips, Tricks & FAQs
The classes you use with the ABC Templates must be ABC Compliant Classes. That is, the classes must conform to the
ABC Library specification as documented in the ABC Library Reference
The ABC Templates generate code that refers to the properties, methods, and method parameters documented in the
ABC Library Reference. If those properties, methods, and parameters are not defined within the classes you specify, the
template generated code will not compile. Further, if the classes do not perform as documented, the template generated
code probably won't work. The easiest way to create ABC Compliant Classes is to derive classes from the ABC Library--
this is what the ABC Templates do. See CLASS in the Language Reference for more information on deriving classes.
Requirements for ABC Compliant Classes
Classes must conform to the ABC Library specification as documented in the ABC Library Reference
The header file containing the CLASS declarations must have the .INC file extension
The header file (.INC) containing the CLASS declarations must be in Clarion's \LIBSRC directory
The header file (.INC) containing the CLASS declaration must contain the following comment before compilable
code begins:
!ABCIncludeFile
familyclass is a string (no quotes) that contains a Class Name used to populate the %pClassCategory built-in template
symbol. If absent, 'ABC' is used (no quotes).
The %pClassCategory is used throughout the templates for debugging, code declarations, and documentation of template
prompts.
The CLASS declarations must have the LINK attribute naming the corresponding implementation (.CLW) files.
Meeting these requirements ensures that your ABC Compliant Classes appear in the Application Builder Class Viewer,
the Embeditor, the Embedded Source dialog, and that the development environment has full information about your
classes. With this information, the development environment can correctly manage embed points and code generation for
the compliant classes.
EXTENDS and FINAL
During the processing of the ABC header files, there are two special parameters that can be added to methods defined
within Classes that control their presence in the Template Source Embed tree interface (only found in the Application
Generator).
These attributes must be preceded with !, (exclamation point followed by a comma) and no spaces between. For
example:
Init PROCEDURE(BYTE Controls) !,EXTENDS
Throw PROCEDURE(SHORT Id),BYTE,PROC !,EXTENDS
Release PROCEDURE !,FINAL
By default, all public methods defined will not be visible in the embed tree. For example:
66
Clarion 7 FAQs
MyMethod PROCEDURE()
The reason for this is to optimize embed processing and eliminate embed points not needed.
If you need to make a public method visible in the embed tree, the EXTENDS symbol is added as follows:
Virtual methods are always visible in the embed tree. If you want to remove (hide) them from the embed tree , the FINAL
symbol is added as follows:
In addition to this, Construct and Destruct are special methods that are automatically called for you when an object is
instantiated and destroyed respectively. They will always appear on the embed tree in a different color.
Construct PROCEDURE()
Destruct PROCEDURE()
Finally, methods designated as PRIVATE are never visible in the embed tree as they cannot be overridden.
67
Tips, Tricks & FAQs
Multiple Document Interface applications make special demands upon a program. Often, the program may support a
variety of document windows, each of which has a slightly different set of commands from which the user may select.
Normally in this situation, the programmer writes code to monitor which window is active, then changes the menu and
toolbar to reflect the options available to the user. Clarion does this automatically.
To create menus for MDI applications:
1. Create a master menu for the APPLICATION frame window.
Most likely, this will include a File menu and a Help menu, since they contain functions that are available even when no
document windows are open.
Clarion's Application Frame procedure template comes with a predefined menu with many of the most common functions
already provided for you.
You will use the Window Designer's Menu Editor to create your menus. Be sure to choose the FIRST attribute for the
File MENU, and the LAST attribute for the Help MENU from the Position drop down list. This ensures that when Clarion
merges this global menu with local menus, File and Help will keep their correct positions.
2. Plan the additional menus for the child windows.
Can they all share the same menu titles? Do they share many of the same commands? Ideally, most of the MENUs and
ITEMs can be active in all the child windows. If there are only a few commands specific to certain windows, plan on
disabling those MENUs and ITEMs in the windows that don't support them, and enabling them in those that do.
3. Create the menu for the first child window.
Again, you will use the Window Designer's Menu Editor to create the menu. Add any window-specific MENUs to the first
child window. That is, the window-specific MENUs the application frame lacks--such as Edit, Insert, etc.
Optionally, add a File MENU to the first child window. This is necessary only if the child window needs an ITEM on the
File MENU that is not already included on the application's File MENU. For example, adding a Close command might be
appropriate. If so, add the File MENU to the first child window. Add the Close ITEM to the File MENU.
Add the Window MENU to the first child window. Window MENUs are standard for most windows programs. A typical
Window MENU includes the following ITEMs: "Arrange Icons," "Tile," "Cascade," plus a document (windows) list that
displays all open child windows and allows the user to switch between them. In many cases this entire MENU, including
the document list, can be implemented with standard ID's (StdID's).
4. Exit the Menu Editor and save the menu.
5. Test the interaction of these first two menus.
Do they merge the way you planned? Are the correct selections available for the window with focus? Make any
adjustments with the Menu Editor.
6. Repeat steps 3 through 5 for other child windows.
68
Clarion 7 FAQs
69
Tips, Tricks & FAQs
Use the Window Designer to visually design window elements--windows, menus, toolbars, list boxes, prompts, entry
fields, and other controls--on screen. The Window Designer automatically generates the Clarion language source code
that defines these elements.
The Window Designer has several key components that help design your window: the Sample Window, the Controls
Toolbox, and the Property Toolbox.
1. Set the size of the window by dragging the handles so that the sample window is the size
you wish.
RIGHT-CLICK the window and choose Properties from the popup menu, or select the
window and choose View Properties.
Other attributes include the window caption, whether the window is resizeable, whether the
window is scrollable, icons, messages, help files, and cursor types associated with the
window, and many others.
4. Place desired controls in the window using the Controls toolbox or Data / Tables Pad.
70
Clarion 7 FAQs
71
Tips, Tricks & FAQs
Customer Name
Customer Address
ShipTo Address
Order Date
Product Ordered
Quantity Ordered
Unit Price
This data could all be stored in each record of one file, but that would be very inefficient. The Customer Name, Address,
ShipTo Address, and Order Date would be duplicated for every item ordered on every order. To eliminate the duplication,
you split the data into separate files.
With this file configuration, the Customer File contains all the customer information, the Order File contains all the
information that is pertinent to one order, and the Item File contains all the information for each item in the order. This
certainly eliminates duplicate data. However, how do you tell which record in what file relates to what other records in
which other files? This is the purpose of the relational terms "Primary Key" and "Foreign Key."
A Primary Key is an index into a file based on a field (or fields) that cannot contain duplicate or null values. To translate
this to Clarion language terms: a Primary Key would be a unique KEY (no DUP attribute) with key components that are all
REQuired fields for data entry. In strict relational database design, one Primary Key is required for every file.
A Foreign Key is an index into a file based on a field (or fields) which contain values that duplicate the values contained in
the Primary Key fields of another, related, file. To re-state this, a Foreign Key contains a "reference" to the Primary Key of
another file.
72
Clarion 7 FAQs
Primary Keys and Foreign Keys form the basis of file relationships in Relational Database. The matching values contained
in the Primary and Foreign Keys are the "pointers" to the related records. The Foreign Key records in "File A" point back
to the Primary Key record in "File B", and the Primary Key in "File B" points to the Foreign Key records in "File A."
Defining the Primary and Foreign Keys for the above example requires that you add some fields to the files to fulfill the
relational requirements.
Item File: Order Number - 1st Primary Key Component and Foreign Key
Product Ordered - 2nd Primary Key Component
Quantity Ordered
Unit Price
In the Customer File, there is no guarantee that there could not be duplicate Customer Names. Therefore, the Customer
Number field is added to become the Primary Key. The Order Number has been added to the Order File as the Primary
Key because there is no other field that is absolutely unique in that file. The Customer Number was also added as a
Foreign Key to relate the Order File to the Customer File. The Item File now contains the Order Number as a Foreign Key
to relate to the Order File. It also becomes the first component of the multiple component (Order Number, Product
Ordered) Primary Key.
The Relational definitions of Primary Key and Foreign Key do not necessarily require the declaration of a Clarion KEY
based on the Primary or Foreign Key. This means that, despite the fact that these Keys exist in theory, you will only
declare a Clarion KEY if your application actually needs it for some specific file access. Generally speaking, most all
Primary Keys will have a Clarion KEY, but fewer Foreign Keys need have Clarion KEYs declared.
File Relationship
There are three types of relationships that may be defined between any two files in a relational database: One-to-One;
One-to-Many (also called Parent-Child) and its reverse view, Many-to-One; and Many-to-Many. These relationships refer
to the number of records in one file that are related to some number of records in the second file.
In the previous example, the relationship between the Customer File and the Order File is One-to-Many. One Customer
File record may be related to multiple Order File records. The Order File and the Item File also have a One-to-Many
relationship, since one Order may have multiple Items. In business database applications, One-to-Many (Parent-Child) is
the most common relationship between files.
A One-to-One relationship means that exactly one record in one file may be related to exactly one record in another file.
This is useful in situations where a particular file may, or may not, need to have data in some fields. If all the fields are
contained in one file, you can waste a lot of disk space with empty fields in those records that don't need the extra
information. Therefore, you create a second file with a One-to-One relationship to the first file, to hold the possibly
unnecessary fields.
To expand the previous example, an Order may, or may not, need to have a separate ShipTo Address. So, you could add
a ShipTo File to the database design.
73
Tips, Tricks & FAQs
In this example, a record would be added to the ShipTo File only if an Order has to be shipped to some address other
than the address in the Customer File. The ShipTo File has a One-to-One relationship with the Order File.
Many-to-Many is the most difficult file relationship with which to deal. It means that multiple records in one file are related
to multiple records in another file. Expand the previous example to fit a manufacturing concern which buys Parts and
makes Products. One Part may be used in many different Products, and one Product could use many Parts.
Without going into the theory, let me simply state that this situation is handled by defining a third file, commonly referred to
as a "Join" file. This Join file creates two One-to-Many relationships, as in this example:
Parts2Prod File: Part Number - 1st Primary Key Component and Foreign Key
Product Number - 2nd Primary Key Component and Foreign Key
Quantity Used
The Parts2Prod File has a multiple component Primary Key and two Foreign Keys. The relationship between Parts and
Parts2Prod is One-to-Many, and the relationship between Product and Parts2Prod is also One-to-Many. This makes the
Join file the "middle-man" between two files with a Many-to-Many relationship.
An advantage of using a Join file is that there is usually some more information that logically should be stored there. In
this case, the Quantity Used (of a Part in a Product) logically only belongs in the Parts2Prod file.
74
Clarion 7 FAQs
Customer FILE,DRIVER('Clarion'),PRE(Cus)
CustKey KEY(Cus:CustNo) !Primary KEY
Record RECORD
CustNo LONG !Customer Number - Primary Key
Name STRING(30) !Customer Name
Address STRING(30) !Customer Address
END
END
Order FILE,DRIVER('Clarion'),PRE(Ord)
OrderKey KEY(Ord:OrderNo) !Primary KEY
CustKey KEY(Ord:CustNo),DUP !Foreign KEY
Record RECORD
OrderNo LONG !Order Number - Primary Key
CustNo LONG !Customer Number - Foreign Key
Date LONG !Order Date
END
END
ShipTo FILE,DRIVER('Clarion'),PRE(Shp)
OrderKey KEY(Shp:OrderNo) !Primary KEY
Record RECORD
OrderNo LONG !Order Number - Primary Key and Foreign Key
Address STRING(30) !ShipTo Address
END
END
75
Tips, Tricks & FAQs
Item FILE,DRIVER('Clarion'),PRE(Itm)
OrderKey KEY(Itm:OrderNo,Itm:ProdNo) !Primary KEY
Record RECORD
OrderNo LONG !Order - Primary Component and Foreign Key
ProdNo LONG !Prod. - Primary Component and Foreign Key
Quantity SHORT !Quantity Ordered
Price DECIMAL(7,2) !Unit Price
END
END
Product FILE,DRIVER('Clarion'),PRE(Pro)
ProdKey KEY(Pro:ProdNo) !Primary KEY
Record RECORD
ProdNo LONG !Product Number - Primary Key
Description STRING(30) !Product Description
END
END
Parts2Prod FILE,DRIVER('Clarion'),PRE(P2P)
ProdPartKey KEY(P2P:ProdNo,P2P:PartNo) !Primary KEY
PartProdKey KEY(P2P:PartNo,P2P:ProdNo) !Alternate KEY
Record RECORD
PartNo LONG !Part - Primary Component and Foreign Key
ProdNo LONG !Prod. - Primary Component and Foreign Key
Quantity SHORT
END
END
Parts FILE,DRIVER('Clarion'),PRE(Par)
PartKey KEY(Par:PartNo) !Primary KEY
Record RECORD
PartNo LONG !Part Number - Primary Key
Description STRING(30) !Part Description
END
END
Notice that only one Foreign Key (in the Order file) was explicitly declared as a Clarion KEY. A number of Foreign Keys
were included as part of Primary Key declarations, but this was simply good fortune.
The Primary Key (Itm:OrderKey) defined on the Item file is there to ensure that an order does not contain duplicate
Products Ordered. If this were not a consideration, Itm:OrderKey would only contain Itm:OrderNo, and would have the
DUP attribute to allow duplicate KEY values. This would make it a Foreign Key instead of a Primary Key, and the file
would not have a KEY defined for the Primary Key.
76
Clarion 7 FAQs
The Item file and the Product file have a Many-to-One relationship, which is One-to-Many looked at from the reverse
perspective. This reverse view is most often used for data entry verification look-up. This means the Product Number
entered into the Item file's data entry procedure can look-up and verify the Product Number against the records in the
Product file.
Referential Integrity
There is one more fundamental issue in the Relational Model which should be addressed: "Referential Integrity." This is
an issue which must be resolved in the executable source code for an application, because it involves the active, run-time
inter-relationship of the data within the database.
Referential Integrity means that no Foreign Key can contain a value that is not matched by some Primary Key value.
Maintaining Referential Integrity in your database begets two questions which must be resolved:
1. What do you do when the user wants to delete the Primary Key record?
2. What do you do when the user wants to change the Primary Key value?
The three most common answers to each of these questions are: Restrict the action, Cascade the action, or (less
commonly) Nullify the Foreign Key values. Of course, there may also be application-specific answers, such as copying
all information to history files before performing the action, which should be implemented as required in individual
programs.
Restrict the action means that when the user attempts to delete the Primary Key record, or change the Primary Key
value, the action is only allowed if there are no Foreign Keys that reference that Primary Key. If related Foreign Keys do
exist, the action is not allowed.
Cascade the action means that when the user attempts to delete the Primary Key record, or change the Primary Key
value, the action cascades to include any Foreign Keys that reference that Primary Key. If related Foreign Keys do exist,
the delete action also deletes those records, and the change action also changes the values in the Foreign Keys that
reference that Primary Key.
There is one consideration that should be noted when you Cascade the action. What if the file you Cascade to (the Child
file) is also the Parent of another Child file? This is a situation which you must detect and handle, because the Cascade
action should affect all the dependent file records. When you are writing source code to handle this situation, you need to
be aware of the file relationships and write code that Cascades the action as far it needs to go to ensure that nothing is
"left hanging."
Nullify the Foreign Key means that when the user attempts to delete the Primary Key record, or change the Primary Key
value, the Foreign Keys that reference that Primary Key are changed to null values (if the Foreign Key fields allow null
values).
The Nullify option does not require as many changes as the Cascade option. This is because the Cascade has to delete
all the related records in as many files as are related. Nullify only needs to null out the individual Foreign Keys that
reference the Primary Key being changed or deleted.
Summary
Each data item should be stored once.
Separate files are used to eliminate data duplication.
Files are related by Primary and Foreign Keys.
A Primary Key is a unique (and non-null) index into a file which provides for individual record access.
A Foreign Key contains a reference to the Primary Key of some other file.
One-to-Many file relationships are the most common. They are also referred to as Parent-Child and Many-to-One
(same relationship, reverse view).
One-to-One file relationships are most commonly created to hold data that is not always needed in every record.
77
Tips, Tricks & FAQs
Many-to-Many relationships require a "Join" file which acts as a broker between the two files. The Join file inserts
two One-to-Many relationships between the Many-to-Many relationship.
Only those Primary and Foreign Keys that the application needs (as a practical consideration) for specific access
to the files need to have Clarion KEYs declared.
Referential Integrity means that all Foreign Keys contain valid references to Primary Keys.
Maintaining Referential Integrity requires executable code that tests for Update or Delete of the Primary Key
values.
The three common solutions to maintaining Referential Integrity are: Restricting (update/delete not allowed),
Cascading (also update/delete the Foreign Key), or Nullifying the Foreign Key (assign null values to the Foreign
Key).
78
Clarion 7 FAQs
Clarion's Browse Wizard generates multi-key browses for files with multiple keys. To see records in a different sort order,
the user simply selects a tab with a different key. However, when switching to a new sort order, the sort column does not
automatically appear as the first (or leftmost) column in the list box. This example uses the embed points from the Clarion
(Compatibility) Templates.
To dynamically shift the sort column to the leftmost position in the list box, follow these steps:
1. Find the FORMAT string for the affected list box and copy it to the clipboard.
In the Application Tree dialog, DOUBLE-CLICK on your browse procedure.
In the Procedure Properties dialog, select the Window tab, and press the Edit as Text button.
On the LIST control declaration statement, highlight the entire FORMAT attribute parameter and choose Edit Copy to
copy it to the clipboard.
Press the Discard button to close without saving.
2. Paste the FORMAT string into the "Control Event Handling, before generated code; ?CurrentTab; NewSelection"
embed point of the Browse procedure.
From the Application Tree, press the Embeds button.
In the Embeds Tree, DOUBLE-CLICK on the "Control Event Handling, before generated code; ?CurrentTab;
NewSelection" embed point.
Choose SOURCE from the Select embed type dialog.
When the Text Editor opens, choose Edit Paste.
3. "Chop up" the FORMAT string so there is only one list box column definition per line.
Each column definition begins with the width of the column immediately followed by a justification letter (L, R, C, or D). If
necessary, you can get the widths and justification for each column from the List Box Formatter.
On each line you need to add enclosing single quotes.
On each line except the last, you need to add a trailing ampersand ( & ) and pipe ( | ). The ampersand is the
concatenation operator, and the pipe is the line continuation character.
Your code should look something like this:
'16L|M~Cust Number~@N4@' & |
'80L|M~Last Name~@S20@' & |
'80L|M~First Name~@S20@' & |
'12L|M~Area Code~@S3@' & |
'32L|M~Phone Number~@S8@' & |
32L|M~Description~@S8@'
4. Add explicit QUEUE field numbers to each list box column definition.
Queue numbers are integer constants surrounded by pound ( # ) signs. The QUEUE field numbers start with 1 and
continue in ascending sequence. Your code should now look something like this:
79
Tips, Tricks & FAQs
Add a CASE structure and property assignment to the embedded source code.
Type ?BROWSE:1{PROP:Format}= before the first column definition. This creates the assignment statement that formats
the list box at run time.
Add a CASE CHOICE(?CurrentTab) statement before the first column definition.
Add an OF 1 statement before the first column definition.
Your code should now look something like this:
CASE CHOICE(?CurrentTab)
OF 1 !Tab1, sorted by Cust Number
?BROWSE:1{PROP:FORMAT} ='16L|M~Cust Number~@N4@#1#' & |
'80L|M~Last Name~@S20@#2#' & |
'80L|M~First Name~@S20@#3#' & |
'12L|M~Area Code~@S3@#4#' & |
'32L|M~Phone Number~@S8@#5#' & |
'32L|M~Description~@S8@#6#'
Duplicate the FORMAT string, with the sort column first, for each OF in the CASE.
You should have a separate OF clause for each tab (sort key) in the browse. Cut and Paste the FORMAT string for each
OF assignment so that the columns appear in the sequence you want them.
Your code should now look something like this:
CASE CHOICE(?CurrentTab)
OF 1 !Tab1, sorted by Cust Number
?BROWSE:1{PROP:FORMAT} ='16L|M~Cust Number~@N4@#1#' & |
'80L|M~Last Name~@S20@#2#' & |
'80L|M~First Name~@S20@#3#' & |
'12L|M~Area Code~@S3@#4#' & |
'32L|M~Phone Number~@S8@#5#' & |
'32L|M~Description~@S8@#6#'
OF 2 !Tab2, sorted by Last Name
?BROWSE:1{PROP:FORMAT} ='80L|M~Last Name~@S20@#2#' & |
'80L|M~First Name~@S20@#3#' & |
'16L|M~Cust Number~@N4@#1#' & |
'12L|M~Area Code~@S3@#4#' & |
'32L|M~Phone Number~@S8@#5#' & |
'32L|M~Description~@S8@#6#'
END
In this example, notice that when the user selects tab 2, QUEUE field number #2# becomes the first column in the
FORMAT string, and will be the leftmost column in the list box!
7. Save and Close the Text Editor and save your changes.
80
Clarion 7 FAQs
Choosing a Configuration
This section is included to help you decide what kind of target file to specify for your project..
Clarion produces executable files which you may distribute on a royalty-free basis. The applications you distribute require
a Windows 32-bit environment (95/98, NT, 2000, XP, etc.).
Clarion executables come in two flavors: .EXE files, and .DLL files. An .EXE file is simply an executable program. A .DLL
(Dynamic Link Library) file is executable code that is linked into an .EXE file at run-time. This is in contrast to .OBJ and
.LIB files which are linked into an .EXE at compile time. The most obvious benefit of the .DLL is that it provides a method
of modifying .EXE operation without remaking (compiling and linking) the .EXE.
Clarion executables may be distributed in the following four configurations where [x] indicates the 32-bit runtime library for
applications running on 32-bit operating systems (95/98, NT, 2000, XP, etc.):
*.EXE
A one-piece .EXE will usually be larger than an .EXE distributed with .DLLs. However, the one-piece .EXE will probably
be smaller than the combined sizes of an .EXE and its associated .DLLs.
The one-piece .EXE is made as small as possible by Clarion's smart linking process that only links in procedures actually
called by the application program (whereas the .DLL contains a fixed set of procedures, whether or not they are actually
called by your program).
A one-piece .EXE cannot have conflicts or problems that arise from linking with the wrong .DLLs at run time.
Make (compile and link) time for a one-piece .EXE is greater than for an .EXE combined with .DLLs.
*.EXE + C70RUN[x].DLL
Splitting the executables between .EXEs and .DLLs allows for more efficient use of disk space. Many Clarion applications
(.EXEs) can share a single C70RUN[x].DLL. Or, a single application suite with several .EXEs can share a single
C70RUN[x].DLL. However, as a developer, you must ensure that your application accesses the correct version of
C70RUN[x].DLL.
An example of .DLL usage is the typical accounting system where the .EXE controls the system main menu, and calls
system subparts such as Accounts Receivable and Accounts Payable from separate .DLLs. This method of distribution
allows for program parts to be sold and maintained separately.
Splitting executables between .EXEs and .DLLs allows for more efficient use of disk space, but less efficient use of RAM.
This is because Windows 95 loads an additional C70RUN[x].DLL into memory for each active Clarion executable, and
because the C70RUN[x].DLL contains some procedures your .EXE never calls.
81
Tips, Tricks & FAQs
To make an .EXE + C70RUN[x].DLL: in the Global Options dialog, set Target Type to .EXE and set Run-Time Library to
Standalone.
You can modify your application's ship list by embedding text at the Inside the Shipping List Global Embed point.
82
Clarion 7 FAQs
Handle Dates before 1900 and beyond 2000 in the Same Procedure
When your program lets users input dates, it should do so as intelligently as possible. If your program is intelligent and
flexible in accepting dates, your end users will appreciate it. For example, forcing your end users to input dates in a rigid
dd/mm/yyyy format (or any fixed format) not only slows them down, it can lead to cursing and other expressions of
frustration when dates are misinterpreted or rejected altogether.
The keys to intelligent date handling with Clarion are the entry field picture token and Clarion's automatic date parsing
functions. Date Notation picture tokens let you display dates in a number of different formats. Better still, date picture
tokens in entry fields automatically invoke Clarion's run-time date parsing functions, so you can enter '21' and Clarion
expands it to the 21st day of the current month and year. Or you can enter 'DEC' and Clarion expands it to the 1st day of
December of the current year. Clarion then formats the expanded date according to the picture token.
The MASK attribute (Entry Patterns check box) on a window preempts the automatic date parsing functions and forces
the user to enter the date in the form of the date picture.
To illustrate, lets look at two different examples: a field containing employee birthdates and a field containing commercial
real estate lease expiration dates.
Birthdates from 1900 to 2000
The birthdate field is likely to contain dates ranging from the early 1900's to about 1980, and, since your application may
be in use for another 10 years, you should probably extend the upper end of this range to 1990 or even 2000.
You want to let your end users input the year of birth without having to explicitly specify the century. For example, in 1997,
your program should interpret an entry of 1/1/15 as January 1, 1915 and not as January 1, 2015.
By default, Clarion assumes that a year specified without the century falls within the 100 year period from today-80 years
to today+19 years. Thus in 1997, Clarion assumes dates entered fall between 1917 and 2016. This default, as illustrated
by our example entry (1/1/15) is not appropriate for your birthday field. However, you can use a date notation picture
token to change the default to fit your particular application.
The assumed 100 year period is always relative to today's date. Therefore, a picture token that is valid for employee
birthdays today will also be valid 10 years from today.
To specify an intelligent assumed date range to handle employee birthdays, simply add <99 to your preferred date picture
token:
@D1<99
You may specify the picture token by typing it into the Picture field in the Entry Properties dialog, or by pressing the
Picture field's ellipsis (...) button to open the Edit Picture String dialog. In the Edit Picture Sting dialog, choose your
preferred date format, then set the Two digit date range to 99.
Now, for this field, Clarion assumes that a year specified without the century falls within the 100 year period between
today-99 years and today+1 year. So, for birthdays entered in 1997, Clarion assumes the birth year falls between 1898
and 1998, and for birthdays entered in 2007 (10 years from now), Clarion assumes the birth year falls between 1908 and
2008.
Lease Expirations from 1997 to 2096
The lease expiration field is likely to contain dates ranging from the current year (1997) to 99 years in the future (2096).
You want to let your end users input the lease expiration year without having to explicitly specify the century. For example,
in 1997, your program should interpret an entry of 1/31/55 as January 31, 2055 and not as January 31, 1955.
By default, Clarion assumes that a year specified without the century falls within the 100 year period from today-80 years
to today+19 years. Thus in 1997, Clarion assumes dates entered fall between 1917 and 2016. This default, as illustrated
by our example entry (1/31/55) is not appropriate for your lease expiration field. However, you can use a date notation
picture token to change the default to fit your particular application.
83
Tips, Tricks & FAQs
The assumed 100 year period is always relative to today's date. Therefore, a picture token that is valid for lease
expirations today will also be valid 10 years from today.
To specify an intelligent assumed date range to handle lease expirations, simply add <0 (or >99) to your preferred date
picture token:
@D1<0
You may specify the picture token by typing it into the Picture field in the Entry Properties dialog, or by pressing the
Picture field's ellipsis (...) button to open the Edit Picture String dialog. In the Edit Picture Sting dialog, choose your
preferred date format, then set the Two digit date range to 0.
Now, for this field, Clarion assumes that a year specified without the century falls within the 100 year period between
today-0 years and today+99 years. So, for lease expirations entered in 1997, Clarion assumes the year falls between
1997 and 2096, and for lease expirations entered in 2007 (10 years from now), Clarion assumes the year falls between
2007 and 2106.
84
Clarion 7 FAQs
Sometimes you need to hide a window as you can hide a control. This is an undocumented feature since there is no HIDE
attribute on a WINDOW, but it is used internally by the IDE so it's likely to stay:
Assign a value to PROP:Hide for the window like this:
TARGET{PROP:Hide} = 1
How to highlight all the text in a control when it gets focus by a mouse click
When you tab to an entry control with the tab key, the entire entry field plus any existing text, is highlighted. Then, when
you begin typing, the highlighted text is immediately overwritten. However, when you select an entry control with the
mouse, you get an I-beam insertion point somewhere inside the entry field, and existing text is not highlighted.
To force a mouse selection to behave like the tab key, add MouseLeft to the list of Alert keys for the control, then embed
some code to "select" the entire field when the mouse is CLICKED:
1. From the Window Designer, RIGHT-CLICK the control and choose Alert from the popup menu.
2. From the Alert Keys dialog, press the Add button.
3. From the Input Key dialog, CLICK on Left Button in the Mouse group.
4. Press OK twice to return to the Window Designer.
5. From the Window Designer, RIGHT-CLICK the control and choose Embeds from the popup menu.
6. Add the following code to the EVENT:AlertKey embed point for the control:
IF KEYCODE() = MouseLeft
SELECT(?,LEN(?{PROP:ScreenText}))
?{PROP:SelStart} = 1
?{PROP:SelEnd} = LEN(?{PROP:ScreenText})
END
85
Tips, Tricks & FAQs
Although nearly all font types used on reports will print accurately, for the best display of reports in the Print preview
window, use a True Type font (Example – Arial 10pt).
If you prefer to hand code your print preview process, see PREVIEW in the Language Reference, for more information
and examples.
There are some menus and commands that you see in almost every windows program. For example, Cut, Copy, and
Paste. Clarion provides an easy method for implementing these standard actions in your application menus--with the
StdID property field on the Menu Editor dialog.
Simply enter one of the equates listed below in the StdID field. Clarion will automatically implement the command using
standard windows behavior; you do not need any other support for it in your code. The standard equate labels and their
associated actions are also contained in the ..\LIBSRC\EQUATES.CLW file.
STD:PrintSetup Printer Options Dialog.
STD:Close Closes active window.
STD:Undo Reverses the last editing action.
STD:Cut Deletes selection, copies to clipboard.
STD:Copy Copies selection to clipboard.
STD:Paste Pastes clipboard contents at the insertion point.
STD:Clear Deletes selection.
STD:TileWindow Arranges child windows edge to edge.
STD:TileHorizontal Arranges child windows edge to edge.
STD:TileVertical Arranges child windows edge to edge.
STD:CascadeWindow Arranges child windows so all title bars are visible.
STD:ArrangeIcons Arranges iconized child windows.
STD:WindowList Adds child window names to menu.
STD:Help Opens .HLP file to the contents page.
STD:HelpIndex Opens .HLP file to the index.
STD:HelpOnHelp Opens Microsoft's .HLP file for the Windows Help system.
STD:HelpSearch Opens Microsoft's Help Search utility for the .HLP file.
86
Clarion 7 FAQs
The Project System (Solution Explorer) allows you to specify external resources to link into the executable. These include
graphics, such as .BMP, .ICO and .WMF files. By linking them into the executable, you can avoid having to ship them as
separate, external files.
If you directly reference a graphic file within a data structure, the compiler automatically links the graphic, so there is no
need to add the graphic file to your Project Tree. For example, if you place an IMAGE control in a window, and specify a
file by name in the Properties Pad dialog, the linker automatically includes that file in your executable. But if you assign a
different graphic to a control using a runtime property assignment statement, the linker will only include the new file in your
executable if you add the file to your Project Tree.
To add graphic files to the executable:
1. In the Solution Explorere, RIGHT-CLICK on the Libraries, Objects and Resource files note and select the Add
Libraries, Objects and Resource files menu item.
Select the bitmap, icon, or metafile graphic from the standard Open File dialog.
2. Press the Open button to return to the Solution Explorer.
3. Highlight the source code file that references the graphic in the Application Tree, press the Embeds button, and
locate the appropriate Embed point.
The source code file is opened by the Text Editor.
4. Place a tilde (~) in front of the graphic file name in the source code assignment statement (not in data section).
For example: change ?Image{PROP:Text} = 'I.ICO' to ?Image{PROP:Text} = '~I.ICO.' The tilde indicates the program
should find the item as a linked in resource, not as an external file.
Optionally, choose Search Find to locate the file name.
5. Choose Save and Close, then CLICK on Yes when asked if you want to save.
Now, when you recompile and link, the executable will no longer require the external graphic file.
87
Tips, Tricks & FAQs
The File Conversion Utility creates source code to convert a file to a different specification. The conversion is automatic
except in the following cases:
If a field's label is changed
If a field is split into two separate fields.
If two or more fields are combined.
If a date is converted to a Clarion standard date from some other file system date format.
In these cases you must modify the source code to handle the field assignments. The portion of the source code you need
to examine is the AssignRecord ROUTINE. This is where field assignments are made. Here is an example:
AssignRecord ROUTINE
CLEAR(CUS:Record)
CUS:NUMBER = IN::NUMBER
CUS:FIRSTNAME = IN::FIRSTNAME
CUS:LASTNAME = IN::LASTNAME
CUS:ADDRESS = IN::ADDRESS
CUS:CITY = IN::CITY
CUS:STATE = IN::STATE
CUS:ZIP = IN::ZIP
CUS:PHONENUMBER = IN::PHONENUMBER
CUS:ENTRYDATE = IN::ENTRYDATE
If you examine the source code, you'll see that the first line in the routine clears the record buffer. Next each field in the
output file is assigned the value from the matching field in the input file.
Changing a Field's Label
However, if the field labels do not match, no assignment is made. For example, if you change the LastName field to
Surname, the File Conversion utility generates a comment to alert you of an assignment you may need to make:
AssignRecord ROUTINE
CLEAR(CUS:Record)
CUS:NUMBER = IN::NUMBER
CUS:FIRSTNAME = IN::FIRSTNAME
! CUS:SURNAME = ''
CUS:ADDRESS = IN::ADDRESS
CUS:CITY = IN::CITY
CUS:STATE = IN::STATE
CUS:ZIP = IN::ZIP
CUS:PHONENUMBER = IN::PHONENUMBER
CUS:ENTRYDATE = IN::ENTRYDATE
To assign the values from the original file, edit the line containing the assignment to assign the value of LastName to the
SurName field as shown below:
CUS:SURNAME = IN::LASTNAME
88
Clarion 7 FAQs
Notice there is an assignment from the original PhoneNumber field to the new PhoneNumber field. However, since the
new field only stores seven digits, you should change this. To handle the field assignments, create an implicit string
variable, assign to it the value of the original PhoneNumber field, then use string slicing to assign the desired portions to
the new fields, as shown below:
AssignRecord ROUTINE
CLEAR(CUS:Record)
CUS:NUMBER = IN::NUMBER
CUS:FIRSTNAME = IN::FIRSTNAME
CUS:LASTNAME = IN::LASTNAME
CUS:ADDRESS = IN::ADDRESS
CUS:CITY = IN::CITY
CUS:STATE = IN::STATE
CUS:ZIP = IN::ZIP
TempPhoneNumber" = IN::PHONENUMBER
CUS:AREACODE = TempPhoneNumber"[1:3]
CUS:PHONENUMBER = TempPhoneNumber"[4:10]
CUS:ENTRYDATE = IN::ENTRYDATE
For more information on String Slicing, see Implicit String Arrays and String Slicing .
89
Tips, Tricks & FAQs
Notice there is an assignment from the original PhoneNumber field to the new PhoneNumber field, but the original
AreaCode is omitted. To handle the field assignments, create two implicit strings and assign them the original AreaCode
and PhoneNumber values, then concatenate the strings and assign the result to the new PhoneNumber as shown below:
AssignRecord ROUTINE
CLEAR(CUS:Record)
CUS:NUMBER = IN::NUMBER
CUS:FIRSTNAME = IN::FIRSTNAME
CUS:LASTNAME = IN::LASTNAME
CUS:ADDRESS = IN::ADDRESS
CUS:CITY = IN::CITY
CUS:STATE = IN::STATE
CUS:ZIP = IN::ZIP
TempAreaCode" = IN::AREACODE
TempPhoneNumber" = IN::PHONENUMBER
CUS:PHONENUMBER = CLIP(TempAreaCode") & TempPhoneNumber"
CUS:ENTRYDATE = IN::ENTRYDATE
For more information on String Slicing, see Implicit String Arrays and String Slicing .
90
Clarion 7 FAQs
Converting a Date
Let's assume the ENTRYDATE field contains a string date in MM/DD/YY format. We want to convert this string date into a
Clarion standard date so we can perform calculations against it and display it in various other formats.
We use the DEFORMAT function to perform the conversion as shown below. The @D1 represents the Clarion Date
Picture that corresponds to the MM/DD/YY format. See Date Pictures in the Language Reference for more information.
AssignRecord ROUTINE
CLEAR(CUS:Record)
CUS:NUMBER = IN::NUMBER
CUS:FIRSTNAME = IN::FIRSTNAME
CUS:LASTNAME = IN::LASTNAME
CUS:ADDRESS = IN::ADDRESS
CUS:CITY = IN::CITY
CUS:STATE = IN::STATE
CUS:ZIP = IN::ZIP
! CUS:AREACODE =
CUS:PHONENUMBER = IN::PHONENUMBER
CUS:ENTRYDATE = DEFORMAT(IN::ENTRYDATE,@D1)
91
Tips, Tricks & FAQs
This FAQ documents development issues that are necessary for Clarion developers familiar with the procedure based
Clarion templates who are considering the use of the Clarion ABC template chain.
You now have a vastly improved development tool at your disposal: Clarion, with its Application Builder Class (ABC)
Templates and ABC Library. These tools write Object-Oriented (OOP) code for you, using the same template interface
that you've grown accustomed to in earlier versions of the Clarion templates. This article provides answers to the most
common questions about making the move to ABC/OOP.
So, the first question you'll probably ask yourself (after doing the lessons in Getting Started and Learning Clarion to
become familiar with the new features) is: "How can I leverage what I already know to get up to speed with Clarion ABC
as fast as possible?" That's the overall question that this informal article answers. You'll probably be surprised at how
much is still the same, how many resources are at your disposal, and how much more power Clarion has put in your
hands with the change to OOP technology.
For those of you who don't write embedded code (or very little) and mostly let the templates handle all the coding, the
answer to the question is: you're already leveraged, you already know it--just keep on working with Clarion as you always
have. You may notice a reduction in the size of your EXEs and an increase in your applications' performance, but you
don't really care how we achieve that, now do you! This article will be the most benefit to those of you who do a
substantial amount of coding for yourselves in embed points.
I've heard that the ABC generated code looks very different.
Yes, that's certainly true. The ABC templates only generate a single line of code (GlobalResponse =
ThisWindow.Run()) into a generated PROCEDURE. All the code to accomplish the functionality of the PROCEDURE is
contained either in the ABC Library, or in overridden methods of the ABC Library. These overridden methods are
specifically generated for you by the ABC Templates to implement the functionality you request when you fill in the
template prompts.
92
Clarion 7 FAQs
For all the various types of procedures, the ABC template generated code gives you the same functionality the Clarion
procedural templates give you (often more, and with more efficient execution). You can easily see this just by looking at
the similarity in the template prompts in the Application Generator. This means that you can simply continue to choose the
functionality your PROCEDURE should perform from the ABC Template prompts just as you did before--without changing
the familiar way of working you're already accustomed to!
93
Tips, Tricks & FAQs
94
Clarion 7 FAQs
95
Tips, Tricks & FAQs
Activity for each record (Process Process Manager Method Executable Code
template) Section,
IF NOT RECORDS(SELF.ListQueue)
!Place your code here (you must write the
!surrounding IF structure, too)
END
Yeah, but I heard that writing File Handling code is very different in ABC.
OK, here's where there really is a fundamental difference. Since the ABC Templates generate their code using the ABC
Library, you'll want to write your embedded code to use the ABC Library methods so that there's no possibility that your
embedded code will "mess up" anything the template generated code is counting on. Naturally, this is going to be easier
to do than you might think.
Here's a table of the ABC methods to use in place of the common Clarion language statements:
96
Clarion 7 FAQs
IF ERRORCODE THEN
STOP(ERROR()).
97
Tips, Tricks & FAQs
Another common file handling situation is the simple file processing LOOP. In the Clarion template embeds, you would
write code like this:
SET(key,key)
LOOP
NEXT(File)
IF ERRORCODE() THEN BREAK. !Break at end of file
!Check range limits here
!Process the record here
END
As you can see, this is all pretty straightforward--only a couple of minor changes to learn.
Another common code construct is getting a record from a file. In the Clarion template embeds, you might write code like
this:
IF File::used = 0
CheckOpen(File)
END
File::used += 1
CLEAR(FIL:record)
Fil:Code = 123
GET(File,FIL:CodeKey)
IF ERRORCODE() THEN CLEAR(FIL:Record).
File::Used -= 1
IF File::used = 0
CLOSE(file)
END
98
Clarion 7 FAQs
And of course, the file Open and Close method calls can be generated for you if you just add the file to the procedure's
Data / Tables Pad. The ABC Library is smart enough to only open a file if it really needs to, making your program more
efficient. Using Clarion's ABC Library methods you write less code to accomplish the same (or more) functionality.
AddItem Adds an item to its object's datastore. The item may be a field, a key, a
sort order, a range limit, another object, etc.--anything the object needs
to do its job.
Kill Does whatever is required to shut down the object, including freeing any
memory allocated during its lifetime.
Reset[what or how] Resets the object and its controls. This includes reloading data,
resetting sort orders, redrawing window controls, etc.
SetItem Sets the value of the named item, or makes the named item active so
that other object methods can operate on the active item.
99
Tips, Tricks & FAQs
TakeItem "Takes" the item from another method or object and continues
processing it. The item may be a window event (Accepted, Rejected,
OpenWindow, CloseWindow, Resize, etc.), a record, an error condition,
etc.
Throw[Item] "Throws" the item to another object or method for handling. The item is
usually an error condition.
TryAction Makes one attempt to carry out the Action. A return value of zero (0 or
Level:Benign) indicates success; any other value indicates failure.
Knowing these consistent naming conventions will make it much easier to understand what an object's methods do,
whether you've read the ABC Library Reference about that specific type of object or not!
In addition to the ABC Library Reference, Clarion also has a Class Viewer to show you the ABC Library properties and
methods in a tree view. On any Classes tab, just press the button labeled "Application Builder Class Viewer" to view the
ABC Library structure. The Class Viewer graphically shows you how the ABC Library classes are derived--which class
inherits properties and methods from which Parent class.
The ABC Template set contains two Code Templates, which will help you learn more about using the ABC Library:
CallABCMethod and SetABCProperty. These were specifically created to "walk you through" writing ABC Library code in
any executable code embed point. These two Code Templates will write your method calls and object property
assignments for you!
If the ABC Templates will perform the task for you, you're done. If they won't, continue on to Step 2.
1. Identify the ABC Object (and its CLASS) that manages the behavior you need to change.
Quite often there are several candidate objects in a single PROCEDURE that might control the behavior you need to
change. Therefore, you may need to identify several objects/classes to look at in the following steps. The easiest way to
identify candidate objects is to look in the Embeditor. Each object you see in your PROCEDURE is derived from the ABC
Library. The object's Parent CLASS name (in parentheses following "CLASS") should give you an idea of the type of
behavior the object controls. The most common objects and their corresponding classes are:
ThisWindow WindowManager
BRWn BrowseClass
ThisProcess ProcessClass
100
Clarion 7 FAQs
Once you've identified the candidate objects and CLASSes, continue on to Step 3.
1. Determine if the object/CLASS has a property that you can set to accomplish the task.
The ABC Library Reference and the Class Viewer are the best sources for this information. Remember that a derived
class inherits all the properties of its parent class.
If setting a property performs the task for you, you're done. If not, continue on to Step 4.
1. Determine if a method of the object/CLASS already does the task.
Again, the ABC Library Reference and the Class Viewer are the best sources for this information. Remember that a
derived class inherits all the methods of its parent class.
If calling an existing method performs the task for you, you're done. If no method already does the task, continue on to
Step 5.
1. Determine which method you can modify to accomplish the task, then override it.
Follow the same process as in Step 4 to identify the method that comes closest to performing the task you need to
accomplish. To override a method, place your code in the embed points for that method. You can use other ABC
properties and methods in your code to do what you need.
If the modified/overridden method is VIRTUAL, you're done. You do not need to call VIRTUAL methods yourself since the
other methods of the CLASS call them for you as part of their normal operations (as in the above example). If the method
is not VIRTUAL or you need to call it outside the normal sequence of events, then you just use a similar process to
determine where to call the method: find the method that manages the behavior and embed your call in an embed point of
that method.
Following these steps, you can accomplish any programming task in the most efficient manner, by always working at the
highest level of abstraction possible in Clarion--that is, do as little "work" yourself as possible to accomplish the greatest
effect.
OK, the theory looks good, but how about some real examples?
Sure. Here're a few:
101
Tips, Tricks & FAQs
Where do you put this one line of code? Since this property is in the ThisWindow object it cannot execute until the
ThisWindow object has been initialized (following the PARENT.Init call in ThisWindow.Init). And, since the purpose of this
task is to "shortstop" the Print Preview, it must execute before the Previewer object is called to display the finished report
(before the PARENT.AskPreview call in ThisWindow.AskPreview). These two requirements limit you to probably only a
few hundred embed points within your report procedure's logic, but the best place to just "set it and forget it" is the end of
the ThisWindow.Init method. You're done at Step Three!
Task: I want to let the end-user dynamically filter a browse list at runtime.
1. The BrowseBox Control Template's documentation in the Template Guide doesn't show any template
settings for a dynamic filter, so you go on to Step Two.
2. In the Embeditor, you see that the only likely candidate object/CLASS is BRW1/BrowseClass, because it
controls the browse list, then go on to Step Three.
3. None of the BrowseClass properties listed in the ABC Library Reference appear to help for this task.
BrowseClass is derived from the ViewManager, which means it inherits all the ViewManager properties
and methods, so you check the ViewManager properties also. None of them apply either, so you go on to
Step Four.
4. The ABC Library Reference documents the BrowseClass methods in addition to its properties. You don't
immediately see any that might apply, so you check the inherited ViewManager methods, also. That's
where you find the ViewManager's SetFilter method, which appears to be exactly what you need for this
task. Therefore, you see that to change the browse filter you can execute code like this:
But where to put this code? Since you want the end user to enter the data to filter on, you obviously need an ENTRY
control the user can type into, and that ENTRY control's USE variable is obviously the NewFilter variable (a STRING(1) in
this example code) you want to use in the SetFilter method. Therefore, the only logical choice for where to place this code
is in the EVENT:Accepted embed point for the NewFilter ENTRY control.You're done at Step Four!
Task: I want the user to be able to copy an existing record when adding a new record.
This task actually means that you want to provide a "Copy" button that does everything the "Insert" button does (like auto-
increment) but gives the user some "starting point" data in the update Form based on the currently highlighted record in
the Browse list.
1. Neither the BrowseBox nor the BrowseUpdateButtons documentation in the Template Guide shows any
template settings for this, so you go on to Step Two.
2. In the Embeditor, you see that the only likely candidate object/CLASS is BRW1/BrowseClass, because it
controls the browse list and calling the update Form, so you go on to Step Three.
3. None of the BrowseClass or inherited ViewManager properties listed in the ABC Library Reference
appear to help for this task, so you go on to Step Four.
102
Clarion 7 FAQs
4. You look at the BrowseClass methods and don't see any that might apply, so you check the inherited
ViewManager methods, also. That's where you find the ViewManager's PrimeRecord method, which
takes a parameter that appears to be exactly what you need for this task. However, this method is
VIRTUAL--automatically called by the base classes--so you don't need to call it, so you go on to Step
Five.
5. Opening the Embeditor for the Browse procedure, you find the BRW1.PrimeRecord method. You can see
that it takes a parameter called SuppressClear which defaults to FALSE (zero). Therefore, you know that
you can just assign TRUE (one) to the SuppressClear parameter before it is passed on to
PARENT.PrimeRecord to suppress clearing the rest of the fields in the record (after auto-incrementing
any necessary fields). However, if you just do a simple assignment statement, you will be overriding this
functionality for every insert. Therefore, you need to declare a local flag variable to the Browse procedure
to flag whether or not to suppress the clear. Scroll back up to the top of the file and, in any Data Section
embed point, add the following code:
Then you can place the following code in the BRW1.PrimeRecord method immediately BEFORE the
PARENT.PrimeRecord call:
This overrides the ABC Library's PrimeRecord method with your own, but still calls the ABC Library's method to handle its
functionality (so we don't have to re-write its code). Since this is a VIRTUAL method, you don't have to worry about calling
it--it's called automatically for you from within the other ABC Library methods.
You're almost done, but not quite. In order for the user to signal when they want to copy a record, you need to add a
"Copy" BUTTON control to the Browse window. Then, in EVENT:Accepted for your ?Copy BUTTON, you place the
following code to set the CopyFlag and initiate adding the copied record:
When the user presses your Copy button, CopyFlag is set to TRUE and then the normal Insert button code sequence
occurs, but your overridden BRW1.PrimeRecord method will execute instead of the ABC Library's standard method.
You're done at Step Five!
103
Tips, Tricks & FAQs
Task: I want to add my new "Copy" button to the Browse's popup menu.
This task requires that you have a "Copy" button as described above.
1. The BrowseBox Control Template documentation in the Template Guide doesn't show any
template settings for this, so you go on to Step Two.
2. In the Embeditor, you see that the only likely candidate object/CLASS is BRW1/BrowseClass,
because it controls the browse list, then go on to Step Three.
3. The BrowseClass documentation in the ABC Library Reference lists a Popup property described
as a "browse popup menu reference." Reading the description of this property you discover that it
is a reference to the PopupClass object used by the Browse, so you look at the PopupClass to
see if there are any properties that will add an item to the popup menu for you. There are no
PopupClass properties, so you go on to Step Four.
4. You look at the BrowseClass methods and don't see any that might apply, so you check the
PopupClass methods, also, since you know the Browse object contains a reference to the
PopupClass object. That's where you find the PopupClass's AddItemMimic method, which will
add an item to the popup menu to press a BUTTON control. This appears to be exactly what you
need for this task. Therefore, you now know that to add the Copy button to the popup menu for
this BrowseBox, you can simply execute:
!Call a PopupClass method through the Browse object's PopupClass !reference property
BRW1.Popup.AddItemMimic('Copy',?Copy)
So where does this one line of code need to go? Since the Popup property must already exist, it must come sometime
after the BRW1 object has been initialized. And, since you just want to add this to the popup menu and not dynamically
enable/disable it, this code needs to happen on the way into the procedure, before the user can do anything on the
window. In the Embeditor, you can see that the BRW1.Init method is called in the ThisWindow.Init method, and you
already know that ThisWindow.Init is always the first method called in any procedure with a window. Therefore, the best
embed point to place this one line of code would be one near the end of the ThisWindow.Init method. You're done at Step
Four!
Task: I want to call a Form directly from the menu (without a Browse) to add records.
This task actually implies the need to do three things: 1) alert the procedure that it will be inserting new records into the
database, 2) ensure that any auto-increment keys are properly incremented, and 3) ensure that all other fields in the file
are properly initialized to their default initial values.
1. The Form Template's documentation in the Template Guide doesn't show any template settings for this,
so you go on to Step Two.
2. In the Embeditor, you see the only object in the Form procedure (other than two Toolbar-related objects)
is ThisWindow/WindowManager. However, you also have a global object for each of the data files your
application accesses. Therefore, a second candidate object/CLASS to look at for this task is
Access:FileName/FileManager.
104
Clarion 7 FAQs
While exploring in the Embeditor you notice that the very beginning of ThisWindow.Init is where the value of the
GlobalRequest variable (which tells the Form procedure what file action to perform) is obtained. You know you need to
deal with this issue, so in the very first embed point available in ThisWindow.Init (immediately following the CODE
statement) you add:
1. None of the WindowManager properties listed in the ABC Library Reference appear to help for this task,
so you check the FileManager properties also. None of these apply either, so you go on to Step Four.
2. The ABC Library Reference shows two FileManager methods (PrimeRecord and PrimeAutoInc) which
appear to be exactly what you need for this task. Now you just need to find where to call them, so you go
on to Step Five.
3. The ABC Library Reference shows a WindowManager method called PrimeFields that looks like the best
place from which to call the FileManager methods. In the Embeditor, you write code like this into any
embed point in ThisWindow.PrimeFields:
Now, when you call this Form procedure directly from a menu (without an intermediate Browse) it will automatically be in
Insert mode and will correctly handle auto-incrementing keys and setting up all the initial values you declared in the Data
Dictionary. You're done at Step Five!
Task: I want total fields on one tab and the BrowseBox which they total on another.
This task implies that the tab which the user sees first is a "summary" tab, and the "detail" Browse list (or multiple lists)
which calculates the totals is hidden on another tab. Simply placing the total fields on a separate tab from the hidden
Browse means that the total fields display zeroes until the user has gone to the tab containing the Browse list and come
back to the tab containing the total fields. The ABC Templates default to only updating a Browse list when it is visible
because this achieves better overall performance for the majority of cases. However, in this one case, the Browse list
needs to be active despite the fact that it is not visible to the user.
1. The BrowseBox Control Template documentation in the Template Guide doesn't show any template
settings for this, so you go on to Step Two.
2. In the Embeditor, you see that the only likely candidate object/CLASS is BRW1/BrowseClass, because it
controls the browse list, then go on to Step Three.
3. The BrowseClass documentation in the ABC Library Reference lists an ActiveInvisible property which,
when set to one (1), makes the Browse list active even though it's not visible. Therefore, you now know
that you can simply execute:
105
Tips, Tricks & FAQs
So where does this one line of code need to go? Since the ActiveInvisible property must already exist, it must come
sometime after the BRW1 object has been initialized. And, this property needs to be set on the way into the procedure,
before the user can see the window so the totals will be calculated and displayed correctly. In the Embeditor, you can see
that the BRW1.Init method is called in the ThisWindow.Init method, and you already know that ThisWindow.Init is always
the first method called in any procedure with a window. Therefore, the best embed point to place this one line of code
would be near the end of the ThisWindow.Init method. You're done at Step Three!
As you can see, this 5-step process leads you to the earliest possible solution to any programming task.
106
Clarion 7 FAQs
This topic will show you how to limit an MDI Child browse procedure to a single instance using messaging.
The simplest solution is to disable the menu item when the browse procedure is active. You can't do this in the menu
itself--you must send a message to the Frame procedure from the browse.
First you need to declare two new events in the Global Properties, Global Data embed point:
EVENT:DisableCustomerItem EQUATE(401h)
EVENT:EnableCustomerItem EQUATE(402h)
(Whenever an MDI procedure is STARTed, a thread number is allocated to it. We need the thread number in order to post
a message to the frame procedure.)
Now, still in the frame procedure, you need to write code in the WindowManager Executable Code--TakeWindowEvent
[Priority: 2800] embed to handle the two user-defined events that the frame procedure will receive.
OF EVENT:DisableCustomerItem
DISABLE(?ShowCust)
OF EVENT:EnableCustomerItem
ENABLE(?ShowCust)
In the Browse procedure, in the WindowManager Executable Code--Init [Priority:5600] embed, type:
POST(EVENT:DisableCustomerItem,,GLO:MainThreadNo)
Now, the first time you select the Browse Procedure from your menu, ShowCust starts up, the POST() statement
executes and an EVENT:DisableCustomerItem is sent to the Frame procedure.
If the user then clicks on the menu again, the message is processed and the item is disabled.
As the user exits ShowCust, the EVENT:EnableCustomerItem message is sent to the Frame. When that message is
processed the menu item is enabled again.
Why store the Frame's thread number - surely it would always be number 1? Well it might NOT be the first thread in the
application.
(Thanks to Rob Mousley of Chariot Software for submitting this topic.)
107
Tips, Tricks & FAQs
A Minimize button is added to a WINDOW if you specify an ICON for the WINDOW. When the user presses the Minimize
button, the window is reduced to an Icon.
In the Window Designer:
1. Make sure the Window is selected.
2. Choose View Properties
The Properties Pad dialog appears, and will have focus.
3. In the Icon property combo box, select a standard icon, type the name of the icon file, or select Select File... to
locate an icon file using the standard Open File dialog.
4. Press the Save and Close button to close the Window Designer dialog.
108
Clarion 7 FAQs
Regarding SQL databases, standard SET(key,key) processing is not always the most efficient approach. This is because
the SET(key,key) statement sets the starting part of the search, but not the ending part of the search.
CLEAR(PHO:Record)
PHO:CategoryID = 1
SET(PHO:FK_CategoryKey,PHO:FK_CategoryKey)
LOOP
IF Access:Photos.Next() <> LEVEL:Benign
BREAK
END
IF PHO:CategoryID <> 1
BREAK
END
END
All of the filtering you need is defined and optimized in the /WHERE driver string via the SEND command.
If you notice that the backend is doing a full table scan, this would indicate that a design problem is possible on the
backend database. Clarion simply sends a SELECT statement to the server. It does NOT tell the server how to fulfill that
SELECT. That decision is left up to the server. For example, if you send to the server:
If there is no corresponding index on the server, then the server has no choice but to do a full table scan. In that case,
instead of rewriting all of the Clarion code to use a Prop:SQL statement, the time would be better spent on optimizing the
database design.
109
Tips, Tricks & FAQs
Using PROP:Where (or SEND(FILE, '/WHERE.....')) can limit the result set you get, and even eliminate using a key in the
SET statement. Clarion does this by setting or adding to the WHERE clause containing your condition, greatly reducing
the load on the server.
Note: Do not use the standard clarion field name syntax (e.g., pre:columnname).
For example:
SET(MyFile)
MyFile{PROP:WHERE} = 'CUSTOMERID = ' & LOC:CUSTOMERID
LOOP
NEXT(MYFILE)
IF ERRORCODE() THEN BREAK.
! process record here
END
SET(MYF:K_DATE)
MYFILE{PROP:WHERE} = 'CUSTOMERID = ' & LOC:CUSTOMERID
will do the same, but order them by the date (whatever is in MYF:K_DATE).
Using PROP:Where also eliminates the hassle of handling "field alignment" when using PROP:SQL to retrieve records. It
accomplishes what you would get if you intend to do the equivalent of a "SELECT *".
You can also improve performance by using a BUFFER statement, like this:
BUFFER(MyFile, 20)
SET(MYF:K_DATE)
MYFILE{PROP:WHERE} = 'CUSTOMERID = ' & LOC:CUSTOMERID
110
Clarion 7 FAQs
Printing labels simply means printing a multi-column report, that is, getting the report rows and columns to match up with
the commercial label forms you use.
1. With a ruler, measure the height and width of the label paper, measure the height and width of the individual
labels, and measure any top or left margins on your label paper. Make your measurements in inches.
2. Create a report of your address file.
Use the Report Wizard if you want, but don't worry about formatting yet. Just make sure the report contains all the
address fields you need for your labels.
3. From the Application Tree, RIGHT-CLICK on your report procedure and choose Report from the popup menu.
4. Delete all report sections, except the Detail section.
5. From the IDE Menu, choose View Properties, and verify that the Report is the selected component in the
Properties Pad.
6. On the General category, choose THOUS in the Units property drop down list.
7. On the Positions category, set the margins you measured earlier.
The X property represents the left margin in thousandths of inches and the Y property represents the top margin in
thousandths of inches. So, if the left margin of your label paper is 1/2 inch, type 500 in the X property. If the margin is
zero, type 0 (zero) in the X property. Do the same for the top margin and the Y property.
8. In the Position category, set the Height and Width property values of the label paper.
In the Width group, verify that the Default property is set to FALSE, and type the paper width in thousandths of inches.
Standard letter size paper is 8 1/2 inches, so type 8500. Do the same for the paper Height property. Standard letter size
paper is 11 inches, so type 11000.
9. In the Report Worksheet, arrange your address fields in a vertical format, that is, one field below another near the
left margin. Use the Alignment tools for precise alignment.
10. RIGHT CLICK on the Detail band and choose Properties from the popup menu.
11. In the Position tab, set the Height and Width properties of the individual labels.
In the Width group, verify that the Default property is set to FALSE, and type the label width in thousandths of inches (eg
for a 2 1/2 inch label, type 2500). Do the same for the label height.
12. Back in the Report Worksheet, readjust the position, size, and font of your address fields if necessary.
13. In the Report Designer toolbar, click on the Print Preview button to preview your label report.
14. Save and Close the Report Designer, saving your changes.
111
Tips, Tricks & FAQs
You can change the windows default printer without calling the PRINTERDIALOG function. This can be done by using
Clarion's property syntax. The property to use is PROPPRINT:Device. This property definition can be found in
..\LIBSRC\WIN\PRNPROP.CLW. This must be included in your application before making use of any of the properties
defined therein.
To include PRNPROP.CLW:
1. Select the Global Embeds tab on the Application Tree.
2. Select the After Global Includes embed point and add the following embedded source code:
INCLUDE('prnprop.clw')
PRINTER{PROPPRINT:Device} = SAV::Printer
PRINTER{PROPPRINT:PrintToFile} = FALSE ! print to file flag
112
Clarion 7 FAQs
When calling procedures and functions, you may want to pass parameters, return values, or both. You can define
(prototype) parameters and return values with the Procedure Properties dialog.
To pass parameters to a procedure, you must do the following.
Add the parameters' datatypes to the prototype in the program's MAP
Add the parameters' names to the PROCEDURE statement
Pass the parameters in the procedure call
MAP
...
WindowsControls FUNCTION(SHORT ControlX,SHORT ControlY),SHORT
...
END
Notice the entire text from the Prototype field, including the parentheses, is appended to the prototype for the function.
The words inside the parentheses are the datatypes and variable name of the parameters passed to the procedure or
function. The word following the parentheses is the data type of the value returned by the procedure.
Again, the entire text from the Parameter field, including the parentheses, is appended to the PROCEDURE statement.
113
Tips, Tricks & FAQs
In the Return Value field in the Procedure Properties dialog, press the ellipsis button (...) to select or define a return
variable for the function, and to generate the following code. Note also the generated ProcedureReturn routine now
RETURNs the value of the return variable you specified in the Return Value field: ReturnCode.
You should add embedded code to assign an appropriate value to the returned variable.
114
Clarion 7 FAQs
There are some occasions when you may want to introduce a timed delay to your Windows applications. You don’t want
to use a LOOP structure to simulate a delay because the LOOP command is processor dependant. Looping 1000 times
on one machine may be quite different from another in regards to length of time or duration.
Instead, use the Windows Sleep API function, which releases the CPU and lets other apps in the system effectively
multitask. The Sleep function suspends the execution of the current thread for a specified interval.
To add the SLEEP prototype to your application, include the following MODULE structure inside the Global Map of your
program or application:
MODULE('')
SLEEP(LONG),PASCAL
END
The SLEEP API has a time parameter, in milliseconds, for which to suspend execution. A value of zero causes the thread
to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other
threads of equal priority ready to run, the function returns immediately, and the thread continues execution.
SLEEP(1000) !delay for 1 second
Besides using SLEEP() to introduce a delay, at times it is also useful to allow other programs to "catch up" with your
applications, and SLEEP() can be useful for this. For example, consider the following sample code:
SETCURSOR(Cursor:Wait)
System{Prop:DDETimeout} = 12000
WordChannel = DDEClient('WinWord','System')
IF NOT WordChannel
RUN('C:\Program Files\Microsoft Office\Office\WinWord.exe',0)
SLEEP(50) !Introduce a little delay to allow MSWord to initialize.
END
WordChannel = DDEClient('WinWord','System')
On slower machines, it is possible that the MSWord program may not finish its initialization sequence on start up before
the DDEClient command is executed. SLEEP() allows the MSWord program to finish its startup and open a proper DDE
channel to the Clarion program.
115
Tips, Tricks & FAQs
116
Clarion 7 FAQs
This corruption can be prevented with the following change to the code:
STREAM(file)
FLUSH(file)
LOGOUT(1,file)
ROLLBACK
Clarion data files, while not as stringent on error checking as TopSpeed files, will post errors if a bad bit is written into a
field containing key information. If the record and key are not matching, then the driver will post and Invalid Key File error
(Error 38) or a Key File Be Rebuilt Error (Error 46).
Both TopSpeed and Clarion files operate in a multi-user environment through shared data access in a station to station
manner. This means that there is no particular station that works as a server controlling the requests made to the files.
This type of data environment requires that the underlying operating system and network requesters work flawlessly to
ensure proper passing of data from station to station. If this layer is faulty or unstable, incorrect bits could be sent to the
data files causing data corruption.
If consistent file corruption are occurring on applications using TopSpeed or Clarion data files, there are two steps to fixing
these problems. First, fix the corrupted data file; second, prevent further corruption.
117
Tips, Tricks & FAQs
OPEN(file)
SEND(file,'FULLBUILD=ON')
BUILD(file)
SEND(file,'FULLBUILD=OFF')
118
Clarion 7 FAQs
The resize feature on listboxes is most useful if the user specified sizing is remembered and reapplied to the list box. The
following procedure uses embedded GETINI, PUTINI, and PROPERTY assignment syntax statements to save and
restore the user specified formatting changes. The formatting is stored in an application specific .INI file.
1. In the Application Tree dialog, DOUBLE-CLICK on your browse procedure.
The Procedure Properties dialog appears.
2. Press the Embeds button.
The Embedded Source dialog appears.
3. In the Embedded Source dialog, DOUBLE-CLICK on the "WindowManager Method Executable Code -- Ask -- ( )
" embed point.
The Select Embed Type dialog appears.
4. DOUBLE-CLICK on SOURCE.
The Text Editor appears, ready to accept your embedded source statements.
5. Type the following statement, then Exit! the Text Editor and save your changes.
?Browse:1{PROP:FORMAT}=GETINI('Preferences','?Browse:1Format',?Browse:1{PROP:FORMAT},'MyApp.INI')
where ?Browse:1 is the field equate label for your list box, and MyApp is the name of your .APP file.
"Preferences" is the section in the .INI file where the information is stored. "?Browse:1Format" is the entry in the
.INI file where the information is stored, and "?Browse:1{PROP:FORMAT}" supplies the current format string as
the default in case there is no formatting information in the .INI file.
6. Set the Priority to "First". This embeds the code before the PARENT.Ask() method.
7. Highlight the "WindowManager Method Executable Code -- Ask -- ( ) " embed point again and press
Insert.
The Select Embed Type dialog appears.
8. DOUBLE-CLICK on SOURCE.
The Text Editor appears, ready to accept your embedded source statements.
9. Type the following statement, then Exit! the Text Editor and save your changes.
PUTINI('Preferences','?Browse:1Format',?Browse:1{PROP:FORMAT},'MyApp.INI')
where ?Browse:1 is the field equate label for your list box, and MyApp is the name of your .APP file.
10. Set the Priority to "Last". This embeds the code after the PARENT.Ask() method.
119
Tips, Tricks & FAQs
The DDEEXECUTE statement takes the DDE channel number as its first parameter, and the command string as the
second. Excel requires you to enclose all DDE commands in square brackets. This command creates a blank
spreadsheet.
The Excel command string enclosed by the square brackets is an Excel macro statement. Excel, and many other
applications allow you to send a macro statement via the DDEEXECUTE statement. In this particular case, you don't have
to know the name of the open Excel file to execute the statement.
Many commercial applications with their own macro languages allow you to both record and edit macros. Use the
application to make a "dry run" of the actions you need it to execute, with its macro recorder turned on. Edit the resulting
macro, and use the clipboard to copy each macro statement to your embedded source in the Text Editor. Put each macro
statement in the second parameter of the DDEEXECUTE statement, and you can be assured of the correct syntax for the
DDE command!
In the next embedded source line, tell Excel to save the new (blank) sheet under a name that you specify.
DDEEXECUTE(Channel, '[SAVE.AS("DDE_TEST.XLS",1,"", FALSE,"",FALSE)]')
Knowing the name allows you to close this channel, then open another specifying the file name as the topic. Note that the
Excel command string requires double-quote marks.
Terminate the channel started under the "System" topic.
DDECLOSE(Channel) ! Close first DDE channel
120
Clarion 7 FAQs
Open the DDE channel and name the file as the topic.
Channel = DDECLIENT('Excel','DDE_TEST.XLS') !New channel under known filename
Following the successful placement of the value in the spreadsheet, you could then send further Excel macro statements
using DDEEXECUTE. This would allow you to send additional spreadsheet data, highlight a range, then tell Excel to draw
a chart.
121
Tips, Tricks & FAQs
1. Click on the DETAIL band where you wish to add the break.
2. From the IDE Menu, choose Report Designer Bands Surrounding Break.
3. Click on the Break( ) just created. If the Property View is not visible, open it now from the
IDE Menu (View Properties)
4. In the Break Properties dialog, type the name of a variable or field, including the prefix, to
break on in the Variable property.
5. Type a valid Clarion label in the Label property to name the break.
This inserts the group BREAK. When the report prints, it groups together all records with the same value for the BREAK
field, and prints any group HEADER and FOOTER defined for the break.
122
Clarion 7 FAQs
If the break variable is a global or local variable, you must be sure that the executable code updates its value, so that it
can generate a group BREAK.
6. Choose Report Designer Bands Group Header from the IDE menu to define a group
HEADER for the BREAK.
7. In the Report Designer worksheet, click on the Group Header( ) just created. If the Property
View is not visible, open it now from the IDE Menu (View Properties)
8. In the Group Header Properties dialog, specify a field equate label and any other special
page breaking behavior.
This inserts the group HEADER band. You may place controls here just as in any other report band. Group footers are
added similarly, using Bands Group Footer from the menu
123
Tips, Tricks & FAQs
124
Clarion 7 FAQs
2. Highlight the Local Data section, and press the Insert button.
3. Type Channel in the Name field.
4. Choose LONG from the Type dropdown list.
5. Press the OK button to close the Field Properties dialog.
125
Tips, Tricks & FAQs
The code example is deliberately simplistic; it would be more efficient to LOOP through the attempt to contact twice, then
warn the end user of the failure.
The code attempts to open a DDE conversation with Excel named as the server. The DDECLIENT function returns a
value corresponding to the channel; it doesn't matter what the channel number is. If it's less than one, it failed. You must
therefore start the server, and try to open the conversation again.
The second parameter of the DDECLIENT function is the DDE "Topic." It tells the server what the DDE conversation is
"about." In most cases, the topic is a file name. In this case, the code names the "System" topic, which tells Excel the
conversation is not regarding a particular document file.
126
Clarion 7 FAQs
How to Store and Display a Graphic Image with a Memo or Blob Data Type
Memo and Blob variables are capable of storing large variable length chunks of binary data. This makes them suitable for
storing graphic images. MEMOs are limited to 64K or less. BLOBS have no size limit. Storing and displaying images with
Memo or Blob variables requires the following:
3. Transfer the image from the IMAGE control to the MEMO or BLOB variable using Clarion's property syntax:
For MEMOs:
CON:TheMemo = ?Image1{PROP:ImageBits}
For BLOBs:
CON:TheBlob{PROP:Handle} = ?Image1{PROP:ImageBlob}
For BLOBs:
?Image2{PROP:ImageBlob} = CON:TheBlob{PROP:Handle}
3. After the MEMO or BLOB has been assigned to the IMAGE with property syntax, a fixed width and height may be
assigned to the IMAGE Control:
?Image2{PROP:Width} = 92
?Image2{PROP:Height} = 88
The shipping SCHOOL example demonstrates using property assignments for images.
127
Tips, Tricks & FAQs
128
Clarion 7 FAQs
Synchronize does not change the number of controls on a window; therefore, synchronization does not replace an Option
plus Radio buttons with a drop-down list and vice versa. In either case, the Application Generator issues a warning that no
synchronization occurred for the asymmetrical controls.
Levels of Synchronization
You can synchronize:
A single control: In the Window Designer or Report Designer, select the control, then choose Edit
Synchronize from the menu (or RIGHT-CLICK and choose Synchronize).
If you synchronize a single control, the synchronizer ignores any #Freeze attribute for the control.
All the controls in a data structure: In the Window Designer or Report Designer, select the data structure
(WINDOW, TAB, GROUP, REPORT, DETAIL, etc.), then choose Edit Synchronize from the menu (or RIGHT-
CLICK and choose Synchronize).
or
In the Window Designer, choose Edit Synchronize Window from the menu.
or
In the Report Designer, choose Edit Synchronize Report from the menu.
All the controls in a procedure: In the Application Tree dialog, select a procedure, then choose Procedure
Synchronize from the menu (or RIGHT-CLICK and choose Synchronize).
All the controls in the application: In the Application Tree dialog, choose Application Synchronize from the
menu.
129
Tips, Tricks & FAQs
Trapping a DOUBLE-CLICK on a list box is built into the Clarion and ABC BrowseBox templates.
To trap a DOUBLE-CLICK on a list control in hand-code:
1. Establish an ALRT(MouseLeft2) attribute on the LIST control.
2. Trap for EVENT:AlertKey on the LIST control.
3. Trap for the MouseLeft2 keycode, as in the following example:
ACCEPT
CASE FIELD()
OF ?List
CASE EVENT()
OF EVENT:AlertKey
IF KEYCODE() = MouseLeft2
CurrentSel = CHOICE(?List1) ! Get current selection in list box
GET(TheQueue, CurrentSel) ! Get corresponding data from queue
END
END
END
The above code finds out what item the user DOUBLE-CLICKED on using the CHOICE() function, then uses the GET()
function to retrieve the item from the QUEUE.
When using the ABC templates, the recommended embed point can be found in the TakeKey method. In the Clarion
template chain, use the Browse Double Click Handler embed.
130
Clarion 7 FAQs
The little tips that appear when you "hover" the cursor over a control for a few second are useful additions to a program.
Some users prefer to have these options turned off. You can disable tooltips on any of three levels: Application-wide, for a
single window, or for an individual control.
To turn tips off:
1. Create a global variable (for the purpose of this example, we'll call it TipFlag). Select the Global button from the
Application Tree, then select the Data button. Create the variable as a BYTE. Return to the Global properties
Window.
2. Choose your favorite spot and method for prompting the user whether they want the tips or not. If they select no
tips, set the global variable flag = 1.
You can set this flag through a toggle on a menu or a checkbox on a window. If desired, you can save the value to your
application's INI file and read it back in during program setup (using PUTINI and GETINI).
3. To implement this for an individual control, a single window, or application-wide. Use the following steps:
For an individual control, in the Window Designer:
RIGHT-CLICK on the control.
Select the Embeds choice from the popup menu.
In the "Preparing to process the Window" embed point, insert the following code:
IF TipFlag = 1
?mycontrol{PROP:notips} = 1
ELSE
?mycontrol{PROP:notips} = 0
END
IF TipFlag = 1
mywindow{PROP:notips} = 1 ! where mywindow is the label of the WINDOW
ELSE
mywindow{PROP:notips} = 0
END
131
Tips, Tricks & FAQs
The release of Clarion 6 introduced a new Edit-in-Place interface which allows better control of column types in a list box.
One of those types is a check box interface, implemented through the EditCheckClass object. Instead of a standard entry
field that is used in EIP mode, a check box control is used in its place.
Problem:
During the edit cycle on each list box line, a check box icon will not be updated until the record (or row) has been saved.
This is confusing to a user who unchecks the Edit-In-place check box control, moves to the next column, and does not
see the icon check box change state.
Goal of this FAQ:
To update the icon checkbox used while editing, and before the record (row) is saved.
Solution:
The embedded source code added below is used to change the icon on a browse using the values in the associated
queue, which have not been updated yet to the primary table (in this example, a check box).
The solution is to add a few lines of source code to the BRW1::EIPManager.TakeAccepted method just after the parent
call. The same code used to change the icon for each column is used, but we need to reference the browse queue
elements. For example,
IF (fieldname = 1)
where fieldname is a value that controls the display of an icon type, and BRW1.Q is the instance prefix of the Browse Box
control template
Also the queue fields needs to be changed to reference the parent browse object(SELF to BRWx)
SELF.Q.fieldname_Icon = 1
to
BRW1.Q.fieldname_Icon = 1
Icon files used in a browse box are set in the BRW1.SetQueueRecord method.
132
Clarion 7 FAQs
IF (fieldname = 1)
SELF.Q.fieldname_Icon = 1 ! Set icon from icon list
ELSE
SELF.Q.fieldname_Icon = 2 ! Set icon from icon list
END
IF (BRW1.Q.fieldname = 1)
BRW1.Q.fieldname_Icon = 1 ! Set icon from icon list
ELSE
BRW1.Q.fieldname_Icon = 2 ! Set icon from icon list
END
If you are using the Clarion template chain instead of ABC, the embed point and solution is exactly the same, with a minor
change to the naming conventions:
IF (Queue:Browse:1.BRW1::fieldname = 1)
Queue:Browse:1.BRW1::fieldname:Icon = 1 ! Set icon from icon list
ELSE
Queue:Browse:1.BRW1::fieldname:Icon = 2 ! Set icon from icon list
END
133
Tips, Tricks & FAQs
Finally, if you are still using the Original EIP implementation (which was only available in the ABC templates), the
technique is still the same, but the embed point changes:
IF (BRW1.Q.fieldname = 1)
BRW1.Q.fieldname_Icon = 1 ! Set icon from icon list
ELSE
BRW1.Q.fieldname_Icon = 2 ! Set icon from icon list
END
This code will get inserted into the following embed as shown:
134
Clarion 7 FAQs
This topic describes how to use a combo box without using the File Drop Combo Control template. For information on
using the template, see File Drop Combo control template .
There are two ways to use a combo box--for a static list and for a list of choices from a file.
For a finite list of static choices:
1. Place a COMBO control on the window.
2. In the Properties dialog, select the USE variable for it to update.
3. Press the Cancel button to close the List Box Formatter (no need to use it).
4. RIGHT-CLICK the combo box, then choose Properties.
5. In the From field, type the list of choices as a string constant (in single quotes with | separating choices), eg
'One|Two|Three'
6. Enter a numeric value into the Drop field.
This the number of rows displayed at one time by the drop down list.
7. Enter the correct picture token in the Picture field.
8. Press the OK button.
For a list of choices from a file:
1. On the Procedure Properties dialog, press the Data button.
2. Add a QUEUE to the local data.
3. Add a single field to the QUEUE to hold the data from the file.
4. Return to the Procedure Properties dialog, then press the Window button.
5. Place a COMBO control on the window.
6. In the Select Field dialog, select the USE variable for it to update.
7. Press the Cancel button to get out of the List Box Formatter (no need to use it).
8. RIGHT-CLICK then choose Properties.
9. Type the name of the QUEUE into the FROM field, or press the ellipsis button to select or define a QUEUE.
10. Enter a numeric value into the Drop field.
This the number of rows displayed at one time by the drop down list.
11. Enter the correct picture token in the Picture field.
12. Press the OK button.
13. Return to the Procedure Properties dialog, then press the Embeds button.
14. Open the Procedure Setup embed point and add code to open the file and build the COMBO control's QUEUE.
15. Open the End of Procedure embed point and add code to close the file and FREE the QUEUE.
135
Tips, Tricks & FAQs
Press the More Field Assignments button to automatically assign values to other fields.
Record Filter
Optionally, type an expression to limit the contents of the drop-down list to only those records which match the filter
expression.
Default to First entry if Use Variable empty
Automatically assign the value of the first field in the list to the USE variable. The fields in the list are sorted alphabetically
(unless you specify Sort Fields).
Displaying Text Data and Storing a Code
In this scenario you want to select a value from a textual field in the lookup file and store its associated code in the
Primary file. For example, a Product File with a field storing a Location Code, with a lookup file of Locations. You want the
user to select the Location from a list of descriptions, but store the Location Number in the Product file.
In this case, complete the prompts as follows:
Use
Create a local variable that matches the text field. You can create this variable when the Application Generator prompts
you with the Select Field dialog.
Using the List Box Formatter, populate the list with the text field from the lookup file (you may populate additional fields,
but be sure to populate the display field first).
136
Clarion 7 FAQs
Press the More Field Assignments button to automatically assign values to other fields.
Record Filter
Optionally, type an expression to limit the contents of the drop-down list to only those records which match the filter
expression.
Default to First entry if Use Variable empty
Automatically assign the value of the first field in the list to the ?USE variable. The fields in the list are sorted
alphabetically (unless you specify Sort Fields).
List Properties:
The List Properties for this control are the same as a list; however, the From entry requires some explanation.
From:
When placing a FileDrop Control, this field defaults to Queue:FileDrop. You should not modify this.
FileDropCombo Control Template (pick from list and add to list)
This Control template scrolls through a data file and assigns the value of the selected field to the COMBO's Use variable.
It also allows adding records by typing a new value in the entry portion of the combo box.
There are two different scenarios for which you can use this Control template:
Storing and Displaying the same data
Displaying text data and storing a code.
Storing and Displaying the Same Data
In this scenario you want to select a value from the lookup file and store it in the Primary file. For example, a Product File
with a field storing a color, with a lookup file of colors.
In this case, complete the prompts as follows:
Use
The field to which the lookup value is assigned: select this field when the Application Generator prompts you with the
Select Field dialog.
Using the List Box Formatter, populate the list with the field from the lookup file (you may populate additional fields, but be
sure to populate the display field first).
Field to Fill From
The field from the lookup file. This value is assigned to the Target Field.
Target Field
The field to which the Fill From value is assigned. In this case this is the same as the USE variable.
Record Filter
Optionally, type an expression to limit the contents of the drop-down list to only those records which match the filter
expression.
Remove Duplicates
Check this box to remove duplicates from the list.
137
Tips, Tricks & FAQs
List Properties:
The List Properties for this control are the same as a list; however, the From entry requires some explanation.
From:
When placing a FileDropCombo Control, this field defaults to Queue:FileDropCombo. You should not modify this.
138
Clarion 7 FAQs
The standard Windows behavior for an entry control is free-form entry. To override this behavior, you must add the MASK
attribute to the WINDOW.
In the Window Designer:
1. Make sure the Window is selected.
2. Choose Edit Properties ( or press ENTER).
3. The Window Properties dialog appears.
4. On the Extra tab, check the Entry Patterns box.
5. Press the OK button.
6. For each entry control in the window, add a Picture token to the Picture field of the Entry Properties dialog.
Using Preview!
You can quickly "preview" alternative layouts for DETAILs, HEADERs, and FOOTERs. Fonts, sizes, colors, and positions
of report controls are all displayed, and you can see these effects all without actually compiling or running your report.
In the Report Designer:
1. Choose Preview! to "visualize" how the printed page will appear.
The Preview Print Details dialog appears. This dialog lets you generate "filler" data for your report. The data have no
values, but serve as placeholders, so you can get a feel for the appearance of your finished report.
2. Highlight a detail (if you have more than one) in the Details list then press the Add button.
Each press of the Add button populates the preview with a filler record. Add one record for a one-record-per-page type
report, or add lots of records to see the effects of the page breaking, group breaking, and header and footer options you
have selected.
3. Press the OK button.
The Report Designer generates a preview of your report including DETAILs, HEADERs, FOOTERs, BREAKs, fonts,
sizes, colors, and positions of report controls.
4. When done "previewing," choose Band View! to continue editing your report.
139
Tips, Tricks & FAQs
140
Clarion 7 FAQs
Spin Controls are commonly used for date or time entry controls. Using a SPIN control gives the end user more flexibility,
allowing data entry by typing or by clicking on the up or down buttons to increment or decrement the value.
In the Window Designer:
1. Place a SPIN control on the window by clicking on the Spin icon in the Controls toolbox and then clicking on the
desired position in the window.
2. RIGHT-CLICK on the spin control and choose Properties from the popup menu.
3. In the Use entry box on the General tab, type the field's label (or press the ellipsis (...) button to select the field
from the Select Field dialog).
4. Select the Extra tab, and specify the Step value.
This is the amount by which the value is incremented or decremented when the Spin Control's Up or Down button is
pressed. For a Date, a step value of 1 increments or decrements by one day. For a Time, a step value of 6000 increments
or decrements by one minute.
5. Optionally, provide an initial value for the fields.
You can specify an initial value in the Data Dictionary or if you are using the Form procedure template or Save button
control template, you can provide an Initial value by specifying it in the Field Priming on Insert dialog. To specify the
current date, assign the TODAY() function to a date field. To specify the current time, assign the CLOCK() function to a
time field.
If you always want spin controls for these fields, specify a SPIN control as the default Window control in the Field
Properties dialog in the Data Dictionary.
141
Tips, Tricks & FAQs
142
Clarion 7 FAQs
1. Highlight a ToDo Procedure in the Procedure Tree and press the Enter key. You can also simply press the Insert key,
and type a procedure name in the New Procedure dialog.
The Select Procedure dialog appears.
2. Select BrowseWizard from the list of Procedure templates located in the Wizards tab.
Press the Select button. The Procedure Wizard dialogs appear.
Answer the questions in each dialog, then press the Next button.
On the last dialog, the Finish button is enabled. If you are satisfied with your answers, press the Finish button.
The Procedure Wizard creates the procedure(s) based on the dictionary file and the answers you provided, and then
displays the Procedure Properties dialog for your new procedure.
You can control some of the wizard options in the Data Dictionary by specifying Options for Files, Fields, Keys, or
relations. See Using Wizard Options for more information.
143
Tips, Tricks & FAQs
The structure is actually printed at the next available position within the detail print area (specified by the
REPORT´s AT attribute).
The position specified by the x and y parameters of the structure's AT attribute is an offset from the next available
print position within the detail print area.
The first print structure on the page is printed at the top left corner of the detail print area (at the offset specified
by its AT attribute).
Next and subsequent print structures are printed relative to the ending position of the previous print structure:
If there is room to print the next structure beside the previous structure, it is printed there.
If not, it is printed below the previous.
The values contained in the AT attribute's x, y, width, and height parameters default to dialog units unless the THOUS,
MM, or POINTS attribute is also present. Dialog units are defined as one-quarter the average character width by one-
eighth the average character height. The size of a dialog unit is dependent upon the size of the default font for the report.
This measurement is based on the font specified in the FONT attribute of the report, or the printer's default font.
145
Tips, Tricks & FAQs
6. For Clarion total fields, simply choose a total type from the TotalType property drop down list.
146
Clarion 7 FAQs
You can use Windows .DLLs which have not been created with Clarion if you know the prototypes for the .DLL's
procedures and functions. See the Programmer's Guide article on Multi-Language Programming for more information on
this topic.
If the source language prototypes are known, then equivalent Clarion prototypes must be created and included in a
CLARION program's MAP for all referenced DLL procedures and functions. Also, Clarion requires a Library (.LIB) file in
the Project Tree under Library and Object files. This Library file entry enables the linker to resolve the procedure and
function references in the .DLL.
If you have a Windows DLL (not created with Clarion) that you want to use in a CLARION program, then the following
steps are required to enable the CLARION program to access the DLL's procedures and functions:
Create Equivalent Clarion Language Prototypes.
Create a Clarion Library (.LIB ) File for the DLL.
Reference the Library (.LIB) File in the Project System.
There are several issues to consider when creating equivalent prototypes in Clarion which are dependent upon a DLL's
source code language. A primary consideration is relating equivalent data types in the other language to Clarion.
Equivalent data types can be determined by considering the "underlying" machine data type represented by each
language data type. For example, the CLARION Language Reference identifies the Clarion data type SREAL as a "four-
byte signed floating point".
The following is an example of C and C++ code data type equivalents.
unsigned char ==> BYTE
short ==> SHORT
unsigned short ==> USHORT
long ==> LONG
unsigned long ==> ULONG
float ==> SREAL
double ==> REAL
147
Tips, Tricks & FAQs
This form of definition reserves space for Struct1 and is equivalent to the C definition:
struct {
unsigned long ul1;
unsigned long ul2;
} Struct1;
A second important prototyping consideration is the procedure/ function calling convention utilized by another language.
Clarion provides support for three different calling conventions: PASCAL, C, and TopSpeed's Register Based.
Create a Clarion Library .LIB File for the DLL.
You can create a .LIB file for the DLL using the LIBMAKER.EXE utility program that comes with Clarion as one of the
example programs. Simply run the program, select the .DLL and have it automatically create the .LIB file for you.
148
Clarion 7 FAQs
Alias Options
Do Not Auto-Populate This Aliased File
Directs the wizards to skip the Aliased File when creating primary Browse procedures or Report procedures.
User Options
User Options let you provide information to utility templates. User Options are comma delimited, that is, each entry is
separated by a comma.
Field Options
Do Not Auto-Populate This Field
Directs the wizards to skip this field when creating Form, Browse or Report procedures.
Population Order
Specifies the order in which the wizards populate fields. Choose Normal, First, or Last from the drop-down list. Wizards
populate in this order: all Fields specified as First, then all Fields specified as Normal, and finally all Fields specified as
Last.
Form Tab
Specifies the TAB onto which the wizards populate the field. Type the Caption for the TAB or select one you have
previously created from the drop-down list. This lets you direct the wizard to group fields in the manner you want.
Add Extra Vertical Space Before Field Controls on Forms
Check this box to direct the wizards to add vertical space between this field's control and the one populated above it.
User Options
User Options let you provide information to utility templates. User Options are comma delimited, that is, each entry is
separated by a comma.
Key Options
Do Not Auto-Populate This Key
Directs the wizards to skip this Key when creating primary Browse procedures or Report procedures.
Population Order
Specifies the order in which the wizards populate keys. Choose Normal, First, or Last from the drop-down list. Wizards
populate in this order: all Keys specified as First, then all Keys specified as Normal, and finally all Keys specified as Last.
149
Tips, Tricks & FAQs
User Options
User Options let you provide information to utility templates. User Options are comma delimited, that is, each entry is
separated by a comma.
Relation Options
User Options
User Options let you provide information to utility templates. User Options are comma delimited, that is, each entry is
separated by a comma.
150
Clarion 7 FAQs
The SHEET control declares a group of TAB controls that offer the user multiple "pages" of controls for the window. The
multiple TAB controls in the SHEET structure define the "pages" displayed to the user.
There are several ways to use SHEETs and TABs on a WINDOW. This topic covers the two most common uses: Placing
Controls within a TAB and Placing Controls "on top of" a TAB but outside of the TAB structure.
TAB structures may contain any number of controls after the TAB declaration and before its END terminator. Controls
which are declared within a TAB structure are only visible when the TAB is selected. When the TAB is not selected, the
controls within the TAB structure are hidden in a different manner than a HIDE statement--that is they can still be
SELECTed or accept any property assignments.
Form procedures made with the Form Wizard or the Application Wizard create Browse procedures for Child files using
this method--the BrowseBox control template (a LIST control) and the BrowseUpdate buttons are within the TAB
structure, so they display only when the user selects the TAB.
You can place Controls "on top of" a TAB, but outside of its structure by specifying its AT() location to be in the same
place as the TAB. To accomplish this in the Window Designer, you would populate the control somewhere outside of the
TAB, then drag it on top of the tab. When the formatter asks if the control should be moved into the TAB, press the NO
button. Another method of controlling the control's placement in code is through the Set Control Order command on the
Edit Menu.
A control outside of the TAB/SHEET structure is always visible. The Browse Wizard and Browse procedures made with
the Application Wizard use this technique for files with more than one KEY. The LIST control is "on" the TAB, but not
within the TAB structure. The Conditional Browse Box behavior is set to change the LIST's sort order based on the
selected TAB. In a similar manner, the BrowseUpdate Buttons are "on" the TAB but also outside the TAB structure. This
allows a single set of BUTTONs to remain active regardless of the selected TAB.
151
Tips, Tricks & FAQs
In the new Clarion thread implementation, is there now a requirement for the developer to explicitly lock an
object/variable?
Both current and prior Clarion versions do nothing to synchronize access to static data (global non-threaded objects).
Therefore the new thread implementation breaks nothing. The decision on how to access global non-threaded data is still
completely for the programmer to decide.
Practice has shown that there are problems with the automatic swapping schema of threaded data. Therefore in the new
thread model data is handled completely differently. The main difference is that in the new implementation every instance
of a threaded variable has its own location/address.
Note that without explicit synchronization of active threads, a thread can be suspended by the Windows O/S and another
switched to at any time, for example a thread switch could occur in the middle of an assignment such as A = B. The
problem that this can highlight comes about if you have more than one thread writing to the same non-threaded variable,
which is in itself a questionable coding technique.
How does the locking of an object or variable occur, does it happen automatically whenever it is accessed?
Threaded variables or objects can be accessed without any locking: local data is created on the thread stack and can't be
directly accessed (by name) from other threads; access to threaded data is controlled by the RTL via code generated by
the compiler. So, possible conflicts can only occur with static data; i.e. _global_ variables declared without the thread
attribute.
152
Clarion 7 FAQs
Now that multiple threads are active concurrently, how can I safely share access to non-threaded static data (global
variables) amongst threads?
Just use a synchronization object such as a critical section or mutex. Named mutexes, semaphores, pipes, events are
targeted for inter-process synchronization.
What are Critical Sections and what do I need to know how to use them?
Critical Sections allow us to enforce mutual exclusion. Critical section objects provide synchronization similar to that
provided by mutex objects, except that critical section objects can be used only by the threads of a single process. Event,
mutex, and semaphore objects can also be used in a single-process application, but critical section objects provide a
slightly faster, more efficient mechanism for mutual-exclusion synchronization. The important property that critical sections
have is that only one thread may have ownership at any one time. If a thread tries to enter a critical section when another
thread is already inside the critical section, then it will be suspended, and only resumed when the other thread has left the
critical section. This provides us with the required mutual exclusion around a shared resource. More than one thread can
be suspended waiting for ownership at one time, so critical sections can be used for synchronization between more than
two threads
Clarion programs can use a CRITICAL_SECTION (and other synchronization objects) and can do so without diving into
their complexity. This can be coded for critical sections as follows:
MAP
MODULE('')
NewCriticalSection PROCEDURE(),*IcriticalSection
END
END
CODE
……
Sync &= NewCriticalSection() ! Create the critical section object
Sync.Wait() ! lock the critical section
153
Tips, Tricks & FAQs
Mutexes are another kind of synchronization object. Their goal is the same as for critical sections: provide mutual
exclusive access to some shared resource. For example, to prevent two threads from writing to shared memory (global
data) at the same time, each thread waits for ownership of a mutex object before executing the code that accesses the
shared resource.
Critical sections can only be used for synchronization of threads owned by the same process. Mutexes can be used for
synchronization of threads that can belong to different processes. If a process creates a mutex with some name and
another (or the same) process has created a mutex with that name already, the system does not create a new mutex. It
returns another handle to the existing mutex instead and sets error code to 183 (ERROR_ALREADY_EXISTS). Unnamed
mutexes are local for the process that created them. Such mutexes can only be used for synchronization of that process's
threads.
When we use a critical section for synchronization and the requested critical section is already "occupied", the thread that
tries to enter it is suspended until the critical section is available, or the method call that "tries" to enter the critical section
can return immediately. The difference is that TryEnterCriticalSection returns immediately, regardless of whether it
obtained ownership of the critical section, while EnterCriticalSection blocks until the thread can take ownership of the
critical section. With a critical section there is no ability to specify a time limit on the wait. The IMutex.Lock() method
behaves in the same manner: the thread that executed this method is suspended until it can gain ownership of the mutex.
But it's possible to limit the waiting time by using the IMutex.Wait method with a parameter equal to the number of
milliseconds to wait. If the mutex is not released within the given time period, the thread is resumed and the method
returns 1. If the mutex is not locked by another thread, or it is released within the given "wait" period, the thread continues
its execution and the method returns 0. Supplying a time parameter equal to 0FFFFFFFFh (-1) means an infinite wait.
How does the new thread model impact working with FILE and VIEW structures?
In the new thread model any FILE declared in the procedure or routine local scope is treated as threaded regardless of
the presence of the THREAD attribute in its declaration.
VIEWs have no THREAD attribute by syntax, but VIEWs declared in the procedure or routine local scope are treated as
threaded. A VIEW declared in the global or module scope is treated as threaded if at least one joined FILE is threaded.
Threaded CLASSes are fully supported now. The constructors and destructors for threaded classes are called for every
thread now. Every new thread gets new instances of CLASSes and variables declared at the global level with the
THREAD attribute. The RTL calls constructors for the threaded classes when the thread is started and the destructors
when the thread is ended. In previous Clarion versions they were called only when the main thread started and ended.
It follows that in previous versions of Clarion, to handle thread specific information within classes there was a need to
have arrays or queues. See for example, Info field of the FileManager class. The only instance of FileManager is
responsible for handling all the instances of a FILE. As a result it must retrieve information about current thread context
(FileManager.SetThread) on every call to any other method. Now an instance of a threaded class can carry thread related
data without involving external structures that require synchronized access to them in the case of preemptive thread
switching.
154
Clarion 7 FAQs
Use of threaded classes can make the whole class hierarchy more complex but
orthogonal. This is because all instances of the same class can share some information. For example, the relation
between two tables is independent from any particular class instance: keys, fields and possibly expressions, are the
same. So, one class can be split into two or more classes: one carries thread specific information and behavior, and
others thread independent data and behavior.
You need to remember that access to static variables (a global variable that doesn’t have the THREAD attribute) is not
synchronized; this means that the value of a variable can be changed at any time from other concurrently running threads.
As a result, any condition involving static variables can be changed just after its evaluation, i.e.
IF A = 0
! Value of A can be changed at this point from another thread
DoSomething(A)
END
The solution to this type of problem is to use the THREAD attribute on declarations, or use synchronization if you actually
intended for the variable to be shared across threads.
You also need to know that the error functions (i.e., ERRORCODE( )) are now thread dependant. This means that an
error raised on one thread are not detectable on other threads. This may effect some of your code if you are using error
states to transmit information between threads.
What has the new thread model changed that I must understand?
In previous Clarion versions all instances of a threaded variable shared the same location in the program. Therefore, the
result of a reference assignment with a threaded variable, or the field of a threaded structure as a source is valid for all
threads, for example:
F FILE,...,THREAD
...
END
A ANY
CODE
A &= WHAT (F.Record, 1)
In all threads A points to the first field of the file's record. In the new model every instance of a threaded variable has its
own address. Therefore, the result of a reference assignment as given above is valid only in the thread where it has been
executed.
155
Tips, Tricks & FAQs
There are a number of structures in ABC which use a field with thread numbers to distinguish data for a particular thread.
Examples are FileThreadQueue or StatusQ in ABFILE.CLW. The fact that every instance of a threaded variable now has
its own address required that the schema for initialization of most FILE-related ABC classes were in need of some
changes. (We have already done the changes and will utilize same as a teaching tool).
On the other hand, global reference variables set to particular instances of threaded variables can be useful for passing
information across threads: for example one thread can change an instance belonging to another thread.
No, no change in syntax. However, because the address of the instance for the starting thread is only known at compile
time the compiler must generate code to calculate the address of a required instance. There are two possibilities here: the
variable is External and imported from another DLL, or it is located in the same executable.
So, one change is that the EXTERNAL and THREAD attributes in data declarations are not mutually exclusive now. The
THREAD attribute is the only way to inform the compiler that it must generate the code to get the correct instance.
The new INSTANCE function: INSTANCE(variable,threadno) returns the address for the instance of the variable allocated
for the specified thread referenced by threadno, provided the referenced thread is active.
addressvar = INSTANCE(SalesFile,THREAD())
!return address of SalesFile entity on the active thread
INSTANCE is also valuable when you need the thread independent ID of the variable.
addressvar = INSTANCE(GLO:LoginID, 0)
!get the thread independent ID of a global threaded var
The Clarion RTL has per-process and per-thread initialization flags in the header. So, every process will get its own copy
of the RTL and Windows does not load the same DLL into process memory space a second time (unless it has been
unloaded manually). So Yes, it's possible to consider the RTL as re-entrant.
156
Clarion 7 FAQs
What is...
Generally, it is to your advantage to use a Control template rather than a simple control.
See Also:
Adding Control Templates
157
Tips, Tricks & FAQs
Redirection File
Clarion's development environment sets the working directory to the one in which the current application or project file
resides. Additionally, Clarion uses the redirection file (%ClarionRoot%\BIN\Clarion7.RED) to keep track of directories for
the various application or project components. This redirection file tells the development environment where to find files
and where to create new files.
The redirection (RED) file system and the way that it works with the project system is a long established and reliable
standard. The difference with Clarion 7 and higher is that you can now include redirection files in other redirection files.
Here is an overview of the role of the redirection file with the Clarion project system.
The project system looks for a redirection (RED) file in the current directory (e.g., the directory where the project is). If it
does not find one there, it uses the default RED file (%ClarionRoot%\BIN\Clarion7.RED).
The RED file controls where files are found and located as well as where they are written and saved. When the project
system wants to find a file, it looks through the RED file, checking if a file being looked for matches the pattern at the
beginning of a line in the red file. If it does match, the project system then looks through each directory in the list on that
line starting at the left hand most directory. Once the file is found in one of the directories, that file is used.
When a file needs to be created by the project system the same system is used as for opening a file. The only difference
is that once a pattern is found to match the file being created, then the first directory of that pattern is used.
The red file is not used at all when a program runs. However, the redirection file is used to find DLLs when the Copy
referenced DLLs to output directory check box in the Project Options is selected.
Backup files are always created in the directory where the original file is located.
To edit the default redirection file, choose Tools Edit Base Redirection File. The text editor opens the appropriate
redirection file for editing.
.
The redirection system also supports transforming ' ' and '..' syntax into directory names based on the location where
the redirection file was opened (not based on the current directory). The redirection file needs to know what ' .' means
because you can have one red file in use in a project that is compiling on one thread while you have a different red file in
use on a different thread for an app that is in a different directory.
It is also recommended that any paths with spaces should be quoted as follows:
*.* = %ROOT%\Accessory\libsrc\win; "%ROOT%\Accessory\my images"
158
Clarion 7 FAQs
Redirection Macros
The redirection file directory can contain macros. Redirection macros are labels surrounded by the percent sign (%).
When a redirection macro is detected, the Clarion environment substitutes the macro's substitution value. You can define
redirection macros and their substitution values in the Redirection File tab located in the Tools > Options > Clarion >
(product name) > Versions section of the IDE:
159
Tips, Tricks & FAQs
Additional Macros:
REDNAME
Converts to the redirection file name based on the version of Clarion you are building with.
For example %REDNAME% will convert to Clarion70.RED when building with Clarion 7 and C60EE.RED when building
with Clarion 6.
REDDIR
Expands to the directory where the default redirection file can be found for the version of Clarion you are building with.
ApplicationDirectory
Expands to the directory where the user application data is stored. Under Windows XP this will be the C:\Documents and
Settins\<User>\Application Data folder by default.
This acts like the contents of the included redirection file is contained at the place where the {include} directive is placed.
The RED file uses a priority system. The earlier a line is read the higher the priority.
For example, if you have:
{include C:\myred.red}
{include C:\otherred.red}
If cancel.ico exists in both locations, then the one in the myicons folder would be used. However, if you reversed the
include lines so you had…
{include C:\otherred.red}
{include C:\myred.red}
160
Clarion 7 FAQs
Redirection lines within a section are only used if the section's corresponding Project System switches are true
(COMMON is always true). Redirection lines without a section are always used. For example:
[DEBUG]
*.obj = c:\test
[RELEASE]
*.obj = c:\release
[COMMON]
*.* = work
In this example if the Build Configuration is set to Release, then .obj files are created in c:\release.
If the Build Configuration is set to Debug, then .obj files are created in c:\test.
The Default Redirection File
[Debug]
*.obj = %ROOT%\obj\debug
*.lib = %ROOT%\obj\debug
*.res = %ROOT%\obj\debug
*.rsc = %ROOT%\obj\debug
[Release]
*.obj = %ROOT%\obj\release
*.lib = %ROOT%\obj\release
*.res = %ROOT%\obj\release
*.rsc = %ROOT%\obj\release
[Common]
*.dll = .;%ROOT%\bin
*.tp? = %ROOT%\template
*.trf = %ROOT%\template
*.* = .; %ROOT%\examples; %ROOT%\libsrc; %ROOT%\images; %ROOT%\template; %ROOT%\convsrc
*.lib = %ROOT%\lib
*.obj = %ROOT%\lib
*.res = %ROOT%\lib
Additional Notes:
1. The default redirection file is designed to work with Clarion's default directory structure. If you change the
directory structure, you should make corresponding changes to the redirection file.
2. You can now specify extra directories that are searched for dlls only by the "Copy Referenced Dlls" feature by
adding a [Copy] section to a redirection file.
161
Tips, Tricks & FAQs
What is a Template
Clarion templates are highly configurable, interactive, interpreted, code generation scripts. A template typically prompts
you for information then generates a custom set of source code based on your responses. In addition to its prompts, many
templates also add source code embed points to your application—points at which you can supply custom source code
that is integrated into the template generated code. You may want to think of the template prompts as a way to define the
static (compile time) characteristics of a program or procedure, and the embedded source as a way to define the changing
(runtime) characteristics of a program or procedure.
Prompts
A template typically prompts you for information at design time. The Application Generator interprets the template and
presents a dialog with all the template's prompts. You fill in the prompts, with assistance from the on-line help, to define
the static (compile time) characteristics of your program or procedure. For example, fill in the Record Filter prompt to
establish a filter for a BrowseBox template.
Embed Points
In addition to its prompts, many templates also add source code embed points to your application or procedure—points at
which you can supply custom source code that is integrated into the template generated code. You can use these embed
points to define the changing (runtime) characteristics of a program or procedure. For example, embed source code to
hide a related listbox when there are no related records to display.
Advantages of Template Use
Templates promote code reuse and centralized maintenance of code. They provide many of the same benefits of object
oriented programming, especially reusability. In addition, templates can compliment and enhance the use of object
oriented code by providing easy-to-use wrappers for complex objects. The ABC Templates and ABC Library are a prime
example of this synergistic relationship between templates and objects.
You can modify templates to your specifications and store your modifications in the Template Registry. You may also add
third party templates and use them in addition to, and along with, the Clarion templates. You may write your own
templates too. The Template Language is documented in the Template Language Reference and in the on-line help.
162
Index
% C
%ROOT% 204 ChangeRecord 42
. Changing the printer device without calling
PRINTERDIALOG 63
.RED files 204
Changing Your Application's Dictionary 64
{
Choose Data Types 65
{INCLUDE} 204
FAQs 27, 28
A Troubleshooting 29
ABC Compliant Classes 92 Clarion Versions - Switching 44
ABC Templates 123 Clip and Concatenate Fields 67
ABCIncludeFile 92 Columns 154
ActiveX Controls Combo Box 173
License Files Common IDE FAQs 1, 2
and Compound Storage Files 35 Common Questions 30
ActiveX Controls 35 Completing an entry field when the last character is
Add a Clarion Version to the IDE 44 entered 69
Add Hot Key Display to a Menu Item 60 Concatenating Fields 67
Add Tables to a Dictionary 7 Controling Page Breaks 70
Adding Applications to an Existing Solution23 Controls
Adding Columns to Data Dictionary Tables 9 freezing 166
Adding Control Templates 45 Controls 166
An Alternative Way to do All of the Above 14 Conversion Errors 21
App Conversion Errors 21 Converting a File 73, 75, 120
APPLICATION Converting Applications from Clarion 6 20
synchronize with dictionary 166 Converting Topspeed Project Files to MSBuild projects
26
APPLICATION 166
Correcting Conversion Errors 21
Application Generator 18
Corrupt data files 152
ApplicationDirectory 204
Create a Data Dictionary 5
Assign an Image to Display at Runtime 61
Create a Dictionary (.DCT) File 6
Autosize all Browse Columns 62
Create a Function with the Application Generator
Auto-tab 69 83
B Create a Key 11
BLOBs Create a New Application File 18
Images in 163 Creating a .DLL (Sub-Application) 80
BLOBs 163 Creating a Complex Assignment Expression76
Browse Procedures with TABs 195 Creating a Simple Assignment Expression89
163
Tips, Tricks & FAQs
164
Index
165
Tips, Tricks & FAQs
166
Index
167
Tips, Tricks & FAQs
S tooltips 168
168
Index
169