ClearBasic Programmer's Guide
ClearBasic Programmer's Guide
Contents 3
Where to Find More Information . . . . . . . . . . . . . . . . . . . . . . . . 33
4 Contents
Uses for UDTs as Contextual Objects . . . . . . . . . . . . . . . . . . 70
When to Use Database Contextual Objects . . . . . . . . . . . . . 71
When to Use UDT Contextual Objects . . . . . . . . . . . . . . . . . 71
When to Use Temporary Contextual Objects. . . . . . . . . . . . 72
Enabling and Disabling Controls. . . . . . . . . . . . . . . . . . . . . . . . . 72
Copy by Reference Versus Copy by Value. . . . . . . . . . . . . . . . . 73
Performance Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Retrieve What You Need in Bulk . . . . . . . . . . . . . . . . . . . . . . 73
Be Careful When Adding and Modifying Views . . . . . . . . 74
Use Global Functions and Procedures . . . . . . . . . . . . . . . . . 74
Object Reference versus Language Reference . . . . . . . . . . . . . . 75
Making Controls Visible or Invisible. . . . . . . . . . . . . . . . . . . . . . 75
Use the SetFocus Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Contents 5
Why and How to Use Constants . . . . . . . . . . . . . . . . . . . . . . . . . 91
Contextual Object Versus Control Manipulation . . . . . . . . . . . 91
Using Functions and Subroutines . . . . . . . . . . . . . . . . . . . . . . . . 92
Don’t Reinvent the Wheel. . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Scoping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
When to Use a Function, When to Use a Subroutine . . . . . 93
Using Global Functions and Subroutines. . . . . . . . . . . . . . . 93
Using Modular Functions and Subroutines . . . . . . . . . . . . . 93
Declaring and Calling a Function . . . . . . . . . . . . . . . . . . . . . 94
Don’t Call a Function as a Subroutine, and Vice Versa . . . 95
When Do You Use Parentheses in a Method Call? . . . . . . . . . . 95
What Happens If You Make a Mistake With Parentheses . 95
6 Contents
Summary of Contextual Objects . . . . . . . . . . . . . . . . . . . . . . . . 114
Contents 7
Coding a Custom List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Loading Data Into a Custom List . . . . . . . . . . . . . . . . . . 137
Writing an Event Procedure to Handle User Selection140
Programming Dropdown Combo Boxes . . . . . . . . . . . . . . . . . 140
Creating a Dropdown Combo Box . . . . . . . . . . . . . . . . . . . 140
Labeling the DropDown Combo Box . . . . . . . . . . . . . . . . . 142
Coding a DropDown Combo Box . . . . . . . . . . . . . . . . . . . . 142
Programming Dropdown List Boxes . . . . . . . . . . . . . . . . . . . . 143
Creating a Dropdown List Box . . . . . . . . . . . . . . . . . . . . . . 143
Labeling the DropDown List Box . . . . . . . . . . . . . . . . . . . . 144
Coding a DropDown List Box . . . . . . . . . . . . . . . . . . . . . . . 145
Filling the Dropdown List Box with Values. . . . . . . . . 145
Getting the User’s Selection (String) . . . . . . . . . . . . . . . 146
Getting the Index of the User’s Selection . . . . . . . . . . . 146
Selecting an Item Through Code . . . . . . . . . . . . . . . . . . 146
Programming Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Creating a Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Coding a Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Using a Label to Display Values . . . . . . . . . . . . . . . . . . 148
Programming List Boxes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Creating a List Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Labeling the List Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Coding a List Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Programming Multiline Text Boxes . . . . . . . . . . . . . . . . . . . . . 151
Creating a Multiline Text Box . . . . . . . . . . . . . . . . . . . . . . . 151
Labeling the Multiline Text Box. . . . . . . . . . . . . . . . . . . . . . 153
Coding a Multiline Text Box. . . . . . . . . . . . . . . . . . . . . . . . . 153
Displaying Text. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Displaying Values in a Multiline Text Box . . . . . . . . . . 153
Programming Option Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Creating an Option Button . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Programming Tab Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Anomalies in Creating Tabs . . . . . . . . . . . . . . . . . . . . . . . . . 155
Essential Facts and Some Limitations of Tabs . . . . . . . . . . 156
Creating a Tab Widget. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Labeling Tab Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Coding Tab Widgets and Tabs. . . . . . . . . . . . . . . . . . . . . . . 158
Programming Text Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Creating a Text Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Labeling a Text Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
8 Contents
Coding a Text Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Displaying Initial Text . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Displaying Values in a Text Box. . . . . . . . . . . . . . . . . . . 161
Using a Text Box in a Selection Mechanism . . . . . . . . . 162
Contents 9
Inserting New Records into the Database . . . . . . . . . . . . . 192
Updating Records in the Database . . . . . . . . . . . . . . . . . . . 194
Deleting Records from the Database. . . . . . . . . . . . . . . . . . 194
Relating Records. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Unrelating Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Database Saves and the Form_Save Callback . . . . . . . . . . 197
Creating a Form_Save Callback . . . . . . . . . . . . . . . . . . . 198
10 Contents
Customizing Menus-Multiple Application Menubars . . . . . . 222
Applying the Menubar Customization. . . . . . . . . . . . . . . . . . . 223
Contents 11
Chapter 14 Testing and Debugging
Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Fixing Compile-Time Errors. . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Fixing Run-Time Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Using the ClearBasic Debugger for Windows. . . . . . . . . . . . . 275
Starting the Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
About the Debugger Toolbar . . . . . . . . . . . . . . . . . . . . . 278
About the Debugger Window Tabs. . . . . . . . . . . . . . . . 279
Modifying Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Setting Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Enabling and Disabling Breakpoints. . . . . . . . . . . . . . . 282
Removing Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . 282
Using the SQL-Log tab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
Watching Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
Adding Watchpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
Removing Watchpoints . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Viewing and Modifying Variables. . . . . . . . . . . . . . . . . 285
Using the Debugger Tools . . . . . . . . . . . . . . . . . . . . . . . . . . 286
Controlling the Execution of Your Code . . . . . . . . . . . 286
Editing Code at Runtime. . . . . . . . . . . . . . . . . . . . . . . . . 287
Support for the Clipboard. . . . . . . . . . . . . . . . . . . . . . . . 288
Setting the Debugger Options . . . . . . . . . . . . . . . . . . . . 288
Ending a Debugging Session . . . . . . . . . . . . . . . . . . . . . 289
Using the ClearBasic Debugger for UNIX . . . . . . . . . . . . . . . . 290
Invoking the Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
Setting Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
Debugging a Module in an Application . . . . . . . . . . . . . . . 295
Debugging Global Modules . . . . . . . . . . . . . . . . . . . . . . . . . 299
Saving Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
Using the Debug Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
Using the SQL Log to Debug the Database . . . . . . . . . . . . . . . 301
Summary of Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
12 Contents
Retrieving Client Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
Functions for Date and Time Manipulation. . . . . . . . . . . . . . . 307
Elapsed Time. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
DateTime Values in Database Records . . . . . . . . . . . . . . . . . . . 309
Using Comparison Operators. . . . . . . . . . . . . . . . . . . . . . . . . . . 310
Contents 13
Exporting Resource Configurations . . . . . . . . . . . . . . . . . . . . . 342
Exporting an Individual Form . . . . . . . . . . . . . . . . . . . . . . . . . . 342
Testing and Debugging. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
Accessing Data From Other Databases. . . . . . . . . . . . . . . . . . . 345
Index
14 Contents
About This Guide
Related Documentation
The following referenced documentation is available on the Clarify
Documentation CD-ROM:
• ClearBasic Object Reference
• ClearBasic Language Referencee
• User Interface Editor Guide
• Data Dictionary Guide
15
Organization of This Guide
Conventions
These special formats are used:
NOTE: Provides additional information that is useful but not always essential.
More Information: Refers you to other sections of this guide or to other documents
for more information.
Overview of ClearBasic
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22
What is ClearBasic? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22
Components of ClearBasic. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23
What are Objects, Properties, and Methods? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24
ClearBasic Programming Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .27
ClearBasic and CeFO Customization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30
Customization Methodology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .32
Where to Find More Information. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .33
21
Overview
Overview
ClearBasic is a new type of programming language. Like Microsoft’s
Visual Basic, it is designed to significantly speed up the development
process. It does this by providing pre-coded objects, methods, and
properties for performing complex, sophisticated tasks. Because most of
the coding work is already done, you can complete your
implementation faster after you have finalized your design.
What is ClearBasic?
ClearBasic is a simplified programming language that you can use to
customize CeFO applications. ClearBasic allows you to add your own
functionality at the CeFO client application level, such as new forms and
controls that access the database in ways that you have customized.
Using ClearBasic, you can create code for new controls embedded in
standard CeFO forms, or you can create code for new forms (and their
controls) that are posted as a result of user activity within a standard CeFO
form or menu.
22 Chapter 1
Components of ClearBasic
Components of ClearBasic
ClearBasic consists of the following components:
• A Basic interpreter embedded in the CeFO applications.
• Basic language functionality intrinsic to the interpreter.
• Objects, methods, and properties developed and optimized for the CeFO
system.
Overview of ClearBasic 23
What are Objects, Properties, and Methods?
If you are not familiar with Visual Basic, you need to take a few moments to
get a grasp on what we mean when we call something a ClearBasic object,
property, or method.
24 Chapter 1
What are Objects, Properties, and Methods?
Object
Internal Methods
Procedures
CeFO
Application Data Fields Properties
Also, notice that objects also monitor certain occurrences (events) caused by
user or system activity and notify the appropriate event handlers that you
create. This is important because nearly all object manipulation via methods
or properties originate in event handlers of one type or another.
Although you cannot create your own objects, you can create and use your
own data types, called “user-defined types” or UDTs.
Overview of ClearBasic 25
What are Objects, Properties, and Methods?
The advantage of keeping the published interface separate from the object’s
internal code is that it keeps your code independent from any changes that
might be made inside the object.
ClearBasic Syntax
General ClearBasic syntax follows standard Basic. If you are unfamiliar with
Basic, you might want to read one of the many books available on Basic
programming. To zero in on the specific capabilities of the ClearBasic dialect,
you should familiarize yourself with the contents of the ClearBasic Language
Reference.
What is new to Basic with the advent of Visual Basic and also featured in
ClearBasic, is the simplified syntax dealing with objects, methods, and
properties.
26 Chapter 1
ClearBasic Programming Fundamentals
What is a Form?
A form is a visible presentation, based on the metaphor of a printed page, of
items (controls) that invite user interaction. For example, a form can contain
data entry fields for the user to fill, and always contains some control to
enable the user to tell it to go away (see Figure 2).
Record List
Form
Form Code Handling List
Selection and Display.
Overview of ClearBasic 27
ClearBasic Programming Fundamentals
What is a Control?
Controls are visual elements placed on a form to invite certain types of user
activity. For example, a text box invites keyboard input, a command button
invites a mouse click. The type of activity that is desired can dictate the use
of a particular control: if you want keyboard input, for example, you must
use a text box or a multiline text box. Likewise, if you want to display a list
of records for user selection, you need to use a custom list.
Because CeFO applications are built around database accesses, you will find
certain combinations of controls particularly useful. For example, the use of
dropdown list boxes and text boxes can be the best way to both present
query-related choices to the user and to retrieve user selections/input into a
filter condition.
28 Chapter 1
ClearBasic Programming Fundamentals
Each form must have a form load event procedure that performs
initialization when the form is posted. In addition, most controls have an
event procedure that gets executed whenever the event occurs for the
control, if a button gets clicked, for example.
The CeFO system handles many of the tasks associated with events. For
example, when an option button gets clicked, the default handling supplied
by CeFO visibly marks the button as “on” and visibly marks the other
buttons as “off”.
However, you need to write an event procedure to perform the work that
you want to have done when the event occurs. Examples of event
procedures could include performing an in-memory search, reading data
from the database, or enabling or disabling controls when an event occurs.
Overview of ClearBasic 29
ClearBasic and CeFO Customization
IMPORTANT: The customization tools are just part of the picture. You can also
customize the behavior of the CeFO system via the system administration layer and
also within the administration-level applications, such as Policies and Customers,
which allows you to set up and maintain business rules, pop-up lists, queues,
privilege classes, status codes, and so on.
30 Chapter 1
ClearBasic and CeFO Customization
Data
Dictionary
Editor Server
CeFO Database
Data
Exchange
Customer Data
CB
Exchange ClearBasic Code
Form Resources
User
Interface
Editor
ClearBasic Code
Customer Data
Form Resources
API Routines
Client
Overview of ClearBasic 31
Customization Methodology
Notice that the API toolkit routines do not route customer data through the
CeFO application. These routines provide direct access to your data, routing
the data to your own application.
Customization Methodology
You should make your customizations in the following order
• Schema changes
• UI changes
• ClearBasic changes
More details on methodology are provided in Appendix D of this guide.
Customization Options
One thing you want to avoid is to implement a complex solution where a
simple solution would have worked. For example, if all you need is to fire
off a stored procedure in the database, you don’t need to go to the effort of
writing ClearBasic code; instead, just use the Action Editor feature included
with the User Interface Editor.
So, before you create aClearBasic solution, take a look at what you need to
do, then familiarize yourself with the various CeFO tools that are available
to determine which tool or tool combinations would be best.
32 Chapter 1
Where to Find More Information
Overview of ClearBasic 33
Where to Find More Information
34 Chapter 1
Chapter 2
A Tutorial in ClearBasic
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .36
Starting the UI Editor in ClearBasic Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .36
Lesson 1: Posting and Modifying an Existing Form . . . . . . . . . . . . . . . . . . . . . . . . . .38
Lesson 2: Creating a New Form. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .47
Lesson 3: Adding Controls for the New Form. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .49
Lesson 4: Writing and Importing CB Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .53
Lesson 5: Verifying the Form Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .55
35
Overview
Overview
Once database customizations have been made, coding customization is a
two-part process. First you modify an existing form or create a new one with
added form components, such as controls and contextual objects. Then you
write ClearBasic code for the new behavior, associate it with the Forms and
form components, and then import it into the CeFO database.
The lessons included in this tutorial demonstrate how to use CeFO User
Interface Editor, or UI Editor, to perform some of these tasks. The lessons
also demonstrate how to use the ClearBasic, or CB, code and the CeFO
CBEX utility to modify the behavior of forms.
NOTE: This tutorial is designed for use on Microsoft Windows platform. You can
easily adapt it for use on other supported platforms, such as UNIX.
This tutorial first describes how to start the User Interface Editor (UI Editor)
and then describes how you can perform the following tasks.
• Posting and modifying an existing form. Add a command button to the
modified form. Later, after adding appropriate CB code, this button posts
a new form.
Create a New Form. This is the form that will be posted from the
modified form.
• Add Controls to the new form. Add a text box and three command
buttons to the new form. Also add a contextual object. Later, after adding
appropriate CB code, one button will change the form title, the second
one will display text string in the text box, and the third one will close the
form and return
• Write CB code, for the modified existing form and the new form associate
it with the forms, and import it into a CeFO database.
• Test the behavior of the forms and controls.
36 Chapter 2
Starting the UI Editor in ClearBasic Mode
For detailed information about how to use the UI Editor, refer to the User
Interface Editor Guide.
A Tutorial in ClearBasic 37
Lesson 1: Posting and Modifying an Existing Form
38 Chapter 2
Lesson 1: Posting and Modifying an Existing
3. In the Filter Value text box to the left of the List button, type the words
“Select Employee” and then click List to list all the existing Select
Employee form names:
Filter Value
text box
4. Select the first entry in the list and then click Open (or double-click the
entry) to display that Select Employee form:
A Tutorial in ClearBasic 39
Lesson 1: Posting and Modifying an Existing Form
40 Chapter 2
Lesson 1: Posting and Modifying an Existing
7. To align the new Command Button, position the cursor inside the button,
press the left mouse button, and while keeping the mouse button
pressed, drag the new button to the desired position.
A Tutorial in ClearBasic 41
Lesson 1: Posting and Modifying an Existing Form
42 Chapter 2
Lesson 1: Posting and Modifying an Existing
13. From the File menu, choose Save As to display the Save Form As dialog
box:
14. In the User Version text box, enter your version name, e.g., “Terri” and
click Save.
The dialog box disappears and you return to the previous window. Note
that the title bar of the window now contains your version name “Terri.”
You have now created your own version of the original Select Employee
form.
A Tutorial in ClearBasic 43
Lesson 1: Posting and Modifying an Existing Form
15. Choose Resource Configs from the Select menu, to display the Resource
Configuration window:
16. Click List to display the entries for the existing Resource Configurations:
44 Chapter 2
Lesson 1: Posting and Modifying an Existing
17. Select the resource configuration (other than the resource_config_1.0) you
want to use and click Open to display the Resource Config window. For
example, you could select the first entry.
18. If not already selected, select User Version in the first dropdown list box.
A Tutorial in ClearBasic 45
Lesson 1: Posting and Modifying an Existing Form
19. In the Filter Value text box, type “Terri” and click List to display names of
forms that have user version Terri:
Filter Value
text box
20. In the left custom list, select the form with the title Select Employee and
click Copy.
21. Click Membership to display the Configuration Membership window.
22. Click List to display all active users in the Database custom list.
23. Locate and select your name in the first custom list and click Copy to
become a member of the Resource configuration.
You must be a member of the Resource Configuration to access the forms
at runtime. When you become a member of one Resource Configuration,
your membership, if any, in any previous Resource Configuration is
cancelled. In other words, a user can be a member of only one Resource
Configuration at any given time.
24. Click Done in the Membership window.
25. Click Done in the Resource Config window.
26. When the Save/Cancel/Discard prompt appears, click Save.
Your version of the form is now added to the Resource Configuration you
selected. Also, you have become a member of this Resource Configuration.
46 Chapter 2
Lesson 2: Creating a New Form
A Tutorial in ClearBasic 47
Lesson 2: Creating a New Form
4. In the Title field, replace the current text, that is “Form nnnn,” with
“More Information.”
This changes the title of the form to More Information.
5. Click the Edit Contextual Objects button to display the Edit Form
Contextual Objects window.
6. In the Contextual Object Name text field, enter the name “Potential.”
7. Click the Database Object Type button to display the Object Type
Selection window.
8. From the “select object database type” custom list choose String.
9. Click Use/Done.
10. Click Add the new contextual object to the form.
11. Click Done in the Edit Form Contextual Objects window.
12. Click OK in the Form attributes window.
13. From the File menu, choose Save to save the new form to the database.
48 Chapter 2
Lesson 3: Adding Controls for the New Form
NOTE: In this lesson you will only add the controls to the form. Actual
functionality will be added by the ClearBasic code as described in the next lesson.
A Tutorial in ClearBasic 49
Lesson 3: Adding Controls for the New Form
50 Chapter 2
Lesson 3: Adding Controls for the New Form
A Tutorial in ClearBasic 51
Lesson 3: Adding Controls for the New Form
22. From the File menu, choose Save to save the form to the database.
Now you are ready to write CB code to add new functionality to both the
forms.
52 Chapter 2
Lesson 4: Writing and Importing CB Code
After the code module for the Select Employee is imported into the CeFO
database, the Details button on that form, when clicked, will display the
More Information form.
The CB code module for the More Information form will add the following
functionality to the form:
• When you click the Change button, the form title text will change.
• When you click the Potential button, it will display text in the text box.
This text will be copied from the contextual object that is linked to the
text box.
• When you click the Done button, the form will close and you will return
to the Select Employee form.
A Tutorial in ClearBasic 53
Lesson 4: Writing and Importing CB Code
54 Chapter 2
Lesson 5: Verifying the Form Operation
The CB code for the new forms now has been saved to the database. To
verify the behavior of the forms, continue with the next lesson.
A Tutorial in ClearBasic 55
Lesson 5: Verifying the Form Operation
56 Chapter 2
Lesson 5: Verifying the Form Operation
6. Click Detail.
The system should display the More Information window:
A Tutorial in ClearBasic 57
Lesson 5: Verifying the Form Operation
58 Chapter 2
Chapter 3
Design Requirements
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .60
Designing Your Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .60
Whether to Use a Form, a Frame or a Tab. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .61
Central Code Storage and Retrieval. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .64
Adding Code to Standard CeFO Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .65
Maximum Character Limits for Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67
Avoiding Errors Due to Lack of Stack Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67
Calling External Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .68
Removing and Renaming Items in UI Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .68
File Size and Pcode Limits for Code Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .69
Case Sensitivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .69
Using Contextual Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .69
Enabling and Disabling Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72
Copy by Reference Versus Copy by Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73
Performance Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73
59
Overview
Overview
This chapter provides important information you need to take into account
before you start coding. One or more of these design limitations or pertinent
facts are bound to impact your work, especially if you learn about them the
hard way, after the fact.
Database Considerations
To develop an implementation in ClearBasic, you first need to determine
which of the existing database tables or views you want to use, and which
types of tables or view you need to add to the database.
60 Chapter 3
Whether to Use a Form, a Frame or a Tab
A typical use for a new form is for main windows that are posted as a result
of a menu selection. The reason this usage calls for a new Form is that the
form posted in this way doesn’t need any information from a parent via
contextual objects inherited from the parent.
You can also use new forms for windows that are posted from another form
via a button click provided that you intend to manipulate a different set of
contextual objects than its functionally preceding (parent) form. If you don’t
need information from the parent form, or if you need many new contextual
objects in your form, using a new Form is preferable due to contextual object
maintenance issues.
Design Tips
Determine whether the form you are creating supplies common
functionality needed in other parts of the application; if it does, then use a
form, not a frame.
Design Requirements 61
Whether to Use a Form, a Frame or a Tab
For example, suppose you need to add a button to post a window containing
custom information about the installed equipment at a site. If you use a
frame to do this, you will restrict the new functionality to a single parent and
you will not be able to post it from other forms. If, on the other hand, you
want to post this information from several forms, such as the Select Sites, Site
Config, and Site Config Details windows, you must use a new form.
A frame is posted from its parent in response to an event (e.g. button click),
and its display backgrounds the parent form (whenever the frame is posted
or activated). Any of the values in the parent’s contextual objects are
immediately available to the frame, without requiring extra code. (You just
have to get the contents of the contextual objects.)
You use a frame if you need access to the parent’s information via the shared
contextual objects and if you don’t need significant numbers of new
contextual objects, and if you don’t need the functionality in the frame
elsewhere in your application.
Using frames can cut down on development time since they share the same
contextual objects as their parent. This eliminates a possible source of errors
because you do not have to code logic to pass data between parent and
frame: it’s already in the contextual objects.
62 Chapter 3
Whether to Use a Form, a Frame or a Tab
Using tabs are a good way to reduce user confusion caused by too much
information being presented at the same time. Because only one tab at a time
is fronted, the user is able to focus entirely on the particular area of interest.
However, there are some limitations to consider when using Frames or Tabs.
As noted above, at creation time, frames and tabs inherit all existing
contextual objects associated with its parent. But if you add a new
contextual object to a parent form after the frames have been created, the
new contextual object does NOT automatically port to the frame, which
means you must add them yourself. Thus, if you use tabs or frames, it is
very important to design all forms involved in the feature up front, not just
one form at a time.
Design Requirements 63
Central Code Storage and Retrieval
TIP: Frames and tabs are REQUIRED to have the EXACT contextual objects as its
parent, and vice versa. Not only do the same contextual objects have to be added to
each parent and tab, but also the contextual objects have to be added in the “same
order”.
64 Chapter 3
Adding Code to Standard CeFO Forms
NOTE: During the attempt to perform Update Desktop the end user may be
prompted to close all open windows, then repeat the Update Desktop.
If you don’t add the DoDefault statement, none of the standard CeFO
behavior for that form will occur. This is true even if you put a DoDefault
statement in subsequent event handlers. You must call DoDefault in your
form_load procedure. (Obviously, if you were coding an entirely new form,
you would not invoke DoDefault because there would be no default
behavior.)
Design Requirements 65
Adding Code to Standard CeFO Forms
Of course, you can add whatever else you want in the form_load procedure.
66 Chapter 3
Maximum Character Limits for Names
Design Requirements 67
Calling External Routines
To avoid this problem, you might want to do any or each of the following:
• Reduce recursion and function call depth
• Reduce the size and number of local variables (UDTs, arrays, etc.)
The default size of this stack is 64K. However, you can set it to a higher value
by assigning that value to the cbStackSize variable. You cannot set to a value
lower than 64K.
68 Chapter 3
File Size and Pcode Limits for Code Modules
However, in some cases, your code can fail to compile at import time even if
your source file is under the maximum size. This can occur if the type of
coding in your module happens to generate a lot of Pcode.
Case Sensitivity
There is one item that is highly case sensitive: the names of record fields. You
must make these all lowercase. If you do not, they will not be recognized as
valid. Other operations are not case sensitive.
Design Requirements 69
Using Contextual Objects
To do this, create the contextual object in the normal way, specifying the
UDT when selecting the data type for the contextual object. Then, you can
link specific fields of the UDT to specific columns of the custom list.
Your CB code can create lists of UDTs and Fill the associated contextual
object. Note that for custom lists you supply a List, not a single item, for the
contextual object. Your code can then manipulate the UDT list in a number
of ways. UDTs can also be used as single contextual objects, and then linked
to text boxes, check boxes, etc.
70 Chapter 3
Using Contextual Objects
TIP: When you have multiple controls on a form (e.g. several text boxes) that
you want to populate with using fields from the same database record or
view, create a single contextual object in your form for that database record
(or view). Then link each of the controls with one of the fields in that
contextual object. That is far more efficient than creating a primitive type for
each control, then getting each field from the record and loading it into the
control.
Design Requirements 71
Enabling and Disabling Controls
IMPORTANT: If you don’t enable and disable controls in these types of situations,
then you will need to implement additional error checking logic to deal with those
cases where a control selection is not appropriate. If you don’t put these safeguards
in, then you could get unexpected runtime errors.
You should also disable certain controls while code is being executed. For
instance, if you have ClearBasic code behind a Done button, you should
disable the other buttons on the form while the code is being executed.
Otherwise the user can click another button and that event will be processed
after the Done event handler is finished. Typically the Done event handler
would close the form. You are now in a state where the application is trying
to execute code behind a form which has been closed. Again, this will cause
problems.
72 Chapter 3
Copy by Reference Versus Copy by Value
For instance, suppose you had a loop which inserted new records into the
BulkSave object. If the record is inserted (InsertRecord) by reference, then
upon finishing the Save operation, the record would have the Object ID
filled in. Upon subsequent loops, if the code did not do a ChangeToNew
method on the record, then you would not save new records but would
overwrite the record last saved. Instead, in this case, you should execute the
InsertRecord method with a “cbByValue” option.
Performance Considerations
When designing your code, you need to be aware of relevant performance
issues. Some of these are described below.
Design Requirements 73
Performance Considerations
74 Chapter 3
Object Reference versus Language Reference
IMPORTANT: The Object Reference always has precedence over the Language
Reference.
Design Requirements 75
Use the SetFocus Method
76 Chapter 3
Chapter 4
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .78
ClearBasic Naming Requirements/Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . .78
Using User Defined Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .88
Why and How to Use Constants. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .91
Contextual Object Versus Control Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . .91
Using Functions and Subroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .92
When Do You Use Parentheses in a Method Call? . . . . . . . . . . . . . . . . . . . . . . . . . .95
77
Overview
Overview
This chapter describes the key fundamentals of the ClearBasic language,
such as naming conventions, assignment statements for objects, declaring
object instances, and so on. This chapter does not provide beginner’s
instructions on programming: it does not cover program control structures
and basic data manipulation. You need to obtain one of the many books
available on programming in the Basic language. Most, if not all, of the
standard Basic features are available in ClearBasic. (For precise details on
supported language functionality, see the ClearBasic Language Reference.)
78 Chapter 4
ClearBasic Naming Requirements/Conventions
Control Names
For readability, control names should either be mixed case with no
underscore, or all upper case with an underscore as necessary.
80 Chapter 4
ClearBasic Naming Requirements/Conventions
Keyword Names
There are no required conventions for referencing keywords. Refer to the
ClearBasic Language Reference manual for a list of keywords.
For Example: Dim, Global, Const, Declare, Set, For, Next, Sub, End Sub,
Function, Exit Function, End Function, Select Case, Else Case, If, Then, Else
If, End If, Integer, List, Record
Constant Names
ClearBasic has a pre-defined set of constants. These are listed in Appendix C
of this guide. Table 5 shows the naming conventions for constants.
Variable Names
Table 6 lists the conventions for control names:
However, for standards and supportability reasons, you should use Mixed
Case. For example, GetField.
82 Chapter 4
ClearBasic Naming Requirements/Conventions
Function Names
The requirements/conventions are the same as for subroutines.
Using Variables
Using variables is fairly straightforward. However, there are a few things
you need to keep in mind. In particular, you need to be aware of general
scoping issues, stack size issues affected by variables, how to declare
variables, and how to assign to an object variable.
Scoping
When a reference is made to a global variable, the ClearBasic interpreter
looks for the declaration first within the subroutine or function in which it is
found, then in the form module outside any subroutine or function, then in
the globals module.
84 Chapter 4
Using Variables
Why is this a potential problem? Because every form that is posted gets a
maximum stack (known as a ‘thread’) of 8K bytes. If you exceed that size by
using many variables or large variables, you can get errors.
NOTE: If you want to set the stack size to LESS than 8K bytes per thread, you can
do so by setting the cbStackSize variable in the Clarify.env file. See the ClearBasic
Object Reference under “StackSize” for details.
Instead, replace the above code as shown in the following code snippet:
If (Screen.AllSpaces(validatePortRecord.GetField
("port"))) Then
App.MsgBox "Must input a valid Port Number"
Exit Function
End If
You must use the keyword new keyword if the variable you are declaring is
an object variable. You don’t use the keyword new when you declare
primitive types and UDTs.
86 Chapter 4
Using Variables
When you set the values of a new record you need to use the "RecordType"
property in order to define what type of data that item can receive.
However, if you are populating that record variable by assigning the results
of a method (such as GetSelected) or a property, then you do not need to
specify the RecordType in advance. Your record will inherit the data type
associated with the object that you are processing.
You cannot set or initialize global variables in the globals file or in the form
module outside functions and procedures! They have to be assigned inside a
function or procedure. If you try to do this, you will get a compile-time error
message.
IMPORTANT: You must set global variable values only inside of a procedure or
function. Doing otherwise will cause a compile time error.
For example:
Set siteContactList = Cobj_lor_CONTACT_VIEW.Contents
siteObjid = siteContactList.GetField("loc_objid")
The first line is assigning data into a record object variable, so it must use
SET. The second is assigning into a long integer variable, so it does not use
SET.
UDTs are very useful and even required for certain kinds of work, for
example, for manipulating data from external databases (see Chapter 16
about accessing external databases with SQL).
UDTs are also very useful for use as contextual object types for custom lists.
You can use them to display information from various sources, including
fields from different database objects, in the custom list control. (Without
them, you would be restricted to displaying only database record or view
fields of a specific single type in a custom list.)
88 Chapter 4
Using User Defined Types
Once you have done this, you can manipulate the UDT contextual object
using most of the regular ClearBasic methods. Notice that you only need one
declared variable for that UDT in your module. This tells the compiler that
the type is really being used, and should not be thrown away.
Rule 2: If you want to use a UDT as a contextual object, you must feed in the
definition to the UI Editor. What you do is define the UDT (and declare one
instance of it!) in the UI Editor globals file, then load that file into the UI
Editor when you start it up. This is described in Chapter 13, “Building Your
Project.”
Rule 3: You cannot use a UDT as the left hand side of an assignment
statement. Consequently, you cannot assign to a UDT using properties, (for
example, MyUdt = MyObject.Property) because these assign to the left.
Rule 4: Only certain methods support UDTs. Do not use a method on a UDT
that does not support UDTs. The ClearBasic Object Reference documents
whether a method supports a UDT. For example, you cannot use the
Contents method to read a contextual object that is a UDT type, but you can
use the equivalent GetContents method.
90 Chapter 4
Why and How to Use Constants
OR
‘Manipulating the Control
Dim contractRec as Contract_Record
If (clb_CONTRACTS.GetSelected (contractRec)) Then
selectedContractNumber = contractRec.contract_id
selectedContractType = contractRec.type
selectedStatus = contractRec.status
selectedPO = contractRec.po_number
newCase.NotifyById 411, 10081
End If
Either one is legal, the only difference is that the Contextual object method
took 7 lines of code (including variables needed) whereas the control only
took 2 lines. So in this case, you should manipulate the control rather than
the contextual object.
In another example, suppose you had multiple text box controls linked to
different fields in a single contextual object. If you wanted to display the
contents using control oriented code, you need to repeat it for each control. It
would be far simpler to just get the record (or view) and Fill it into the
contextual object because this will automatically flush the field values to the
text boxes.
92 Chapter 4
Using Functions and Subroutines
Scoping
As with other language components, the interpreter looks first in the form
module for a subroutine or function. If it cannot find it, it looks in the globals
module.
Note that there are parentheses around the parameters and that a function
returns a value.
Note that there are no parentheses around the parameters and that there no
value is returned.
IMPORTANT: If you accidentally place parenthesis around the parameter list, you
will get a compile time error similar to this one:Compile error on line 12 of 411.cbs:
GetChildrenList is not a variable
94 Chapter 4
When Do You Use Parentheses in a Method Call?
You need to use parenthesis when the method call is an expression that is
part of a statement. For example:
set myList = myBulkRet.GetRecordList(0)
and
myMenu.AppendItem "Desktop", "New Item"
96 Chapter 4
Chapter 5
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .98
What is a Contextual Object? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .98
When Are You Required to Use Contextual Objects? . . . . . . . . . . . . . . . . . . . . . . . .99
Creating a Form: the Role of Contextual Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . .99
Creating a Control: the Role of Contextual Objects . . . . . . . . . . . . . . . . . . . . . . . . .108
97
Overview
Overview
In order to create and program forms and controls in the CeFO GUI, you
need to know a few things about CeFO contextual objects. You have to know
what they are, how you use them in the form and control creation process,
and generally how to use them in your ClearBasic code to get data to and
from controls. To provide you with the information you need, this chapter
covers the following material:
• It briefly defines contextual objects.
• It describes how contextual objects are involved in the creation of forms,
including ClearBasic coding considerations.
• It describes how contextual objects are involved in the creation of
controls, again, including ClearBasic coding considerations.
NOTE: This chapter covers general concepts about contextual objects: for details on
programming with controls, see the chapter titled "Programming Controls."
98 Chapter 5
When Are You Required to Use Contextual Ob-
Planning Issues
During the form design process, you must develop a fairly complete idea of
the type of user activity you want the form and its controls to support. You
must decide which information from the database you want to display in the
controls, which type of user input you want the controls to receive, and so
on.
To be more precise, before you can start implementing your form design,
you must know which database tables the form is going to access. For
example, you must know whether you want to use information from the
Contact table, or the Site table or the site_parts table. Which database tables
are to be used by the form become a crucial issue when you link contextual
objects to the form.
You also need to know which type of local (non-database) data your form
and controls is going to display or receive. You need to know, for example,
whether you want to display a count of records retrieved when the user
accesses the database.
In Figure 4, notice that you can assign size dimensions for the form, along
with other attributes. The most important part of this window is the button
for editing contextual objects in the lower left of the figure. You must click
on this to open the contextual objects window (see Figure 5) and begin the
work of linking contextual objects to the form.
100 Chapter 5
Creating a Form: the Role of Contextual Objects
NOTE: Within a given form, you must assign unique contextual object names.
(Uniqueness of names is enforced by the User Interface Editor.)
Specifying a data type for a contextual object means that it can contain only
that type of data. If you select the type Contract for a contextual object, that
contextual object can only be used to contain records from the Contract table
in the database.
After you select the desired type, click on the Add button to link the
contextual object with the form.
CAUTION: In the User Interface Editor, if you link a form to a contextual object
that has a user defined type, and then link one or more controls to that contextual
object, you cannot remove the definition of the user defined type from your globals
file before first removing all references to that contextual object in the form.
Removing the definition first can prevent you from reposting that form in the User
Interface Editor.
102 Chapter 5
Creating a Form: the Role of Contextual Objects
Form5050
Cobj_MyContacts
objid first_name last_name phone ....
Custom List 1 xxxx Senya Cuffink 125-4567 ....
xxxx Kevin CRKing 321-7654 ....
xxxx Mike Treacle 132-5476 ....
Cobj_MySiteParts
ClearBasic Code
(Get data from database)
Database
(Contact
Site_Part)
Notice that the figure shows that only three fields in MyContacts are linked
to the custom list. This means that the custom list control displays only the
values in those three fields.
104 Chapter 5
Creating a Form: the Role of Contextual Objects
In this example, the two lists of records are retrieved from the BulkRetrieve
object and placed into their respective list variables and loaded into the
proper contextual objects using the Fill method.
In the above example, contact records are retrieved from MyBulk into
ContactList. Then each of the values in the "last_name" field in those records
is copied over into NameList, and NameList is loaded into the contextual
object. (Cobj_MyList has the list primitive type.)
106 Chapter 5
Creating a Form: the Role of Contextual Objects
In the above example, a record is retrieved from a contextual object with the
Contents property and placed into qryObj, which is then loaded into a
BulkSave object to be saved to the database.
NOTE: Instead of getting data from a contextual object, you could get the data
directly from the control linked to that contextual object. In fact, in many cases,
using control methods is more effective. For more information, see the chapter titled
"Programming Controls."
If you feel the need to add several more contextual objects, you might want
to consider using an entirely new form rather than a frame.
When you create a control for a form, you select the control you want (text
box, list box, etc.) in the User interface Editor and place it on the form.
Then you double click on the control to display the Attributes Window.
Figure 7 shows the attribute window for a list box.
108 Chapter 5
Creating a Control: the Role of Contextual Ob-
NOTE: Although these list controls support the use of static lists of items defined at
control design time, such static lists are not fully supported by ClearBasic.
For custom list controls, you specify separate fields in a contextual object to
be the sources of the columns in the control; the contextual object in this case
must be a multi field contextual object that is either a database table or view
type, or a user defined type.
For check box, command button, label, tab button, and option button
controls, specifying a source contextual object is not required, because a
source contextual object is used mainly for labeling purposes. Normally,
instead of using a source, you would simply specify a text label for these
controls at design time.
To set a control’s initial state at form load, you can either directly set the
control using control methods/values, or you can fill a control’s destination
contextual object with the desired value. You can do this to display initial
text in a text box, for example, or to highlight a particular selection in a list
box, custom list, etc.
110 Chapter 5
Creating a Control: the Role of Contextual Ob-
NOTE: In some CeFO documentation, a source link is called a title link or tlink; a
destination link is called a value link or vlink.
This window displays, in alphabetic order, all of the fields for the form’s
contextual objects. In this figure, there are two contextual objects:
• MyContacts, which has the database type Contact and has several fields
• MySourceList, which has the primitive type List and has only one field.
Because the control is a list box, you must link a source contextual object that
has the List primitive type. The list box will display the values in the
contextual object at runtime when the form is posted, assuming you load the
data into the contextual object in the form load event.
Table 10 Controls and required datatypes for source and Contextual objects
Control Required Data Type for Source Required Data Type for Destination
Contextual Object Contextual Object
Check Box String. (Optional) Integer.
Command Button String. (Optional) No destination.
Custom List Varies for each field in the custom list. List.
Dropdown Combo List*. String.
Box
Dropdown List Box List*. String.
Label String. (Optional) No destination.
List Box List*. List.
Multiline Text Box No source. String.
Option Button String. (Optional). String.
Text Box No source. String
* You can use a static list of items defined at control design time instead
of a source contextual object. However, you can only read the values in
these static lists in your ClearBasic code: you cannot add or delete
items from the list, or change their order. For this reason, the use of a
source may be more desirable.
112 Chapter 5
Creating a Control: the Role of Contextual Ob-
Form5050
Cobj_MyContacts
1CRKing
Treacle
MyListBox 1.
Cuffink
CRKing
Treacle
Treacle Cobj_MyString
ClearBasic Code
(Get data from database)
ClearBasic Code
(Use Treacle in a Filter
Conditon to retrieve other Database
Records From Database) (Contact
Table and
All Other
Tables)
114 Chapter 5
Chapter 6
Programming in Forms
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116
What You Need to Do First . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116
Initialization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116
What Every Form Module MUST Have . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116
Types of CeFO Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117
If You Do ANY Programming in a CeFO Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117
If You Create a New Form, Frame, or Tab Frame . . . . . . . . . . . . . . . . . . . . . . . . . . .119
If You Create a New Frame or Tab Frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120
115
Overview
Overview
This chapter provides a few tips to help you get started programming in
forms.
Initialization
Form initialization is described in Chapter 9 of this guide.
At the very least, your form module must have these lines:
Sub Form_Load
End Sub
If you don’t have at least a dummy form_load procedure, none of your code
will be executed.
116 Chapter 6
Types of CeFO Forms
IMPORTANT: In this discussion, “form” refers to form, frame, and tab frame. If
something applies only to a particular type of form but not the others, we will call
your attention to it.
Like this:
Sub MyButton_Click()
Me.DoDefault
‘Your code here....
End Sub
118 Chapter 6
If You Create a New Form, Frame, or Tab Frame
In this example, the Close message is handled, then all other messages are
passed on to the default handler by calling DoDefault. (Of course, in a
standard CeFO window, you don’t need to handle the Close message; that is
done for you by the default handler.)
Notice that all of this applies to a frame or tab frame that you have created.
The reason for this is that the CeFO system knows about those types of new
form and has message handlers for those also.
If the contextual object is a list type, you are currently limited to only
reading that list.
Notice that this message handler does not call DoDefault. A new form does
not have a default handler, so you don’t need to do this.
Notice also, that none of this applies to a frame or tab frame that you have
created. The reason for this is that the CeFO system knows about those types
and already has message handlers for those.
CAUTION: If you don’t add a message handler to a new form that handles the Close
message, the application will not be able to close properly if that form is still open.
IMPORTANT: Tab frames are covered in Chapter 8, so look there for details.
Likewise, if you add a contextual object to a frame, you must add that same
contextual object to the parent form.
This is why it’s a good idea to add all of the contextual objects you are going
to use to the parent first, before you create a frame.
120 Chapter 6
If You Create a New Frame or Tab Frame
IMPORTANT: If you use do use messaging, read the chapter in this guide about
messaging, particularly the material about what you MUST include in your
message handlers.
122 Chapter 6
Chapter 7
Programming Controls
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .124
Code Execution and Control Updating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .124
Control Names and Reserved Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .124
What You Can and Cannot Put Into a Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126
Programming Check Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126
Programming Command Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .132
Programming Custom Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .133
Programming Dropdown Combo Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .140
Programming Dropdown List Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143
Programming Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147
Programming List Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149
Programming Multiline Text Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .151
Programming Option Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .153
Programming Tab Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .155
Programming Text Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .159
123
Overview
Overview
The information in this chapter assumes that you have already created the
form and linked contextual objects to it, as described in Chapter 5
"Contextual Objects and the CeFO GUI."
CAUTION: In the User Interface Editor, if you link a form to a contextual object
that has a user defined type, and then link one or more controls to that contextual
object, you cannot remove the definition of the user defined type from your globals
file before first removing all links to that contextual object in the form and controls.
Removing the definition first can prevent you from reposting that form in the User
Interface Editor.
Note that Ctl_ is prepended only on control names that are reserved
keywords.
124 Chapter 7
Control Names and Reserved Keywords
Lists of simple values. The following list controls accept lists of simple values
such as integers, strings, etc: dropdown combo boxes, dropdown list boxes,
and list boxes.
Lists of objects. Only custom lists accept lists of objects such as a list of
records or a list of user-defined types.
NOTE: Only a custom list control can accept a list of objects. All other list controls
can accept only lists of simple values!
126 Chapter 7
Programming Check Boxes
Name. You must assign a name that is unique within the form you are
coding. Also, you might want to avoid reserved keywords to simplify things
(see "Control Names and Reserved Keywords" earlier in this chapter).
The name you assign is the name you must use when you write code for that
control. For example, if you want to read the value of a check box with the
name MyCheckBox, you would use this line:
MyCheckBox.Value
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
Label. Enter the label for the check box. (You can change the label in your
code with the Caption property at run time.) If you want to use a label from
a source contextual object, leave this field blank.
AutoSize. You might want to turn this on if you plan on changing the label
via the Caption property at run time.
Source. Ignore this button if you want to specify a label in the Label text box.
You use this button only if you want the control label to come from a source
contextual object. (See Chapter 5, "Contextual Objects and the CeFO GUI"
for more information about source contextual objects.)
Destination. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must be an integer type, because the check box returns a 0
to that field if unchecked, and a 1 if checked. (You can use a contextual object
that has an integer type, or you can use an integer field in a contextual object
that has a database or a user defined type.
There are three tasks involved when you code a check box:
• Set the initial state of the check box when the form is posted.
• Write code that checks the check box value.
• Write code that is sensitive to the check box value.
128 Chapter 7
Programming Check Boxes
In the above example, the destination contextual object for the check box
(Cobj_YourChkBox) is filled with the integer value of 0. This means that
the check box is unchecked when the form is posted.
The following code fragment shows one way to implement the pseudo code:
Dim recList as New List
Dim sumElem as New Record
Dim Category as String
Dim extension as double
Dim billable as Integer
Set recList = Cobj_Case_Rec.Contents
For i=0 to recList.count-1
Set sumElem = recList.ItemByIndex (i)
Category = sumElem.GetField("subtotal_cat")
extension = sumElem.GetField("extension")
billable = sumElem.GetField("billable")
Next
Although you can’t see it in code, a check box is linked to the integer field
"billable ." So, what the code is doing here in this line is getting the
checked/unchecked value for each record in the list. Notice that the check
box control itself is not queried in any way; only the contextual object that
has a field linked to the check box is accessed.
130 Chapter 7
Programming Check Boxes
Name. You must assign a name that is unique within the form you are
coding. Also, you might want to avoid reserved keywords to simplify things
(see "Control Names and Reserved Keywords" earlier in this chapter).
The name you assign is the name you must use when you write code for that
control. For example, if you want to invoke the click event of a command
button with the name Command1, you would use this line:
Command1.Value = 1
Command, Frame, Frame Init. Ignore Frame Init. Use the default selection,
Command.
132 Chapter 7
Programming Custom Lists
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
Label. Enter the label for the command button. (You can change the label in
your code with the Caption property at run time.) If you want to use a label
from a source contextual object, leave this field blank.
AutoSize. You might want to turn this on if you plan on changing the label
via the Caption property at run time.
Default. You can check this if you want the command button to be the default
for the form. You can also set and reset this attribute at runtime using the
Default property.
Source. Ignore this button if you want to specify a label in the Label text box.
You use this button only if you want the control label to come from a source
contextual object. (See Chapter 5, "Contextual Objects and the CeFO GUI"
for more information about source contextual objects.)
When you click on this button, the caption on it changes to Hello. You
probably will want to write your own code that does a little more.
Using custom lists. Normally, you use a custom list to display summary type
information about the record or view so the user can determine whether to
"open" a new window to carry out some activity related to that record. The
user does this by double-clicking on that item in the custom list or by
clicking on a command button, such as an Open button.
Coding custom lists. You normally need to write an event procedure for the
click event on the command button and another event procedure to handle
the double-click on the selected item; the contents of each procedure must be
the same, the only difference is that they handle different events. By the way,
the double-click event happens to the custom list control itself, not to the
row occupied by the selected item, so you would name this double-click
event procedure like this:
Sub MyCustomList_DblClick()
where MyCustomList is the name of the custom list. The event procedure
then does whatever you have coded it to do when invoked.
Create a custom list control as described in the User Interface Editor Guide.
When you create the control, notice that you can assign several attributes as
shown in Figure 12.
134 Chapter 7
Programming Custom Lists
Name (for the control). You must assign a name that is unique within the
form you are coding. Also, you might want to avoid reserved keywords to
simplify things (see "Control Names and Reserved Keywords" earlier in this
chapter).
The name you assign is the name you must use when you write code for that
control. For example, if you use the name MyCustomList, you would use the
following line to get the items selected by the user:
Dim MyList as New List
Set MyList = MyCustomList.SelectedList
Name (for each column). Assign a name to be displayed as the header for the
column. Assign a name to each column that you create in the custom list
control. These are for display only; you don’t write any code for them. The
column header names do not have to be unique, but it would be uncommon
to assign the same name to different columns.
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
Multiple. Turn this on if you want to allow the user to select more than one
item from the custom list. Leave this unchecked if you want to allow only a
single selection.
Destination. You must click on this button and then carry out the task of
assigning one contextual object field to this control. The contextual object
field you choose must have the type List. When the user makes a selection,
the indexes (integer values) of the selected item are returned to the
destination.
Field Name, DataType.These fields are filled in automatically when you select
the source or destination contextual object. (If you fill these in manually you
introduce a possible source of error, so you might want to avoid this
practice.)
Justify. For each column in the custom list, you must choose the type of
justification you want. If you select Left, the values in the column are left
justified; if you select Right, the values are right justified.
Width. For each column, specify the default width, in characters. This will
determine how wide the column is when initially displayed. The user will be
able to resize the column at run time (unless you turn on the Fixed attribute).
Fixed. For most purposes, you might want to leave this unchecked. If you
check this, and turn on this attribute for a column, the column width is fixed
at the size specified in the Width attribute; the user cannot resize the column.
Visible. Leave this checked. If you want to hide or disable controls at run
time, use the appropriate ClearBasic properties for the control to hide or
disable the control.
Source. For each column, you must click on this button and then carry out
the task of assigning a field in the source contextual object to this control.
You can assign any contextual object field you want to the column. Of
course, the data type of the contextual object field must match the type of
data you want to load into the column.
NOTE: All of the contextual object fields that are used as source contextual objects
must come from the same contextual object! You cannot link fields from two
separate contextual object to the same custom list.
136 Chapter 7
Programming Custom Lists
The following code snippet sets the type of a record variable (MyCase) to be
a case record variable, then retrieves some case records from the database.
The list of case records retrieved is placed into MyList and the first record in
the list is placed into MyCase. Finally, MyCase is appended into the custom
list control.
Dim MyCase as new Record
Dim MyList as new List
Dim MyBulk as new BulkRetrieve
MyCase.RecordType = "case"
MyList.ItemType = "Record"
MyBulk.SimpleQuery 0, "case"
MyBulk.AppendFilter 0, "title", cbLike, "ClearBasic"
MyBulk.RetrieveRecords
Set MyList = MyBulk.GetRecordList(0)
Set MyCase = MyList.ItemByIndex(0)
MyCustomList.AppendItem MyCase
138 Chapter 7
Programming Custom Lists
Of course, the items you Fill into the contextual object must have the same
data type as the contextual object. For example, if the source contextual
object has the database type "Case", you can only Fill the contextual objects
with case records.
The following code snippet sets the type of a record variable (MyCase) to be
a case record variable, then retrieves some case records from the database.
The list of case records retrieved is placed into MyList and the first record in
the list is placed into MyCase. Finally, MyCase is filled into the source
contextual object for the custom list control.
Dim MyCase as new Record
Dim MyList as new List
Dim MyBulk as new BulkRetrieve
MyCase.RecordType = "case"
MyList.ItemType = "Record"
MyBulk.SimpleQuery 0, "case"
MyBulk.AppendFilter 0, "title", cbLike,"ClearBasic"
MyBulk.RetrieveRecords
Set MyList = MyBulk.GetRecordList(0)
Set MyCase = MyList.ItemByIndex(0)
Cobj_MyCustomList.Fill MyCase
140 Chapter 7
Programming Dropdown Combo Boxes
Name. You must assign a name that is unique within the form you are
coding. Also, you might want to avoid reserved keywords to simplify things
(see "Control Names and Reserved Keywords" earlier in this chapter).
The name you assign is the name you must use when you write code for that
control. For example, if you use the name MyDropDownCombo, you would
use the following line to get the user’s selection:
MyStringVariable = MyDropDownCombo.Selected
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
IMPORTANT: You should make the control wide enough to display the longest item
in the list. If you don’t, part of the item will not be displayed. (However, the item is
still selectable, and the entire string is still returned to the destination contextual
object.
AutoSize. You might want to turn this on if you plan on changing the label at
run time with the Caption property. This attribute only affects the width of
the label field for the control: it does not affect the width or length of the
dropdown itself.
Disabled. Leave this unchecked. You can enable and disable controls using
control methods at run time.
Visible. Leave this checked. If you want to hide or disable controls at run
time, use the appropriate ClearBasic properties for the control to hide or
disable the control.
Required. Setting this attribute requires the user to fill in the text box. You
can set this attribute at design time if you want, or you can set it at run time
using the Required property. In addition, you can use the RequiredColor
property to highlight the text box as a required text box.
Source. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type List. The list of items loaded into the
source contextual objects is what is displayed in the control for the user to
select.
Destination. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type String.
When the user makes a selection, the selected string is returned to the
destination contextual object.
List Items. Avoid using this feature: instead, use a source contextual object
for the list of items to display in the control.
142 Chapter 7
Programming Dropdown List Boxes
Name. You must assign a name that is unique within the form you are
coding. Also, you might want to avoid reserved keywords to simplify things
(see "Control Names and Reserved Keywords" earlier in this chapter).
The name you assign is the name you must use when you write code for that
control. For example, if you use the name MyDropDownList, you would use
the following line to get the user’s selection:
MyStringVariable = MyDropDownList.Selected
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
IMPORTANT: You should make the control wide enough to display the longest item
in the list. If you don’t, part of the item will not be displayed. (However, the item is
still selectable, and the entire string is still returned to the destination contextual
object.
PopUp List, Static List, Clarify List. Select Clarify List. The other types of
list are not fully supported by ClearBasic.
AutoSize. You might want to turn this on if you plan on changing the label at
run time with the Caption property. This attribute only affects the width of
the label field for the control: it does not affect the width or length of the
dropdown itself.
Visible. Leave this checked. If you want to hide or disable controls at run
time, use the appropriate ClearBasic properties for the control to hide or
disable the control.
Disabled. Leave this unchecked. You can enable and disable controls using
control methods at run time.
Source. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type List. The list of items loaded into the
source contextual objects is what is displayed in the control for the user to
select.
Destination. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type String.
When the user makes a selection, the selected string is returned to the
destination contextual object.
144 Chapter 7
Programming Dropdown List Boxes
NOTE: The Click event occurs at different times for drop-down combo boxes and
drop-down list boxes. For combo boxes, the Click event occurs after opening the list
box, i.e., before you select an item from the box. For list boxes, the Click event
occurs after selecting an item from the list.
NOTE: For a longer example that uses dropdown list boxes in a filtering
mechanism, see sections Using Control Propertiesand Sample Button Click Event
Procedure on page 164.
MyDropDown.Fill MyStatesList
There are two ways to get the user’s selection: through control properties or
through contextual object properties.
The following code gets the selection from a control named MyDropDown:
Dim MyStringVar as as string
MyStringVar = MyDropDown.Selected
The following code gets the selection from the contextual object
Cobj_MyDropDown:
Dim MyStringVar as string
MyStringVar = Cobj_MyDropDown.Contents
The following code selects the item "Case ID" in the control MyDropDown:
MyDropDown.SetSelected "Case ID"
146 Chapter 7
Programming Labels
Programming Labels
The Label control is used to label the following controls: custom lists,
dropdown list boxes, list boxes, multiline text boxes, and text boxes. (Check
boxes, command buttons, and option buttons all contain their own label, so
you would not normally use the Label control to label them.)
The label control can also be used to display a string value, for example, it
could be used to display a count of records returned from the database.
However, you normally would use a read-only text box for these kinds of
display purposes.
Creating a Label
Create a label control as described in the User Interface Editor Guide. When
you create the control, notice that you can assign several attributes to the
check box as shown in Figure 15.
Name. You must assign a name that is unique within the form you are
coding. Also, you might want to avoid reserved keywords to simplify things
(see "Control Names and Reserved Keywords" earlier in this chapter).
The name you assign is the name you must use when you write code for that
control. For example, if you use the name MyLabel, you would use the
following line to change the caption:
MyLabel.Caption = "Hello"
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
AutoSize. You might want to turn this on if you plan on changing the label at
run time with the Caption property. This attribute only affects the width of
the label field for the control.
Visible. Leave this checked. You can enable and disable controls using
control methods at run time.
Source. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type String. Whatever is in the contextual
object is displayed in the label.
Coding a Label
A simple use of a label is to toggle the caption to reflect some changed state.
In the following example, a click event results in the label being changed to
display a status.
Sub ClickMe()
MyLabel.Caption = "Done"
End sub
The following code converts an integer value (a count) to a string, then loads
it into a contextual object source linked to the label:
Cobj_MyLabel.Fill str$(MyList.Count)
148 Chapter 7
Programming List Boxes
Name. You must assign a name that is unique within the form you are
coding. Also, you might want to avoid reserved keywords to simplify things
(see "Control Names and Reserved Keywords" earlier in this chapter).
The name you assign is the name you must use when you write code for that
control. For example, if you use the name MyListBox, you would use the
following line to get the user’s selection:
MyString = MyListBox.Selected
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
NOTE: You should make the control wide enough to display the longest item in the
list. If you don’t, part of the item will not be displayed. (However, the item is still
selectable, and the entire string is still returned to the destination contextual object.
AutoSize. You might want to turn this on if you plan on changing the label at
run time with the Caption property. This attribute only affects the width of
the label field for the control: it does not affect the width or length of the list
box itself.
Disabled. Leave this unchecked. You can enable and disable controls using
control methods at run time.
Item. Do not fill in any items. This creates a static list, which is not fully
supported by ClearBasic
Source. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type List. The list of items loaded into the
source contextual objects is what is displayed in the control for the user to
select.
Destination. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type List.
When the user makes a selection, the selected string is returned to the
destination contextual object.
150 Chapter 7
Programming Multiline Text Boxes
Name. You must assign a name that is unique within the form you are
coding. Also, you might want to avoid reserved keywords to simplify things
(see "Control Names and Reserved Keywords" earlier in this chapter).
The name you assign is the name you must use when you write code for that
control. For example, if you want to place some text in a text box with the
name MyMultiline, you would use this line:
MyMultiline.Text = YourNote
Notice the use of a string variable (YourNote) here. Normally, you would
use assign the text to a variable, then supply the variable to the property Text
or to the destination contextual object.
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
Max Length. You may want to specify the maximum number of characters
accepted by the text box. You need to consider the length of text you expect
the user to input. If the text is destined for the database, you need to make
sure that the number you supply does not exceed the maximum characters
allowed for the destination field.
Instead of using this design time setting to limit the number of input
characters, you could trap each user keypress at run time; however, this
involves much more overhead.
AutoSize. You might want to avoid turning on this attribute because, in most
cases, you need to make sure the control fits into a defined space in the form.
Visible. Leave this checked. If you want to hide or disable controls at run
time, use the appropriate ClearBasic properties for the control to hide or
disable the control.
Required. Setting this attribute requires the user to fill in the text box. You
can set this attribute at design time if you want, or you can set it at run time
using the Required property. In addition, you can use the run time
RequiredColor property to highlight the text box as a required text box.
ReadOnly. This attribute prevents the user from entering text in the control;
you might want to turn this on if the text box is used only to display values.
However, instead of using this design time attribute, you could instead use
the more flexible run time ReadOnly property.
Password. Set this attribute if the text box is going to accept password input.
Input text is displayed as asterisks. Normally, however, you would use the
text box control to accept passwords.
Destination. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type String.
152 Chapter 7
Programming Option Buttons
Displaying Text
You can cause the desired text to be displayed in the control when the form
is posted by inserting the following line in the form load procedure:
Dim MyText as string
MyText = "Let’s pretend that this is actually " &
"several lines of text."
YourMultiline.Text = MyText
You can also display initial text by filling the destination contextual object
for the control during the form load procedure. For example:
DisplayMe = "Display this text."
Cobj_YourBox.Fill DisplayMe
Name. You must assign a name that is unique within the form you are
coding. Also, you might want to avoid reserved keywords to simplify things
(see "Control Names and Reserved Keywords" earlier in this chapter).
The name you assign is the name you must use when you write code for that
control.
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
Label. Enter the label you want displayed next to this control.
AutoSize. You might want to avoid turning on this attribute because, in most
cases, you need to make sure the control fits into a defined space in the form.
Default. Set this attribute if you want this button to be the default.
154 Chapter 7
Programming Tab Widgets
Source. If you want to use a source contextual object for a label, you must
click on this button and then carry out the task of assigning some contextual
object field to this control. The contextual object field you choose must have
the type String.
Destination. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type String. The value in this destination will
be 0 if the button is unselected or 1 if the button is selected. (Note that this is
in String format: if you want to use this in your code as a numeric value, you
need to convert it to an integer with the conversion function CInt.)
156 Chapter 7
Programming Tab Widgets
After you place all of the tab widgets on the form, select the first tab widget
and drag its lower right handle until the widget is sized large enough to
accept the largest tabbed frame--the one that requires the most screen
display space. All of the rest of the tabbed frames will be automatically sized
to fit in this space when fronted.
Make sure you do this sizing procedure; if you don’t resize at all, the tabs
will not display. It may take some trial and error to get it exactly right in
terms of size. However, the tabs will automatically align.
CAUTION: You must select one of the tabs and resize it to a larger than default
size! If you don’t, there will be no tab area other than the tab widgets themselves.
Name. In order for the tab control to be recognized as a tab rather than as an
option button, you must use the following naming convention:
Tab_D_FormID
Where FormID is the ID of the tabbed form. For example, if you want a tab
to post a form with ID 5050, you must first create the new frame with the ID
of 5050, then create a tab that has the following name:
Tab_D_5050
The name you assign is the name you must use when you write code for that
control.
Label. Enter the label you want displayed next to this control.
Default. Set this attribute if you want this button to be the default. You must
set one of the tab widgets to be a default tab.
CAUTION: One of the tab widgets must be the default tab. Otherwise the tabs may
not display properly.
Source. If you want to use a source contextual object for a label, you must
click on this button and then carry out the task of assigning some contextual
object field to this control. The contextual object field you choose must have
the type String.
Destination. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type String. The value in this destination will
be 0 if the button is unselected or 1 if the button is selected. (Note that this is
in String format: if you want to use this in your code as a numeric value, you
need to convert it to an integer with the conversion function CInt.)
You cannot trigger a tab’s form_load event by setting the tab widget value.
158 Chapter 7
Programming Text Boxes
Oh, and don’t try to code a Close button in a tab to close the tab. It won’t
work.
Name. You must assign a name that is unique within the form you are
coding. Also, you might want to avoid reserved keywords to simplify things
(see "Control Names and Reserved Keywords" earlier in this chapter).
The name you assign is the name you must use when you write code for that
control. For example, if you want to place some text in a text box with the
name MyTextBox, you would use this line:
MyTextBox.Text = "Your Text Here."
Size attributes. You can change these as you want, but you should be aware
that the design time values are machine independent and therefore may
vary slightly from run time values, depending on the client machine.
Max Length. You may want to specify the maximum number of characters
accepted by the text box. You need to consider the length of text you expect
the user to input. If the text is destined for the database, you need to make
sure that the number you supply does not exceed the maximum characters
allowed for the destination field.
Instead of using this design time setting to limit the number of input
characters, you could trap each user keypress at run time; however, this
involves much more overhead.
AutoSize. You might want to avoid turning on this attribute because, in most
cases, you need to make sure the control fits into a defined space.
Visible. Leave this checked. If you want to hide or disable controls at run
time, use the appropriate ClearBasic properties for the control to hide or
disable the control.
Required. Setting this attribute requires the user to fill in the text box. You
can set this attribute at design time if you want, or you can set it at run time
using the Required property. In addition, you can use the run time
RequiredColor property to highlight the text box as a required text box.
ReadOnly. This attribute prevents the user from entering text in the control;
you might want to turn this on if the text box is used only to display values.
However, instead of using this design time attribute, you could instead use
the more flexible run time ReadOnly property.
Password. Set this attribute if the text box is going to accept password input.
Input text is displayed as asterisks.
Destination. You must click on this button and then carry out the task of
assigning some contextual object field to this control. The contextual object
field you choose must have the type String.
160 Chapter 7
Programming Text Boxes
You can also display initial text by filling the destination contextual object
for the control during the form load procedure. For example:
DisplayMe = "Display this text."
Cobj_YourBox.Fill DisplayMe
You must be aware that the text box displays only string values, so you must
convert non string values to string before loading them into the control.
After this line is executed, the text box displays the count.
162 Chapter 7
Programming Text Boxes
Dropdown List 1
(User Selects a
Field)
Dropdown List 2
(User Selects a
Filter Operator)
Text Box
(User Fills in the
Value)
Custom List
(Displays
Records
Retrieved From
Database.)
In Figure 21, the first dropdown list box contains a list of field names from
the site table, the second dropdown list box contains a list of filter operators,
and the text box accepts a text string supplied by the user. When the user
finishes selecting and entering data, the user presses the List button to
retrieve the filtered records from the database and display them in the
custom list control.
The following sample code implements this activity, and consists of two
parts: form load code that loads values into the two dropdown list boxes,
and event procedure code for the List button.
This code fills the dropdown list boxes with values for the user to select.
Although you can’t see it in code, Cobj_DropDown1 is the source contextual
object for Dropdown List 1 in Figure 21, Cobj_DropDown2 is the source
contextual object for Dropdown List 2.
164 Chapter 7
Programming Text Boxes
case "contains"
Filter = "%" & FiltSpec & "%"
FilterOp = cbLike
case "Is"
Filter = FiltSpec
FilterOp = cbEqual
End Select
’Put a query into the bulkretrieve object BulkRet;
’we want site records. Then append a Filter (we
’don’t want all the site records!) that contains
’the user’s filter conditions. Notice that we just
’stick in the variables we’ve already filled. Then
’go get the records. First entry index is always 0.
BulkRet.SimpleQuery 0, "site"
BulkRet.AppendFilter 0, FiltField, FilterOp, Filter
BulkRet.RetrieveRecords
’Get the list of returned records and stick them
’in CLList. Finally, load them into the custom list
’control; this will cause the records to be
’displayed in the custom list. (The custom list
’displays only those record fields that are linked
’to the custom list!
Set CLList = BulkRet.GetRecordList (0)
‘Now Fill source contextual object.
Cobj_CustomList1.Fill CLList
End Sub
166 Chapter 7
Chapter 8
Programming Tabs
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168
Peculiarities of CeFO Tabs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168
Crucial Facts About a Parent Form and Its Tabs . . . . . . . . . . . . . . . . . . . . . . . . . . .169
Designing Your Tabs: What Not to Do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .170
Creating Tab Widgets and Tab Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .171
Parent/Child Relation Set Automatically for Tabs . . . . . . . . . . . . . . . . . . . . . . . . . . .172
167
Overview
Overview
This chapter provides a few tips to help you get started with tab
programming. It includes practical advice on what to do at control/form
design time and advice on coding tabs. We’ll limit the discussion to things
you really ought to know, so please read it carefully.
If you do attempt to write your own event handler to post the frame yourself,
you will override system behavior and the tab frame will not be posted in
the tab area but will be posted over the parent form as if it were an
independent form (a “tear-off tab”). This is not recommended.
168 Chapter 8
Crucial Facts About a Parent Form and Its Tabs
Likewise, if you add a contextual object to a tab frame, you must add that
same contextual object to the parent form and all of the other tab frames.
This is why it’s a good idea to add all of the contextual objects you are going
to use to the parent first, before you create any tab frames.
For that reason, you should avoid invoking the form_load procedures of the
tabs from the parent’s form_load procedure.
170 Chapter 8
Creating Tab Widgets and Tab Frames
Why not? Well, from GUI design standards, it is not good practice because
you are wasting display space by displaying the same information twice.
Instead, rethink your design.
Equally or more importantly, doing this can cause you problems because
you cannot assume that any change in value in the contextual object field
will be immediately flushed to the controls. Thus, you could have one value
displayed in a control in the parent form while another value is displayed in
the tab form.
You should try to keep things simple, communicating directly between tab
and parent, and avoiding communicating between tabs directly.
IMPORTANT: If you use do use messaging, read the chapter in this guide about
messaging, particularly the material about what you MUST include in your
message handlers.
First, if you are adding tabs to an existing form, change the height/width
settings of the parent form to accommodate the tab area you’ll need. Change
the size settings in the size text boxes, just dragging the form to a larger size
may not work.
Second, when you create the tab frames, size them for your convenience, but
be aware that the final displayed size is determined by the tab area, which
you set when you create tab widgets. Make sure you write down the tabs’
Form IDs, user versions, and CeFO versions. You need this information later
when you import the form code modules.
Third, create the tab widgets after you create the frames. Remember to use
the option button control, and give each the name TAB_D_formID, for
example, TAB_D_1066. The first widget you create must be the first in the
row of widgets; use it with the largest tab frame. The reason for this is that
you size the tab area using the first tab widget, by sizing it to the size you
need for the tab frames.
172 Chapter 8
Chapter 9
Initializing Forms
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .174
initializing a new form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .174
Initializing a Customized Version of a CeFO Form. . . . . . . . . . . . . . . . . . . . . . . . . .174
Typical Initialization Tasks in Form_Load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .175
Some Tips on Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .176
173
Overview
Overview
In CeFO suite of applications, the forms (or windows) are posted when a
specific event takes place. This event can be selecting a menu item, selecting
a list item, clicking a button, etc. Before the form is posted, however, the
event initiates a Form_Load procedure that initializes the form in terms of
physical layout, display color scheme, initial values retrieved from the
database and displayed in various text boxes and lists, etc.
The requirements for a Form_Load procedure are slightly different for the
entirely new form that you created than for the form that is based on a
standard CeFO form.
174 Chapter 9
Typical Initialization Tasks in Form_Load
Thus, the general format for the Form_Load procedure for a customized
version of an existing standard CeFO form is as follows:
Sub Form_Load()
Me.DoDefault
‘Optional, additional
‘initialization code
‘appears here.
End Sub
The initialization tasks that the user-written ClearBasic code can perform
includes the following:
• Fill lists with static text or text retrieved from the database
• Fill text boxes with static text or text retrieved from the database
• Enable/Disable existing controls
• Use a specific color scheme
In this sample Form_Load procedure, some required text box controls are
assigned a particular color to highlight them as required. Notice the absence
of any code that establishes colors and color schemes. This means that the
color setup (creating and setting color schemes) has already been performed
elsewhere, probably in the initialize_app procedure in the globals file.
Then all of the records are retrieved from a user-defined table called
“courses” and are loaded into a custom list. Finally, two controls are
disabled before the form is posted.
176 Chapter 9
Some Tips on Initialization
Also, be aware that you cannot set/initialize global variables in the globals
file or in the modular globals section. They have to be assigned within a
function or procedure. If you try to, you will get a compile-time error
message.
178 Chapter 9
Chapter 10
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180
Retrieving Records With BulkRetrieve . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181
Saving to the Database With BulkSave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .190
179
Overview
Overview
This chapter provides information on retrieving records from the CeFO
database and saving records. It also provides information on accessing
databases other than the login database during an application session.
IMPORTANT: This chapter applies to CeFO databases only. For information about
foreign (non CeFO) databases, see Chapter 16 "Accessing External Databases
Using SQL."
180 Chapter 10
Overview
CAUTION: If a record is a row from a view, you must NOT update or change in
any way any of the fields in that view. If you do, you can damage the database. If a
record is from a table, you can change field values.
Several queries and their filter and sort conditions can be batched up into a
BulkRetrieve object and sent to the database to return the specified records
in one network round trip, although large queries may have to be parceled
out over several round trips.
When the records are found in the database, they are loaded into separate
lists, one list for each query, in the BulkRetrieve. (Even if only one record or
no record is found, the return is still a list.) These lists can be extracted using
either the GetRecordList method or the GetRelatedRecordList method.
You may also declare a BulkRetrieve object within a form procedure, its
scope would then be limited to that procedure.
Loading queries. After the declaration, the first thing you must do is to load
one or more queries into the BulkRetrieve, using any of the three query
methods: SimpleQuery, TraverseFromParent, or TraverseFromRoot. You
must load a query into the BulkRetrieve before you can specify any filter or
sort conditions for that query.
When you load a query into the BulkRetrieve, you must specify its entry
index. You must assign the first query loaded the index of 0, the second
query the index of 1, and so on. You must assign the indexes sequentially
from 0.
NOTE: Although you can assign a name rather than an integer index, this is not
recommended because it makes your code more difficult to read and maintain.
Loading filters and sort conditions. After you load a query into the
BulkRetrieve, you need to load one or more filter conditions for that query
and you may want to load sort conditions for the returned records. When
you load a filter or a sort condition, you must specify the entry index of the
query to which you want to apply the filter or sort.
Retrieving records. When you finish loading queries, filters and sort
conditions into the BulkRetrieve, invoke the RetrieveRecords method to
execute the retrieval.
Accessing the returned records. The records returned for a query are placed
into a list in the BulkRetrieve object at the same entry index as that
belonging to the query. For example, if the query has the entry index of 0, the
list of returned records for that query also has the entry index of 0.
Before you can do anything to the list of returned records, you need to
extract that list from the BulkRetrieve using the GetRecordList method or
the GetRelatedRecordList method and place the list of records into a List
object.
182 Chapter 10
Overview
Index 0
SimpleQuery (get case records) RetrieveRecords
appendFilter (whose ID < 123)
Index 1 CeFO Database
SimpleQuery (get CR records)
appendFilter (whose ID < 321)
Returned
BulkRetrieve Object Records
BulkRetrieve Object
In Figure 22, a BulkRetrieve object is loaded with two queries, one for case
records, the other for CR records. Filters are appended to each query to limit
the search to records whose id_number field is less than the specified
number. A separate list of records is returned for each query. Finally, the
contents of each list is retrieved into a List object.
The following ClearBasic code does all the work in Figure 22:
Dim MyBulk as new BulkRetrieve
Dim List1 as new List
Dim List2 as new List
MyBulk.SimpleQuery 0, "case"
MyBulk.SimpleQuery 1, "bug"
MyBulk.AppendFilter 0, "id_number", cbLess, "123"
MyBulk.AppendFilter 1, "id_number", cbLess, "321"
MyBulk.RetrieveRecords
List1.ItemType = "record"
List2.ItemType = "record"
Set List1 = MyBulk.GetRecordList(0)
Set List2 = MyBulk.GetRecordList(1)
In the sample code, notice the order of invocation: the query is invoked
before the filter condition. Also, notice that each list object is specified to
contain items of type "record." You do not have to set the item type of a list: if
those two lines are omitted, the code still works. However, specifying the
item type of lists will make your code more readable.
Finally, notice the use of "Set." Whenever the variable on the left side of an
assignment statement is an object variable, you must use the keyword "Set."
You don’t use Set if the variable on the left side is a primitive type such as a
string or a integer type.
184 Chapter 10
Overview
SimpleQuery
There are two ways to use a SimpleQuery. You can use it simply to get
records of a single type where you don’t want any related records. Or, you
can use it as the first step in building up a TraverseFromParent or
TraverseFromRoot query, as described later under those queries.
TraverseFromRoot
You use this query if you want to get all the records that have a specific
relation to a specific record (the root record). For example, you might want a
case record and all of the log notes for that case. Because only one root can be
set for a given BulkRetrieve, you can only use TraverseFromRoot once per
BulkRetrieve object.
Notice that this method is efficient only in the instance where you are
concerned with only one particular record (the root record) and are primarily
focused on getting other records that are related to that root record. If
instead you really need to retrieve several records along with their related
records, you should use the TraverseFromParent query.
To use this query, use a SimpleQuery first to get the desired record. Then,
use SetRoot to specify that returned record as root. Finally, use a
TraverseFromRoot specifying the desired relation name.
In the following example, a case record is retrieved, used as root, then all of
its log notes are retrieved:
Dim MyBulk as new BulkRetrieve
Dim List1 as new List
Dim CaseRec as new Record
MyBulk.SimpleQuery 0, "case"
MyBulk.AppendFilter 0, "id_number", cbEqual, 123
MyBulk.RetrieveRecords
Set List1 = MyBulk.GetRecordList(0)
Set CaseRec = List1.ItemByIndex(0)
MyBulk.Clear
MyBulk.SetRoot CaseRec
MyBulk.TraverseFromRoot 0, "case_notes2notes_log"
MyBulk.RetrieveRecords
Set List1 = MyBulk.GetRecordList(0)
In the example, a case record is retrieved from the database, dumped into
List1, and placed into CaseRec. The root of MyBulk is set to CaseRec, then all
of the log notes for CaseRec are retrieved from the database. Notice that you
use GetRecordList to retrieve the records from the BulkRetrieve. Both
SimpleQuery and TraverseFromRoot use GetRecordList;
TraverseFromParent queries require GetRelatedRecordList.
The coding for this example is fairly straightforward, but there is a key piece
of information you need before you start: namely, the relation between a
case and its log notes. If you look at the Data Dictionary Guide, you’ll notice
that the relation name between a case record and log notes is
case_notes2notes_log, and that this is a one-to-many relation--one case
can have many log notes.
You can use SetRootByID instead of SetRoot, if you happen to have the valid
objid of the desired root record (the root record must be an existing database
record). Also, you can use relations and inverse relations with this query.
TraverseFromParent
Suppose you want to get a list of case records from the database, and also get
all of the log note records for each of those case records. To do this, you
would use a SimpleQuery or a TraverseFromRoot to get the single list of case
records that you want. Then, in that same BulkRetrieve, you must use
TraverseFromParent, specifying the index of that SimpleQuery or
TraverseFromRoot query and the relation you want to use.
186 Chapter 10
Overview
When you do this, the list of case records is retrieved first, then a separate
list of log notes records is retrieved for each case record that was retrieved.
Here is some code that does this:
Sub Mysub
Dim MyBulk as new BulkRetrieve
Dim List1 as new List
Dim List2 as new List
Dim num1 as new integer
Dim num2 as integer
Dim CaseRec as ne Record
Dim id as string
MyBulk.SimpleQuery 0, "case"
MyBulk.AppendFilter 0, "id_number", cbLess, "123"
MyBulk.TraverseFromParent 1,
"case_notes2notes_log", 0
MyBulk.RetrieveRecords
Set List1 = MyBulk.GetRecordList(0)
num1 = List1.Count
For I = 0 to num1 -1
Set CaseRec = List1.ItemByIndex(I)
Set List2 = MyBulk.GetRelatedRecordList
(CaseRec, "case_notes2notes_log)
num2 = list2.count
id = CaseRec.GetField ("id_number")
debug.print "case num = " &id &
"NotesNum ="&str$(num2)
Next I
End Sub
Notice that the parent records are obtained in the same retrieval operation as
the TraverseFromParent query. This is required.
What you must do is what we did do here. First, get the first record out of
the parent list (List1), then use this record as input to the
GetRelatedRecordList. You have to input a record here, not an index. Based
on that record and the specified relation, the correct list of related items is
retrieved into List2.
The rest of the loop basically displays the case number and the number of
log notes for that case, using a debug print statement. Not terribly useful,
but you get the idea of how to get multiple lists of records out of a returned
TraverseFromParent Query.
NOTE: If the query that is the parent to the TraverseFromParent query only has
one record returned, you do not have to use GetRelatedRecordList on the results of
TraverseFromParent. You could just use GetRecordList, because only one list of
records is returned.
The main considerations here are the usual database performance issues:
how long will it take? You need to test this if you go this route.
When you use AppendFilter, you need to supply the entry index of the
query you want to filter, the field name (in lowercase) that you want to use
for comparing, the filter operator constant that is the basis of the
comparison, and the value you want to compare. For example, in the
following line,
188 Chapter 10
Overview
MyBulk.SimpleQuery 0, "case"
MyBulk.AppendFilter 0, "id_number", cbEqual, "123"
the filter is for the query at MyBulk entry index 0, and the filter is searching
for the case record whose id_number field contains the value 123.
GetRecordList. You can use this method to get the list of records returned by
a SimpleQuery, TraverseFromRoot query, or a TraverseFromParent query
that returns only one list. Simply specify the entry index of the query that
retrieved the records. For example:
MyBulk.SimpleQuery 0, "case"
MyBulk.AppendFilter 0, "id_number", cbLess, "123"
MyBulk.RetrieveRecords
Set List1 = MyBulk.GetRecordList(0)
If you suspect that your BulkRetrieve queries may exceed these limits, you
may need to set the QuerySize property in the initialize_app procedure
in the global module:
Sub initialize_app
‘Other initialize_app code here
App.QuerySize = 25
End sub
Once this is invoked, all BulkRetrieve queries during the application session
are automatically separated into smaller blocks by the CeFO system before
being sent to the database. For more information, see QuerySize in the
ClearBasic Object Reference.
190 Chapter 10
Saving to the Database With BulkSave
Declaring and scoping. BulkSave objects are declared in the form module
and are form scoped. They are declared as follows:
Dim YourBulkSav as new BulkSave
Inserting new database records. After you declare a BulkSave object, you
can insert new records into it that are destined for the database as new
database records. You use InsertRecord to insert these one at a time, using a
loop if you want.
Updating existing database records. You can also insert updated version of
records that you modified or that the user modified in some way. These
records will overwrite the originals that are in the database. You use
UpdateRecord to insert this type of record, one at a time, using a loop if you
want.
Relating records. You use a BulkSave to relate records. There are several
ways to do this, as described later in this chapter.
Unrelating records and deleting records. You also use a BulkSave to remove
relations between records and to delete records from the database.
A new record does not have a valid objid until the Save method is invoked
on the BulkSave.
If you use the default of ByRef, the record in the BulkSave, the input variable
containing the record, and the record returned by the method all refer to the
same record. For example, in the line
Set MyRetRecord = MyBulkSav.InsertRecord (MyRec)
192 Chapter 10
Saving to the Database With BulkSave
Why you need ByRef. Why do you need this? Well, suppose you want to
relate two records that you placed in the BulkSave: Rec1 and Rec2 as follows:
MyBulkSav.InsertRecord Rec1
MyBulkSav.InsertRecord Rec2
MyBulkSav.RelateRecords Rec1,Rec2,
"relate_this2that"
If you inserted the records ByValue, the records in the BulkSave are
completely new, separate records with no connection with the external
variables Rec1 and Rec2. So the RelateRecords call would have no effect on
the records in the BulkSave and they would not get related. But if you insert
the records ByRef, relating Rec1 and Rec2 will cause the records in the
BulkSave to be related.
When you need ByValue. There are times when you don’t want to use
ByRef. For example, in the following loop:
For I% = 0 to 10
Rec1.SetField "id_number", "case" & Str(I%)
MyBulkSav.InsertRecord Rec1, cbByValue
Next I
MyBulkSav.Save
If you did not specify ByValue here, this loop would simply overwrite the
same record in the BulkSave 11 times; only one record would get saved to
the database, not eleven records.
If you copy a record and want to save the copy as new, make sure you use
ChangeToNew or copy the record with the parameter cbChangeToNew to
reset the objid. Otherwise, the copy will not get inserted as a new record but
will overwrite the original in the database.
The UpdateRecord method also makes use of ByRef and ByValue; for details
see the description under "Inserting New Records Into the Database" earlier
in this chapter.
The DeleteRecord method also makes use of ByRef and ByValue; for details
see the description under "Inserting New Records Into the Database" earlier
in this chapter.
194 Chapter 10
Saving to the Database With BulkSave
Relating Records
The following methods are available for relating records:
• RelateRecords
• RelateRecordsFromID
• RelateRecordsToID
• RelateRecordsFromToID
You can use any of these, depending on which is more convenient to you,
and depending on the data you have available. Each of these methods is
described briefly below.
RelateRecords. You must use this method if the records you are relating are
new records. You can use this method on existing database records.
However, if you use this method, you must add the records to the BulkSave
(by InsertRecord or UpdateRecord) using ByRef. For example:
MyBulkSav.InsertRecord Rec1
MyBulkSav.InsertRecord Rec2
MyBulkSav.RelateRecords Rec1,Rec2, "relate_this2that"
RelateRecordsFromID. You can use this method if you have the objid of a
database record that you want to use as the source of the relation, and you
want to relate that record to another record in the BulkSave. For example,
suppose you wanted relate a case record to a log note:
Dim MyRec as New Record
Dim BulkSav as New BulkSave
MyObj = CaseRec.GetField ("objid")
MyBulkSav.InsertRecord Rec1
MyBulkSav.RelateRecordsFromID "case", MyObj, Rec1,
"case_notes2notes_log
However, if you use this method, you must add the target record to the
BulkSave (by InsertRecord or UpdateRecord) using ByRef.
NOTE: If you modified the source record locally, you must add that record to the
BulkSave or the modifications will not be saved.
RelateRecordsToID. You can use this method if you have the objid of a
database record that you want to use as the target of the relation, and you
want to relate that record to another record in the BulkSave. To use a familiar
example, let’s relate a case record to a log note:
Dim MyRec as New Record
Dim MyBulkS as New BulkSave
MyObj = LogNote.GetField ("objid")
MyBulkS.InsertRecord CaseRec
MyBulkS.RelateRecordsToID CaseRec, "notes_log"
MyObj, "case_notes2notes_log"
However, if you use this method, you must add the source record to the
BulkSave (by InsertRecord or UpdateRecord) using ByRef.
NOTE: If you modified the target record locally, you must add that record to the
BulkSave or the modifications will not be saved.
RelateRecordsFromToID. You can use this method if you have the objids of
the two database records that you want to relate. Notice that there is no
requirement here to use ByRef, because no records are placed into the
BulkSave.
Illustrating the virtues of code reuse, let’s relate a case record to a log note:
Dim MyRec as New Record
Dim MyBulkS as New BulkSave
MyLogObj = LogNote.GetField ("objid")
MyCaseObj = CaseRec.GetField ("objid")
MyBulkS.RelateRecordsFromToID "case",MyCaseObj,
"notes_log", MyLogObj, "case_notes2notes_log"
NOTE: If you modified the source or target records locally, you must add those
records to the BulkSave or the modifications will not be saved.
Unrelating Records
If you delete a record from the database, relations to that record are
automatically removed. However, you may want to remove relations
without deleting records. To do this, use the UnRelateRecords method as
follows:
196 Chapter 10
Saving to the Database With BulkSave
where Rec1 is the source of the relation, Rec2 is the target of the relation, and
relate_this2that is the name of the relation you want to remove. Notice
that this method requires you to insert the records to be unrelated into the
BulkSave.
NOTE: These callbacks are entirely optional. You are not required to use any of
them.
By using one of these callbacks, you can suspend the default Save operation
at a particular point while you perform some activity in a BulkSave object,
such as inserting new records, changing record fields, deleting records, and
so on. The Save operation resumes when your callback procedure is finished
doing its work. You can use any, all, or any combination of these callbacks in
your form module. Of course, you can have only one of each type of callback
in a given form.
Whenever a standard CeFO Save is performed, the form module for that
CeFO form (if you created one for it) is automatically scanned for the
presence of any of the callbacks and executes them at the proper time.
NOTE: You can use the Contents method on a contextual object in a Form_Save
callback.
198 Chapter 10
Saving to the Database With BulkSave
Of course, in the above example, you replace Sub Form_Save1 with Sub
Form_Save2 or Sub Form_Save3, depending on when you want the
interception to occur.
NOTE: Any changes to the BulkSave are committed to the database ONLY if the
changes are made in either the Form_Save1 or Form_Save2 callback, because the
data has already been committed to the database by the time the Form_Save3
callback is made.
200 Chapter 10
Chapter 11
Message Handling
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .202
Handling Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .204
Sending Messages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .207
201
Overview
Overview
Messages are one way to communicate between forms that are loaded into
memory. You can use them to pass form closing notifications and to pass
data between forms. Also, if you create a new form (one that is not a frame
or a tab frame), you are required to use messaging, at least to handle the Close
message from the CeFO system.
IMPORTANT: You can send a message to a form only if is loaded into memory.
If you don’t handle the Close message in the new form, the application will
not be able to exit properly if your new form is still open.
202 Chapter 11
What Code is Required in Every Message Han-
Notice that the Close message is defined as cbCloseMessage. You must use
this value.
Notice also the Case Else....Me.DoDefault statement. If you don’t have this,
you may experience unexpected behaviors. The reason for this is that your
event handler becomes the event handler for the form, overriding any
default message handling and intercepting all messages. The only way for
the default handler to get messages is if your message handler invokes
DoDefault for those messages you don’t handle.
NOTE: The requirement to include the Me.DoDefault logic does not apply to new
forms, which have no default message handler. It only applies to standard CeFO
forms, frames, and tab frames.
Handling Messages
A message does not itself perform any action. It is simply a notification to
perform some action. The action performed as a result of a message is
actually performed by the receiving form’s message handler.
You can send a CeFO predefined message to forms or you can define your
own message to be handled by the form’s message handler.
204 Chapter 11
Handling Messages
Notice that this procedure doesn’t handle any message strings that might be
passed. The message string parameter is entirely optional.
Me.Notify cbRefreshMessage
You must declare your message (the number component of it, which is the
only required component) as a GlobalLong, because it is a Long type of
value. Then you instantiate it, then set its value. After you set its value in the
initialize_app procedure, you cannot reset its value.
206 Chapter 11
Sending Messages
Sending Messages
You can use any of several methods to send a message, depending on your
circumstances:
• Notify
• NotifyByID
• NotifyByKey
• NotifyChild
• NotifyParent
Each of these methods is described below.
Notify
If you want to send a message to an unrelated form, or to a form that has
multiple instances posted, you can use this method. Because you specify the
form variable of the receiving form, this method allows you to specify which
instance gets the message (each instance has a different form variable). You
would generally not use this method to send message to related forms
(parent form/child form) because other methods are more efficient for this
purpose. An example of using this message is as follows:
Sub MyUpdateButtonClick()
MyOtherForm.Notify cbRefreshMessage
End Sub
NotifyByID
If you want to send a message to an unrelated form, or to every instance of a
form that has multiple instances posted, you can use this method. Because
you specify the form ID of the receiving form, this method allows you to
broadcast the message to all of the form instances. You would generally not
use this method to send message to related forms (parent form/child form)
because other methods are more efficient for this purpose.
208 Chapter 11
Sending Messages
A common way to use SetParent is to post the child form from the parent
form, then invoke SetParent, as shown in the following example:
Sub ButtonClick()
Dim ChildWin as new Form
ChildWin.Show 5050
ChildWin.SetParent Me
Me.EnableControls "Jettison"
MyCustList.Unselect
End Sub
In the above example, the “parent” form (it’s not the parent yet!) contains a
button click event that posts another form. That new form loads, executes its
form_load procedure, then returns control to the button click procedure and
returns focus to the “parent” form. Now both “parent” and “child” are
posted and the focus is on the “parent.” It is at this point that SetParent is
invoked to establish the parent/child relation.
Notice that there is more code after the SetParent call. This shows that the
rest of the button click event procedure is executed prior to returning control
and focus to the child form that was just posted.
NotifyChild
Use this method to broadcast a message to all of a parent form’s children.
For example:
If Control1.DataChanged = True
Me.NotifyChild MyMessage1
Else
Me.NotifyChild MyMessage2
End If
In most cases, you will want to send a close message to child forms when the
parent is closed, as follows:
YourParent.Close cbCloseChildren
NotifyParent
Use this method if you want a child form to tell the parent about some event
or result of an event. For example:
If Button1.Value = 1
Me.NotifyParent ClickMessage
End If
210 Chapter 11
Sending Messages
NotifyByKey
This method makes use of the form Key property, which is a runtime
property unique to each form and each instance of a form. You use this
method if you want to notify a particular instance of a form. (There is also a
third, optional, parameter for passing string data.)
If Button1.Value = 1
Me.NotifyByKey FormKey, ClickMessage
End If
212 Chapter 11
Chapter 12
Customizing Menubars
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .214
Modifying the initialize_app Procedure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .215
Customizing Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .216
Customizing Menus-Multiple Application Menubars. . . . . . . . . . . . . . . . . . . . . . . . .222
Applying the Menubar Customization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223
213
Overview
Overview
Using ClearBasic code, you can modify menubars in various CeFO
applications. Specifically, you can do the following:
• Add new menu items to the pulldown menus
• Rename existing menu items
• Remove menu items from a pulldown menu
• Associate new event procedures to newly modified and existing menu
items
• Disable (gray out) menu items and re-enable grayed out ones
• Append separators (horizontal lines) between menu item groups
You include the ClearBasic code that modifies a menubar in the
initialize_app procedure in the global module of CeFO applications
supported in the CeFO executable. When you start the CeFO applications,
the global procedure executes first to initialize the applications. This
procedure, in turn, calls the initialize_app procedure to execute any
ClearBasic code that customizes the applications’ pulldown menus and
menu items. The CeFO applications for which the pulldown menus were
modified then display the modified menus.
Note that the new or modified menus and menu items will do nothing
unless you write suitable ClearBasic code in the Form_Load procedure for
those forms and import it into the database.
NOTE: While this chapter discusses menu customization only through the
initialize_app procedure, you can also customize an application menu in any of
your own procedures. However, in such cases, the customization stays active only
during the current session. When you restart CeFO, only those customizations are
available that are coded in the initialize_app procedure.
214 Chapter 12
Modifying the initialize_app Procedure
The file global.cbs now contains a copy of the initialize_app procedure. You
can open it using any text editor. It may contain an empty procedure that
looks as follows:
Sub initialize_app()
End Sub
You are now ready to add ClearBasic code for customizing the menus and
menu items.
Customizing Menus
You can customize menus in a specific CeFO application or multiple CeFO
applications by including the appropriate ClearBasic code in the
initialize_app procedure. In general, you include the following ClearBasic
statements in the initialize_app procedure:
• A dim statement that declares each menu you want to customize
• Application menubar ID statements that identify the CeFO applications
in which the menus are to be customized
• Various method statements for the customization
• A method statement that posts the customized menu
The following sections describe various customization tasks in an
incremental fashion. That is, you keep on adding ClearBasic code to the
initialize_app procedure.
NOTE: You must not attempt to modify the File menus. Otherwise your
application may not function properly.
216 Chapter 12
Customizing Menus
In the above ClearBasic code, the dim statement declares a new menu called
MyAppMenu.
NOTE: You must insert a MenuBarID statement before adding any modification
code.
Referring to the PressMe event, nothing will happen unless you write an
event procedure with the name PressMe_Click() to handle that event. For
example, it could be the following:
Sub PressMe_Click()
Dim MyFormas new Form
MyForm.Show 5050
End sub
You then associate this event procedure to the applicable form and import it
into the database.
1002 ClearSupport
1007 ClearLogistics
1008 ClearQuality
For example, if in the Edit menu, you wanted to rename the menu item
Copy to Duplicate, you would add the following ClearBasic code in the
initialize_app procedure:
MyAppMenu.RenameItem "Edit", "Copy", "Duplicate"
In this code fragment, "Edit" refers to the menu name, "Copy" to the menu
item that is to be renamed, and "Duplicate" to the menu item that will
replace the menu item "Copy."
218 Chapter 12
Customizing Menus
When you rename a menu item, the event associated with the original menu
item is associated with the new menu item.
For example, if you wanted to remove the menu item "Switch User" from the
"Desktop" menu, you would add the following ClearBasic Code to the
initialize_app procedure:
MyAppMenu.RemoveItem "Desktop", "Switch User"
In this code fragment, "Desktop" refers to the menu label and "Switch User"
to the menu item that is to be removed.
When you remove a menu item, the event associated with it is also removed.
For example, if in the New menu, you wanted to associate a new event
procedure PostSolut to the menu item Solution, you would add the
following ClearBasic Code to the initialize_app procedure:
MyAppMenu.SetFunction "New", "Solution", "PostSolut"
In this code fragment, "New" refers to the menu label and "Solution" to the
menu item that, when selected, is to generate a new event procedure, and
PostSolut is the name of the new event procedure.
220 Chapter 12
Customizing Menus
In the above syntax, State refers to a Boolean value: False or True. To disable
a menu item, you use False and to re-enable a previously disabled menu
item, you use True.
For example, if in the Edit menu, you wanted to diable (gray out) the Cut
menu item, you would add the following ClearBasic Code to the
initialize_app procedure:
MyAppMenu.Enable "Edit", "Cut", False
In this code fragment, "Edit" refers to the menu label, "Cut" to the menu item
that is to be disabled, and False represents the False State.
In this code fragment, "Select" refers to the menu label, "Subcases" to the
menu item that is to be re-enabled, and True represents the True State.
You insert this statement after the statement that defines the menu item
below which you want to insert the separator line. You can use this
statement multiple times to insert separator lines after different menu items.
For example, review the following code fragment and the embedded
comments:
DIM MyAppMenu as new AppMenu
‘In the Edit pulldown menu, add the Undo command
MyAppMenu.AddItem "Edit", "Undo", "Revert"
‘Insert a separator line
MyAppMenu.AppendSeparator "Edit"
‘Add couple of more commands
MyAppMenu.AddItem "Edit", "Cut", "Remove"
MyAppMenu.AddItem "Edit", "Paste", "Insert"
‘Insert another separator line
MyAppMenu.AppendSeparator "Edit"
222 Chapter 12
Applying the Menubar Customization
If any users do not exit and restart CeFO applications, they will not have
access to the customized menubars.
224 Chapter 12
Chapter 13
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .226
Creating GUI Components For Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .226
Starting the UI Editor in ClearBasic Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .227
Using User Defined Types in the UI Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .227
Coding Global Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .228
Creating and Using a Directives File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .230
Creating and Using a Directives File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .230
Invoking CBEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .238
Getting Ready to Use CBEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .245
Performing CBEX Operations-Global/Form Modules . . . . . . . . . . . . . . . . . . . . . . . .255
225
Overview
Overview
Once you have defined your project and made necessary additions
and/or modifications to the database, you are ready to get started in
implementing your project design. In general, you will need to do the
following:
• Create Graphical User Interface (GUI) components. You do this by using
User Interface Editor Guide, or UI Editor, to modify the physical layout of
forms and associate names and labels with various components of forms.
Then, import these forms to the database.
• Define User-defined Data Types (UDTs) if you want to use UDTs.
• Create source files containing ClearBasic code for global and form
modules.
• Create a directives file for use with the ClearBasic Exchange, or CBEX,
utility.
• Use CBEX to compile and import form and global modules code into the
database.
• Use CBEX to perform certain maintenance operations on the global and
form modules. These operation include exporting source code to local
files and/or purging the code from the database.
This chapter describes these processes and discusses other related topics.
226 Chapter 13
Starting the UI Editor in ClearBasic Mode
You can enter this command at the UNIX prompt. Alternatively, you can set
it in the Properties>Shortcut dialog box associated with the UI Editor icon in
MS Windows. The current version of the UI Editor cannot be started from
the DOS prompt in the MS-DOS Prompt window.
CAUTION: The -cb mode should only be used if you have purchased the ClearBasic
Toolkit.
By default, only the CeFO standard data types are displayed in the User
Interface Editor and are available for use as contextual object types. To
display and use your own types, you need to supply a ClearBasic module
with the UDT definitions when you start the UI Editor.
When invoked as above, the UI Editor displays your UDTs in the list of
available data types presented in the Object Type Selection dialog box.
Beginning with the current release, the above restriction is removed. You can
now have any number of globals files and you can use any name for each
file, but you must use the .cbs extension. You can use the globals files to
define and use your own global variables, constants, subroutines, etc.
As was in CeFO 4.5, CeFO system globals are loaded in a different area than
the user globals.
Code for each form module starts with Form_Load procedure. After this
procedure you can code any number of procedures associated with events,
contextual objects, querying the database, decision making, etc.
228 Chapter 13
Coding Form Modules
Currently, a form module may not be larger than 60,000 bytes. You can
workaround this limit by moving common form code into one or more of the global
modules, thus reducing the effective size of the form code.
The general format for coding in ClearBasic is same as that used for coding
in MicroSoft Visual Basic. However, the available suites of objects,
properties, methods, etc. are very different in the two languages. Needless to
say, you must use only the ClearBasic elements in your code.
Each file containing the ClearBasic source code must have a .cbs extension.
You may find it helpful to name your source files after the form ID for which
you have written the code. For example, if the form module is for form 5050,
the source file name could be pat5050.cbs.
IMPORTANT: You make physical layout changes to forms in the User Interface
Editor (UIE), you compile and import the associated form modules via the CBEX
utility. Because CBEX caches the resource configuration information when you log
in, if you keep both UIE and CBEX running and make more changes to the same
form, attempting to compile and import the modified form module gives compile
errors. To rectify this problem, you must exit CBEX, restart it, and then recompile
and reimport the modified form module.
Also, if you add a form to your resource config, you must exit CBEX and then
restart it. Again, this is required because CBEX caches current user’s resource
config and any changes to the resource config require that you exit CBEX and
restart it.
Once you have created a directives file, you can selectively enable or disable
individual entries. You enable an entry by removing the single quote
character, if any, from the beginning of the line. (The single quote (’) is a
"comment out" character.) To disable an entry, you comment out the
corresponding line by placing a single quote character at the beginning of
the line.
You can also enable or disable a directives file module entry in the CBEX
window by selectively turning it On or Off.
NOTE: The CBEX operations apply only to those global or form modules in a
directives file that are enabled.
You can use the directives file both in interactive or command line mode.
When you use CBEX in the interactive (GUI) mode, the information about
each line in the directives file appears in the Active Directive List in the
CBEX window. Refer to the section Invoking CBEX on page 238 for details
about using CBEX the interactive, or GUI, mode.
The directives file can have any name, but must have the extension .cbi.
230 Chapter 13
Creating and Using a Directives File
2. Repeat the preceding step, as necessary, for adding more global modules
to your directives file.
NOTE: You can add comment lines at any location in the directives file. Each
comment line must start with a single quote character (’).
232 Chapter 13
Creating and Using a Directives File
NOTE: You can add comment lines at any location in the directives file. Each
comment line must start with a single quote character (’).
NOTE: This procedure assumes that you have already invoked CBEX in interactive
mode, which is described in the procedure To invoke CBEX in interactive mode on
page 238.
6. Repeat Step 2 through Step 5 for including any additional form modules
in the directives file.
234 Chapter 13
Creating and Using a Directives File
7. Save the directives file by using the Save or Save As command from the
File menu.
The form associated with form module must have a User Version. The CBEX
utility does not recognize a space or null as a valid user version. Even if you
add code to a standard CeFO form which does not involve changing the
form, you must still use the UIEditor to save a User version of that standard
CeFO form.
If the source code files are located in a directory other than the one in which
CBEX is located, you must specify full path for each source file. You can do
this only when you are using CBEX in interactive mode.
When you use CBEX to export source code files from the database, it
normally places them in the directory in which CBEX executable resides. If
you want to save files to a different directory, you must specify full path for
each file. Again, you can do this only when you are using CBEX in
interactive mode.
The directives file can have any name, but it must have a .cbi extension.
In batch mode, the default operation is import. You can specify the following
operations:
-imp for import (default)
-exp for export
-pur for purge
-exp -pur for export and then purge
If the -batch option is omitted and any of the above explicit operation
options is specified, CBEX performs the specified operation and then posts
the GUI.
In summary, use of the -batch option is required whenever you want to use
CBEX in non-interactive, command-line mode to operate on a single or
multiple (via directives file) global and/or form modules.
236 Chapter 13
Creating and Using a Directives File
Figure 23 Log file contents when compile succeeded but import failed
Invoking CBEX
You can invoke and use CBEX in two modes:
• Interactive, or GUI, mode
• Non-interactive, or command-line, mode
The interactive mode provides an easy-to-use graphic user interface (GUI)
while the command-line mode provides for speed for advanced users.
NOTE: You can specify any of the legal options in any order. However if you
specify any of the options, you must also specify the associated parameters
immediately after the option. Table 13 on page 243 describes all the available
CBEX options.
238 Chapter 13
Invoking CBEX
NOTE: Various text boxes in the above dialog box are empty only when you
invoke CBEX for the very first time. On all subsequent occasions, except for
the Password text box, other text boxes display the entries made in the most
recent session according to the clarify.env file.
240 Chapter 13
Invoking CBEX
NOTE: Various text boxes in the above dialog box are empty only when you
invoke CBEX for the very first time. On all subsequent occasions, except for
the Password text box, all other text boxes display the entries made in the
most recent session.
2. If the preceding step displayed a login dialog box, enter the required
information and click Login.
Following Step 2 above, CBEX executes the command used in Step 1 and
writes the success/failure information to the cbex.log file.
242 Chapter 13
Invoking CBEX
244 Chapter 13
Getting Ready to Use CBEX
NOTE: Unless noted otherwise, module(s) refers for both global and form
module(s).
Before you can perform any of the above operations, you must load (only if
using GUI) and set up the directives in the directives file as described in the
next two section.
To operate on multiple form modules using the CBEX command line, you
must edit the directives file to set up the directives in it.
While you are setting up your directives file, you can also perform the
following two useful operations:
• Find out which form is associated with a form module. This information
can be very useful if your new code affects the behavior of the form
associated with the module, in which case you may want to modify the
form too.
• Add comment lines—not comment fields—to your directives file. A
comment line is a line by itself, while a comment field is a field at the end
of a module definition line.
Setting up the directives involves selecting and enabling the module entries
that are to be operated on. CBEX can perform its operations only on those
modules that are enabled.
In the Action Directives List in the CBEX main window, an enabled module
displays "On" in its first field, while a disabled one shows an "Off" in the first
field.
In the directives file, a module entry is enabled when the corresponding line
is not commented out. That is, the first character in the line is not a single
quote character (’). A module entry is disabled when the corresponding line
is commented out.
246 Chapter 13
Getting Ready to Use CBEX
NOTE: Omit this step if the form modules you want to use are already
enabled, i.e., they have an "On" in their first field.
a. In the Action Directive List window, highlight the module you want to
use by clicking it once.
If the module you highlighted is a global module, the Global option
button appears checked and the text box labels displayed are
Application, Subsystem, Label, Code File, and Comments.
If the module you highlighted is a form module, the Form option
button appears checked and the text box labels displayed are FormID,
CeFO Version, Customer Version, Code File, and Comments.
b. Click the On option button in the State options.
c. Click the Replace button.
This action changes the value in the first field of the selected directive
to On.
d. Repeat the preceding three substeps, to enable any additional
modules.
5. Disable the modules you do not want to use:
NOTE: Omit this step if the form modules you do not want to use are already
disabled, i.e., they have an "Off" in their first field.
a. In the Action Directive List window, highlight the module you want to
disable by clicking it once.
b. Click the Off option button in the State options.
c. Click the Replace button.
This action changes the value in the first field of the selected directive
to Off.
d. Repeat the preceding three substeps, to disable any additional
modules.
6. If you want to add to the Action Directives List one of your form
modules already existing in the database, do the following:
248 Chapter 13
Getting Ready to Use CBEX
IMPORTANT: You can use Step 7 to add totally new entries to the Action Directive
List, which can then be saved to the directives file.
NOTE: When you save a directives file, the disabled module lines (lines with
the Off setting) appear as commented out lines in the file. The enabled module
lines are not commented out.
Note that even after saving the information to a file, the CBEX main window
stays filled with the information.
250 Chapter 13
Getting Ready to Use CBEX
NOTE: You can also start CBEX in interactive mode without specifying a
directives file on the command line.
2. If you want to add to the Action Directives List one of your form
modules already existing in the database, do the following:
a. Click the Modules button to display the Modules window.
This window displays the Modules window, similar to the one shown
below, that shows the modules available for the current user in the
database.
a. In the Action Directive List window, highlight the module you want to
modify by clicking it once.
This action copies information about the selected form module to the
corresponding text boxes in the CBEX main window.
b. Enable or disable the form module, as desired, as described in Step 4.
and Step 5 on page 248.
c. Edit, as appropriate, the information in the FormID, CeFO Version,
Customer Version, Code File, and Comments text boxes.
d. If you want to replace the existing module information with the edited
information, click the Replace button.
e. If you want to create a new module based on the modified module
information and add it to the list, click the Add button.
f. Repeat Step 3 as necessary.
4. If you want to create and add a new module entry into Action Directives
List, do the following:
a. Enter appropriate information in the FormID, CeFO Version,
Customer Version, Code File, and Comments text boxes.
b. Click the Add button.
c. Repeat Step 4 as necessary.
252 Chapter 13
Getting Ready to Use CBEX
3. Click Add.
CBEX adds the comment line at the end of the Action Directives List. You
can position the comment line anywhere in the list by using the Up and
Down buttons.
254 Chapter 13
Performing CBEX Operations-Global/Form Mod-
NOTE: Unless noted otherwise, module(s) refer to both global and form module(s).
IMPORTANT: The forms associated with the form modules you are compiling and
importing must be in the resource config of the user executing the cbex utility. If
not, you cannot import the modules.
NOTE: CBEX stops at the first error encountered in each module. You can
locate additional errors only by fixing the current error and then running the
command again.
256 Chapter 13
Performing CBEX Operations-Global/Form Mod-
c. If you want to ignore the current module, and continue with the next
module in your directives file, click Ignore.
CBEX displays the system Info window similar to the following:
258 Chapter 13
Performing CBEX Operations-Global/Form Mod-
260 Chapter 13
Performing CBEX Operations-Global/Form Mod-
NOTE: You need to specify subsystem and -N label only if you used
these parameters when you originally imported the globals file into the
database.
Example:
cbex -batch -exp -spec MyGlobal.cbs -G clarify -N
global_1
This command exports the global module with the label global_1 from
the database to the destination file MyGlobal.cbs in the current
directory.
If you wanted to export the global module from a subsystem
(e.g., subsys_1), you would enter the above command as follows:
262 Chapter 13
Performing CBEX Operations-Global/Form Mod-
NOTE: When you perform an Export operation using the command line, you can
export source modules only to the current directory and only under the original
module name. You cannot specify a different directory or a different file name.
NOTE: In the above command format -spec dest_file are required dummy
place holders. They do not perform any function but CBEX expects to find them on
the command line.
Example:
cbex -batch -pur -spec jeff5050.cbs -F 550 jeff
This command purges, or deletes, the user form module “550 jeff”
from the database.
If you wanted to purge, or delete, a module that was compiled against an
earlier CeFO version (e.g., 1.0), you would enter the above command as
follows:
cbex -batch -pur -spec jeff5050.cbs -F 550 1.0 jeff
264 Chapter 13
Performing CBEX Operations-Global/Form Mod-
NOTE: In the above command format -spec dest_file are required dummy
place holders. They do not perform any function but CBEX expects to find them on
the command line.
Also, you need to specify subsystem and -N label only if you used these
parameters when you originally imported the globals file.
Example:
cbex -batch -pur -spec MyGlobal.cbs -G clarify -N
global_1
This command purges, or deletes, the global module with the label
global_1 from the database.
If you wanted to purge the global module from a subsystem
(e.g., subsys_1), you would enter the above command as follows:
cbex -batch -pur -spec MyGlobal.cbs -G clarify
subsys_1 -N global_1
266 Chapter 13
Performing CBEX Operations-Global/Form Mod-
NOTE: In the above command format, you need to specify subsystem and -N
label only if you used these parameters when you originally imported the globals
file you now want to purge.
Example:
cbex -batch -exp -pur -spec MyGlobal.cbs -G
clarify -N global_1
This command exports the global module with the label global_1 to
the destination file MyGlobal.cbs in the current directory and then
purges the module from the database.
If you wanted to export/purge the global module from a subsystem
(e.g., subsys_1), you would enter the above command as follows:
cbex -batch -exp -pur -spec MyGlobal.cbs -G
clarify subsys_1 -N global_1
268 Chapter 13
Performing CBEX Operations-Global/Form Mod-
NOTE: When you perform an Export/Purge operation using the command line,
you can export source modules only to the current directory and only under the
original module names. You cannot specify a different directory or a different file
name.
270 Chapter 13
Chapter 14
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .272
Fixing Compile-Time Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .273
Fixing Run-Time Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .274
Using the ClearBasic Debugger for Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . .275
Using the ClearBasic Debugger for UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .290
Using the Debug Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .300
Using the SQL Log to Debug the Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .301
Summary of Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .302
271
Overview
Overview
While developing CB customization code for various CeFO applications,
you are likely to encounter three types of errors:
• Compile-time errors
• Run-time errors
• Logic errors
Compile-time error messages are generated by the ClearBasic Exchange
(CBEX) utility. CBEX does so when it encounters syntactical errors in the CB
source file you are attempting to compile and import into the database.
Logic errors are in your CB code. For example, you may have forgotten to
include a key statement or a procedure.
In the case of compile-time and runtime errors, error messages are displayed
on your screen. The compile -time messages are also written to the log file
cbex.log. These error messages are self-explanatory.
Logic errors, on the other hand, do not display any error messages. You can
locate and fix these problems by either using the ClearBasic Debugger or
the ClearBasic Debug.Print statement.
The Debugger is a very powerful tool that lets you automate the debugging
process to a considerable degree.
The Debug.Print statement can be used to trace the logic problems in your
CB source module, but you must manually insert these statements in your
source code at strategic locations. Then, after fixing the problems, you must
manually remove these statements.
272 Chapter 14
Fixing Compile-Time Errors
NOTE: To view run-time error messages in the format shown in this section, you
must start clarify with the -cbdebugger option.
274 Chapter 14
Using the ClearBasic Debugger for Windows
NOTE: The ide.dll file must be present in the application directory for the
debugger to launch. In addition, the -cbdebugger option is case sensitive;
specify it using all lower case.
To specify this option from Windows, you must create a shortcut for the
application and add the -cbdebugger option to the shortcut properties.
IMPORTANT: During future sessions, you must use this shortcut to launch
ClarifyCRM eFrontOffice with the ClearBasic Debugger. Double-clicking directly
on the program file launches the application without the debugger.
276 Chapter 14
Using the ClearBasic Debugger for Windows
If you do not need to edit code using the debugger window, you can enable
the caches again by launching the client with the -editor option. The
-editor option prevents code modules from being modified by the
ClearBasic Debugger and also enables the application’s caches. Enabling the
caches can often lead to better performance of ClarifyCRM eFrontOffice
during debugging sessions.
Undo Calls
Toggle
Breakpoint
278 Chapter 14
Using the ClearBasic Debugger for Windows
• The Sql-log tab displays the SQL transactions that have occurred so far in
this session.
• The Editor tab lets you modify ClearBasic code during a debugging
session. (This tab appears when you open a code module and select Edit
Code from the debugger window’s File menu.)
Modifying Breakpoints
In any debugging session, you use breakpoints to stop the execution of the
ClarifyCRM eFrontOffice application so that you can view the current state
of your code. When a breakpoint is reached, you can examine the values in
any variables or step through your code line by line to see where any
problems are occurring.
Using the ClearBasic Debugger, you can set, disable, enable, and remove
breakpoints.
Setting Breakpoints
You can add breakpoints to your code at any time during your debugging
session. If you are starting a new debugging session, it is usually a good idea
to set one or more breakpoints at the beginning of a top-level subroutine
such as Form_Load. You may also want to set additional breakpoints at the
beginning of key subroutines where problems are likely to occur.
280 Chapter 14
Using the ClearBasic Debugger for Windows
You must always set your first breakpoint using the Breakpoints tab. Once
the first breakpoint is reached, you can set additional breakpoints directly in
the code.
All new breakpoints are enabled by default. You do not need to enable them
explicitly. You also do not need to save breakpoints before exiting the
debugger. When you exit ClarifyCRM eFrontOffice, the debugger
automatically remembers your current set of breakpoints and restores them
for the next debugging session.
After you begin your debugging session, you can set breakpoints directly for
code displayed in the Debugger tab.
When you add a breakpoint to your code from the Debugger tab, the
debugger adds a corresponding breakpoint entry to the Breakpoints tab. If
you want to modify or remove that breakpoint later, do so from the
Breakpoints tab.
You enable and disable breakpoints from the Breakpoints tab. Next to each
breakpoint is a checkbox you can click to toggle the breakpoint state.
Breakpoints with a check mark next to them are enabled. Breakpoints
without the check mark are disabled.
IMPORTANT: Changes to the state of a breakpoint do not take effect until the next
time the code is loaded from the database. Closing the form and reopening it forces
the debugger to reload the code with the new breakpoint settings.
Removing Breakpoints
After you finish debugging your code, you can remove any breakpoints you
no longer need. You must remove breakpoints from the Breakpoints tab of
the debugger window. To remove a breakpoint, select the desired breakpoint
from the list and click the Remove button. To remove all of the current
breakpoints, click the Remove All button.
IMPORTANT: Changes to the state of a breakpoint do not take effect until the next
time the code is loaded from the database. Closing the form and reopening it forces
the debugger to reload the code with the new breakpoint settings.
282 Chapter 14
Using the ClearBasic Debugger for Windows
The SQL-Log tab displays the SQL statements for all of the database
transactions in the current debugging session. You can use this log as an
additional tool for debugging your application. Figure 30 shows a the
SQL-Log tab with some sample statements.V
Watching Variables
During a debugging session, you use a watchpoint to track the current value
of a variable. In the ClearBasic Debugger, you create and remove
watchpoints from the Debugger tab. The debugger displays the current list
of watchpoints just beneath the toolbar on the Debugger tab.
The debugger tracks any changes to a watched variable during the execution
of your code. If the value in the variable changes, the debugger updates the
value displayed in the list of watchpoints.
The ClearBasic Debugger lets you add watchpoints for variables of any type.
However, you can only modify the values of primitive variables such as
strings and integers.
Adding Watchpoints
The ClearBasic Debugger provides two ways to add watchpoints to
variables. You can add watchpoints directly from the Debugger tab or you
can use the Add Watch dialog.
4. From the Add Watch dialog, choose the desired Script, Procedure, and
Variable name from the dropdown lists.
These three lists contain the known code modules, subroutines, and
variables, respectively.
5. Click the OK button to add the watchpoint.
When you add a new watchpoint, the debugger displays that watchpoint
just below the toolbar in the Debugger tab. The watchpoint contains
information about the name of the variable, its current value, and the context
in which the variable is defined. Figure 32 shows a sample watchpoint set
for the gadgetList variable.
284 Chapter 14
Using the ClearBasic Debugger for Windows
Removing Watchpoints
You must remove watchpoints from the Debugger tab of the debugger
window.
To remove a watchpoint
1. Select the watchpoint from the list of watchpoints in the Debugger tab.
2. Press the Delete key to delete the watchpoint.
You can change the value of variables that contain primitive types such as
strings, long integers, or dates. You cannot change the value of lists, records,
or other complex data types.
The toolbar defines the following tools to control the execution of your code.
Start
When you click the Start button, the debugger executes the rest of your
ClearBasic code and goes into the idle state. The debugger will stop at any
additional breakpoints, dropping out of the idle state to do so.
Break
During a lengthy ClearBasic script, you can click the Break button to pause
the execution of the script.
End
When you click the End button, the debugger terminates the execution of the
current script and goes into the idle state. You can use this script to prevent
the ClearBasic Engine from running faulty code. The debugger does not stop
at any additional breakpoints until you initiate another action in the
ClarifyCRM eFrontOffice application.
Calls
When you click the Calls button, the debugger displays a stack trace of
method calls. You can use this information to trace backwards through the
calling sequence and determine where the call to the current method
originated.
286 Chapter 14
Using the ClearBasic Debugger for Windows
Single Step
When you click the Single Step button, the debugger executes the current
line of code and stops before executing the next line. If the current line of
code contains a call to another user-defined function or subroutine, the
debugger steps into the routine so that you can step through its code.
Procedure Step
When you click the Procedure Step button, the debugger executes the
current line of code and stops before executing the next line. If the current
line contains a call to another user-defined function or subroutine, the
debugger executes the routine but does not let you step through its code.
IMPORTANT: To prevent conflicts from arising during the debugging session, the
ClearBasic Debugger does not let you import code for forms that are currently
open.
The ClearBasic Debugger also lets you edit the code module you are
currently debugging. When a breakpoint is triggered, the debugger displays
the module containing the breakpoint. Choosing Edit Code from the
debugger window’s File menu displays the code in the Editor tab where you
can make any changes. However, before you save your changes you must
first close the form that uses the code module. The debugger cannot replace
a code module if it is currently being used.
288 Chapter 14
Using the ClearBasic Debugger for Windows
NOTE: The debugger also shuts down automatically when you close the
ClarifyCRM eFrontOffice application.
290 Chapter 14
Using the ClearBasic Debugger for UNIX
The CeFO application window containing the Session Login dialog box
appears:
NOTE: If you or somebody else has previously invoked the CeFO application,
the User Name, Server, and Name fields are filled with the information used
during the previous session. In such a case, you can use the provided
information and just type your password.
Setting Breakpoints
You can set breakpoints in your application or module prior to or while
running the application or the module. Table 14 summarizes where and how
to set the breakpoints. You can also set breakpoints at different locations
(lines) after starting the application.
NOTE: The process for setting breakpoints in global modules is identical to the
process for setting breakpoints in form modules. However, the debugging process is
slightly different, Refer to the section Debugging Global Modules on page 299 for
details.
You can save the set breakpoints. The saved breakpoints are in effect when
you run the application/module again.
292 Chapter 14
Using the ClearBasic Debugger for UNIX
The new breakpoints take effect only when you run the application/module again.
To run the application again, you must first either run the entire application/
module or stop the debugger. In other words, you must bring the debugger to the
Idle state.
The only exceptions are the breakpoints set using the Toggle Breakpoint button,
which take immediate effect. Refer to Step 2 on page 294 for details.
To set breakpoints
1. Using the information provided in Table 14, enter applicable values in
the Module and Proc/Line text boxes.
2. Click Set.
The breakpoint setting appears in the Breakpoint Info area of the
Debugger window at the end of any previous settings as shown below:
To set breakpoint(s) ... In the Module text box ... In the Proc/Line ...
In a specific module at a specific line number Enter target module name or Enter line number
module number
In a specific module at all functions that have Enter target module name or Enter target function
the same specified name number name
In a specific module at each function* Enter target module name or Leave blank
number
To set breakpoint(s) ... In the Module text box ... In the Proc/Line ...
In each module at all functions that have the Leave blank Enter target function
same specified name name
In each module at each function* Leave blank Leave blank
NOTE: You can specify the module name for form modules either as a full name
(e.g., it could be 263,8500,’Jeff’) or just as the Form ID (e.g., it could be 8500).
When specifying a global module, you must specify its full name.
To remove breakpoints
1. In the Breakpoint Info matrix, select the breakpoint you want to remove
by clicking it once.
2. Click Delete.
NOTE: The debugger actually removes the breakpoints only after it goes idle.
You can make the debugger idle as described in the procedure To stop the
debugger on page 298. When the debugger is idle, you do not need to exit it.
You can minimize it until you are ready to debug another module.
294 Chapter 14
Using the ClearBasic Debugger for UNIX
2. Click the Add Watch button to display the Add Watch dialog box:
NOTE: You can also select a different variable from the Variable list box.
3. In the Procedure list box, select the procedure in which the target variable
is declared.
4. In the Script list box, select the module in which the variable is declared.
NOTE: If the target variable is a Global or Public variable, select All Scripts.
296 Chapter 14
Using the ClearBasic Debugger for UNIX
5. Click OK.
If not already present, the debugger creates a watch pane and adds the
variable to the watch list showing the context (module name), variable
name, and the variable’s current value.
NOTE: If the entire text in the watch pane is not visible, increase the overall
window width to view the entire text.
In the case of a complex variable (Record, List, BulkSave, etc.) The value
field shows the address of the complex variable.
NOTE: If the complex variable is of User-defined Data Type (UDT), the value
field shows "Error" in it. In the case of UDTs, you can view only individual
field values. For details, refer to the Note in Step 1 above.
b. Enter the new value in the Value field and click OK.
NOTE: The new value stays in effect until you change it again or exit the
debugger. You can run the application with different values to locate the
problem in the source code.
NOTE: While single stepping, if you execute a statement that calls another
procedure, the execution continues in the called procedure. After the execution
of the called procedure is completed, the debugger returns to the statement
immediately after the statement that called the other procedure.
3. If you want to step over a procedure, i.e., execute all the statements in the
procedure and stop at the next executable statement, click the Procedure
Step button in the Debug window toolbar
298 Chapter 14
Using the ClearBasic Debugger for UNIX
Saving Breakpoints
Once you have set the breakpoints and completed your debug session, you
can save the settings for later debug sessions. The debugger does not save
the breakpoints in the module file; it saves them to a separate file.
NOTE: If in the next session you choose to debug a different module than the on e
used in the previous session, debugger attempts to apply the saved breakpoints
NOTE: If you set only the "Any Module" and "Any function" breakpoints,
the debugger does not display this confirmation box and the breakpoints are
not saved.
Also, if you were using the previously set and saved breakpoints and you did
not make any changes to the previous settings (deleted or added any
breakpoints) this confirmation box does not appear.
IMPORTANT: When you start the debugger next time and debug the same module,
the debugger uses the breakpoints set and saved during the previous session. If you
want to debug a different module, you must remove the previously set breakpoints
and set new ones. Otherwise, the debugger attempts to apply the old breakpoints to
the new module, which may not be what you want.
The general format for using this statement is shown below. You can use one
or more strings and/or variable names in any order. However, they must be
separated by commas.
Debug.Print variable_name, "string"
300 Chapter 14
Using the SQL Log to Debug the Database
You can place any number of this statement at strategic locations in your CB
source code. For example, you can place the following Debug.Print statement
at a location to determine whether the application executes the code
immediately preceding this statement.
Debug.Print "This code segment executed OK."
As another example, you can use the following statement sequence to view
the value of MyVariable before and after assignment of the new value to
which expression evaluates.
Debug.Print MyVariable, "This is the previous value"
MyVariable = expression
Debug.Print MyVariable, "This is the new value"
When you run a customized application that has your CB code with
Debug.Print statements in it, the DebugW window appears showing
responses to all Debug.Print statements that executed. The window does not
show responses to the Debug.Print statements that do not execute.
To generate a SQL logfile for your CB form modules, you need to add a line
similar to the following:
App.LogSQL "C:\clarify\CB_tlkt\sqllog", SQLON,
OVERWRITE_LOG
You can place this line within the Initialize_App procedure that is in the
globals file, or within any of your form modules. This created a SQL logfile
that we could use to verify that the correct updates to the database had
occurred.
Summary of Debugging
To reiterate the steps and techniques used in debugging your code, you
should do the following:
• Make sure that the correct version of the code module is imported and
associated with the correct user version of the form.
• Resolve all compile errors.
• Do one or both of the following:
– Use Debug.Print to resolve all runtime errors:
Strategically place Debug.Print statements to watch/verify the flow
of data through your routine.
Examine the SQL log to insure correct database updates.
– Use the ClearBasic Debugger to set breakpoints and view values of
suspect variables.
302 Chapter 14
Chapter 15
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .304
The Server Clock and Client Clock. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .304
ClearBasic and Server/Client Clock Differences . . . . . . . . . . . . . . . . . . . . . . . . . . .305
Manipulating Date and Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .305
Retrieving Server Date and Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .306
Retrieving Date and Time From Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .306
Converting DateTime Strings To Date Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .306
Retrieving Client Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .307
Functions for Date and Time Manipulation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .307
Elapsed Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .308
DateTime Values in Database Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .309
Using Comparison Operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .310
303
Overview
Overview
This chapter describes the date and time characteristics of the CeFO system
and the date and time capabilities of ClearBasic that allow you to determine,
examine, and modify date and time values. These ClearBasic capabilities
extend to the retrieval of the date and time fields in database records and the
setting of those fields. ClearBasic supports the retrieval of both client time
and server time.
Before diving into the subject of ClearBasic and date and time
manipulations, it is helpful to understand a central issue regarding date and
time in the CeFO system, namely the difference between server time and
client time, and the adjustments that occur between these.
Server clock. Similarly, the server machine has its own clock. The server
machine time is used in the CeFO database as the 'standard' time for all
records in the database. If a record has date and time fields, then these fields
are always relative to the server machine.
NOTE: The time and date values stored in database records are ALWAYS expressed
in Server time.
Clock differences. Of course, the client and server times may differ, for
several reasons. The client and server can be in different time zone, causing
their clocks to have the standard time zone difference. In addition to this
standard and predictable time differential, the client and server clocks may
also have “irregular” differences due to some accidental time skew between
the two machines. This latter difference can vary over time as a result of
network management tools that synchronize the various client clocks in the
network.
304 Chapter 15
ClearBasic and Server/Client Clock Differences
Clock differences are handled by CeFO. The CeFO client has the ability to
automatically manage all of the time differences between the server and
client clock through a variety of mechanisms that are under the user control.
For details, see the description of client time handling in the appropriate
CeFO system administration documentation.
Therefore, if a server time is retrieved and then shown to the user, it will be
shown in relation to the client's local time. For example, if the server is in
Boston and the client in California, then the value retrieved at the client is
adjusted by 3 hours when retrieved from the database.
To get server and database record time and dates, you use the objects,
methods, and properties provided. To get the client time, you use the Time
and Time$ functions provided. These are described later.
NOTE: When the server time is retrieved, or date and time is retrieved from a
record, the date and time retrieved is in the form of a DateTime string; you must
convert this string to a Date data type in order to manipulate the value.
Notice that this date and time is returned as a single datetime string, which
can be displayed without any conversion. However, this means that you
need to convert the string to a Date data type in order to manipulate it with
the various ClearBasic Date functions.
Again, the date and time value is returned as a single datetime string, which
can be directly displayed without conversion. However, this means that you
need to convert the string to a Date data type in order to manipulate it with
the various ClearBasic Date functions.
306 Chapter 15
Retrieving Client Time
To convert a CeFO date and time string to the Date type, you use the CDate
function as follows:
Dim DateTimeStr as String
Dim MyDate as Date
DateTimeStr = App.CurrentDate
MyDate = CDate(DateTimeStr)
In this example, the current server time is retrieved and converted to the
Date data type. This value may now be manipulated by a variety of
functions, as described later in this chapter.
The above code converts the date type value back into a string that can be
displayed directly to the user.
Function Description
DateAdd Add a number of date intervals to a date
DateDiff Subtract a number of date intervals from
a date
Function Description
DatePart Return a portion of a date
DateSerial Assemble a date from date parts
DateValue Convert a string to a date
Day Return the day component of a date
value
Hours Return the hour part of a date value
Minute Return the minute part of a date value
Month Return the month part of a date value
Now Return the date and time
Second Return the seconds part of a date value
Time, Time$ Return the current client time
TimeSerial Assemble a date and time value from
time components
TimeValue Convert a string to a date and time value
Weekday Return the day of the week of a date
value
Year Return the year part of a date value
Elapsed Time
A datetime value (expressed either as a String or as a Date) is a time relative
to a time zone. There is another type time value called elapsed time. An
elapsed time is an interval of time. Elapsed time values have the Long data
type and represent an interval of time in seconds.
The datetime values can be adjusted using elapsed time values and the
DateAdd function. Additionally, other date and time functions like Second,
TimeSerial, and DateSerial can by used in combination with elapsed time
values for a variety of calculations.
308 Chapter 15
DateTime Values in Database Records
Common dialogs also support the ability to present both datetime values
and elapsed time dialogs to the user, usually for the purpose of allowing the
user to change or enter a value. For details, see the documentation on the
DateTime and ElapsedTime common dialogs in the ClearBasic Language
Reference.
Date variables can then be assigned back into date and time fields of Record
objects, by first converting them to strings and then loading them into the
Record field via SetField:
Dim MyDate as Date
Dim DateTimeStr as String
DateTimeStr = CStr(MyDate)
YourRecord.SetField("datetime_field", DateTimeStr)
Another way to compare is with the DateDiff function, which allows you to
compare two dates with a given interval (days, months, seconds, etc). You
can use this function with an interval of seconds, for instance, to see if two
date and times are 'virtually' the same, or greater, and so on.
310 Chapter 15
Chapter 16
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .312
Declaring a SQLDB Object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312t
Connecting to a Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .312
Checking For a Valid Connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .313
Disconnecting From the Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .313
Disconnecting From the Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .313
Issuing a SQL Select Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .315
Invoking a Stored Procedure that Returns Values . . . . . . . . . . . . . . . . . . . . . . . . . .316
311
Overview
Overview
ClearBasic provides the SQLDB object and related methods to allow you
access CeFO databases or foreign databases using SQL (isql), either at the
local server or at a remote server. They permit an auxiliary connection to a
database without affecting the current connection with the login database.
You can use that connection to issue a Select statement or to issue other
statements that do not return values, such as updates or deletes.
The most important restriction on the use of this object and its methods is
that you can use it only on databases that are of the same type and release
number as the login database. This means that if your login database is a
Sybase 4.9-served database, you cannot connect to an Oracle database, or
even a Sybase 10-served database.
Connecting to a Database
To connect to a database, use the following syntax:
YourSQLDB.Connect("Server", "DBName", "UserName",
"Password", Timeout
For short term connections you might want to do as much processing as you
can before calling Connect, to minimize connection times.
312 Chapter 16
Checking For a Valid Connection
You cannot use this method to terminate the connection to the login
database.
Sample Code
In the following code, in response to a user selection from a custom list and
subsequent button click, a record field in the database is filled with the
current date and the display of that record is updated with the current date.
Notice that the SQLStatement is built up before calling Connect.
Sub Update_Click()
Dim Ind as Integer
Dim SqlState as String
Dim theDate as String
Dim ordRecord as Order_Record
Dim ordList as New List
Dim toDB as New SQLDB
‘Get current date to update the record field, then ‘get
index of the selected item in the custom list. ‘We need
index later to get the selected record.
theDate = App.CurrentDate
Ind = Order_Array.ListIndex
‘Put list of records in the control into ordList, ‘then
use index of the selected item to get the ‘record.
ordList.ItemType = "Order_Record"
set ordList = Cobj_ord_record.GetContents
ordList.GetItemByIndex Ind, ordRecord
‘Set up sql statement to update the record field.
SqlState = "update order_tbl set notify_dt='" & _
theDate & "' where uId=" & ordRecord.uId
‘Connect to DB, execute SQL, then disconnect.
toDB.Connect "SUSM", "cbforeign", "sa", "sax"
toDB.Execute SqlState
toDB.Disconnect
‘Update the displayed record to match DB record.
ordRecord.notify_dt = theDate
ordList.ReplaceByIndex Ind, ordRecord
Cobj_ord_record.Fill ordList
End Sub
314 Chapter 16
Issuing a SQL Select Statement
This method issues an 'isql' select statement into the database that the
SQLDB object is connected to by the Connect method. Any results are placed
into the specified destination list. If you use user defined types, you need to
define a type that contains the fields you want, then specify that the
DestinationList parameter is of your user-defined type.
You can supply the optional DestinationFields parameter if you only want
the values of certain fields returned. DestinationFields is the list of the field
names that you want filled. Only values from those fields are placed into
DestinationList.
This method returns the count of records obtained as a result of the select
operation.
Sample Code
In the following example, a SQL statement is put together using the fields of
a user-defined type (Order_Record). A connection to the database is made,
the Select statement is executed and the requested records are put in ordList.
The list of records is looped through and each record is checked for a certain
date: if found, that date field is cleared and the revised record replaces the
original in ordList. When the loop completes, the list is loaded into
obj_ord_record where it is displayed in a custom list control.
Sub Form_Load()
Dim Ind as Integer
Dim SqlStatement as String
Dim ordRecord as Order_Record
Dim ordList as New List
Dim toDB as New SQLDB
ordList.ItemType = "Order_Record"
If the stored procedure requires a list of input values of different data types,
you must set the ItemType of the List object containing those values to
Variant before placing the values in the List. Notice that the only List
method that can be used on a variant List is AppendItem.
Sample Code
The following sample procedure contains a sub procedure that invokes
ExecuteProc.
316 Chapter 16
Invoking a Stored Procedure that Returns Values
After the input list for the stored procedure is filled, ExecuteProc is called
with the values in InList provided as the inputs to the Test1 stored
procedure. Test1 returns values to OutVals, which has a user-defined type
(MyType). From the type definition, notice the sorts of values expected back,
objid, name, status, privclass, etc.
Type MyType
ObjId as Integer
Name as String * 255
Status as Integer
PrivClass as Long
Test1 as String * 255
End Type
Sub TestExecuteProc
Dim DB as New SQLDB
Dim InList as New List
Dim OutVals as MyType
InList.ItemType = "variant"
InList.AppendItem 1
InList.AppendItem "alpo"
DB.ExecuteProc "Test1", InList, OutVals
End Sub
318 Chapter 16
Appendix A
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .320
319
Overview
Overview
This appendix lists the entries that were formerly required entries in your
globals file. They represented items needed by other CeFO applications.
However, the globals file for CeFO applications has been moved elsewhere.
CAUTION: You still need the initialize_app procedure in your global file if you
want to perform certain intializations, including menubar setup.
For your convenience, these now obsolete entries are provided to help you
eliminate clutter from your globals file.
NOTE: The obsolete entries do no harm if they are left in. However, we recommend
that you remove the items.
Type GLSummary
320 Appendix A
Overview
FromAccount as String * 25
FromDesc as String * 25
ToAccount as String * 25
ToDesc as String * 25
Value as String * 20
Credit as String * 20
Debit as String * 20
End Type
Type GLRun
PeriodName as String * 50
RunDate as String * 50
BeginDate as String * 50
EndDate as String * 50
PrevPeriod as String * 50
TimeBombId as Long
End Type
default_label = "ADD"
Else
default_label = "REPLACE"
End If
Sub Initialize_App
Dim CLMenu as New AppMenu
CLMenu.MenuBarId = 1007
CLMenu.SetFunction "Actions", "GL Interface",
"ShowGL"
App.ShowDefaultMenu
gl_inv_mode = SEL
End Sub
Sub ShowGL_Click
322 Appendix A
Overview
324 Appendix A
Appendix B
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .326
What is DDE?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .326
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .328
Using DDE Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .328
A Usage Example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .329
325
Overview
Overview
ClearBasic provides support for a subset of Dynamic Data Exchange (DDE)
protocols for inter-application communications. This subset allows a user’s
DDE client application to send a command string to the DDE server to
trigger the execution of the specified global procedure.
The DDE client application can be coded in any language that supports the
DDE protocols. However the global procedure to be executed must be coded
in ClearBasic.
What is DDE?
DDE is set of messaging protocols that two windows applications—a client
application and a server application—use to dynamically exchange data
between themselves. The DDE client and DDE server applications use the
following DDE messages to communicate with each other. However, as
indicated, ClearBasic does not support all of these messages.
Message Description
DDE_ACK Acknowledges receiving or not receiving a message.
DDE_ADVISE The client requests the server to send a notification or an
(Not supported) updated data item value when the value of the data item
changes. This message establishes a permanent "warm"
or "hot" link.
DDE_DATA The server sends a data item value.
(Not supported)
DDE_EXECUTE The client sends a string to the server. The server then
processes the string as an executable command or a
series of commands. This message establishes a "cold"
link.
DDE_INITIATE The client sends this message to initiate a conversation
with the server.
DDE_POKE The client sends a data item to the server.
(Not supported)
DDE_REQUEST The client requests the server for the value of a data item.
(Not supported)
326 Appendix B
What is DDE?
Message Description
DDE_TERMINATE The client/server sends this message to the server/client
to terminate a conversation.
DDE_UNADVISE Terminates a permanent link established by a
(Not supported) DDE_ADVISE message.
Link Modes
Normally, DDE messages establish the following three types of links
between the client and server applications. However, ClearBasic supports
only the Cold Link.
• Hot link
• Warm link
• Cold Link
During a Hot link, the server application automatically sends the value of a
data item every time the value changes.
During a Warm link, the server only notifies the client of the change. It sends
the new value only when explicitly requested by the client.
During a Cold link, the server acknowledges the message and provides the
requested service.
NOTE: ClearBasic supports only the Cold Link. It does not support Hot and Warm
Links.
This means that a user’s DDE client application can only establish a "cold"
link and send a command string to the DDE server. The server then sends a
message acknowledgment and executes the command string.
Prerequisites
To use the DDE support, you need the following:
• Your client application must support DDE.
• You must have the CeFO executable with license for at least one of the
CeFO applications.
Write a ClearBasic global procedure that will be executed whenever the DDE
client sends a request. This procedure must reside in the global module that
you import into the database.
NOTE: This procedure must be coded using ClearBasic and imported into the
database using the CBExchange utility.
328 Appendix B
A Usage Example
The global procedure is loaded into memory whenever the CeFO executable
is started. Note that only one procedure can be run at a time. However, a
single procedure can have multiple threads or subprocedures. When more
than one procedures are loaded, the user must provide appropriate program
logic such that the only the appropriate procedure is executed.
On the DDE client side, you need to do the following using a programming
language, such as Microsoft Visual Basic, that supports DDE protocols:
1. Assemble an "application:topic" string.
This string specifies the DDE server application with which the client
DDE application wants to communicate. In this case, the application is
always ClarifyApp and the topic is always Clarify.
2. Assemble an "initiate conversation" message.
3. Assemble an "execute command string" message.
4. Assemble a "terminate conversation" message.
A Usage Example
This section describes how to use DDE protocols with the CeFO
applications. This example uses Microsoft Visual Basic. You can use any
other language with equivalent code.
330 Appendix B
A Usage Example
332 Appendix B
Appendix C
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .334
333
Overview
Overview
ClearBasic has a set of constants to supply with certain methods. These
constants are listed below.
IMPORTANT: There are also many pre-defined constants for the ClearBasic
functions and statements. Please refer to the Constants (topic) section of the
ClearBasic Language Reference for a complete list of these constants.
:
334 Appendix C
Overview
336 Appendix C
Appendix D
Customization Methodology
In This Chapter
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .338
User Version Numbering for Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .338
Parallel Development of Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .339
Porting Customizations to Another Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . .340
Exporting Resource Configurations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .342
Exporting an Individual Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .342
Testing and Debugging. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .344
Accessing Data From Other Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .345
337
Overview
Overview
This appendix contains a few notes on customization methodology that may
be useful to you.
If you use this methodology, the same version number is always the same
revision of the form in all databases in which that form/version is stored.
For example, suppose you want to customize the baseline New Case screen.
You would complete the following steps:
1. In the Development database, open the New Case screen, and use File/Save
As to save the window under user version 1.0.
2. Make or update a resource configuration to include the new user version.
3. Make yourself a member of that configuration.
4. Make the required modifications to the screen, and re-save.
5. Test the edits using the CeFO application.
6. Repeat steps 4 and 5 until you are satisfied with the edits. Pay particular
attention to the Tab order.
7. Export the window using the Export button, or the resource
configuration if you want both the resource configuration and its
associated custom forms.
8. Use dataex to import the definition(s) into the Test database.
338 Appendix D
Parallel Development of Forms
9. If the testing team is not satisfied with the screen, revisit the
Development database and use File/Save As to save the screen as version
1.1. (Saving it as a new version even though it hasn’t gone into
production is a good idea. The users are apt to change their minds and
want the original 1.0 version. This way you have preserved the 1.0
changes and won’t have to back out the 1.1 changes.)
10. Repeat steps 4 to 8 until the screen is accepted.
11. Import into the Production and Golden databases.
Table 18
Version Reason
e1.1 Mainstream English Customizations
e1.2 Next version of mainstream English development.
e1.1X A version based on e1.1 with some changes
e1.1Y A version based on e1.1 with changes different to X.
NOTE: the version numbering scheme in this example has the language indicator
first so you could search for all the forms of a particular language. If you put it last
you can then search and get all the 1.1 forms bunched together. You need to decide
which style best satisfies your searching requirements.
SUGGESTION: Add all your schema changes (if possible) in one session of
DDEditor. Then restart the UIEditor. The UIEditor does NOT cache data
except when it starts. You cannot do an Update Desktop in UIEditor.
When importing customized forms into another database, make sure that all
the necessary schema changes have been applied first, otherwise, when you
go to test the form you are apt to see a runtime error message similar to the
following:
Mapping of generic field ID XXXXXX of object schema
thinga_majig is invalid
In general, this type of error means that there is a mis-match between the
database schema and the form that is being displayed. Sometimes the
resolution is as simple as deleting the local .cfy and .042 files. However, this
is more typical if a customized form has been imported but the database
schema was not updated to include a field that the screen is using. This error
can also occur if a control on the screen does not have a source identified for
it.
340 Appendix D
Porting Customizations to Another Database
That means that you have to assign a new ID to the new object that you are
adding. This is fine, just be aware that if you will be subsequently porting
any forms that utilize this database object (i.e. linked via a contextual object),
that the form export file will reference the original Type ID number, which is
no longer valid for this object.
In this case, you will need to manually edit the form export file and look for
that Type ID number associated with any contextual objects (i.e. ctx_obj_db
objects). For example, we had the form export file 1015.dat which had a
contextual object as such:
OBJECT TYPE="ctx_obj_db",
NAME="CTX_OBJ_DB_1015_1.0_1.0_employee_skill"
UNIQUE_FIELD = title UNIQUE_RELATION = ctx_obj2window_db
FIELDS
title ="employee_skill";
type=489;
idx=6;
behavior=16;
str_size=0;
END_FIELDS
RELATIONS
TO_NAME="WINDOW_DB_1015_1.0_1.0"
REL=ctx_obj2window_db;
END_RELATIONS
END_OBJECT
NAME="CTX_OBJ_DB_1015_1.0_1.0_employee_skill"
In this example, the custom table employee_skill has ID = 489, which we had
to change to 491 since 489 was already being used in the destination
database. We simply changed the reference of 489 to 491 in this file, saved it,
and then imported this screen via dataex.
NOTE: If you do not modify this form export file, it will import without errors,
however, when you go to open this form in the UIEditor, you will get an error about
fields not existing for a specific object and it will not post the form.
342 Appendix D
Exporting an Individual Form
You can either add this custom privilege class to the destination database, or
you can use a text editor to remove the first part of the file which contains
reference type data similar to the following sample:
RELATIONS
END_RELATIONS
END_REFERENCE NAME="PRIVCLS_CSR"
Delete all reference type data up until you get to the first line that references
a “window_db” object as such:
OBJECT TYPE="window_db", NAME="WINDOW_DB_610_1.0_2.0"
Save your changes, and then run dataex again to import your custom form.
NOTE: If this privilege class is associated with any of the controls on this new
form, however, then you need to add this privilege class to the destination database
rather than deleting it from the form export file.
344 Appendix D
Accessing Data From Other Databases
RULE: The select statement fields must be in the same order as the elements
of your UDT.
TIP: If utilizing a “like” filter within the select statement, you must end the
wildcard piece of that select statement with “%%” rather than just “%”.
346 Appendix D
Index
A ByRef
Action Directives list when to use 193
directly setting up directives in 251 ByValue
adding comment lines to a directives file 253 when to use 193
adding controls for a form 49
C
applying menubar customization 223
caches 277
B callbacks
breakpoints Form_Save 197
enabling 282 creating 198
case sensitivity
removing 282
in record fields 69
setting 281
CB code
BulkRetrieve
writing and importing 53
filtering 188
-cb mode 36
objects 181
CBEX
accessing returned records 182
declaring 181 command line options and flags 242
loading filters 182 directives file for 230
loading queries 181 getting ready to use 245
loading sort conditions 182
retrieving records 182 invocation modes 238
scoping 181 invoking in command line mode 241
querying 184 invoking in interactive, or GUI, mode 238
breaking up large queries 190 using the -batch option in 236
loading queries 181
CBEX cache file, role of 229
retrieving results 189
SimpleQuery 185 cbex command, use of 215, 216
TraverseFromParent 186 CBEX operations
TraverseFromRoot 185 performing on global and form modules 255
retrieving records with 181
cbex.log file
sorting 188
format of 237
synopsis of 183
use of 237
BulkSave
changing stack size 68
and objids 193
character limits 67
objects 191
checking syntax in source modules 255
ByRef 192, 194
ByValue 192, 194 ClearBasic
declaring 191 components of 23
saving to database with 190 defined 22
scoping 191
designing 60
347
database considerations 60 contextual objects
tips for forms 61 maintenance 63
UI considerations 60
using forms 61 removing 68
using frames 62 renaming 68
using tabs 63 using UDTs as 70, 89
event driven programming 29
controls 28
interpreter 23
events in 28
language intrinsics 23
removing 68
syntax 26
renaming 68
ClearBasic and MicroSoft Visual Basic, similarities
creating a new form 47
in 229
creating and using directives file 230
ClearBasic Debugger
customization tools 33
capabilities of 290
customization, a two-part process 36
invoking 290
customizing menus 216
ClearBasic Project
customizing menus in multiple menubars 222
general steps to implement 226
ClearBasic project D
implementing the design of 226 date
ClearBasic tutorial functions for manipulation 307
adding controls for a form 49 manipulating 305
creating a new form 47 retrieving from server 306
posting and modifying an existing form 38 retriving from records 306
starting the UI Editor 36 type
summary of lessons in 36 converting back to string 307
verifying the form operation 55 converting from DateTime string 306
writing and importing CB code 53 using comparison operators for 310
clock value in database records 309
client 304 DDE client applications 328
differences DDE links supported by ClearBasic 327
ClearBasic and server/client 305 DDE Protocols, using 328
server and client 304 Debug.Print statement, how used 272
server 304 debugger
coding global modules 228 adding breakpoints 280–282
Cold Link (DDE) 327 adding watchpoints 284
comparison operators breakpoints tab 279
used for dates 310 clipboard support 288
compile-time error messages 272 closing 289
compile-time errors continuing execution 286
fixing 273 editing code 280, 287
samples of 273 enabling breakpoints 282
compiling/importing modules into database 259 main tab 279
348 Index
options 288 event procedures 29
pausing 286 form load event 29
removing breakpoints 282 event procedures, associating to menu items 219
sql-log tab 280 exporting a single form module 262
stepping through code 287 exporting a single global module 262
stopping script execution 286 exporting and purging a single form module 267
toolbar 278–279 exporting and purging a single global module 268
viewing the call stack 286 exporting and purging modules 266
debugging a Module in an Application 295 exporting form modules 261
debugging global modules 299 exporting initialize_app procedure to the database
directives file 215
creating and using 230 exporting multiple modules 263
creating from within the CBEX 233 exporting purging multiple modules 268
enabled/disabled modules in 230
F
enabling/disabling modules for use in
command line mode 252 Filter Value text box 39
format of global modules in 231 form module and associated form, determining 253
global modules in 231 form module(s)
loading and settting up directives 246 exporting a single 262
procedures for creating 231 exporting and purging a single 267
setting up for use in command line mode 252 format in a directives file 232
some requirement for 235 importing 261
when to use 236 importing a single 259
directives file for CBEX 230 purging 263
directives file, adding comments line to 253 purging a single 264
disabling menu items 220 form module(s) maximum size of a 229
Dynamic Data Exchange (DDE) form modules
a usage example 329 procedure for entering in a directives file 232
described 326 Form_Load procedure 228
link modes 327 forms 27, 61
prerequisites for using 328 code
protocols for inter-application communications adding 65
flushing changes 64
326
module size/limit 69
support for 325, 333, 337 not supported 66
what is supported 328 required for additions 65
retrieval 64
E storage 64
supported 66
enabled and disabled modules in directives file 230 updating modules 64
Enabling menu items 220 useful tips 67
enabling/disabling modules for use in command code for 28
line mode 252 design tips 61
Index 349
events in 28 L
events that cause their posting 173 loading and setting up a directives file, procedure
GUI components of 27 for 247
initializing customized 174 loading directives file and setting up directives 246
initializing new 174 logic errors 272
typical initialization tasks 175
when to use 61 M
frames 61 maintenance
maintenance 63 contextual objects 63
when to use 62 frames 63
froms maximum size of a form module 229
initializing 173 MenuBar IDs, table of 218
menubars
G and ClearBasic code requirement 214
global module(s) changes you can make in 214
exporting and purging a single 268 menus
expoting a single 262 adding items to 217
importing a single 260 applying the customization 223
global modules in a directives file 231 associating items to event procedures 219
global modules, creating 228 customizing 216
global modules, format in directives file 231 customizing in multiple menubars 222
global stack, how used 67 disabling items in 220
GUI Components, creating for your code 226 enabling items in 220
inserting separators between items 221
H
removing items from 219
Hot Link (DDE) 327
renaming items in 218
I methods 24, 26
importing a single form module 259 modifying initialize_app procedure 215
importing a single global module 260 module source code files, specifying 235
importing multiple modules 260 O
initialize_app procedure
objects 24, 25
exporting to the database 215
and inheritance 25
how it works 214
objids
modifying 215
in BulkSave 193
initializing a new form 174
Option Explicit, using 273
initializing customized forms 174
invoke the ClearBasic debugger 290 P
invoking CBEX in interactive, or GUI, mode 238 Performing CBEX Operations 255
invoking CBEX in the n command line, mode 241 performing CBEX operations on global and form
modules 255
350 Index
posting and modifying an existing form 38 setting up directives file for use in command line
Project design mode 252
implementing your 226 source module(s)
tasks for implementing 226 checking syntax in 255
properties 24, 26 suntax checking in multiple 258
purging a single form module 264 syntax checking in aglobal 257
purging form modules 263 syntax checking using CBEX in GUI mode 255
purging multiple modules 265 specifying module source code files 235
stack size
R changing 68
record fields stacks
and case sensitivity 69 local
records exceeding 68
deleting from database 191, 194 setting 67
inserting in database 191, 192 public
relating in database 191, 195 setting 68
stopping the debugger 298
RelateRecord 195
RelateRecordsFromID 195 summary of debugging tasks 302
RelateRecordsFromToID 196 syntax checking in multiple source modules 258
RelateRecordsToID 196 syntax checking in source global module 257
unrelating in database 191, 196
updating in database 191, 194 T
requirements for a Form_Load procedure 174 tabs 61
restarting CBEX, when necessary 229 when to use 63
routines time
calling 68 client
running an application or module in debug mode retrieving 307
295 elapsed 308
run-time error messages 272 functions for manipulation 307
run-time errors manipulating 305
fixing 274 retrieving from records 306
samples of 274 retrieving from server 306
type
S converting from DateTime string 306
saved breakpoints 292 value in database records 309
saving the currently set breakpoints 300 typical forms initialization tasks 175
separators, inserting in menu pulldowns 221
Setting breakpoints U
table explaining 293 UDTs 25, 89
setting breakpoints 292 as contextual objects 70, 89
setting breakpoints during a debug session 294 UI Editor
-cb option 226
Index 351
-cb option, when not to use 227
starting in ClearBasic mode 227
starting in Clearbasic mode 36
using 226
UI Editor, what you can do with it 226
user-defined data types (UDTs)
creating file containing 228
using 227
using the Debug Window 300
using the SQL Log to debug database 301
V
verifying the form operation 55
viewing and modifying the contents of a variable
296
viewing the call stack 298
W
Warm Link (DDE) 327
watchpoints
adding 284
removing 285
what you can do with the UI Editor 226
writing and importing CB code 53
352 Index