0% found this document useful (0 votes)
24 views352 pages

ClearBasic Programmer's Guide

The ClearBasic Programmer’s Guide for ClarifyCRM® eFrontOffice 11.5 provides an overview of the ClearBasic programming language, including its components, syntax, and programming fundamentals. It contains tutorials and design requirements for creating and customizing forms, as well as guidelines for coding and performance considerations. The document is intended for authorized users and is subject to Amdocs' software licensing terms.

Uploaded by

MerucoScribd
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views352 pages

ClearBasic Programmer's Guide

The ClearBasic Programmer’s Guide for ClarifyCRM® eFrontOffice 11.5 provides an overview of the ClearBasic programming language, including its components, syntax, and programming fundamentals. It contains tutorials and design requirements for creating and customizing forms, as well as guidelines for coding and performance considerations. The document is intended for authorized users and is subject to Amdocs' software licensing terms.

Uploaded by

MerucoScribd
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 352

ClarifyCRM® eFrontOffice 11.

ClearBasic Programmer’s Guide

Part Number. M30030-00E11050000


September, 2002
© 1995–2002, Amdocs. All Rights Reserved.
Amdocs Confidential
This manual and the software described herein are subject to your Amdocs Software License and are copyrighted with
all rights reserved. This manual and the software may not be copied, in whole or in part, without written consent of
Amdocs, except as permitted by your Amdocs Software License.
The information in this manual is furnished for informational use only by authorized persons, is subject to change
without notice, and should not be construed as a commitment by Amdocs. Amdocs assumes no responsibility or
liability for any errors or inaccuracies that may appear in this book.
The trademark and service marks of the respective Amdocs companies, including the Amdocs mark and logo, are the
exclusive property of such companies, and may not be used without permission. All other marks mentioned in this
material are the property of their respective owners.

For technical assistance, visit http://clearanswer.clarify.com to submit a case at any time.


Contents

About This Guide


Audience for this Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Related Documentation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Organization of This Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
What’s New in This Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

Chapter 1 Overview of ClearBasic


Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
What is ClearBasic? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Components of ClearBasic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
The ClearBasic Interpreter. . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
ClearBasic Language Intrinsics . . . . . . . . . . . . . . . . . . . . . . . 23
ClearBasic Objects, Methods and Properties . . . . . . . . . . . . 24
What are Objects, Properties, and Methods? . . . . . . . . . . . . . . . 24
What Are Objects in ClearBasic? . . . . . . . . . . . . . . . . . . . . . . 25
Can You Extend ClearBasic Objects Using
Inheritance?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
What Are Methods in ClearBasic? . . . . . . . . . . . . . . . . . . . . . 26
What Are Properties in ClearBasic?. . . . . . . . . . . . . . . . . . . . 26
ClearBasic Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
ClearBasic Programming Fundamentals . . . . . . . . . . . . . . . . . . 27
What is a Form? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Database Storage of GUI Components . . . . . . . . . . . . . . 27
Database Storage of Form Code . . . . . . . . . . . . . . . . . . . . 28
What is a Control? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
What are Events in Forms and Controls? . . . . . . . . . . . . . . . 28
Welcome to Event Driven Programming . . . . . . . . . . . . . . . 29
Writing Event Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Event Procedure Naming Conventions . . . . . . . . . . . . . . . . 29
ClearBasic and CeFO Customization . . . . . . . . . . . . . . . . . . . . . 30
Customization Methodology . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Customization Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

Contents 3
Where to Find More Information . . . . . . . . . . . . . . . . . . . . . . . . 33

Chapter 2 A Tutorial in ClearBasic


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

Chapter 3 Design Requirements


Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Designing Your Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Database Considerations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
User Interface Considerations . . . . . . . . . . . . . . . . . . . . . . . . 60
Whether to Use a Form, a Frame or a Tab . . . . . . . . . . . . . . . . . 61
When to Use a Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Design Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
When to Use Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
When to Use Tab Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Critical Contextual Object Maintenance Issues . . . . . . . 63
Central Code Storage and Retrieval . . . . . . . . . . . . . . . . . . . . . . 64
Updating Code Modules. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Flushing Code Changes to the Client During
Runtime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Adding Code to Standard CeFO Forms . . . . . . . . . . . . . . . . . . . 65
Required Code for All Additions to CeFO Forms. . . . . . . . 65
What Kind of Coding is Supported? . . . . . . . . . . . . . . . . . . . 66
What Kind of Coding is Not Supported? . . . . . . . . . . . . . . . 66
Useful Tips for Coding in a Standard CeFO Form . . . . . . . 67
Maximum Character Limits for Names . . . . . . . . . . . . . . . . . . . 67
Avoiding Errors Due to Lack of Stack Space . . . . . . . . . . . . . . . 67
Setting the Local Stack. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Possible Ways to Exceed the Stack . . . . . . . . . . . . . . . . . 68
Setting the Public Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Calling External Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Removing and Renaming Items in UI Editor . . . . . . . . . . . . . . 68
File Size and Pcode Limits for Code Modules. . . . . . . . . . . . . . 69
Case Sensitivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Checking Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Using Contextual Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Three Main Categories of Contextual Objects. . . . . . . . . . . 70

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

Chapter 4 ClearBasic Language Fundamentals


Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
ClearBasic Naming Requirements/Conventions . . . . . . . . . . . 78
Form Module Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Contextual Object Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Other Important Considerations . . . . . . . . . . . . . . . . . . . 80
Keyword Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Constant Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Methods and Property Names . . . . . . . . . . . . . . . . . . . . . . . . 82
Event Procedure Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Subroutine Procedure Names. . . . . . . . . . . . . . . . . . . . . . . . . 83
Function Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Using Variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Scoping. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
What Kind of Variables Do You Need? . . . . . . . . . . . . . . . . 84
Restrictions on the Use of Variables (Stack) . . . . . . . . . . . . . 85
Ways to Get Around the Stack Size Limit. . . . . . . . . . . . 85
Declaring Variables of UDT or Primitive Type . . . . . . . . . . 86
Declaring Object Variables (Using NEW). . . . . . . . . . . . . . . 86
Initializing Certain Object Variables . . . . . . . . . . . . . . . . . . . 87
Declaring Global Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Assigning to Object Variables (You Must Use Set) . . . . . . . 88
Using User Defined Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Declaring User-Defined Types . . . . . . . . . . . . . . . . . . . . . . . . 89
Declaring UDTs as Contextual Objects . . . . . . . . . . . . . . . . . 89
Some Rules for Using UDTs . . . . . . . . . . . . . . . . . . . . . . . . . . 90

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

Chapter 5 Contextual Objects and the CeFO GUI


Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
What is a Contextual Object? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
When Are You Required to Use Contextual Objects? . . . . . . . 99
Planning Issues. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Creating a Form: the Role of Contextual Objects . . . . . . . . . . . 99
Linking Contextual Objects to the Form. . . . . . . . . . . . . . . 100
Assigning a Name to the Contextual Object . . . . . . . . 101
Specifying the Contextual Object Data Type . . . . . . . . 102
Determining Which Data Types to Assign. . . . . . . . . . 102
If You Forget to Link a Contextual Object . . . . . . . . . . 103
Placing Data into a Form’s Contextual Objects . . . . . . . . . 103
Placing Database Records Into a Contextual
Object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Placing Values From a Single Field into
Contextual Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Placing Local Data Into a Contextual Object . . . . . . . . 106
Using One Contextual Object With Several Controls. . . . 107
Contextual Objects and Existing CeFO Forms. . . . . . . . . . 107
Contextual Objects and New Frames . . . . . . . . . . . . . . . . . 108
Creating a Control: the Role of Contextual Objects . . . . . . . . 108
Source and Destination Contextual Objects. . . . . . . . . . . . 109
Control and Source/Destination Matrix. . . . . . . . . . . . 110
Linking a Source Contextual Object to a Control . . . . . . . 111
Controls and Data Types. . . . . . . . . . . . . . . . . . . . . . . . . 112
Linking a Destination Contextual Object to a Control . . . 112
Sample Interaction Between Control and
Contextual Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

6 Contents
Summary of Contextual Objects . . . . . . . . . . . . . . . . . . . . . . . . 114

Chapter 6 Programming in Forms


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
Special Form_Load Requirements . . . . . . . . . . . . . . . . . . . . 117
If You Add Code for a Standard Control . . . . . . . . . . . . . . 118
If You Add a Message Handler to a Standard Form,
or to a New Frame or Tab Frame . . . . . . . . . . . . . . . . . . . 118
Reading and Writing to CeFO Contextual Objects . . . . . . 119
If You Create a New Form, Frame, or Tab Frame . . . . . . . . . . 119
New Forms Require a Message Handler . . . . . . . . . . . . . . 119
If You Create a New Frame or Tab Frame . . . . . . . . . . . . . . . . 120
You Must Maintain “Mirroring” of Contextual
Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
You Must Add Contextual Objects in the Same
Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Form Activation Happens for Parent Only . . . . . . . . . . . . 121
Passing Information Between Parent Form
and Frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

Chapter 7 Programming Controls


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
Creating a Check Box. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Coding a Check Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Setting the Initial State . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Checking For a Checked/Unchecked Condition. . . . . 129
Writing "Check Box-Sensitive" Code . . . . . . . . . . . . . . . 131
Programming Command Buttons . . . . . . . . . . . . . . . . . . . . . . . 132
Creating a Command Button . . . . . . . . . . . . . . . . . . . . . . . . 132
Coding a Command Button . . . . . . . . . . . . . . . . . . . . . . . . . 133
Programming Custom Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Creating a Custom List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Labeling the Custom List . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

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

Chapter 8 Programming Tabs


Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Peculiarities of CeFO Tabs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
A Tab Widget is Not a Tab Frame . . . . . . . . . . . . . . . . . . . . 168
Posting the Tab: No Code Required . . . . . . . . . . . . . . . . . . 168
Tip: If You Need a Widget Click Handler. . . . . . . . . . . 168
Crucial Facts About a Parent Form and Its Tabs . . . . . . . . . . . 169
You Must Maintain “Mirroring” of Contextual
Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Form Activation Happens for Parent Only . . . . . . . . . . . . 169
What Happens To Tabs During Form_Load? . . . . . . . . . . 169
How Do You Front the Tab? . . . . . . . . . . . . . . . . . . . . . . . . . 170
Avoid Invoking Tab Form_Load From Parent
Form_Load Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Designing Your Tabs: What Not to Do . . . . . . . . . . . . . . . . . . . 170
Don’t Link a Contextual Object Field to Multiple
Controls. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Creating Tab Widgets and Tab Frames. . . . . . . . . . . . . . . . . . . 171
Parent/Child Relation Set Automatically for Tabs . . . . . . . . . 172

Chapter 9 Initializing Forms


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

Chapter 10 Accessing the CeFO Database


Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Description of BulkRetrieve Objects . . . . . . . . . . . . . . . . . . 181
Synopsis of the BulkRetrieve Mechanism. . . . . . . . . . . 183
Querying the Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
Filtering and Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Retrieving Query Results from the BulkRetrieve . . . . . . . 189
Breaking Up Large Queries. . . . . . . . . . . . . . . . . . . . . . . . . . 190
Saving to the Database With BulkSave . . . . . . . . . . . . . . . . . . . 190
Description of BulkSave Objects . . . . . . . . . . . . . . . . . . . . . 191

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

Chapter 11 Message Handling


Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
How Many Message Handlers Per Form? . . . . . . . . . . . . . . . . 202
When are You Required to Have a Message
Event Handler? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
What Code is Required in Every Message Handler? . . . . . . . 203
What Numbers Can Be Used For Messages . . . . . . . . . . . . . . 204
What Message Passing Functionality is available?. . . . . . . . . 204
Handling Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Handling Predefined CeFO Messages . . . . . . . . . . . . . . . . 205
Handling Your Own Messages . . . . . . . . . . . . . . . . . . . . . . 206
Assigning Values to Your Messages . . . . . . . . . . . . . . . 207
Using Message Strings. . . . . . . . . . . . . . . . . . . . . . . . . . . 207
Sending Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
Notify . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
NotifyByID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Notifying Parent and Child Forms . . . . . . . . . . . . . . . . . . . 209
Parent Forms, Child Forms, and Messaging . . . . . . . . . . . 209
Setting Up the Parent/Child Relationship . . . . . . . . . . 209
NotifyChild . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
NotifyParent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
NotifyByKey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

Chapter 12 Customizing Menubars


Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Modifying the initialize_app Procedure. . . . . . . . . . . . . . . . . . 215
Exporting the Global Module. . . . . . . . . . . . . . . . . . . . . . . . 215
Importing the Global Module . . . . . . . . . . . . . . . . . . . . . . . 215
Customizing Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Adding a Menu Item to an Existing Menubar. . . . . . . . . . 217
Renaming a Menu Item. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
Removing a Menu Item. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
Linking Event Procedures to Existing Menu Items . . . . . 219
Disabling and Enabling Menu Items. . . . . . . . . . . . . . . . . . 220
Inserting Separators Between Menu items. . . . . . . . . . . . . 221

10 Contents
Customizing Menus-Multiple Application Menubars . . . . . . 222
Applying the Menubar Customization. . . . . . . . . . . . . . . . . . . 223

Chapter 13 Building Your Project


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
Coding Form Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
Creating and Using a Directives File. . . . . . . . . . . . . . . . . . . . . 230
Creating a Directives file . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Some Directives File Requirements . . . . . . . . . . . . . . . . . . . 235
Before Using CBEX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
Specifying Source Code Files . . . . . . . . . . . . . . . . . . . . . 235
When to Use a Directives File . . . . . . . . . . . . . . . . . . . . . 236
Using the -batch option . . . . . . . . . . . . . . . . . . . . . . . . 236
About the CBEX Log File. . . . . . . . . . . . . . . . . . . . . . . . . 237
Invoking CBEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
CBEX Command Line Options and Flags. . . . . . . . . . . . . . 242
Getting Ready to Use CBEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
Loading the Directives file and Setting Up
the Directives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
Using Action Directives List to Directly
Specify and Set Up Directives . . . . . . . . . . . . . . . . . . . 251
Setting up a Directives File for Use in
Command Line Mode . . . . . . . . . . . . . . . . . . . . . . . . . . 252
Determining Which Form is Associated With
a Specific Form Module . . . . . . . . . . . . . . . . . . . . . . . . 253
Adding Comment Lines to a Directives File . . . . . . . . 253
Performing CBEX Operations-Global/Form Modules. . . . . . 255
Checking Syntax in Source Modules . . . . . . . . . . . . . . . . . . 255
Compiling and Importing Modules into the
Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Exporting Modules From the Database. . . . . . . . . . . . . 261
Purging Form Modules From the Database . . . . . . . . . 263
Exporting and Purging Modules From the
Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266

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

Chapter 15 Handling Date and Time


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
Converting Date Data Types Back to String . . . . . . . . . . . 307

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

Chapter 16 Accessing External Databases With SQL


Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Declaring a SQLDB Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Connecting to a Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Checking For a Valid Connection . . . . . . . . . . . . . . . . . . . . . . . 313
Disconnecting From the Database . . . . . . . . . . . . . . . . . . . . . . . 313
Issuing a Non-Returning SQL Statement . . . . . . . . . . . . . . . . . 313
Sample Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Issuing a SQL Select Statement . . . . . . . . . . . . . . . . . . . . . . . . . 315
Sample Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Invoking a Stored Procedure that Returns Values . . . . . . . . . 316
Sample Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316

Appendix A The Former Default Global File


Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
The Default CeFO Global File . . . . . . . . . . . . . . . . . . . . . 320

Appendix B Writing Procedures for DDE Clients


Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
What is DDE? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Link Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
What is Supported by CeFO Applications? . . . . . . . . . . . . 328
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
Using DDE Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
A Usage Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329

Appendix C ClearBasic Pre-Defined Constants


Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334

Appendix D Customization Methodology


Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
User Version Numbering for Forms . . . . . . . . . . . . . . . . . . . . . 338
Parallel Development of Forms . . . . . . . . . . . . . . . . . . . . . . . . . 339
Porting Customizations to Another Database . . . . . . . . . . . . . 340
Recommended Order of Customizations . . . . . . . . . . . . . . 340
Porting Individual Customizations . . . . . . . . . . . . . . . . . . . 340

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

This guide provides information about programming in ClearBasic. Key


concepts are introduced and how-to coding information is provided, along
with code samples and descriptions.

Audience for this Guide


Developers familiar with the CeFO applications and database.

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

Organization of This Guide


This programmer’s guide consists of the following chapter and appendixes:
• About This Guide
Provides an overview of the guide by summarizing individual chapters
and appendices.
• Chapter 1, Overview of ClearBasic
Describes ClearBasic and its relation to CeFO applications. Introduces
some concepts.
• Chapter 2, A Tutorial in ClearBasic
Provides a sample program that guides you through GUI creation, code
creation, and code compilation.
• Chapter 3, Design Requirements
Provides important considerations related to the design and
implementation of your code.
• Chapter 4, ClearBasic Language Fundamentals
Provides information on key parts of the ClearBasic language.
• Chapter 5, Contextual Objects and the CeFO GUI
Provides a detailed description of contextual objects.
• Chapter 6, Programming in Forms
Provides information you need to know before coding a form module.
• Chapter 7, Programming Controls
Provides details on creating forms and controls and coding them.
• Chapter 8, Programming Tabs
Provides details you need to know to program tabs and tab widgets.
• Chapter 9, Initializing Forms
Describes required code for form initialization and provides some useful
tips.
• Chapter 10, Accessing the CeFO Database
Describes the use of the BulkRetrieve and BulkSave objects in retrieving
data from the database and saving data to the database.

16 About This Guide


Organization of This Guide

• Chapter 11, Message Handling


Describes how to send messages between forms, how to handle the
messages that are sent, how to set up child and parent forms.
• Chapter 12, Customizing Menubars
Provides details on changing the standard menubars for the CeFO
applications.
• Chapter 13, Building Your Project
Describes what you need to do to develop and use forms and form
modules.
• Chapter 14, Testing and Debugging
Provides some details on debugging.
• Chapter 15, Handling Date and Time
Handling Date and Time.
• Chapter 16, Accessing External Databases With SQL
Describes what you need to do to communicate with databases using
SQL.
• Appendix A, The Former Default Global File
Lists the obsolete CeFO entries in your global file. Provided so you can
remove them from your globals.
• Appendix B, Writing Procedures for DDE Clients
Describes how to write a ClearBasic global procedure that can be
triggered by a DDE client.
• Appendix C, ClearBasic Pre-Defined Constants
Lists the predefined constants used by ClearBasic.
• Appendix D, Customization Methodology
Provides tips and suggestions for customizing.

About This Guide 17


What’s New in This Guide

What’s New in This Guide


This guide is a substantial revision of an earlier version. Here is what has
changed:
• Chapter 13, Building Your Project documents the new GUI-based CB
Exchange utility CBEX.
• Chapter 14, Testing and Debugging documents the new GUI-based CB
debugger.

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.

IMPORTANT: Highlights key considerations to keep in mind.

CAUTION: Highlights important situations that could potentially damage data or


cause system failure.

TIP: Highlights guidelines and helpful hints.

• Monospace is used for programming elements (such as code fragments,


objects, methods, parameters, and HTML tags) and system elements
(such as file names, directories, paths, and URLs).

18 About This Guide


Conventions

• Monospace bold is used to distinguish system prompts or screen


output from user responses, as in this example:
username: oracle
home directory: home\app\oracle
• Monospace italic is used for placeholders, which are general names
that you replace with names specific to your site, as in this example:
Clarify_home_directory\dbadmin\dbupgrade\
• Straight brackets signal options in command-line syntax.
deRead [-llf log_filename] [-debug]

About This Guide 19


Conventions

20 About This Guide


Chapter 1

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.

This chapter describes general characteristics of ClearBasic, including


• Its purpose
• Its object-based manipulation of the CeFO applications
• Its event-driven programming model
• Its place in the CeFO customization framework
• Its development environment
Even if you are familiar with Basic or Visual Basic, you should at least scan
through this chapter. In any case, you must understand how the
development environment works before you try to use ClearBasic.

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.

IMPORTANT: This product is a customization tool for existing CeFO applications.


It is not a development tool for creating new stand-alone applications.

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.

The ClearBasic Interpreter


The ClearBasic interpreter is embedded in the CeFO application. It performs
the translation between your code and the CeFO system, and vice versa.

ClearBasic Language Intrinsics


The ClearBasic language intrinsics include the functions and statements that
are normally provided in a Basic language for program flow control and
data manipulation. This guide assumes you are familiar with Basic
programming. If you are unfamiliar with Basic, you should consult one of
the many books available on the subject, along with the ClearBasic Language
Reference.

Overview of ClearBasic 23
What are Objects, Properties, and Methods?

ClearBasic Objects, Methods and Properties


The ClearBasic objects, methods, and properties (defined later in this
chapter) are the core of the ClearBasic product. They provide full and
simplified access to the CeFO system and encompass the following range of
functionality:
• Full control over all aspects of the CeFO user interface including the
following:
– facilities for getting or setting control values, displaying information
from the database, handling user selections or input, enabling or
disabling controls, and automating the flow of data from database to
control and back to the database through the use of contextual objects.
– facilities for initializing forms as desired before posting, posting and
closing forms, setting parent/child relations between forms, and
sending messages between forms.
– Facilities for modifying standard baseline CeFO forms by overriding
baseline functionality or by supplementing it.
• Full access to CeFO databases and non CeFO databases through
easy-to-use mechanisms.
• Full manipulation of database records and record fields through
easy-to-use objects and methods.
• Simplified and centralized control of application behavior through
application-wide objects and methods.

What are Objects, Properties, and Methods?


The way ClearBasic uses objects, methods, and properties is very similar to
the way Visual Basic uses them. So, if you are already familiar with Visual
Basic’s approach, the only new things you need to learn are the particulars
about ClearBasic.

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?

What Are Objects in ClearBasic?


An object is a pre-coded and logically coherent set of behaviors that you can
activate by invoking its internal procedures via method calls or by setting
values in its data fields via property settings (see Figure 1). For example, the
Printer object contains a variety of printing-related procedures and property
settings that affect printing, such as font family and font size.

Figure 1 ClearBasic Objects, Methods, and Properties

Object

Internal Methods
Procedures
CeFO
Application Data Fields Properties

Event Event Handlers


Monitor
Code

As indicated in Figure 1, an object is manipulated by its methods and


properties in order to obtain some desired effect in the application. The
object is just an interface, albeit a highly simplified one, between you and the
application behavior that you want to produce.

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.

Can You Extend ClearBasic Objects Using


Inheritance?
No. The ClearBasic object types and their methods/properties are fixed: you
cannot create a new object type by inheriting from an existing object and
then adding new functionality. (In this sense, ClearBasic is object-based,
rather than object oriented.)

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?

What Are Methods in ClearBasic?


In the definition of objects, we said that the object is a set of behaviors that
can be activated by calling its internal procedures. A method is the public
way to invoke the object’s private internal procedures.

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.

What Are Properties in ClearBasic?


An object’s set of behaviors can also be activated or modified by setting
values in certain of the object’s data fields using the published property
interface. A property is the public way to access an object’s private data
fields.

Again, as with methods, the advantage of keeping the property interface


logically separate from the object’s internal data fields is that it keeps your
code independent from CeFO changes.

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.

For method calls, the general syntax is:


Object.Method Parameter
For property settings, the syntax is:
Object.Property = Value
Of course, there are other details you’ll need to know to code in ClearBasic.
These are covered in the rest of this guide.

26 Chapter 1
ClearBasic Programming Fundamentals

ClearBasic Programming Fundamentals


To program in ClearBasic, you need to know about forms, controls, and
events, and you need to be prepared to write event-driven code.

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).

Figure 2 Sample Form and Controls

Sort By Form Code Handling Text


Filter By Box Input

Record List
Form
Form Code Handling List
Selection and Display.

Form Code Handling


Done Button Click.

As shown in Figure 2, ClearBasic forms consist of visual GUI components


and the form code for those GUI components. You create or modify the
form’s GUI components in the User Interface Editor; you create form code in
a text editor and import it into the database using the CB Exchange utility.

Database Storage of GUI Components


The GUI components of a form are system resources that are designed in the
User Interface Editor and stored in the CeFO database until the application
starts (runtime); then they are loaded into the client machine to be managed
by the native windowing system such as Windows or Motif.

Overview of ClearBasic 27
ClearBasic Programming Fundamentals

Database Storage of Form Code


You use a text editor to develop ClearBasic code for a form in a single file
called a form module. Then you import that code into the database using the
CBExchange utility. During the code import process, you associate the form
module with the form’s GUI component. Subsequently, when the
application is started, both the GUI component and the form code
component of the form are downloaded to the client. When a form is
actually loaded into memory (posted) in response to some event, its form
code initializes (form_load) the form and then waits to handle the specified
events. A form must be loaded before any of its code can be invoked.

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.

What are Events in Forms and Controls?


Events occur in forms and controls, normally caused by user activity such as
clicking on a form or control with a mouse, double-clicking to make a
selection, entering text via the keyboard, or even by planting a pair of size
nine Cordovans on the keyboard during a coffee break. You can only handle
those events that are supported for the form or control, but you can handle
those events in any way you wish.

Of course, you can always simulate user-generated events in your code by


invoking the appropriate method or by setting a property.

28 Chapter 1
ClearBasic Programming Fundamentals

Welcome to Event Driven Programming


Programming in ClearBasic follows the event driven model, in which you
write code to respond to some event that the user generates or that is
generated by some condition that occurs during the application session. This
type of programming is called event driven because you design procedures
to be activated by certain events and the general flow of control to be
directed by events. Because events are normally generated by the user, this
programming style is sometimes called “user-driven.”

This style of programming is in contrast with the program driven type of


coding where either the program runs itself after being invoked (batch
mode) or pauses only to prompt the user for certain expected input then
resumes control until it prompts the user again or finishes.

Writing Event Procedures


Most or all of the user activity handled in a form is handled within the form
module code in event procedures, which can in turn invoke general
procedures within the form or in the global module.

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.

Event Procedure Naming Conventions


Each event procedure must have a name that consists of the name of the
control and the name of the event: ControlName_EventName. For example, if
you wanted to create a click event procedure for a command button named
MyButton, you would call the event procedure MyButton_Click().

Overview of ClearBasic 29
ClearBasic and CeFO Customization

ClearBasic and CeFO Customization


ClearBasic is only one of several tools available for customizing the CeFO
database and applications. It is important to note this because your
customization work in ClearBasic requires you to use other tools, such as the
User Interface Editor and CB Exchange.

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.

CeFO provides the following customization tools:


• ClearBasic Toolkit (includes CBExchange)
• Data Exchange
• ddcomp, the schema compiler
• Data Dictionary Editor
• User Interface Editor
• API Toolkit
What each tool does is briefly described in Table 1.

Table 1 CeFO Customization Tools

Tool Description Other Tools Required


Data Imports customer data from legacy None
Exchange databases.
ddcomp compiles the schema file: required
if you add tables.
CB Exchange Imports ClearBasic code. None
Data Imports schema changes such as May require User Interface Editor to create
Dictionary new or modified table fields or corresponding form resources. May require CB
Editor new tables. Exchange to import ClearBasic code to link new tables
to the GUI. May require API toolkit routines to access
new tables programmatically, if you bypass the GUI.

30 Chapter 1
ClearBasic and CeFO Customization

Table 1 CeFO Customization Tools

Tool Description Other Tools Required


User Creates or modifies form resources. Requires CB Exchange to import ClearBasic code for
Interface Allows you to assign versions of new forms/controls.
Editor forms to specific users.
API routines Allows you to write applications Requires the data dictionary editor to perform any
that access the database, bypassing required database changes.
the CeFO application GUI

A visual synopsis of the customization tools is shown in Figure 3.

Figure 3 CeFO Customization Tools

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

CeFO Applications Customer


Application

Overview of ClearBasic 31
Customization Methodology

Function of Tools. As shown in Figure 3, Data Dictionary Editor modifies


the database itself, Data Exchange imports/exports customer data, CB
Exchange imports/exports ClearBasic code, and User Interface Editor
modifies the forms and controls of the CeFO application GUI. The API
routines provide a way to access customer data directly, bypassing the CeFO
applications GUI. (The API routines are an alternative to ClearBasic, they
currently cannot be called from ClearBasic code.)

Flow from database to client. As shown in Figure 3, when the CeFO


applications start up, the form resources and the code behind those
resources are downloaded from the database. They act as the conduit
through which customer data flows to and from the database.

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

Where to Find More Information


For more information, see the appropriate documentation:
• For information on the Data Dictionary Editor, see the Data Dictionary
Guide.
• For information on Data Exchange, see the Setting Up Your Data.
• For information on CB Exchange, see this guide.
• For information on the Data Dictionary Editor, see the Data Dictionary
Editor online help.
• For information on the User Interface Editor, see the User Interface Editor
Guide.
• For information on the API Toolkit routines, see the API Toolkit Reference
and the High-Level API Programmer’s Guide.

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.

Starting the UI Editor in ClearBasic Mode


To start the UI Editor in ClearBasic mode, do the following:
1. Display the Properties window for the UI Editor icon, and make sure that
the -cb option is specified for the uieditor.exe command.

36 Chapter 2
Starting the UI Editor in ClearBasic Mode

2. Double-click UI Editor icon.


The system displays the Session Login dialog box.

3. Enter the required information and then click Login.


The system displays the UI Editor window.

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

Lesson 1: Posting and Modifying an Existing


Form
The procedure for modifying an existing form is relatively straightforward.
You first post an existing form, modify it, and then save it as your own user
version. You can also first save it as your own version, modify it as needed,
and then repost it. Once you have saved it as your own version, you can
repost it any time and modify/save it as needed.

In this lesson, you will learn to do the following:


• Open an existing baseline Select Employee form
• Add a command button
• Change the caption of the button
• Save the modified form as a your own version
• Add the form to an existing Resource Configuration

38 Chapter 2
Lesson 1: Posting and Modifying an Existing

To modify an existing form:


1. Start the UI Editor with the -cb option.
2. From the Select menu, choose Form.
The system displays a Form Select window with no entries.

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

5. From the Controls menu, choose the Command Button command.


The cursor changes to a crosshair.
6. Position the cursor next to the List button and click the left mouse button.
A button labeled “Command Button” appears and the cursor resumes its
original arrow shape.

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.

8. Double-click the new button to display its attributes window:

A Tutorial in ClearBasic 41
Lesson 1: Posting and Modifying an Existing Form

9. Clear the Name/ID field and enter “Detail_Button.”


Make note of this string, i.e., Detail_Button. You will need to use this in
the CB code.
10. Clear the Label field and enter “Detail” in it to change the caption of the
new command button.
This is the label that will appear on the new command button.
11. Click Apply.
12. Click Done.
The Attribute window disappears and original form now looks as
follows. Notice the Detail button in the top right area.

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

First dropdown list

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

Lesson 2: Creating a New Form


In this lesson, you will learn to do the following:
• Create a new form
• Change its title.
• Add a contextual object
To accomplish these tasks:
1. If it is not already running, start the UI Editor with the -cb option to
display the UI Editor main window.
2. From the New menu, choose Form.
The system displays an empty form. Note that the form number shown
in the title bar is automatically created by the program.

3. Double-click the new form to display its attributes window:

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

Lesson 3: Adding Controls for the New Form


In this lesson, you will do the following.
• Add a command button that, when clicked, will change the form title.
The name of this button will be Change_Button and its label will be
Change.
• Add a text box that will be linked to the contextual object created in the
preceding lesson.
• Add a second command button that, when clicked, will populate the text
box from the contextual object. The name of this button will be
Potential_Button and its label will be Potential.
• Add a third command button that will close the new form and returns
you to the original form. The name of this button will be Done _Button
and its label will be Done.
• Add the form to the same Resource Config to which you added the
original Select Employee 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.

To accomplish these tasks:


1. In the UI Editor window, from the Select menu, choose Forms to display
the Form Select window.
2. Select User Version from the first dropdown list.
3. In the Filter Value text box, type “Terri” and click List.
4. Select the form with the title “More Information” and click Open.
5. From the Controls menu, choose Command Button.
The cursor changes to a crosshair.
6. Position the cursor in the right lower corner of the form and click the left
mouse button to place the new button.
7. Double-click the new button to display its attributes window.
8. In the Name/ID fields, enter “Change_Button” in the Name field. Leave
the ID field unchanged.
Make note of this string, i.e., Changel_Button. You will need to use this in
the CB code.

A Tutorial in ClearBasic 49
Lesson 3: Adding Controls for the New Form

9. In the Label field, enter “Change.”


This changes the button label to Change.
10. Click OK to apply the changes.
11. Using the process described in Step through Step above, add another
command button that has its Name set to “Potential_Button” and its
Label set to “Potential.”
Make note of this Name string, i.e., Potential_Button. You will need to
use this in the CB code.
12. Similarly, add another command button that has its Name set to
“Done_Button” and its Label set to “Done.”
Make note of this Name string, i.e., Done_Button. You will need to use
this in the CB code.
13. From the Controls menu, choose Text Box.
14. Position the cursor in the middle of the upper half of the form and click
the left mouse button to place the text box.
15. Double-click the text box to display its attributes window.
16. In the Name/ID fields, enter “Potential_Msg” in the Name field. Leave
the ID field unchanged.
17. Clear the Text field.

50 Chapter 2
Lesson 3: Adding Controls for the New Form

18. Double-click the text box to display its attributes window:

19. In the Name field enter TextBox1.


20. Click Destination to display the Contextual Objects Fields window:

A Tutorial in ClearBasic 51
Lesson 3: Adding Controls for the New Form

21. Select the Potential contextual object and click Use/Done.


The Contextual Objects Fields window disappears.
The text box is now linked to the contextual object Potential, which in
ClearBasic code will be referenced as Cobj_Potenial.
The form should now look like the following:

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

Lesson 4: Writing and Importing CB Code


In this lesson you write CB code modules for the Select Employee form
created in Lesson 1 and the new More Information form created and
developed in Lessons 2 and 3. Then, you will import these modules into the
CeFO database.

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.

To perform these tasks:


1. Using a text editor, such as Word Notepad, create a text file called
SelEm702.cbs that contains the following CB code:
Sub Form_Load()
Me.DoDeFault
End Sub
‘The following event-handler executes when the
‘Details button is clicked. It displays
‘the form whose ID is 1010
Sub Detail_Button_Click()
Dim TestF as New form
TestF.Show 1010, 0
End Sub
2. Create another text file named Details.cbs that contains the following CB
code.
(This code will be used for the new form 1010, More Information.)
Sub Form_Load()
End Sub

A Tutorial in ClearBasic 53
Lesson 4: Writing and Importing CB Code

‘The following event-handler executes when the


‘Change button is clicked. It changes
‘the form title to “This is a new title.”
Sub Change_Button_Click()
Me.Caption = "This is a New Title"
End Sub
‘The following event-handler executes when the
‘Potential button is clicked. It displays
‘a string in the text box.
Sub Potential_Button_Click()
COBJ_Potential.Fill "Employee is a super
performer. Suitable for supervisory position."
End Sub
‘The following event-handler executes when the
‘Done button is clicked. It closes the window and
returns you to the Select Employee window.”
Sub Done_Button_Click()
Me.Close
End Sub
3. Move the two files created in the preceding steps to the directory that
contains the CBEX program.
4. Import the CB code for the Select Employee form into the database by
running the following command from a DOS window:
cbex -spec Selem702.cbs -F 702 1.0 terri
The system displays the login dialog box for the CeFO database.
5. Enter the password and click Login.
The system displays a confirmation box indicating the success of the
import operation.
6. Click OK.
7. Import the CB code for the More Information form into the database by
running the following command from a DOS window:
cbex -spec Details.cbs -F 1010 1.0 terri
The system displays the login dialog box for the CeFO database.

54 Chapter 2
Lesson 5: Verifying the Form Operation

8. Enter the password and click Login.


The system displays a confirmation box indicating the success of the
import operation.
9. Click OK.

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.

Lesson 5: Verifying the Form Operation


To verify the functionality of the forms developed in the preceding lessons,
follow the steps described below. If any of the step fails, review the
preceding lessons and, if necessary, start all over again.

To verify the form operation:


1. Start and log into the CeFO database that contains your forms and CB
code.
2. From the File menu, choose License to display the CeFO License
window:

3. Check the ClearSupport check box and click OK.


This is necessary because the Select Employee form belongs to the Clear
Support application.
4. From the Apps menu, choose the ClearSupport option.
5. From the Select menu, choose the Employees option.
The system displays the Select Employees window:

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:

7. Click Change in the More Information window.


The title of the form should change to “This is a New Title.”

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.

Designing Your Project


Designing in ClearBasic has two aspects to it, namely, database
considerations and the user interface. On the database side, you need to
know what information you need to retrieve and store. On the user interface
side, you need to know what forms and controls to employ in order to
display information and retrieve user input.

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.

Ultimately, you need to familiarize yourself with the CeFO database by


studying the type of information presented in the CeFO applications and by
studying the Data Dictionary Guide. You need to be aware of the various
CeFO tables and views and the types of data they contain.

User Interface Considerations


During the design process, you must develop a fairly complete idea of the
type of user activity you want your forms and controls to support. Among
other things, you must decide which information from the database you
want to display in the controls and which type of user input you want the
controls to receive.

60 Chapter 3
Whether to Use a Form, a Frame or a Tab

Whether to Use a Form, a Frame or a Tab


At some point, your customization effort is likely to require you to create a
new form. When this occurs, you must be aware of the three flavors of CeFO
form that are available to you. Choosing the wrong form type for your task
can cause you a lot of unnecessary work; not knowing the differences
between the form types can cause you a lot of unneccessary grief.

Here are the types of CeFO form:


• Form
• Frame
• Tab
Each of these types is described below.

When to Use a Form


A new Form is a main window, created with the UI Editor by selecting
New--->Form from the menubar. The key thing to remember about a Form is
that it has NO contextual objects automatically linked to it: you need to link
it with all the contextual objects you plan on using in your code. Because
you don’t have to worry about inherited contextual objects and the problem
of maintaining these, this type of form provides the greatest flexibility

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.

When to Use Frames


A Frame is a sub-form linked to a parent form (that is, it is a child window).
You create this in the UI Editor by first selecting the parent form that you
want to link the frame to, then selecting New-->Frame from the menubar.
The key thing to remember about a frame is that it automatically inherits all
of the contextual objects currently linked to its parent at frame creation time.

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

Critical Frame Maintenance Issues


The crucial thing about using frames is that if you add new contextual
objects to a frame, you must also add them to the parent in the same order as
you added them in the frame. Likewise, new contextual objects added to the
parent must be added to the frame, in the same order.

When to Use Tab Frames


A tab frame, also called a tab, is a type of frame that is posted from a tab
widget. However, when the tab widget is clicked the tab form appears within
the parent form; it does not background the parent, as a frame does. As is the
case with frames, tabs also inherit the contextual objects currently linked to
its parent when the tab is created.

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.

If the reasons to use a Form don’t apply in this particular customization,


then using frames and tabs does cut down on development time since they
share the same contextual objects as their parent. They also eliminate a
possible source of errors since you do not have to code logic to pass data
between them.

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.

Critical Contextual Object Maintenance Issues


The crucial thing about using frames is that if you add new contextual
objects to a frame, you must also add them to the parent in the same order as
you added them in the frame. Likewise, new contextual objects added to the
parent must be added to the frame, in the same order.

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”.

Central Code Storage and Retrieval


When you import your form code modules into the database, you bind each
code module to the form for which it was designed. At run time, (every time
the application starts), the application forms and the code for the forms are
downloaded and cached at the client workstation. The forms and their code
are then posted from the cache in response to user activity during runtime.

Updating Code Modules


Because the code is centrally stored in the database, you can update a form
module for a form used by all the users who are assigned that form (via the
resource config mechanism) simply by making the desired changes to the
module and re-importing the module into the database. The changes will
take effect the next time the user restarts the application.

Flushing Code Changes to the Client During


Runtime
With some very important restrictions, you can update form code (and
forms!) and flush the updated forms and code to the CeFO client during
runtime, making use of the Update Desktop command invoked by the end
user at the client.

64 Chapter 3
Adding Code to Standard CeFO Forms

Here are the rules:


• You cannot update the global module during runtime. Changes to the
global module go into effect for the client only upon restarting the client.
• You cannot update form modules that depend on a global module that
was updated during runtime: doing so can cause a runtime error.
• If the form code does not rely on global code changed during runtime,
the new form and its form code will be successfully put into effect at the
client when the end user performs an Update Desktop.

NOTE: During the attempt to perform Update Desktop the end user may be
prompted to close all open windows, then repeat the Update Desktop.

Adding Code to Standard CeFO Forms


If you create an entirely new form, you can pretty much do what you want,
within the limits of the language. If you are tying some new ClearBasic code
to an existing (standard) CeFO form, you must be aware of what you must
do, what you can do, and what you cannot do.

Required Code for All Additions to CeFO


Forms
The first thing you must do before any coding activity in a standard CeFO
form is to create a form_load event procedure in your form module. At the
minimum, this procedure can be a dummy procedure consisting of the
following:
Sub Form_Load
Me.DoDefault
End Sub

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.

What Kind of Coding is Supported?


You can perform these types of activity in a standard CeFO form:
• Create a new event handler for a new control
• Create a new event handler for a standard control (you have to invoke
DoDefault either before or after your code, depending on where you
want the standard behavior to occur)
• Read the contents of a standard contextual object
• Fill a standard contextual object with your own value, as long as the
contextual object is not a list type
• If the contextual object is a list type, you can read its contents, replace
values in the list with your own values (of the same type!) and fill the list
back into the contextual object; just don’t add or subtract items so the list
is of a different size
• Create a Form_Save callback for the form which will execute your code
every time there is a Save activity generated from that form; you would
do if you wanted to save your own material to the database whenever a
standard CeFO Save occurred.
• Post other standard CeFO forms that are enabled to be posted from
ClearBasic calls, for example, ShowContact and ShowCase; see the
ClearBasic Object Reference for the various Show methods that are
supported

What Kind of Coding is Not Supported?


You cannot perform these types of activity in a standard CeFO form:
• Directly invoke underlying CeFO code functions
• Post standard CeFO forms that are not enabled for ClearBasic posting: if
you post these forms, they will appear, but will have no standard
functionality
• Fill a list of values into a standard contextual object that is a list type

66 Chapter 3
Maximum Character Limits for Names

Useful Tips for Coding in a Standard CeFO


Form
If your event handler executes after the standard CeFO default behavior,
you should always check the results of your Me.DoDefaults statement. If the
statement returns cbDefClosedWindow, this means that the default behavior
would have closed the form if not for the existence of your code. In this case,
you must perform a Me.Close at the end of your event handler.

Maximum Character Limits for Names


For function names and code module names you cannot exceed 80
characters. The first 20 characters must be unique.

Avoiding Errors Due to Lack of Stack Space


CeFO applications use two types of stacks, local and public. The local stack
holds the local variables (except strings and arrays) and the public stack
holds the public variables, including strings and arrays. You can modify the
size of these stacks by assigning different values to the cbStackSize and
cbPublicSize variables in the Clarify.env file for the application.

Setting the Local Stack


The ClearBasic execution engine assigns a local stack to every form that is
posted (known as a 'thread'). By default, the size of this stack is 8K. You can
reset this value by using an environment variable called 'cbStackSize'. You
can set this variable to no lower that 2K (2048) and no higher than 8K (8192)
in the Clarify.env file in the directory from which the CeFO client is started.
The syntax is cbStackSize = 8192.

Design Requirements 67
Calling External Routines

Possible Ways to Exceed the Stack


Even using the maximum stack size, you can run out of stack space if you
use a lot of variables that are declared inside functions and subroutines. You
can run into the same problem if these types of variables are large, such as
can be the case with user-defined types that contain large fixed-length
strings.

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.)

Setting the Public Stack


The cbPublicSize environment, set in the Clarify.env file, specifies the size of
the “public,” or “global” stack, which is shared by all local and public
variables, including strings and arrays.

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.

Calling External Routines


If you want to call routines in external DLLs, you need to use the Declare
statement. Note that you can do this only on the Windows platform. See the
ClearBasic Language Reference for more information on what you need to do.

Removing and Renaming Items in UI Editor


If you delete a control, or rename it, or rename or remove contextual objects
for a control or form, the ClearBasic code that depends on these will
generate an error at runtime. You can add additional controls.

68 Chapter 3
File Size and Pcode Limits for Code Modules

File Size and Pcode Limits for Code Modules


Each source code module can be a maximum of 60000 bytes: exceeding this
limit can prevent your code from compiling into Pcode when you import
into the database.

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.

Checking Your Code


Checking for results is normally good practice. With certain methods, you
can run into trouble if you don’t check. For example, if you don’t check the
results of the GetSelected method before processing the resulting record
variable, you could get a runtime error when you attempt to do this.
Suppose a record object was not successfully selected into that record
variable: if you subsequently executed the "GetField" method against that
record variable, you would get the following runtime error:
’This record has an unknown record type. The record type
property must be set before performing this operation.

If you don’t check results, then make sure to appropriately enable/disable


controls to prevent the situation that would cause this runtime error.

Using Contextual Objects


Contextual objects are described in detail in Chapter. However, the
following items are considerations you might want to have in mind during
the design phase.

Design Requirements 69
Using Contextual Objects

Three Main Categories of Contextual


Objects.
When you open the contextual object window in the UI Editor, you’ll notice
that there are quite of few listed there. Breaking all of them into their
categories will help you get a handle on what it is you’re looking at.

There are basically three categories of contextual objects: Database, UDTs, or


Temporary.
• A database contextual object is predefined for use with a specific CeFO
table or view or a specific custom table or view. Using one of these
contextual objects for a form or control means that you intend to use it (or
some fields in it) to contain a specific type of record or view.
• A UDT contextual object is a User Defined Type. Unlike database types,
which can only contain a specific database record or view, or specific
fields from a specific record or view, a UDT type can contain just about
anything from anywhere, within the limits of a UDT.
• A temporary contextual object stores primitive data that is not linked to
the database, but rather is calculated/displayed in memory only. This is
sometimes referred to as an in-memory contextual object.

Uses for UDTs as Contextual Objects


One of the best ways to use UDT contextual objects is for contextual objects
that are linked to custom lists. Previously, if you wanted to show 'ad hoc'
information in a custom list, you needed to use a database object type. This
meant that some applications created 'dummy' datatypes that were never
instantiated in the database but were used strictly to display information in
custom list.

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

When to Use Database Contextual Objects


If you have a control on a form that you want to populate with data from the
CeFO database, then you use a database contextual object.

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.

When to Use UDT Contextual Objects


There are two common scenarios which would require you to use a UDT
contextual object:
• If you have a custom list that needs to be populated with data from an
external database, you must create a UDT to handle the returned values.
The reason for this is that when the SQLDB object and its methods are
applied to an external database, only the specific record fields (i.e.,
primitive values) that you requested in your query are returned, not the
entire record object. Rather than create dummy objects in the CeFO
database to temporarily hold this data, you should use a UDT contextual
object.
• If you have a form in which you want to add a custom list that displays
data from both a database object (table or view) and also “calculated/
adhoc” data in one or more of the columns, then you must use a UDT
contextual object as the source of that custom list. The reason for this is
that the User Interface Editor only allows a single contextual object to be
the source for the custom list. You must create a UDT contextual object
that has the necessary fields defined, and then individually populate the
UDT with the appropriate data.

Design Requirements 71
Enabling and Disabling Controls

When to Use Temporary Contextual Objects


If you have a control(s) on a form that you want to populate with data that is
“adhoc/calculated” rather than from a specific database record or view, then
you use a temporary contextual object. This field is typically a read-only
field. A common example of this is the “Items” count associated with
custom lists.

Enabling and Disabling Controls


Enabling and disabling controls at certain times can be very effective.
Perhaps the best example of this is with Custom Lists. Usually these lists
have an Open button (or similar function like Add, Replace, Delete). It is
good practice to add ClearBasic code so that the button is initially disabled.
Then, when a user selects an item in the list, the button is enabled. When an
appropriate action occurs, such as opening or deleting the item, or clearing
the list, the button should be disabled. In other words, only have the buttons
enabled when the function for the button is appropriate. This normally
requires only minimal code.

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

Copy by Reference Versus Copy by Value


There are many methods which give you the option of executing “By
Reference” which means you are actually manipulating the original object,
or “By Value” which means you are manipulating a copy of that original
object. You need to be careful with this choice. Use By Reference if you want
to change the original version and By Value if you want to create a new
version using data from the original.

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.

IMPORTANT: When you are passing a structure (i.e. UDT) it has to be by


reference.

Performance Considerations
When designing your code, you need to be aware of relevant performance
issues. Some of these are described below.

Retrieve What You Need in Bulk


You should keep the number of round trips back to the database server to a
minimum, taking full advantage of the BulkRetrieve and BulkSave objects to
batch queries and database updates or insertions.

Design Requirements 73
Performance Considerations

Be Careful When Adding and Modifying


Views
There are times when customizations require adding one or more tables to
an existing view or adding an entirely new view. Be careful. You should
consider the following points:
• Although the RDBMS may allow a high limit of tables per view, every
table you add to a view slows it down, so be sure to add only the
necessary tables.
• If you are considering adding tables to an existing view for a new feature,
and some of the existing tables in that view are not needed for your new
feature, perhaps it might be better to create a new view that has only the
tables that your feature needs.
• Be smart about how you join the tables together. You may adversely
affect the key driving table(s) and thus hamper performance.
• Maintain your views. For instance, you may need to remove obsolete
tables from views if you change the application areas that utilize those
views.
• CeFO now supports outer joins in schema files. Make sure you know
whether the join you are adding should be an inner or outer join. If you
add an inner (default) join, and it should be an outer (optional) join, the
view will lose rows that it should include.

Use Global Functions and Procedures


When designing your customizations, be aware of the “big picture”. If there
is logic that will be needed in multiple places within this customization, then
create modular functions or subroutine procedures. If there is logic that is
needed for multiple customizations, then create global ones. If a certain
routine is very complex, break up the logic into more readable and
maintainable functions or procedures.

Having common code in one shared routine rather than duplicated


throughout various modules will reduce the maintenance effort, and also
increase supportability because it reduces the chance of missing individual
modules when upgrading this logic.

74 Chapter 3
Object Reference versus Language Reference

Object Reference versus Language Reference


If there is a Method, Property, or Object available within the ClearBasic
toolkit (as documented in the ClearBasic Object Reference), then that should be
used instead of whatever comparable entity is documented in the ClearBasic
Language Reference. The reasons for this are as follows:
• CeFO has redefined some of the BasicScript objects defined in that
language reference, and thus has changed what you can and cannot do
with these objects.
• ClearBasic objects, methods, and properties presents a different
methodology for dealing with some items than is described in the
language reference.
• The use of the BasicScript User Dialogs and Dialog manipulation
documented in the language reference is not supported.

Please refer to the “The CeFO ClearBasic Guide to Summit’s BasicScript”


section of the ClearBasic Language Reference manual. This contains a chart of
all the BasicScript Language components and identifies whether it is
supported by CeFO and on what platforms.

IMPORTANT: The Object Reference always has precedence over the Language
Reference.

Making Controls Visible or Invisible


Consider making controls visible/invisible to further reduce clutter. For
example, consider the New Case screen. You can add radio-buttons to allow
selection of parts or site_parts for a case. There is a set of controls for each of
these choices, and the radio button allows only one set to be used at one
time. Consider overlaying the controls in the same area, and making only
one set visible, based on the state of the radio button. This is much clearer
than putting two sets of controls on the screen at the same time.

Design Requirements 75
Use the SetFocus Method

Use the SetFocus Method


Make extensive use of the SetFocus method. SetFocus allows the
programmer to programmatically make any control the active control. This
is particularly useful in the form load method, and in validation methods.
When validating data (for example, when the Add button is pressed), if a
field value is not valid, it is useful to the user to put up an error message,
and then move the active focus to the control in error. If it is a text field, you
might also want to highlight the text for them.

TIP: Be aware of the properties associated with your controls. A control


must be both visible and enabled in order to have focus.

76 Chapter 3
Chapter 4

ClearBasic Language Fundamentals

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.)

ClearBasic Naming Requirements/Conventions


Some of the following naming conventions are enforced by the compiler,
and some are simply recommendations that should be followed unless you
have your own consistent set of naming standards.

Form Module Names


Table 2 lists the conventions for form module names.

Table 2 Naming Form Modules

Name Size Recommendations


Requirements Requirements
Names must start Names cannot Names should begin with the FormID.
with an exceed 80 Names should end with the CeFO Version and the User version
alphanumeric characters. of the associated form, if you have multiple versions of the same
character. form
Names should either be all lower case with an underscore as
necessary for readability, or mixed case with no underscore.
Modules should have an informative file identifier. You should
use “.cbs” to signify “ClearBasic Source”.
Example: 1009_4.0_1.0.cbs
This is a module for form ID 1009 with CeFO version 4.0 and user
version 1.0.

78 Chapter 4
ClearBasic Naming Requirements/Conventions

Contextual Object Names


For readability, contextual object names should either be mixed case with no
underscore, or all upper case with an underscore as necessary.

Table 3 lists the conventions for contextual object names:

Table 3 Naming Contextual Objects

Name Size Recommendations


Requirements Requirements
Names must start Names cannot Contextual objects should start with a three-character lower case
with the prefix exceed 80 prefix that reflects the specific ‘type’ of contextual object. Our
cobj_ characters. suggestions:
Name in form The first 20 los List of Selected elements
module must characters must Contextual object whose database type is LIST. This is
match name be unique. for the Destination of a custom list box control.
assigned at form lor List of Records
or control design Contextual object whose data type is a list of records
time. (CeFO database objects). This is for the Source of a
custom list control.
lou List of UDTs
Contextual object whose data type is a list of UDT type
items. This is for the Source of a custom list control.
lop List of Primitive type
Contextual object whose content is a list of primitive
type (i.e. string, long, single, etc.).
rec Single database record
Contextual object whose content is a single database
record.
udt Single UDT item
Contextual object that contains a single item of user
defined type.
pri Single Primitive type
Contextual object whose content is a single primitive
type (i.e. string, long, single).
Example: Cobj_lor_ContactView

ClearBasic Language Fundamentals 79


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.

Table 4 lists the conventions for control names:

Table 4 Naming Controls

Name Size Recommendations


Requirements Requirements
Cannot Use Names cannot Controls should start with a three-character lower case prefix that
Keywords. exceed 80 reflects the specific ‘type’ of control. Our suggestions:
Cannot use characters. chk check box
names already The first 20 btn command button
used by standard characters must
CeFO controls in be unique. dcb dropdown combo box
the form. txt text box
clb custom list box
lst list box
mle multi-line edit
ddl drop down list
opt option button
tab_d tab (required for tabs)
lbl label
Example: cbAvailableCourses

Other Important Considerations


When you modify a standard CeFO form, don’t rename the standard
controls in it. Some of the controls have inherent logic behind their names.
See the chapter on control programming later in this guide for more
information.

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.

However, for supportability reasons, you should start keywords with an


upper case letter followed by lower case letters for the remainder of the
word.

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.

Table 5 Naming Constants

Name Requirements Size Requirements Recommendations


Must start with a letter. Names cannot exceed For readability, constant names should either be
May contain letters, digits, 80 characters. mixed case with no underscore, or all upper case
and the underscore The first 20 characters with an underscore as necessary.
character. must be unique.
Cannot be a reserved word
(see Keywords in the
ClearBasic Language
Reference)

ClearBasic Language Fundamentals 81


ClearBasic Naming Requirements/Conventions

Variable Names
Table 6 lists the conventions for control names:

Table 6 Naming Variables

Name Requirements Size Requirements Recommendations


Must start with a letter. Names cannot exceed For readability, variable
May contain letters, digits, and the underscore 80 characters. names should either be mixed
character. The first 20 characters case with no underscore, or
must be unique. all upper case with an
Cannot be a reserved word (see Keywords in underscore as necessary.
the ClearBasic Language Reference)
Punctuation is NOT allowed. The exclamation
point (!) can appear within the name if it is not
the last character.
The last character of a variable name can be any
of the following characters if and ONLY if being
used as a type-declaration:
$ ‘string data type
% ‘integer data type
& ‘long data type
# ‘double data type
@ ‘currency data type
! ‘single data type

Methods and Property Names


The ClearBasic Engine is not case sensitive when referencing method and
property names.

However, for standards and supportability reasons, you should use Mixed
Case. For example, GetField.

82 Chapter 4
ClearBasic Naming Requirements/Conventions

Event Procedure Names


The ClearBasic Engine requires the following rules to be observed when you
name your procedures:

Table 7 Naming Event Procedures

Name Requirements Size Requirements Recommendations


Names must follow the convention Names cannot exceed For readability, event
control_event where control is the name of your 80 characters. procedure names should
control and event is the name of the event (i.e. The first 20 characters either be mixed case with no
click, keypress, activate, etc.). must be unique. underscore, or all upper case
For example: btnUseDone_Click (),‘ with an underscore as
necessary.
Form_load procedures must be named
form_load or they won’t work. The same for the The naming convention for
init_app procedure in the globals file. the control prefix should be
consistent with your naming
convention for the control

Subroutine Procedure Names


Table 8 Naming Subroutines

Name Requirements Size Requirements Recommendations


Must start with a letter. Names cannot exceed For readability, subroutine
May contain letters, digits, and the underscore 80 characters. names should either be mixed
character. The first 20 characters case with no underscore, or
all upper case with an
Punctuation is NOT allowed. The exclamation must be unique. underscore as necessary.
point (!) can appear within the name if it is not
the last character.

Function Names
The requirements/conventions are the same as for subroutines.

ClearBasic Language Fundamentals 83


Using Variables

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.

If a variable is in a subroutine or function (function-scoped), the variable


“goes out of scope” when that function or subroutine ends: all its data is
removed as a part of memory cleanup. If the variable is form scoped (in the
form module but outside of the function/subroutine bodies), the variable
lives until the form is closed.

If a variable is global-scoped, in the global module, it is always available to


all the form modules that need it.

What Kind of Variables Do You Need?


Let’s first review the three types of variables:
• A Local variable is available only within a particular procedure or
function (procedure-scoped). A local variable is defined within its
procedure or function. Note: this is the default type.
• A Modular variable is available throughout the form module
(form-scoped). A modular variable is defined within the form module
but outside of all its procedures and functions.
• A Global variable is available to all code in all form modules
(global-scoped). It must be defined both within the globals file and in
each form module that uses it.

84 Chapter 4
Using Variables

Restrictions on the Use of Variables (Stack)


You can run into trouble using variables in the following two ways:
• You use a lot of variables in your form module (“lot” is somewhat
subjective here)
• You use UDTs that are quite large (for example, ones that contain very
large fixed-length strings)

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.

Ways to Get Around the Stack Size Limit


How do you get around this stack size limit and still do what you need to
do? One way is to make variables form-scoped by declaring variables in the
form module outside of any procedure. You would want to do this if a
variable is used in multiple procedures within your form module. In this
way, you avoid declaring multiple occurrences of the same variable.

Using Methods/Properties Instead of Variables


Another way to avoid using up the stack is to use a ClearBasic method or
property in an “expression” instead of declaring a variable to store a value to
be used in the expression. For example, you could avoid the approach in
the following code snippet, which declares a variable:
Dim port as String
port = validatePortRecord.GetField ("port")
If (Screen.AllSpaces(port)) Then
App.MsgBox "Must input a valid Port Number"
Exit Function
End If

ClearBasic Language Fundamentals 85


Using Variables

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

An example of how a property could be used within an expression is shown


by this code snippet:
actLogRec.SetField “entry_time”, App.CurrentDate

This eliminates creating a variable to store the results of App.CurrentDate


only to turn around and use that variable value to set the value of the
entry_time field.

Declaring Variables of UDT or Primitive Type


Declaring variables of UDT or primitive type is fairly straightforward. You
just determine what scope (see below) you want the variable to have, then
declare it in the proper location, either in the global module, in a form
module outside any procedure, or inside a form module procedure. (Notice
that a variant type is really just a primitive type and is treated as such.)

Here are examples of declaring a string primitive and a UDT:


dim MyString as String
dim MyType as OneReallyBigCollection

Declaring Object Variables (Using NEW)


You’ll notice that some variable declarations use NEW, and some don’t. For
example:
Dim siteRecord as new Record
Dim siteObjid as Long

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

IMPORTANT: You must declare object variables within a subroutine or function. If


you try to define one in the globals file or the modular section of a form module, you
will get a compile error.

Initializing Certain Object Variables


The RecordType property initializes the record object variable, so make sure
that you place this in the correct area of the code module. It not only sets the
type, but it also initializes the record.

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.

Declaring Global Variables


Currently, you must declare global variables not only in the globals file, but
also in any of the form modules that need to use the global variable. The
global variables should be defined at the top of the form module, outside of
any functions or subroutines.

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.

ClearBasic Language Fundamentals 87


Using User Defined Types

Assigning to Object Variables (You Must


Use Set)
You must use the Set keyword when assigning into an object variable (i.e.
database object, contextual object, control). When assigning into primitive
type variables, or a UDT, you do not use the SET keyword.

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.

Using User Defined Types


User-Defined Types (UDTs) are structure definitions created using the Type
statement. UDTs are equivalent to C language structures. UDTs can be
passed to user-defined routines and external routines, and they can be
assigned. (For details on creating user defined types, see the ClearBasic
Language Reference.)

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

Declaring User-Defined Types


User-defined types (UDTs) can be declared in ClearBasic by using the
Type...End Type construct, for example, MyType in the following:
Type MyType
A as Long
B as Single
C as String * 20
D as String * 20
End Type

This declaration is roughly analogous to a C structure. Variables of this


type may be declared and used, and passed to other functions as
parameters, as in the following use of the MyType type:
Dim AnInstance as MyType
AnInstance.A = 1111
AnInstance.D = "abcde"

For more information, see the ClearBasic Language Reference.

Declaring UDTs as Contextual Objects


To use a UDT as a contextual object, the type must be declared in the
ClearBasic code for that form. Additionally, you must declare at least one
variable that uses this type. If you don’t do this, the compiler will optimize
out any UDTs that are not used in the module.

ClearBasic Language Fundamentals 89


Using User Defined Types

You can do this using the following example:


‘in the form module
Type MyType
A as Long
B as Single
C as String * 20
D as String * 20
End Type
‘in the form load procedure
Sub Form_Load()
Dim Dummy as MyType
End Sub

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.

Some Rules for Using UDTs


Rule 1: You must declare the type in the ClearBasic form module that uses it,
and you must declare at least one variable of that UDT type. (If you don’t,
the compiler will optimize out that UDT.)

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

Why and How to Use Constants


Using constants is the best way to keep your code readable and
maintainable. You can read the constant name and get some idea of what it
does, as opposed to some value. You can change the value in one place and
have it go into effect throughout your code.

Contextual Object Versus Control Manipulation


In ClearBasic, you can manipulate the contextual object behind a control or
you can manipulate the control directly, using the contextual object
methods/properties or the control methods/properties as appropriate.
Which approach is best depends on what you are trying to do. For instance
the following snippet which is trying to populate a UDT record of type
Contract_Record, could be accomplished in one of two ways:
‘Manipulating the contextual object
Dim contractRec as Contract_Record
Dim contractListas New List
Dim indexas Integer
contractList.ItemType = "Contract_Record"
index = clb_CONTRACTS.ListIndex
set contractList = Cobj_lou_Contracts.Contents
contractList.GetItemByIndex index, contractRec

ClearBasic Language Fundamentals 91


Using Functions and Subroutines

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.

Using Functions and Subroutines


Functions and subroutines make your code easier to maintain primarily
because they allow you to change your code in just one place. Also, they
make your code more readable.

Don’t Reinvent the Wheel


Before you sink any time into coding a function, scan through the ClearBasic
Language Reference manual and familiarize yourself with the pre-defined
functions that are available to you. Substantial functionality is already
provided in many areas, including data conversion, date/time
manipulation, string manipulation, and so on.

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.

When to Use a Function, When to Use a


Subroutine
Knowing which of these to use requires knowing what is different about
them. The key difference between a function and a subroutine is that a
function returns a value and a subroutine cannot return one. For that reason,
you would use a function if you wanted some value returned, as in the case
where you need to check on the success or failure of your code’s operation.
Likewise, if you wanted to use a procedure in an expression, you would
have to use a function.

NOTE: Interestingly enough, if in your subroutine you pass an object by reference


to the subroutine, you can indirectly check the status of a subroutine’s action by
checking some property in the object that was passed by reference.

Using Global Functions and Subroutines


If you want a function or subroutine to be available to all form modules, you
need to define it in the globals file.

Using Modular Functions and Subroutines


If you want a function or subroutine to be available only to procedures
inside a given form module, you must define it only inside that form
module.

ClearBasic Language Fundamentals 93


Using Functions and Subroutines

Declaring and Calling a Function


You must define a function within the form module before any of the
procedures or other functions that call it. If you don’t, you will get the
following cryptic runtime error “Return type is different from a prior
declaration.”

To declare a function, you use the following Function/End function body, as


follows:
Function YourFunctionHere() as Integer
‘your code here
End Function

To call a function, use the following syntax:


return_var = function_name (param_1, param_2, param_n )

Note that there are parentheses around the parameters and that a function
returns a value.

Declaring and Calling a Subroutine


To declare a subroutine, you use the following Sub/End Sub body, as
follows:
Sub YourSubHere
‘your code here
End Sub

To call a subroutine, use the following syntax:


subroutine_name param_1, param_2, param_n

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?

Don’t Call a Function as a Subroutine, and


Vice Versa
If you call a function and don’t use parentheses you will get errors.
Likewise, if you call a subroutine and do use parentheses, you will get
errors.

When Do You Use Parentheses in a Method Call?


Here is a general guideline for determining when to use parenthesis when
invoking a method:

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)

When the only thing the statement is doing is calling a method, no


parenthesis are needed. For Example:
myBulkRet.SimpleQuery 0, "case"

and
myMenu.AppendItem "Desktop", "New Item"

What Happens If You Make a Mistake With


Parentheses
If you either use parentheses when you shouldn’t, or don’t use them when
you should, you’ll get a compile error similar to this one:
Compile error on line 143 of ‘1007’:
SetField is not a method of the object
143: newAssignedPortRecord.SetField ("port_number",
port_no_value)

ClearBasic Language Fundamentals 95


When Do You Use Parentheses in a Method Call?

96 Chapter 4
Chapter 5

Contextual Objects and the CeFO


GUI

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.

The information in this chapter is presented almost as a tutorial, so you


should read this chapter sequentially. After you read this chapter, you
should have the knowledge you need regarding contextual objects.

NOTE: This chapter covers general concepts about contextual objects: for details on
programming with controls, see the chapter titled "Programming Controls."

What is a Contextual Object?


A contextual object is a memory area linked to a form in order to hold values
(somewhat like a data structure) for a control in the form. The main point to
notice in this definition is that contextual objects serve as memory storage
for controls. At this point, the definition may not seem terribly clear or
useful, but don’t panic; the definition should make more sense after you
finish this chapter.

98 Chapter 5
When Are You Required to Use Contextual Ob-

When Are You Required to Use Contextual


Objects?
You must use contextual objects if you create a new form, and you may need
to use them if you create a new frame or tab frame. You must use contextual
objects if you create new controls.You cannot concern yourself with
contextual objects until the basic form design phase is complete.

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.

Creating a Form: the Role of Contextual Objects


After you know what type of data your form and its controls are going to
contain, you can begin implementing your design by creating the form.
Because a form is useless without contextual objects, one of the most
important parts of the form creation process is to link contextual objects to
the form. You must link contextual objects to the form before you attempt to
create controls in the form.

Contextual Objects and the CeFO GUI 99


Creating a Form: the Role of Contextual Objects

Linking Contextual Objects to the Form


You start your implementation by creating a new form in the User Interface
Editor (in ClearBasic mode!) by selecting New in the main menubar, then
Form., This is only part of the creation process, however. You then need to
double click on the new form to display the Form Attributes window (see
Figure 4).

Figure 4 Form Attributes Window

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

Figure 5 Contextual Objects Window

Assigning a Name to the Contextual Object


When you link a contextual object, you need to assign a name to the
contextual object you want to link to the form. You do this by entering a
name in the Contextual Object Name text box, which is shown in the upper
left of Figure 5. This is fairly trivial: you can use any name you want,
although you may want to adopt some consistent naming conventions to
make your code easier to read.

The Contextual Object Name Becomes an Implicit Variable


When you assign a name to a contextual object for a form, the name becomes
an implicitly declared variable (with Cobj_ prepended to it) that you must
use when writing code in that form’s code module. You must use this when
you move data in and out of that contextual object with the ClearBasic
methods for contextual objects. For example, if you use the name MyContacts
for a contextual object that contains records from the Contact table, your
ClearBasic code that moves data to and from this contextual object must
refer to it as Cobj_MyContacts, as shown in the following code snippet:
Cobj_MyContacts.Fill MyRecordList

A point to emphasize is that an implicit variable for a contextual object is


automatically created when you link the contextual object to the form. You
don’t declare the contextual object variable in your code.

Contextual Objects and the CeFO GUI 101


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 the Contextual Object Data Type


After you assign a name to the contextual object, you must specify a data
type for it by clicking on the Database Object Type button and selecting an
item from the displayed list. The list that is displayed consists of primitive
data types (integer, string, etc.), any user defined types that you have
created, and the data types for the individual database tables and views.

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.

Determining Which Data Types to Assign


The data type you should assign to a contextual object depends entirely on
the control you intend to use with that contextual object. For example, if you
want to display a list of values in a list box, dropdown list box, or dropdown
combo box, you must assign the List primitive type. If you want to use a
contextual object to receive user input from a text box, you must assign the
String primitive type. The contextual object data types required for each
control are listed later in this chapter.

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

If You Forget to Link a Contextual Object


You may forget to link a particular contextual object to a form, or you may
discover during the control creation phase that you need another contextual
object. You can go back and link contextual objects to the form any time you
want (except runtime).

Placing Data into a Form’s Contextual


Objects
After you link contextual objects to the form, you could use ClearBasic code
to load data into the form’s contextual objects, although this data would be
hidden and inaccessible to the user because there aren’t any controls yet.

Placing Database Records Into a Contextual


Object
When you pull data from the database to load it into the form and display it
in the controls, you should be aware that only entire records (or entire rows
of views) are retrieved from the database. If you load this data into a
contextual object that has the appropriate database type specified, the entire
record or list of entire records is loaded into the contextual object. (see
Figure 6).

Contextual Objects and the CeFO GUI 103


Creating a Form: the Role of Contextual Objects

Figure 6 Contextual Objects Containing Database Data

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

objid instance_name serial_no ....


Custom List 2 xxxx widget4A 001 ....
xxxx widget24B 003 ....
xxxx widget22C 005 ....

ClearBasic Code
(Get data from database)

Database
(Contact
Site_Part)

In Figure 6, two contextual objects, MyContacts andMySiteParts are linked to


form 5050 and have the database types Contact and site_part, respectively.
Notice that the data they contain consists of entire records (or entire rows of
a view), a requirement for contextual objects that have database types.
(There is not enough room to show all the record fields, but if you’re curious,
you can find the complete list of the fields in Contact and Site_Part records
in the Data Dictionary Guide.)

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

Finally, to place everything in context, Figure 6 shows the layer of ClearBasic


code between the contextual objects and the database. You need to write the
ClearBasic code that performs the actual database access to get records and
load the records into the contextual objects. (Likewise, you need to write the
code that saves information back to the database.) How to write code that
accesses the database is described in the chapter titled "Accessing the CeFO
Database" later in this guide.

Sample ClearBasic Code


The following snippet gives an indication of how you would load the
records in Figure 6 from the database into a contextual object in Form 5050.
In the example, the lists of records are already retrieved from the database
into the BulkRetrieve object named MyBulk. The list of contact records is at
entry index 0 in MyBulk, the list of site part records is at entry index 1.
dim MyBulk as new BulkRetrieve
dim ContactList as new List
dim SitePartList as new List
Set ContactList = MyBulk.GetRecordList (0)
Set SitePartList = MyBulk.GetRecordList (1)
Cobj_MyContacts.Fill ContactList
Cobj_MySiteParts.Fill SitePartList

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.

Placing Values From a Single Field into Contextual


Objects
For controls that are not custom lists, you would not load entire records into
a contextual object. List boxes, dropdown list boxes, and dropdown combo
boxes, for example, all require a list of values from the contextual object. This
means that you must do some additional ClearBasic processing to get a list
of field values from the records and load that list into a contextual object
(one that has the list primitive type), rather than load the list of records
directly into a contextual object.

Contextual Objects and the CeFO GUI 105


Creating a Form: the Role of Contextual Objects

The following code indicates one way to do this:


dim MyBulk as new BulkRetrieve
dim ContactListas new List
dim NameListas new List
Set ContactList = MyBulk.GetRecordList (0)
ContactList.ExtractList NameList, "last_name"
Cobj_MyList.Fill NameList

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.)

Placing Local Data Into a Contextual Object


Loading local data into a contextual object is similar to loading records or
record fields into the contextual objects as described above. You must load it
into a contextual object that has a primitive type or a user defined type,
however. The following code shows one way to use local data:
dim MyBulk as new BulkRetrieve
dim ContactListas new List
Set ContactList = MyBulk.GetRecordList (0)
Cobj_MyContacts.Fill ContactList
Cobj_MyCounter.Fill ContactList.Count

In this code, a list of contact records is retrieved and dumped into


Cobj_MyContacts, then the count of the retrieved contact records is dumped
into Cobj_MyCounter, which has the integer primitive type.

106 Chapter 5
Creating a Form: the Role of Contextual Objects

Getting Data From Contextual Objects


To get data out of a contextual object, you can use the Contents property or
the GetContents method. (If the contextual object has a user defined type,
you must use GetContents.) The following code snippet illustrates this:
dim qryObj as New Record
dim bulk as New BulkSave
set qryObj = Cobj_Edit_Query.Contents
bulk.ChangeRecord qryObj
bulk.Save

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."

Using One Contextual Object With Several


Controls
You may find it useful to link the individual fields of a single contextual
object to several controls, such as text boxes, check boxes, and so on. For
example, you could do this to allow the user to fill in data in a record.

Contextual Objects and Existing CeFO


Forms
If the form you are working with is an existing CeFO form, you may not
need to link any additional contextual objects because contextual objects are
already linked to those forms. You need to link additional contextual objects
only if you want to add controls for local or database data that is not already
provided by the form’s current set of contextual objects.

Contextual Objects and the CeFO GUI 107


Creating a Control: the Role of Contextual Objects

Contextual Objects and New Frames


If a form cannot display all of the particular information you want
displayed, you can create a frame, rather than a new form, to display that
"overflow" information. When the user clicks on a tab button or a More
button on the parent form, the frame is posted to display the additional
information. The frame has all of the contextual objects that its parent form
has, so you do not normally link additional contextual objects.

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.

Creating a Control: the Role of Contextual


Objects
In the CeFO system, once you link contextual objects to the form, you have
the memory containers for all of the data that your form makes available to
the user. However, to actually display the data contained in those contextual
objects or to enable users to interact with that data, you must create controls
and link them to the appropriate contextual objects.

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-

Figure 7 Attributes Window for List Box

In Figure 7, notice the two command buttons labeled Source and


Destination. You use these buttons to link contextual objects to the control.
You can link only one source contextual object and only one destination
object to a control. "Source" and "destination" are explained below.

Source and Destination Contextual Objects


Source. You need to link a contextual object as a source to a control if you
want initial values to be loaded into the control when the form is posted.
You must link source contextual objects to list boxes, dropdown list boxes,
dropdown combo boxes and custom lists. If you don’t, these controls will
contain no values for the user to select.

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.

Contextual Objects and the CeFO GUI 109


Creating a Control: the Role of Contextual Objects

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.

Destination. You must link a contextual object as a destination to a control to


hold the item that the user selects or enters. For example, the destination
contextual object for a dropdown list box contains the string that the user
selects; the destination contextual object for a text box contains the text
string the user enters. You should be aware that the destination contextual
object merely contains the value or values: you still must write ClearBasic
code to get this value and use it.

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.

Control and Source/Destination Matrix


Table 9 lists each control type and indicates whether source and/or
destination contextual objects are supported:

Table 9 Controls, source, and destination

Control Source Destination


Check Box Yes Yes
Command Button Yes No
Custom List Yes Yes
Dropdown Combo Box Yes Yes
Dropdown List Box No Yes
Label Yes No
List Box Yes Yes
Multiline Text Box No Yes
Option Button Yes Yes
Text Box No Yes

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.

Linking a Source Contextual Object to a


Control
To link a source contextual object to a list box, click on the Source command
button, which is shown in the upper left of Figure 7. This posts the
contextual object fields window (see Figure 8).

Figure 8 Contextual Object Fields Window

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.

Contextual Objects and the CeFO GUI 111


Creating a Control: the Role of Contextual Objects

Controls and Data Types


An important fact to notice in Figure 7 and Figure 8 is that you cannot link
just any available field in the contextual objects window to your control.
Each type of control has a different requirement regarding the type of data it
can accept. The required data types for each control’s source and destination
contextual object are listed in Table 10:

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.

Linking a Destination Contextual Object to a


Control
To link a destination contextual object to a list box, click on the Destination
command button (see Figure 7) to post the contextual object fields window
(see Figure 8). Link the list box to a contextual object that has the type List.

112 Chapter 5
Creating a Control: the Role of Contextual Ob-

Sample Interaction Between Control and


Contextual Objects
Figure 9 shows a list box that displays a list of names from a source
contextual object. When a user selects one of these names, that name string is
returned to Cobj_MyString. In this case, the string "Treacle" is returned. One
use of a value returned from a list box or dropdown list box is to use it as an
argument to the AppendFilter method to help specify which records are to
be retrieved from the database.

Figure 9 Flow of Data Through Contextual Objects

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)

Contextual Objects and the CeFO GUI 113


Summary of Contextual Objects

Summary of Contextual Objects


Contextual objects are memory storage spaces of a specified type that are
linked to a form when a form is created; they serve as conduits through
which data flows into and out of controls. When you create a control, you
normally select one of the form’s contextual objects to be the source of initial
data in the control and another of the contextual objects to be the destination
of the value selected or entered in the control.

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.

What You Need to Do First


Before you start coding a form module, you need to create all of the GUI
components first, using the User Interface Editor. (A tutorial is provided in
Chapter 2.) You need to do this first because your form code will reference
control names, contextual objects, and possibly form IDs, all of which are
assigned at GUI design time.

Initialization
Form initialization is described in Chapter 9 of this guide.

What Every Form Module MUST Have


No matter which type of coding activity you want to perform, from
modifying something in an existing CeFO form, to creating a new form, a
new frame, or new tabs, you must put in a form_load procedure in your
form module.

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

Types of CeFO Forms


If you are creating a new form, you should be aware of the three options
available to you, form, frame, or tab frame. These are described in Chapter 3
of this guide. You can also write a form module for an existing CeFO form,
frame, or tab frame, again following the requirements listed in Chapter 3 of
this guide. In this guide, we refer to standard CeFO forms, frames, and tab
frames generically as “forms.”

If You Do ANY Programming in a CeFO Form


You can get into trouble very quickly if you customize in a standard CeFO
form. Here are the key things you need to do to stay out of trouble.

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.

Special Form_Load Requirements


If you write any code for a CeFO form, even just a button click event
handler, you must have a form_load procedure for that form and you must
also call DoDefault somewhere in that form_load procedure. If you have
code in that procedure that you want executed before CeFO initialization,
call DoDefault after that code. If you want the default CeFO initialization to
happen first, call DoDefault before your code, as follows:
Sub Form_Load
Me.DoDefault
‘your code here....
End Sub

Programming in Forms 117


If You Do ANY Programming in a CeFO Form

If You Add Code for a Standard Control


If you write an event handler for a standard CeFO control, you must call
DoDefault somewhere in your procedure code. Call it before your code if
you want standard CeFO behavior to happen first, call it after your code if
you want your code executed first.

Like this:
Sub MyButton_Click()
Me.DoDefault
‘Your code here....
End Sub

If You Add a Message Handler to a Standard


Form, or to a New Frame or Tab Frame
CeFO has default message handlers for its own forms. If you add your own
message handler, that message handler will intercept all CeFO system
messages, which will cause undesirable behavior. So you need to make sure
the CeFO messages get through to their own handler.

To allow CeFO system messages to pass through to the default handler,


handle your own messages, then call DoDefault for all other messages. One
way to do this is to use the Case...Else construct as follows:
Sub Message (ByVal messageNum as Long,
ByVal messString as String)
Select Case messageNum
Case cbCloseMessage
Me.Close
Case Else
Me.DoDefault
End Select
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.

Reading and Writing to CeFO Contextual


Objects
You can read from and write to standard CeFO contextual objects in a form,
so long as that contextual object is not a list type. The values you write will
be handled by the CeFO system.

If the contextual object is a list type, you are currently limited to only
reading that list.

If You Create a New Form, Frame, or Tab Frame


If you create a new form, frame, or tab frame, make sure you create at least a
dummy form_load procedure for each of them.

New Forms Require a Message Handler


For new forms only (not new frames or tab frames), you must create a
message handler that handles the Close message. Like this:
Sub Message (ByVal messageNum as Long,
ByVal messString as String)
If messageNum = cbCloseMessage Then
Me.Close
End If
End Sub

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.

Programming in Forms 119


If You Create a New Frame or Tab Frame

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.

If You Create a New Frame or Tab Frame


If you create a new frame, you should be aware of a few crucial things about
parent form/frame behavior.

IMPORTANT: Tab frames are covered in Chapter 8, so look there for details.

You Must Maintain “Mirroring” of Contextual


Objects
When you create a frame, it automatically inherits all of the parent’s
contextual objects. After the creation of a frame, if you add any contextual
object whatsoever to a parent form, you must also add it manually to any of
the parent’s frames.

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.

You Must Add Contextual Objects in the


Same Order
You must add contextual objects in the same order in the parent and in the
frame. For example, if you add contextual object A, then contextual object B,
then contextual object C to the parent form, then you must add first A, then
B, then C to the frame.

120 Chapter 6
If You Create a New Frame or Tab Frame

Form Activation Happens for Parent Only


You should count on the form activate and deactivate events happening for
the parent form only, not for its frames.

Passing Information Between Parent Form and


Frame
There are two ways to pass information between parent and frame: via
messages, and via the reading of contextual objects. (Remember, they all
have the same contextual objects, so they all have immediate access.) The
preferred method is by reading from and writing to the contextual objects,
first, because it is simplest, and second, because it is less prone to error than
messaging.

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.

Programming in Forms 121


If You Create a New Frame or Tab Frame

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.

Code Execution and Control Updating


During the execution of a ClearBasic procedure, redraw is delayed until the
entire procedure is finished in order to obtain better performance. In most
cases, this works transparently.

However, in some cases this behavior may be undesirable, especially where


your code manipulates the GUI in ways that affect user access to forms or
controls, such as operations that enable or disable controls. What could
happen is that controls may not actually be disabled (or enabled) until the
entire procedure is finished executing. This could result in unexpected
results. In these situations, use the ForceRedraw method to force execution
of the code up to the point where ForceRedraw is called.

Control Names and Reserved Keywords


When you assign a name to a control in the User Interface Editor, you can
use any name you want, if the name is unique within the form module code.
However, if the name you assign is a reserved keyword, the name is
automatically prepended with CTL_. For example, if you named a control
"ACCESS", the name assigned is CTL_ACCESS, for example,
Ctl_Access.Enabled = TRUE

Note that Ctl_ is prepended only on control names that are reserved
keywords.

124 Chapter 7
Control Names and Reserved Keywords

Table 11 lists all of the reserved ClearBasic keywords:

Table 11 ClearBasic Reserved Keywords

Keyword Keyword Keyword Keyword


ACCESS EQV MKDIR SHARED
ALIAS ERASE MODULE_NAMEMOD SINGLE
AND ERR MSGBOX SPC
APPEND EROR NAME STATIC
AS EXIT NEXT STEP
BEEP EXPLICIT NOT STOP
BINARY FOR NULL STRING
BYVAL FUNCTION ON SUB
CALL GLOBAL OPEN TAB
CASE GOTO OPTION TEXT
CLOSE IF OR THEN
COMPARE IMP OUTPUT TO
CONST INPUT PRINT TYPE
CURRENCY INTEGER RANDOM TYPEOF
DECLARE IS RANDOMIZE UBOUND
DEFAULT KILL READ UNLOCK
DIM LBOUND REDIM UNTIL
DO LEN REM VARIANT
DODEFAULT LET RESET WIDTH
DOEVENTS LIB RESUME WHILE
DOUBLE LINE RETURN WRITE
ELSE LOCK RMDIR XOR
ELSEIF LONG SEEK
END LOOP SELECT

Programming Controls 125


What You Can and Cannot Put Into a Control

What You Can and Cannot Put Into a Control


The type of control determines the type of value you can place into it. For
example, text boxes accept only string values (and only one line of text!
otherwise use the multiline text box). This is probably fairly obvious.
However, what may not be obvious is the fact that not every control type can
accept a list of values: for example, you cannot place a list of string values in
a text box. (Instead, you must extract one string value from a list and place it
into the text box.)

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!

Programming Check Boxes


The following information on using check boxes assume that you have
already created the form and linked contextual objects to it, as described in
Chapter 5 "Contextual Objects and the CeFO GUI."

Creating a Check Box


Create a check box control as described in the User Interface Editor Guide.
When you create the check box, notice that you can assign several attributes
to the check box (see Figure 10).

126 Chapter 7
Programming Check Boxes

Figure 10 Assigning Attributes to 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.

Visible, Disabled. Leave these checked and unchecked, respectively. 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. 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.)

Programming Controls 127


Programming Check Boxes

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.

Coding a Check Box


You can code a check box using either control methods or contextual object
methods, depending on which is more convenient.

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.

Setting the Initial State


During the form load event, all contextual objects that are not explicitly
initialized are filled with initial values automatically at the end of the form
load procedure. Therefore, you are not required to explicitly set the initial
state of the check box; you can use the initial setting that is provided
automatically.

Setting the Initial State Using Control Properties


In some cases you may want the check box to be always checked or always
unchecked when the form is posted. To set the desired initial state, you can
use the Value property to set the desired value in the form_load procedure.
Assigning the value 0 makes the box unchecked; assigning the value 1
makes the box checked, as in the following:
Sub Form_Load()
YourCheckBox.Value = 1 ‘ the check box is checked
End Sub

128 Chapter 7
Programming Check Boxes

Setting the Initial State Using Contextual Object Methods


You can also set the initial value of the check box control using the
contextual object Fill method, as shown in the following code snippet:
Sub Form_Load()
Dim CheckOff as Integer
CheckOff = 0
Cobj_YourChkBox.Fill CheckOff
End Sub

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.

Checking For a Checked/Unchecked Condition


There are two ways to determine whether the check box is checked: by
checking the control value directly, or by getting the value from the
contextual object and checking that value. Which of these approaches is
optimal depends on what you want to accomplish. If you are doing some
record-based processing in which one of the record fields is set by a check
box, you might want to get the value from the contextual object.

Checking the Control Value


The simplest way to check the current state of the check box is to read the
value of the control:
If YourCheckBox.Value = 1 then
‘do this
Else
‘do that
End If

Programming Controls 129


Programming Check Boxes

Checking the Contextual Object Value


You can also get the checked/unchecked value from the contextual object.
The following pseudo code illustrates how you would do this in the case of a
contextual object that contains records, one field of which is an integer field
linked to the check box:
Retrieve the record list from the contextual object
Get the value in the record field that is linked to the check box.

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

The above example retrieves records from a contextual object


(Cobj_Case_Rec) and places them in a list. The code then loops through
this list of records. In each iteration of the loop, a record is retrieved, and the
value of three fields in that record (subtotal_cat, extension, and
billable) are retrieved.
Notice the line
billable = sumElem.GetField("billable")

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

Writing "Check Box-Sensitive" Code


The following code sample is part of a loop that cycles through a list of
records to obtain the values in three fields. In each iteration, the value in the
first field (Category) is used in a Select Case construct, with each possible
case being further tested for the check box state (the field "billable"). If the
check box is checked, the value in the field "extension" is assigned to the
variable billtime.
Dim recList as New List
Dim sumElem as New Record
Dim Category as String
Dim extension as double
Dim billable as Integer
Dim billtime as double
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")
Select Case Category
Case "T"
If billable = 1 Then
billtime = extension
Else
billtime = 0
End If
Case "E"
If billable = 1 Then
billtime = extension
Else
billtime = 0
End If
End Select

Programming Controls 131


Programming Command Buttons

Programming Command Buttons


Command buttons are useful for posting windows, or invoking some
procedure.

Creating a Command Button


Create a command button 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 11.

Figure 11 Assigning Attributes to Command Buttons

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.

Visible, Disabled. Leave these checked and unchecked, respectively. 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.

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.)

Coding a Command Button


Coding a command button is fairly straightforward. You need to write a
click event procedure for it. Here is a sample one:
Sub MyButton_Click()
MyButton.Caption = "Hello"
End Sub

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.

Programming Custom Lists


You use a custom list control to display a list of objects, such as a list of rows
from a view or from a user defined type. The user can select one or more
rows in this control, depending on design time attribute settings.

Programming Controls 133


Programming Custom Lists

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.

Creating a Custom List


NOTE: Before you create a custom list control in the User Interface Editor, go to
the File menu, select Preferences, then change the mode to Platform Independent.

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

Figure 12 Assigning Attributes to 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.

Programming Controls 135


Programming Custom Lists

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

Labeling the Custom List


A custom list control has no self-labeling abilities. Therefore, if you need to
label this control, you must place a Label control next to it.

Coding a Custom List


When you write code for a custom list, you typically need to do the
following:
• Load data into the custom list to display it
• Write a button click event procedure and selection double-click event
procedure that are identical except for their names. If you want to these
procedures to post another form, the event procedure must
– Get the user’s selection and put it where the new form you are calling
can get it.
– Invoke the form_load event for the new form; that form_load event
procedure executes in entirety before returning control back to the
calling event procedure. This procedure gets the user’s selection and
does whatever else you want it to do.
– Enable/disable any controls on the calling form, if required.
– Invoke SetParent, if this is desired.
– Perform any other actions before returning control to the newly posted
form.

Loading Data Into a Custom List


You can load data into a custom list in two ways:
• Load data into the control using AppendItem on the control.
• Load data into the contextual object using the Fill method.
Each of these methods is described below.

Programming Controls 137


Programming Custom Lists

Using AppendItem to Load Custom Lists


The AppendItem method allows you to append either one record or one list
of records to the control. The records you append must have the same data
type as the contextual object that is used as the source for the control. For
example, if the source contextual object has the database type "Case", you
can only append 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 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

The following example specifies a list variable (MyList) to contain records,


then retrieves some case records from the database. The list of case records
retrieved is placed into MyList then is appended into the custom list control.
Dim MyList as new List
Dim MyBulk as new BulkRetrieve
MyList.ItemType = "Record"
MyBulk.SimpleQuery 0, "case"
MyBulk.AppendFilter 0, "title", cbIn, "ClearBasic"
MyBulk.RetrieveRecords
Set MyList = MyBulk.GetRecordList(0)
MyCustomList.AppendItem MyList

138 Chapter 7
Programming Custom Lists

Using Fill to Load Custom Lists


You can use Fill during form load or at any other time to load data into the
source contextual object for the custom list. (The data loaded in this way is
automatically displayed in the custom list.) However, you need to be aware
that Fill overwrites any existing data in the contextual object.

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

The following example specifies a list variable (MyList) to contain records,


then retrieves some case records from the database. The list of case records
retrieved is placed into MyList and then is filled into the source contextual
object for the custom list control.
Dim MyList as new List
Dim MyBulk as new BulkRetrieve
MyList.ItemType = "Record"
MyBulk.SimpleQuery 0, "case"
MyBulk.AppendFilter 0, "title", cbIn, "ClearBasic"
MyBulk.RetrieveRecords
Set MyList = MyBulk.GetRecordList(0)
Cobj_MyCustomList.Fill MyList

Programming Controls 139


Programming Dropdown Combo Boxes

Writing an Event Procedure to Handle User


Selection
You need to write an event procedure to handle the user’s selection of an
item in the control by clicking on a command button or by double-clicking
on the item itself (this is actually a form click event). Use the same event
procedure for both events, but name them differently, as follows:
‘This is for button click
Sub MyButtonName_Click()
‘This is for doubleclick event on the selected item
Sub MyCustomListName_DblClick()

Programming Dropdown Combo Boxes


You use a dropdown combo box to allow the user to select from a list of
simple values (not lists of objects!). Its functionality and use is closely related
to the dropdown list box control. Frequently, the selected value is used for
filtering purposes. Notice that dropdown combo boxes do not allow the
multiple selection of items; the user can select only a single item.

Creating a Dropdown Combo Box


Create a dropdown combo box 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 13.

140 Chapter 7
Programming Dropdown Combo Boxes

Figure 13 Assigning Attributes to 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.

Programming Controls 141


Programming Dropdown Combo Boxes

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.

Labeling the DropDown Combo Box


A dropdown combo box control has no self-labeling abilities. Therefore, if
you need to label this control, you must place a Label control next to it.

Coding a DropDown Combo Box


Coding for dropdown combo boxes is identical to dropdown list boxes. See
"Coding a DropDown List Box" later in this chapter for more information.

142 Chapter 7
Programming Dropdown List Boxes

Programming Dropdown List Boxes


You use a dropdown list box to allow the user to select from a list of simple
values (not a list of objects!). Frequently, the selected value is used for
filtering purposes. Notice that dropdown list boxes do not allow the
multiple selection of items; the user can select only a single item.

Creating a Dropdown List Box


Create a dropdown list box 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 14.

Figure 14 Assigning Attributes to 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

Programming Controls 143


Programming Dropdown List Boxes

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.

Object Col. Leave this unchecked.

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.

Labeling the DropDown List Box


A dropdown list box control has no self-labeling abilities. Therefore, if you
need to label this control, you must place a Label control next to it.

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.

Coding a DropDown List Box


You can write code for a dropdown list box that does the following tasks:
• Fill the dropdown list box with values to be displayed to the user
• Get the string selected by the user
• Get the index of the item selected by the user
• Select an item in your code
The following section describes how to write the code corresponding to
these tasks.

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.

Filling the Dropdown List Box with Values


You can fill this control with a list of values using the AppendItem method
on the control or by using the Fill method on the control’s source contextual
object. Both of these approaches are described below.

Using the AppendItem Method


The following code snippet fills a dropdown list with a list of values:
MyDropDown.AppendItem "CA"
MyDropdown.AppendItem "PA"
MyDropDown.AppendItem "WA"

Using the Fill method


The following code snippet fills a dropdown list control with a list of values
using Fill:

Programming Controls 145


Programming Dropdown List Boxes

MyDropDown.Fill MyStatesList

where MyStatesList is a list of some state names.

Getting the User’s Selection (String)


The user’s selection results in a string value (the selected item) being placed
in the contextual object or control.

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

Getting the Index of the User’s Selection


The user’s selection results in a string value (the selected item) being placed
in the contextual object or control. To get the index, you would use the
SelectedIndexes property, as follows:
Dim MyIntVar as integer
MyIntVar = MyDropDown.SelectedIndexes

Selecting an Item Through Code


Instead of waiting for the user to select an item from the dropdown list box,
you can select an item in your code. You would do this, for example, if you
want a particular item to be displayed in the control when the form is
posted.

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.

Figure 15 Assigning Attributes to a Label Control

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"

Programming Controls 147


Programming Labels

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

Using a Label to Display Values


Although you may think there’s not much you can do with a label other than
toggle the caption, you can use a label to display values, for example you
could use a label to display a count of records. However, the label displays
only string values, so you must convert non string values to string before
loading them into the control.

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)

After this line is executed, the label displays the count.

148 Chapter 7
Programming List Boxes

Programming List Boxes


You use a list box to allow the user to select from a list of simple values (not
a list of objects!). Frequently, the selected value is used for filtering purposes.
List boxes do not allow the multiple selection of item; the user can select
only a single item.

Creating a List Box


Create a dropdown list box 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 16.

Figure 16 Assigning List Box Attributes

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

Programming Controls 149


Programming List Boxes

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.

Labeling the List Box


A list box control has no self-labeling abilities. Therefore, if you need to label
this control, you must place a Label control next to it.

Coding a List Box


Coding a list box is the same as a dropdown list box or a dropdown combo
box, which are described earlier in this chapter. Refer to those sections of the
chapter for more information.

150 Chapter 7
Programming Multiline Text Boxes

Programming Multiline Text Boxes


Multiline text boxes are used to accept multiple lines of user input or display
multiple lines of information. In CeFO applications, multiline text boxes are
commonly used to fill or edit certain record fields that support multiple lines
of text, normally consisting of user notes or comments that are stored with
the record, for example, log notes or case history for a case.

NOTE: Multiline text boxes do not accept lists of values!

Creating a Multiline Text Box


Create a multiline text box control as described in the User Interface Editor
Guide. When you create the text box, notice that you can assign several
attributes to it as shown in Figure 17.

Figure 17 Assigning Attributes to a Multiline Text Box

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

Programming Controls 151


Programming Multiline Text Boxes

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.

Text, Format. Leave the Text and Format fields blank.

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

Labeling the Multiline Text Box


A multiline text box control has no self-labeling abilities. Therefore, if you
need to label this control, you must place a Label control next to it.

Coding a Multiline Text Box


You can manipulate multiline text boxes in a variety of ways, including
using it to enter user notes of one sort or another. This chapter covers only
the display of text in this control.

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

Displaying Values in a Multiline Text Box


Although you can display values in a multiline text box, you normally
would not use this control for this purpose; instead, you should use the text
box control. However, if you want to do this, see the example provided for
the text box control.

Programming Option Buttons


Option buttons are used to present mutually exclusive choices to the user.

Programming Controls 153


Programming Option Buttons

Creating an Option Button


Create an option button as described in the User Interface Editor Guide. When
you create the control, notice that you can assign several attributes to it as
shown in Figure 18.

Figure 18 Assigning Attributes to an Option Button

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.

Visible, Disabled. Leave these checked and unchecked, respectively. 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.

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.)

Programming Tab Widgets


Using tabs is an effective way to display "sub forms" (also called tabbed
frames) as if they were part of the parent form. The tab widget control
appears as a visible tab in the parent form; when clicked, it posts the sub
form without sending the parent form into the background. The whole
purpose of this control is to simplify navigation for the user and to make the
data in the tabbed form more accessible from the parent.

Anomalies in Creating Tabs


The tab widget is not listed in the list of controls in the UI Editor, nor is there
a separate Attribute dialog for this control. Instead, you create it as an option
button and assign it the desired attributes using the Option Button
Attributes dialog. What identifies it as a Tab to the CeFO system is the name
you provide (as described later under the Name attribute).

Programming Controls 155


Programming Tab Widgets

Essential Facts and Some Limitations of


Tabs
Tabbed frames and contextual objects. Currently, each tabbed frame must
have the same identical contextual objects as the parent form. This has
several consequences:
• You must create a new Frame and not a new form to use as the tabbed
form (a frame has all of the contextual objects of the parent at the time of
frame creation).
• If you subsequently add contextual objects to the parent, you must add
them in the same order to all of the tabbed forms.
• If you want to add new contextual objects to a tabbed form you must first
add the contextual objects to the parent form, then add them in the same
order to all of the tabbed forms.

General limitations. The following limitations currently apply:


• You can have only one set of tab widgets per parent form.
• You can have only one row of tab widgets per parent form.
• Both color and size of the tab label is fixed.
• You must have a form load event procedure for each tabbed form

Creating a Tab Widget


To create a tab widget, create an option button as described in the User
Interface Editor Guide. When you create the control, notice that you can assign
several attributes to it as shown in Figure 19.

156 Chapter 7
Programming Tab Widgets

Figure 19 Assigning Attributes to Tab Controls

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.

Size attributes. The tab label size is fixed.

Programming Controls 157


Programming Tab Widgets

Label. Enter the label you want displayed next to this control.

AutoSize. Don’t select this.

Visible, Disabled. Leave these checked and unchecked, respectively. 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.

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.)

Labeling Tab Widgets


You can set the label at design time using the label field, or you can label it
via the source contextual object. Try to keep the label fairly short; the tabs do
not resize to accept larger labels.

Coding Tab Widgets and Tabs


You don’t write a click event handler for tab widgets. The CeFO system
automatically posts the frame when the widget is clicked. If you do write an
event handler to do this, it will override the system behavior, which is not
recommended.

Each tab frame must have a form_load procedure, or it won’t function.

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.

For more information, see the chapter on Programming Tabs.

Programming Text Boxes


Text boxes are used to accept a single line of user input or to display a single
line of information. In CeFO applications, text boxes are commonly used to
fill or edit certain record fields or for filtering. You can also use a text box to
display a string value, for example, you can use it to display a count of
records returned from the database.

NOTE: Text boxes do not accept lists of values!

Creating a Text Box


Create a text box control as described in the User Interface Editor Guide. When
you create the text box, notice that you can assign several attributes to it as
shown in Figure 20.

Figure 20 Assigning Attributes to a Text Box

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).

Programming Controls 159


Programming Text Boxes

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.

Text, Format. Leave the Text and Format fields blank.

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

Labeling a Text Box


A text box has no self-labeling abilities. Therefore, if you need to label a text
box, you must place a Label control next to the text box control.

Coding a Text Box


You can manipulate text boxes in a variety of ways. This chapter covers the
following ways to code a text box:
• Displaying Initial Text
• Displaying Values
• Using a Text Box in a Selection Mechanism

Displaying Initial 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:
YourTextBox.Text = "Display this text."

where YourTextBox is the name of the control, and "DisplayThisText." is the


desired text string.

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

Displaying Values in a Text Box


A common use of a text box is to display a value. For example, you can use a
text box to display a count of records. If you use a text box for this purpose,
you should make the text box read only either at design time or at run time
using the ReadOnly property.

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.

Programming Controls 161


Programming Text Boxes

Using Contextual Object Methods


The following code converts an integer value (a count) to a string, then loads
it into the destination contextual object for the text box:
Cobj_MyTextBox.Fill str$(MyList.Count)

After this line is executed, the text box displays the count.

Using Control Properties


You could also achieve the same result by using the Text property to write
directly to the control:
MyTextBox.Text = str$(MyList.Count)

Using a Text Box in a Selection Mechanism


As shown in Figure 21, text boxes are frequently used together with
dropdown list boxes to implement filtering. The values selected and entered
are supplied as filter conditions appended to a query that is sent to the
database.

162 Chapter 7
Programming Text Boxes

Figure 21 Using a Text Box For Filtering

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.

Programming Controls 163


Programming Text Boxes

Sample Form_Load Code


For the dialog in Figure 21, you need to include the following lines in the
form_load procedure for the form.
Sub Form_Load
Dim DropList1 as New List
Dim DropList2 as New List
DropList1.AppendItem "Site ID", "Name"
DropList2.AppendItem "Starts With", "Ends With",
"Contains", "Is"
‘the contextual object MUST be a List type
Cobj_DropDownSource1.Fill DropList1
Cobj_DropDownSource2.Fill DropList2
End Sub

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.

Sample Button Click Event Procedure


Once the form in Figure 21 is posted, the user is able to select values and
enter a text string. The click event procedure for the List button must accept
this information and get the specified Site records from the database and
display them in the custom list control.

The following code shows one way to implement this functionality;


comments explaining the code are included in the sample.
Sub List_Click()
’Declare variables. Notice that object variables
’are declared with keyword New.
Dim site_info as string
Dim FiltField as string
Dim FilterCond as string
Dim FiltSpec as string
Dim Filter as string
Dim FilterOp as integer
Dim CLList as new List

164 Chapter 7
Programming Text Boxes

BulkRet as new BulkRetrieve


‘Get the user selection from the first dropdown.
’This gets the value from the destination
’contextual object. You could alternatively get
’the value using the control property Selected on the
control.
Set site_info = Cobj_DropdownDest1.Contents
’Depending on the user selection, put a field name
’into FiltField; this will be used as the second
’parameter in an AppendFilter statement.
Select Case site_info
case "Site ID"
FiltField = "site_id"
case "Name"
FiltField = "name"
End Select
’Get the user selection from the second dropdown,
’then get user input from the text box.
Set FilterCond = Cobj_DropdownDest2.Contents
FiltSpec = Textbox1.Text
Select Case FilterCond
’Depending on the user selection, put a filter
’operator (a Clarify-defined integer constant) in
’FilterOp; this will be used as the third parameter
’in an AppendFilter statement.
’Depending on which filter the user selects,
’concatenate the wildcard character % with
’the user’s text string (FiltSpec) and store the
’whole thing in Filter. This will be used as the
’fourth parameter to ApppendFilter.
case "Starts With"
Filter = FiltSpec & "%"
FilterOp = cbLike
case "Ends With"
Filter = "%" & FiltSpec
FilterOp = cbLike

Programming Controls 165


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.

Peculiarities of CeFO Tabs


The following items are some crucial facts about tabs.

A Tab Widget is Not a Tab Frame


Like tabs in other environments, CeFO tabs consist of a tab widget that
fronts the tab when clicked, and the tab frame, which gets fronted when you
click the tab widget. Keeping this distinction in mind will help you avoid
trying to trap form events in the tab widget or widget events in the tab
frame. Remember that a widget and a tab frame support different sets of
properties and methods (see the ClearBasic Object Reference for details).

Posting the Tab: No Code Required


The CeFO system automatically posts the tab frame when the widget gets
clicked (or when you set the widget value property to 1). You don’t code an
event handler for the tab widget click event to post the tab frame.

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.

Tip: If You Need a Widget Click Handler


You can write an event handler for the widget click, as long as you don’t
post the tab frame in your event handler. However, MAKE SURE you invoke
the DoDefault method somewhere in that event handler.

168 Chapter 8
Crucial Facts About a Parent Form and Its Tabs

Crucial Facts About a Parent Form and Its Tabs


Both at form/control design time and when you write your code you need
to remember a few crucial things about parent form/tab frame behavior.

You Must Maintain “Mirroring” of Contextual


Objects
When you create a tab frame, it automatically inherits all of the parent’s
contextual objects. After the creation of a tab frame, if you add any
contextual object whatsoever to a parent form, you must also add it
manually to each of the parent’s tab frames.

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.

You Must Add Contextual Objects in the Same


Order
You must add contextual objects in the same order in the parent and all
tabbed frames. For example, if you add contextual object A, then contextual
object B, then contextual object C to the parent form, then you must add first
A, then B, then C to each of the tab frames.

Form Activation Happens for Parent Only


You should count on the form activate and deactivate events happening for
the parent form only, not for its tab frames.

What Happens To Tabs During Form_Load?


When the parent form is posted, its form_load procedure is processed first,
then the Form_Load event of the default tab is processed. The Form_Load
events of the other tabs are not processed until they get a user generated or
programmatic event.

Programming Tabs 169


Designing Your Tabs: What Not to Do

How Do You Front the Tab?


Set the widget value property to 1 (integer), like this:
MyWidget.Value = 1

Avoid Invoking Tab Form_Load From Parent


Form_Load Procedure
As mentioned earlier, when the parent is posted, only parent and default tab
form_load procedures are processed. The reason for this is that there can be
a substantial performance penalty if all the tab form_loads were processed
every time you post the parent.

For that reason, you should avoid invoking the form_load procedures of the
tabs from the parent’s form_load procedure.

Designing Your Tabs: What Not to Do


Generally, each tab should have a separate functionality and display
different information than the parent form or the other tabs. Also, you need
to be careful in your method of passing information between parent and
tabs.

170 Chapter 8
Creating Tab Widgets and Tab Frames

Don’t Link a Contextual Object Field to


Multiple Controls
You should not use the same contextual object field for more than one
control. For example, don’t link the same field in a contextual object to a text
box in the parent and to a text box in a tab frame.

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.

Passing Information Between Parent Form and


Tabs
There are two ways to pass information between parent and tabs: via
messages, and via the reading of contextual objects. (Remember, they all
have the same contextual objects, so they all have immediate access to the
same data in them.) The preferred method is by reading from and writing to
the contextual objects, first, because it is simplest, and second, because it is
less prone to error than messaging.

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.

Creating Tab Widgets and Tab Frames


The procedures for creating tab widgets and frames are described in detail in
the User Interface Editor Guide. (Read that material before creating tabs.)
However, there are a few things that are important enough to highlight
again here.

Programming Tabs 171


Parent/Child Relation Set Automatically for Tabs

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.

Parent/Child Relation Set Automatically for Tabs


The parent/child relationship is set automatically for tabs. (The parent is the
parent form, the children are its tab frames.) This means that you do not use
the SetParent method to set this relation for tabs and their parent.

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 forms can be customized versions of existing CeFO default forms or


totally new forms that are created by the users.

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.

initializing a new form


If the form is an entirely new form that you created, the Form_Load
procedure can be an empty procedure or it can be quite an elaborate one.
The general format for the Form_Load procedure for a new form is as
follows:
Sub Form_Load()
‘Optional, additional
‘initialization code
‘appears here.
End Sub

Initializing a Customized Version of a CeFO Form


Each of the standard CeFO forms has a predefined default appearance and
behavior. For example, it can have a set of controls (such as text boxes, lists,
command buttons, etc.) that act/react in a manner specified by the
underlying code.

To activate the default behavior in the customized versions of the default


CeFO forms, you must include a Me.DoDefault statement in the beginning
of the Form_Load procedure. Otherwise, the results will be unpredictable.

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

Typical Initialization Tasks in Form_Load


For a new form, you use the Form_Load procedure to perform all the initial
setup and behavior specified by the user-written ClearBasic code. For a
customized version of a standard CeFO form, you use the Form_Load
procedure to activate all the underlying default behavior for that form and
the customized setup and behavior specified by the user-written ClearBasic
code.

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

Initializing Forms 175


Some Tips on Initialization

The following Form_Load procedure shows some of the typical


initialization you can perform:
Sub Form_Load()
Dim RCourse as New Record
Dim ListCourses as New List
Dim bulkR as New BulkRetrieve
Dim retVa as Integer
Me.DoDefault
course_title.RequiredColor="Urgent"
course_length.RequiredColor="Low"
course_location.RequiredColor="Important"
course_start_date.RequiredColor="Weak"
RCourse.RecordType = "courses"
Cobj_the_course.Fill RCourse
Cobj_courses.Fill ListCourses
bulkr.SimpleQuery 0, "courses"
bulkr.RetrieveRecords
Set ListCourses = bulkr.GetRecordList(0)
Cobj_courses.Fill ListCourses
Me.DisableControls "Replace", "Delete"
End Sub

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.

Some Tips on Initialization


Have your form load method initialize any captions that might change
during normal usage of the form. Otherwise, when you re-enter that form, it
will have the "changed" value rather than the initial value.

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.

Initializing Forms 177


Some Tips on Initialization

178 Chapter 9
Chapter 10

Accessing the CeFO Database

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.

ClearBasic provides two objects for accessing the CeFO database:


BulkRetrieve, for retrieving records and BulkSave, for inserting records,
updating existing records, deleting records and relations, and relating
records.

IMPORTANT: This chapter applies to CeFO databases only. For information about
foreign (non CeFO) databases, see Chapter 16 "Accessing External Databases
Using SQL."

This chapter provides details on the following:


• For BulkRetrieve:
– Description of the BulkRetrieve object
– The three types of query and how to use them
– Filtering queries and sorting query results
– Getting the returned query results from the BulkRetrieve object
– Breaking large queries into smaller blocks so the database server can
handle them
• For BulkSave:
– Description of the BulkSave object
– Inserting new records into the database and updating existing
database records
– Deleting records from the database
– Relating and unrelating records
– Database saves and the Form_Save callback

180 Chapter 10
Overview

Retrieving Records With BulkRetrieve


You must use a BulkRetrieve object to retrieve records from a CeFO
database. Notice that only a complete record can be obtained using the
BulkRetrieve object; if you want to manipulate individual fields you need to
first retrieve the entire record or view row in a BulkRetrieve object, then use
the appropriate Record or List methods to perform the desired work.

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.

Description of BulkRetrieve Objects


In the following description of the BulkRetrieve mechanism, an overview is
sketched out first and afterward the central methods of the mechanism are
described in more detail.

Declaring and scoping. BulkRetrieve objects can be declared in the form


module and can be form scoped. They are declared as follows:
Dim YourBulkRet as new BulkRetrieve

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.

Accessing the CeFO Database 181


Overview

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

Synopsis of the BulkRetrieve Mechanism


Figure 22 shows the flow of the BulkRetrieve operations.

Figure 22 The BulkRetrieve Mechanism

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

Record1 GetRecordList(0) Index 0


List1 Record2 List of case records
RecordN Record1
Record2
RecordN
Index 1
Record1 GetRecordList(1) List of CR records
List2 Record2 Record1
RecordN Record2
RecordN

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.

Accessing the CeFO Database 183


Overview

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.

Querying the Database


As previously mentioned, there are three query methods for the
BulkRetrieve object:
• SimpleQuery
• TraverseFromRoot
• TraverseFromParent
SimpleQuery can be used at any time. TraverseFromParent and
TraverseFromRoot require a prior retrieval of the record that is used as the
parent record and the root record, respectively.

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.

When you specify a SimpleQuery for a BulkRetrieve, you need to specify an


index for it; make sure you assign these sequentially from 0. You also need to
specify, in lowercase, the name of the table or view you want to search. You
can specify standard CeFO tables or your own tables.

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)

Accessing the CeFO Database 185


Overview

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.

Also, notice how GetRelatedRecordList is used. The simple query brings


back a list of case records, and the traverse from parent brings back a list of
log notes for each case. We can get the list of case records easily by doing an
itembyindex call, but how do you get to those multiple lists of log notes?

Accessing the CeFO Database 187


Overview

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.

How Many TraverseFromParent Queries Per BulkRetrieve?


You can stack up these queries to more than one level, if you want. For
example, you could retrieve a list of records with a simple query, then use a
traverse from parent to get a list of related records for each of the simple
query’s records. Then you could do another traverse from parent query to
get a list of related records for each record in each list of the first traverse
from parent query.

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.

Filtering and Sorting


Filtering. Normally, you need to supply at least one filter condition for each
query in the BulkRetrieve, using the AppendFilter method. AppendFilter
appends one filter condition to a query; if you want to use several filters,
you need to use AppendFilter once for each filter. (The filters are ANDed
together.)

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.

Sorting. By default, all of the fields in the records returned in the


BulkRetrieve are sorted in ascending order. If you want to change this, you
can specify a different sort order for a field using the AppendSort method.
You must use AppendSort once for each field whose sort order you want to
change.

Retrieving Query Results from the


BulkRetrieve
The records returned in the BulkRetrieve are not usable unless they are
retrieved from the BulkRetrieve and placed into a List object. There are two
methods you can use: GetRecordList and GetRelatedRecordList.

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)

In this example, the SimpleQuery at entry index 0 returns a list of records at


the same index, 0. This index is passed to GetRecordList, which returns the
list of records at that index in the BulkRetrieve to a List object, List1.

GetRelatedRecordList. If the query is a TraverseFromParent that returns


more than one list, you must use this method to retrieve the records out of
the BulkRetrieve.

Accessing the CeFO Database 189


Saving to the Database With BulkSave

Breaking Up Large Queries


The queries contained in a BulkRetrieve object are translated into SQL
statements prior to being sent to the database. Depending on the number
and type of queries, the amount of SQL that is generated can be quite large.
However, some database servers place limits on the size of an incoming
block of SQL statements that they will service, and will not process queries
that exceed these limits.

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.

Saving to the Database With BulkSave


You must use a BulkSave object to save records or relations back to the CeFO
database. Normally, to reduce network round trips, you should batch up in a
single BulkSave object the records and relations you want to save to the
database.

BulkSave and transaction states. When a BulkSave object is used to save


data to the database, it uses the same mechanism that is used by the
standard CeFO executable. That is, the new and modified objects and
relations in a BulkSave are committed in a single transaction. The
transaction is automatically rolled back if there is an error and deadlocks are
automatically detected and retries are attempted until the transaction
succeeds or a certain configurable number of failures is reached.

190 Chapter 10
Saving to the Database With BulkSave

BulkSave and Form_Save callbacks. Because the same mechanism is used


by CeFO default applications and BulkSave operations, it is possible to
insert a callback in a form module for a default CeFO form that intercepts all
default CeFO Save operations in order to perform manipulations and
checking via BulkSave before the transaction is committed. This is described
in detail later in this chapter.

Description of BulkSave Objects


In the following description of the BulkSave mechanism, an overview is
sketched out first and afterward the central methods of the mechanism are
described in more detail.

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

Of course, if you declare a BulkSave object within a form procedure, its


scope is limited to that procedure.

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.

Accessing the CeFO Database 191


Saving to the Database With BulkSave

Inserting New Records into the Database


To insert a new record in the database, use the InsertRecord method. You
need to supply the record to insert, as shown in the following example:
Dim MyRec as New Record
Dim NewRec as New Record
Dim BulkSav as New BulkSave
set MyRec = Cobj_CustList.Contents
set NewRec = MyRec.Copy(cbChangeToNew)
BulkSav.InsertRecord NewRec
BulkSav.Save

In the above example, notice the parameter cbChangeToNew: this parameter


resets the objid field in the copy (NewRec) so that it will be treated as a new
record. If you copy an existing record and want to insert it as a new record,
you must do this or invoke ChangeToNew.

A new record does not have a valid objid until the Save method is invoked
on the BulkSave.

ByValue and ByRef in BulkSave Operations


For InsertRecord, and other BulkSave methods, you’ll notice an optional
parameter that specifies ByValue or ByRef, with the default of ByRef. This is
a critical parameter that you need to pay attention to.

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)

when executed, MyRetRecord, the record in MyRec that is now in MyBulkSav,


and the external variable MyRec all refer to the same underlying record. This
means that whatever is changed in MyRetRecord is changed in the record in
MyBulkSav and MyRec; whatever is changed in MyRec is changed in
MyBulkSav and MyRetRecord, and so on.

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.

Objids and BulkSave Operations


Objids for records are assigned by the database server when the records are
saved for the first time to the database. Therefore, if you create new records
and fill in some of the fields, do not fill in the objid field. A valid objid is
assigned to each new record when Save is invoked on the BulkSave object.

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.

Accessing the CeFO Database 193


Saving to the Database With BulkSave

Updating Records in the Database


To update an existing record in the database, use the UpdateRecord method.
You need to supply the record to update, as shown in the following example:
Dim MyRec as New Record
Dim BulkSav as New BulkSave
Set MyRec = Cobj_CustList.Contents
BulkSav.UpdateRecord MyRec
BulkSav.Save

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.

Deleting Records from the Database


To delete an existing record in the database, use the DeleteRecord method.
This method deletes the record and any relations to the deleted record. You
need to supply the record to delete, as follows:
Dim MyRec as New Record
Dim BulkSav as New BulkSave
Set MyRec = Cobj_CustList.Contents
BulkSav.DeleteRecord MyRec
BulkSav.Save

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.

Instead of DeleteRecord, you can use DeleteRecordByID, if you have the


objid of the record you want to delete from the database.

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.

Accessing the CeFO Database 195


Saving to the Database With BulkSave

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

MyBulk.UnRelateRecords, Rec1, Rec2, "relate_this2that"

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.

Database Saves and the Form_Save


Callback
If you create a form module for a standard CeFO form, you may occasionally
want to intercept the default CeFO save operations to the database. You may
want to do some last minute checking on the data, or you might want to add
in your own changes to records or relations to be saved in the same
transaction as the standard CeFO save.

NOTE: These callbacks are entirely optional. You are not required to use any of
them.

ClearBasic provides three flavors of callbacks to intercept these standard


CeFO saves:
• Form_Save1: intercepts before any database transactions for the default
CeFO behavior: after records and relations are added but before any
objids of new records have been assigned. Use this callback to cause your
changes to take effect before any default CeFO changes.
• Form_Save2: intercepts after the objids of any new records have been
assigned, but before records or relations have been committed to the
database. Use this callback to cause your changes to take effect after
default CeFO operations assign objids to new records.
• Form_Save3: "intercepts" after records and relations have been
committed to the database. Use this to save your changes after default
CeFO operations are finished.

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.

Accessing the CeFO Database 197


Saving to the Database With BulkSave

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.

Creating a Form_Save Callback


To create a Form_Save callback, insert the following procedure anywhere in
your form module code:
Sub Form_Save1(YourBulkSave as BulkSave)
Dim YourBulkSave as new BulkSave
‘Dim whatever you want here
‘Do your BulkSave operations here whatever
’you do, DON’T invoke the Save method
End Sub

CAUTION: When you perform the BulkSave operations in a form_save callback,


NEVER call the Save method. Doing so can cause unpredictable results. The
default CeFO behavior will cause the BulkSave changes to occur.

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.

As indicated in the example, once in the callback, the BulkSave can be


examined and manipulated using the BulkSave properties and methods. In
the callback, you can examine the objects of the BulkSave using the
CountByType or GetRecordByIndex methods. Also, you can modify the
BulkSave using the normal BulkSave methods such as UpdateRecord,
InsertRecord, and so on.

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.

Accessing the CeFO Database 199


Saving to the Database With BulkSave

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.

This chapter provides information on the requirements of messaging: which


forms must have message handlers, and how you must code all of your
handlers.

In addition, this chapter describes passing messages to forms and between


forms, including information on the related methods, message constants,
and required procedures to handle the messages.

IMPORTANT: You can send a message to a form only if is loaded into memory.

How Many Message Handlers Per Form?


You can have just one handler for a form.

When are You Required to Have a Message Event


Handler?
If you create a new form (one that is not a frame or tab frame), your form
code module for that form requires a message handler. Why? Because every
form must be able to handle the Close message from the CeFO system.
Although standard CeFO forms, frames, and tab frames all have CeFO
message handlers built in to handle the Close message (and other messages)
new forms do not. You must create a message handler to handle at least the
Close message.

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-

What Code is Required in Every Message


Handler?
Every message handler must do at least the following two things: handle the
CeFO system Close message, and have a Case Else statement that invokes
DoDefault. The following code is an example:
Sub Message (ByVal messageNum as Long,
ByVal messString as String)
Select Case messageNum
Case cbCloseMessage
Me.Close
Case Else
Me.DoDefault
End Select
End Sub

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.

Message Handling 203


What Numbers Can Be Used For Messages

What Numbers Can Be Used For Messages


The recommended method for numbering is to use values beginning with
the value cbFirstMessage + 1. Other numbers may conflict with the CeFO
numbers. (However, if you like to live dangerously, valid numbers are in the
range of 5000 to 30000; numbers in the range of 500 to 4999 are reserved for
CeFO.)

What Message Passing Functionality is


available?
ClearBasic provides the following form methods to use for message passing:
• Notify
• NotifyByID
• NotifyByKey
• NotifyChild
• NotifyParent
You can use any of these, depending on the circumstances, to pass messages
to a form. Of course, the receiving form must currently be loaded and must
have a message handler for that message, in order to be affected by it. The
message can be a CeFO defined message, or your own message that you
defined as a global constant in the global module.

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

Handling Predefined CeFO Messages


If you want to send a close message to a form or a refresh message to a form
you can use two predefined CeFO messages:
• cbCloseMessage which tells the receiving form to close itself
• cbRefreshMessage, which tells the receiving form to refresh itself
If you want a form to respond to these messages, you must write one
message handling procedure (and only one!) in the form module as follows:
Sub Message (ByVal num as Long, ByVal data as String)
‘Your handler routine code here
End sub

IMPORTANT: A form can have only one message handler procedure!

Sample message handler. The following example is a message handler that


handles the Close and Refresh messages. This handler must be in the form
module for the form you want to affect.
Sub Message (ByVal num as Long, ByVal info as string)
If num = cbCloseMessage then
Me.Close
Else If num = cbRefreshMessage Then
Me.Refresh
Else
Me.DoDefault
End If
End Sub

Notice that this procedure doesn’t handle any message strings that might be
passed. The message string parameter is entirely optional.

Interestingly enough, instead of using the Refresh method in the above


example, you could cause refresh behavior by having the form notify itself
to refresh. In this case, the notification would cause the refresh:
Else If num = cbRefreshMessage Then

Message Handling 205


Handling Messages

Me.Notify cbRefreshMessage

However, this is unique to the refresh message.

Handling Your Own Messages


You will probably want to define your own messages to send to forms. To
create a message you must declare a global constant in the global module,
and instantiate it and set its value in the initialize_app procedure of the
global module. Then declare the global constant in each form that uses it. An
example of the required entries is as follows:
‘In the global module
Global YourMessage as GlobalLong
Sub initialize_app()
Set YourMessage as new GlobalLong
YourMessage.SetValue cbFirstMessage + 1
‘Whatever else initialize_app code you want
End Sub
‘In your form module
Global YourMessage as GlobalLong

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

Assigning Values to Your Messages


Your first message must start at the value cbFirstMessage + 1, your second
message must have the value cbFirstMessage + 2, and so on.

Using Message Strings


In the message handler routines, notice that there is a parameter for a
message string. This is entirely optional. If you want to supply a message
string, declare a GlobalString for it following the instructions provided
above for declaring the message. You are responsible for passing this
message string to the handler when you notify a form; you are also
responsible for handling this message string in the handler routine.

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.

Message Handling 207


Sending Messages

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.

An example of using this message is as follows:


Sub MyUpdateButtonClick()
Me.NotifyByID 5050 cbRefreshMessage
End sub

208 Chapter 11
Sending Messages

Notifying Parent and Child Forms


You can use the NotifyChild or NotifyParent methods to notify a related
form. However, before you can use these methods, you must first establish
the parent/child relationship using the SetParent method.

The parent/child mechanism is useful because it is sometimes difficult to


keep track of whether a child is posted, whether it has a parent, how many
children a parent has, and so on. If you use SetParent to set up this relation,
then you don't have to worry about keeping track of the children. The use of
child forms also allows a form to be written more efficiently; for example,
you can code a form to send a certain message to its children upon
processing a certain event.

Parent Forms, Child Forms, and Messaging


If a form is posted and has children posted, you should not close the parent
without closing the children, nor should you exit the application without
first closing all child forms. Instead, you should add message handlers in the
child forms that can handle a close message from the parent and you should
send a close message to those children when you want to close them.

Setting Up the Parent/Child Relationship


To set up the parent/child relationship, you must use SetParent, which has
the following syntax:
YourChild.SetParent YourParent

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

Message Handling 209


Sending Messages

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

Message Handling 211


Sending Messages

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

Modifying the initialize_app Procedure


The initialize_app procedure resides in the CeFO database. To modify it, you
first "export" a copy of the module containing it to your local system, modify
it, and then import it back into the database.

Exporting the Global Module


To export the module that contains the initialize_app procedure:
1. From the DOS prompt run the following command:
cbex -spec global.cbs -G clarify -exp
You can specify any file in place of the global.cbs. However, it must have
the .cbs extension.
The system displays the CBEX window with a login dialog box inset.
2. Enter the required information in the dialog box and click Login.
CBEX displays a message that CBEX indicates that the module
containing initialize_app procedure has been exported.
3. Click OK to close the CBEX window.

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

If you or somebody had earlier added ClearBasic code to this procedure to


modify the menus and menu items, then that code will also appear in it.

You are now ready to add ClearBasic code for customizing the menus and
menu items.

Importing the Global Module


Once you have inserted the customizing ClearBasic code into the
initialize_app procedure you must import it back to the database.

Customizing Menubars 215


Customizing Menus

To do this, follow these steps:


1. From the DOS prompt run the following command:
cbex -spec global.cbs -G clarify -imp
You must specify the same .cbs file to which you exported the module
containing the initialize_app procedure.
The system displays the CBEX window with a login dialog box inset.
2. Enter the required information in the dialog box and click Login.
CBEX displays a message that indicates that the module already exists.
The message box also contains an "Overwrite?" button.
3. Click Overwrite to close the CBEX window.

The modified initialize_app procedure is now saved to the CeFO database.


When you invoke the CeFO application(s) next time, you will see the
customized menus.

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

Adding a Menu Item to an Existing Menubar


Let us say you want to customize the "Edit" menu in the ClearSupport
application window. To this menu, you want to add a menu item "Display
Form" that generates the event "PressMe." To accomplish this, you edit the
initialize_app procedure to look as follows:
Sub initialize_app()
Dim MyAppMenu as new AppMenu
MyAppMenu.MenuBarID = 1002
MyAppMenu.AddItem "Edit", "Display Form", "PressMe"
App.ShowDefaultMenu
End Sub

In the above ClearBasic code, the dim statement declares a new menu called
MyAppMenu.

In the MyAppMenu.MenuBarID statement, 1002 refers to the menubar


associated with the ClearSupport window. Refer to Table 12 for description
of all MenuBarIDs.

NOTE: You must insert a MenuBarID statement before adding any modification
code.

In the MyAppmenu.AddItem statement, "Edit" refers to the menu label,


"Display Form" to the menu item, and "PressMe" to the event to be
generated when "Display Form" is chosen.

The App.ShowDefaultMenu statement posts the modified menu. This


statement must always be the last statement.

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.

Customizing Menubars 217


Customizing Menus

Table 12 Menubar IDs

MenuBarID Associated CeFO Application window

1000 StartUp menubar

1001 Policies and Customers

1002 ClearSupport

1005 Product Manager

1007 ClearLogistics

1008 ClearQuality

Renaming a Menu Item


To rename a menu item you use the RenameItem method using the
following syntax:
MyAppMenu.RenameItem "menu_label",
"old_menu_item", "new_menu_item"

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."

The initialize_app procedure would now look as follows:


Sub initialize_app()
Dim MyAppMenu as new AppMenu
MyAppMenu.MenuBarID = 1002
MyAppMenu.AddItem "Edit", "Display Form", "PressMe"
MyAppMenu.RenameItem "Edit", "Copy", "Duplicate"
App.ShowDefaultMenu
End Sub

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.

Removing a Menu Item


To remove a menu item, you use the RemoveItem method using the
following syntax:
MyAppMenu.RemoveItem "menu_label","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.

The initialize_app procedure would now look as follows:


Sub initialize_app()
Dim MyAppMenu as new AppMenu
MyAppMenu.MenuBarID = 1002
MyAppMenu.AddItem "Edit", "Display Form", "PressMe"
MyAppMenu.RenameItem "Edit", "Copy", "Duplicate"
MyAppMenu.RemoveItem "Desktop", "Switch User"
App.ShowDefaultMenu
End Sub

When you remove a menu item, the event associated with it is also removed.

Linking Event Procedures to Existing Menu


Items
To associate a new event procedure to a menu item, you use the
SetFunction method using the following syntax:
MyAppMenu.SetFuntion "menu_label",
"menu_item","new_event_procedure"

Customizing Menubars 219


Customizing Menus

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.

The initialize_app procedure would now look as follows:


Sub initialize_app()
Dim MyAppMenu as new AppMenu
MyAppMenu.MenuBarID = 1002
MyAppMenu.AddItem "Edit", "Display Form", "PressMe"
MyAppMenu.RenameItem "Edit", "Copy", "Duplicate"
MyAppMenu.RemoveItem "Desktop", "Switch User"
MyAppMenu.SetFunction "New", "Solution", "PostSolut"
App.ShowDefaultMenu
End Sub
Sub PostSolut_Click()
Dim My SolutionForm as new Form
‘Your code
MySolutionForm.Show 5050
App.DoDefault
End Sub

IMPORTANT: You must include the App.DoDefault statement in the event


procedure to use both the default behavior of the menu item (in this case, Solution)
as well as the new behavior you defined.

Disabling and Enabling Menu Items


To disable (gray out) as well as to re-enable a previously disabled menu item
you use the Enable method using the following syntax:
YourAppMenu.Enable Menu_Label, Menu_Item, State

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.

Similarly, if in the Select menu, you wanted to re-enable the previously


disabled Subcases menu item, you would add the following ClearBasic
Code to the initialize_app procedure:
MyAppMenu.Enable "Select", "Subcases", True

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.

The initialize_app procedure would now look as follows:


Sub initialize_app()
Dim MyAppMenu as new AppMenu
MyAppMenu.MenuBarID = 1002
MyAppMenu.AddItem "Edit", "Display Form", "PressMe"
MyAppMenu.RenameItem "Edit", "Copy", "Duplicate"
MyAppMenu.RemoveItem "Desktop", "Switch User"
MyAppMenu.SetFunction "New", "Solution", "PostSolut"
MyAppMenu.Enable "Edit", "Cut", 0
MyAppMenu.Enable "Select", "Subcases", 1
App.ShowDefaultMenu
End Sub

Inserting Separators Between Menu items


Sometimes its desirable to group related menu items and separate them
from other menu items groups by inserting a horizontal separator line. To do
this, you use the AppendSeparator method using the following syntax:
YourAppMenu.AppendSeparator "Menu_Label"

Customizing Menubars 221


Customizing Menus-Multiple Application Menubars

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"

Customizing Menus-Multiple Application


Menubars
Each CeFO application has its own menubar. To customize more than one
menubar, you do the following:
• Declare separate AppMenu objects for each menubar that you want to
customize.
• Set the MenuBarID property to correspond to each menubar that is to be
customized.
• Modify each AppMenu object as desired
For example, if you wanted to customize the menubars in the ClearSupport
and ClearQuality menubars, you would insert ClearBasic code in the
initialize_app procedure that looks similar to the following:
Sub initialize_app()
dim MyCS_MenuApp as new AppMenu
dim MyCQ_MenuApp as new AppMenu

222 Chapter 12
Applying the Menubar Customization

‘Set menubar ID to ClearSupport menubar


MyCS_MenuApp.MenuBarID = 1002
‘Set menubar ID to ClearQuality menubar
MyCQ_MenuApp.MenuBarID = 1008
‘Modify the Desktop menu in the ClearSupport menubar
MyCS_MenuApp.RemoveItem "Desktop", "Switch User"
‘Modify the Edit menu in the ClearQuality menubar
MyCQ_MenuApp.AddItem "Edit", "Display Form", "Press"
MyCQ_MenuApp.RenameItem "Edit", "Copy", "Duplicate"
‘Modify the Desktop menu in the ClearSupport menubar
MyCS_MenuApp.SetFunction "New", "Solution", "Choices"
App.ShowDefaultMenu
End Sub

Applying the Menubar Customization


After you have added ClearBasic code to the initialize_app procedure to
customize the menubars.

To make the modifications effective:


1. Import the initialize_app procedure into the database as described in the
section Importing the Global Module in the beginning of this chapter.
2. To make the customized menubars available to all users, make sure that
they all exit CeFO applications and restart them.

If any users do not exit and restart CeFO applications, they will not have
access to the customized menubars.

Customizing Menubars 223


Applying the Menubar Customization

224 Chapter 12
Chapter 13

Building Your Project

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.

Creating GUI Components For Your Code


You create the GUI components using the UI Editor. Tasks you need to
perform in the UI Editor include the following:
• Create new forms.
• Modify existing forms by adding/modifying controls, lists, command
buttons, adding new forms, etc.
• Associate names and labels for various form components. Later you use
these names and labels to associate ClearBasic code with the
components.

226 Chapter 13
Starting the UI Editor in ClearBasic Mode

Starting the UI Editor in ClearBasic Mode


To access the features needed for programming in ClearBasic, you must
invoke the UI Editor with the -cb option. If you want to use User Defined
Data Types, you must also specify the UDT file name on the command line.
The general command format for invoking the UI Editor is as follows:
uieditor -cb [-c=UDTs_file]

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.

Using User Defined Types in the UI Editor


ClearBasic supports User-defined Data Types, or UDTs, in the form code
modules. For the form itself at design time, you can create custom list
controls that are hooked up to a UDT, that is, that are tied to a contextual
object that is of a user defined type.

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.

Building Your Project 227


Coding Global Modules

To create a module with UDT definitions


1. Using a suitable text editor create a file that contains the definition and
declaration for each UDT.
2. Invoke the UI Editor using a command in the following format:
uieditor -cb -c=YourUDTs
YourUDTs is the name of the file that contains definitions and
declarations for your UDTs. This file must be in the UI Editor directory.

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.

Coding Global Modules


In previous releases, ClearBasic used a single user global module named
globals.cbs for all CeFO applications and for your own customizations.

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.

Coding Form Modules


You can use most any text editor to code the form modules.When you code a
form module, make sure the control names and contextual object names you
use in your code match the ones assigned to the form and controls in the UI
Editor.

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.

There are no dependencies on other modules when you compile a form


module. This means that all constants, global variables, and type
declarations must also be declared within each module.

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.

Building Your Project 229


Creating and Using a Directives File

Creating and Using a Directives File


The directives file contains one or more lines that define individual form and
global modules. You can create a directive file using any suitable text editor.
You can also create it from within the CBEX main window by picking entries
from the Modules window and the Forms window.

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.

IMPORTANT: While using a directives file is a very convenient method for


organizing modules by project or application, you do not always need a directives
file. You can also specify and set up both global and form modules in the Action
Directives list as described in the section Using Action Directives List to Directly
Specify and Set Up Directives on page 251.

230 Chapter 13
Creating and Using a Directives File

Creating a Directives file


A directives file can contain entries for both global and form modules. You
can add these entries to a new file or to an existing file.

To specify global modules in a directives file


1. Using a suitable text editor, create a directives file and add one-line
entries for each global module in the format shown below. Alternatively,
add entries to an existing directives file.
global_file.cbs -G clarify [subsystem] [-N
label]
Where
global_file.cbs
is either the source file that contains your global
module to be imported into the database, or it is
the destination file to which source code is to be
exported from the database. The globals file,
must have the .cbi extension.
-G indicates that it is globals file and that the
next argument is the application name.
clarify is the name of the application. Currently, clarify
is the only valid application name.
subsystem is an any string value that is optional. You
can use this string to organize your globals
definitions under specific names referred to as
subsystems.
-Nspecifies that the next argument is a
self-documenting label for the global module
that could be used as a one-word comment.
labela self-documenting label for the global
module. This allows for importing multiple
parts of the same module. Since the size of a
global module is limited to 60,000 bytes, you
can use this feature as a workaround.

Building Your Project 231


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 (’).

Example of a global module entry:


MyGlobal.cbs -G clarify helpdesk -N part_1

To specify form modules in a directives file


1. Using a suitable text editor, create a directives file and add one-line
entries for each form module in the format shown below. Alternatively,
add entries to an existing directives file.
src_file -F FormID [ClarifyVer] UserVer
Where
src_file is either the source file that contains your form
module to be imported into the database, or it is
the destination file to which source code is to be
exported from the database.
-Fspecifies that the next argument is the numeric ID
of the baseline CeFO form.
FormID is the numeric ID of the form you want to
perform some operation on.
ClarifyVer is the CeFO version of the FormID against
which a previous form was compiled/imported.
operation. You need to specify this only if you
want to export and/or purge a module that
was compiled/imported against this
CeFO version. You need not specify it for the
import operation.

232 Chapter 13
Creating and Using a Directives File

If you specify this parameter for an import


operation, CBEX ignores it and uses the current
CeFO baseline form
If you omit ClarifyVer, CBEX uses the
current CeFO baseline form.
UserVeris the user version of the FormID against
which you want to perform the CBEX
operation.
The form associated with a form module
must have a user version.
2. Repeat the preceding step, as necessary to add more form 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 (’).

Example of a form module entry:


jeff5050.cbs -F 5050 jeff

Creating a Directives File From Within the CBEX Window


You can create a directives file from within the CBEX main window by
including your modules that are already in the database. The following
procedure describes this. You can also use this procedure to add new form
modules to an existing directives file.

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.

Building Your Project 233


Creating and Using a Directives File

To create a Directives file from a CBEX window


1. In the CBEX window, 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.

2. Highlight the module you want to include in the directives file.


3. Click Done to close the Modules window.
4. Click the Add button.
This action places the module information in the Action Directives List.
5. If you want to know which form is associated with the current module,
click the Forms button.
This action displays the Forms window, similar to the one shown below,
that displays information about the form associated with the current
module.

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.

Some Directives File Requirements


While your database may have many different previous CeFO Versions that
have the same Form ID. The current CeFO application uses only the latest
baseline versions of forms when you compile/import a form into the
database. Therefore, you cannot compile and import a form module against
a previous baseline version. You can, however, export and/or purge a
module that has been compiled and imported against a previous CeFO
version.

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.

Before Using CBEX


Before staring to use CBEX, you should know about the following issues:
• How to specify the source code files
• When to use the directives file
• When to use the -batch command line option
• Role of the CBEX log file

Specifying Source Code Files


If the source code files are located in the same directory as the one in which
CBEX utility (cbex.exe) is located, you need to specify only the name for
each file. You do not need to specify path for any of the files.

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.

Building Your Project 235


Creating and Using a Directives File

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.

When to Use a Directives File


You use the directives file whenever you want to perform any one of the
CBEX operations on multiple source modules. Directives files also provides
a convenient way to organize your modules, e.g., by project.

The directives file can have any name, but it must have a .cbi extension.

Using the -batch option


When you invoke CBEX with the -batch option it executes the specified
command, briefly flashes the CBEX graphical user interface, and then exits.
If the command encounters any warnings and/or problems, it does not
display any interactive messages. However, it saves these messages to the
log file cbex.log. If the command is used with a directives file, CBEX
executes the specified operation on all "active," or "On," source modules
before exiting.

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

About the CBEX Log File


CBEX writes the status of successful or unsuccessful compiling and
importing to the log file cbex.log. CBEX creates this file (or overwrites an
existing one) in the current directory. The log file entries depend on the type
of operation performed and whether it was successful.

Figure 23 through Figure 25 show some sample log file entries.

Figure 23 Log file contents when compile succeeded but import failed

Figure 24 Log file contents when compile and import succeeded

Figure 25 Log file contents when a syntax error was found

Building Your Project 237


Invoking CBEX

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.

In command line mode, CBEX executes the command line without


displaying the GUI.

To invoke CBEX in interactive mode


1. Enter the CBEX command in one of the following formats at the DOS
prompt (in the MS-DOS Prompt window) or UNIX prompt or
double-click the CBEX icon that has been set to run one of these
commands:
cbex
cbex [options] -spec src_file -F FormID
[ClarifyVer] userVer
cbex [options] -dir directives_file

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

If your clarify.env file does not contain "Autologin = True" entry,


the login dialog box shown below appears. Otherwise, CBEX displays
the window shown in Step 2 on page 239.

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.

2. Enter the required information and click Login.


If your invocation command did not contain any options, the system
posts the main CBEX window similar to the one shown below. Note that
except for the Module Name and App fields, all fields are empty.

Building Your Project 239


Invoking CBEX

If your invocation command contained options (and required


parameters), the system posts a window similar to the following. Notice
that all the information specified on the command line is displayed in
corresponding fields.

240 Chapter 13
Invoking CBEX

To invoke and use CBEX in non-interactive, or command line, mode


1. Enter the CBEX command in one of the following formats at the DOS
prompt (in the MS-DOS Prompt window) or UNIX prompt or double-
click the CBEX icon that has been set to run one of these commands:
cbex -batch [options] -spec src_file -F FormID
[ClarifyVer] userVer
cbex -batch [options] -spec dest_file -F FormID
[ClarifyVer] userVer
cbex -batch [options] -spec src_file -G clarify
[subsystem] [-N label]
cbex -batch [options] -spec dest_file -G clarify
[subsystem] [-N label]
cbex -batch [options] -dir directives_file]
In the above formats, you specify the src_file (source file) when you
want to perform an import operation and you specify the dest_file
(destination file) when you want to perform an export and/or purge
operation.

NOTE: To invoke CBEX in non-interactive mode, you must specify the


-batch option. You can also specify any of the other legal options in any
order. You must also specify all other required options and parameters.

Table 13 on page 243 describes all the available CBEX options.

If your clarify.env file does not contain "Autologin = True" entry,


the login dialog box shown below appears. Otherwise, CBEX executes
the command used in Step 1 and writes the success/failure information
to the cbex.log file.

Building Your Project 241


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.

CBEX Command Line Options and Flags


Table 13 lists and describes all command line options and flags for the CBEX
utility.

242 Chapter 13
Invoking CBEX

Table 13 CBEX options, flags, and parameters

Option/Flag/Parameter Description Comments


-batch Specifies that CBEX be invoked in You must not use this option if you
command line mode to execute the want to use CBEX interactively.
specified command without
displaying the Graphic User
Interface (GUI).
In -batch mode, CBEX does not
automatically overwrite an existing
module unless the -overwrite
option is specified.
ClarifyVer The CeFO version of a form. A form When this parameter is not specified
(CeFO Version) can have several versions, but only (i.e., the text box is left blank or the
one is the current baseline. parameter is omitted from a
command line) the current baseline
version of the form is used.
This parameter is required only if
you are exporting and or purging a
form that was compiled against an
earlier CeFO baseline version
UserVer The user version of the form. Users must create their own
(Customer Version) versions of the CeFO forms.
-dir directives_file Specifies the directives file.
The file contains source module
directives. It must have a .cbi
extension.
-exp Specifies that the module specified Cannot be used with the -imp
on the command line or the modules option. However it may be used with
enables in the directives file be the -pur option, in which case the
exported to the current directory. module is first exported to a file on
your system and then purged from
the database.
-F FormID UserVer Specifies the CeFO baseline form on
which the UserVer is based against
which the CB code is to be
compiled/imported. FormID is a
numeric string.

Building Your Project 243


Invoking CBEX

Table 13 CBEX options, flags, and parameters (Continued)

Option/Flag/Parameter Description Comments


-G clarify subsystem Indicates that the module specified Can only be used with global
on the command line is a global modules. Currently, the only legal
module for the CeFO application. application name is clarify.
subsystem is an optional string that
can be used to identify/organize
different subsystems in the main
application
-imp Indicates that the source module Cannot be used with the -exp or
specified on the command line or -pur options.
enabled in the directives file is to be
compiled and imported into the
database. -imp is the default when
-exp, or -pur is not specified.
-N label Specifies the label to be used to Can only be used when a -G flag and
identify a global module. The label is a global module is used.
a self-documenting one-word string
that can be used to identify
individual module of a multi-part
global module.
-overwrite Specifies that if a module already Can only be used when importing
exists, unconditionally overwrite it modules into the database.
(i.e., without displaying the
confirmation prompt).
-pur Indicates that the module specified Cannot be used with the -imp
on the command line or modules option. However it may be used with
enabled in the directives file be the -exp option, in which case the
purged from the database. module or modules are first
exported to a file or files on your
system and then purged from the
database.
-spec dest_file Specifies the destination file to which Cannot be used with the directives
a form or global module is to be file.
exported. The dest_file should
have the .cbs extension.
-spec src_file Specifies the module on which the Cannot be used with the directives
CBEX operation is to be performed. file.
src_file contains source code for the
form or global module. The src_file
must have a .cbs extension.

244 Chapter 13
Getting Ready to Use CBEX

Table 13 CBEX options, flags, and parameters (Continued)

Option/Flag/Parameter Description Comments


subsystem A string value that identifies a This is an optional parameter that is
subsystem of the application. used when importing global
modules
-syntax Specifies that only the syntax of the
statements in the source module
specified on the command line or
enabled in the directives file be
checked. It further specifies that the
source module, even if it has no
errors, must not be imported into the
database.

Getting Ready to Use CBEX


While you can perform CBEX operations on individual global and form
modules without using a directives file, to perform CBEX operations on
multiple global and/or form modules, you must use a directives file that
contains definitions of individual modules. Refer to the section Creating and
Using a Directives File on page 230 for details.

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.

Building Your Project 245


Getting Ready to Use CBEX

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.

Loading the Directives file and Setting Up the


Directives
You can pre-load a directives file by specifying it on CBEX command line.
Alternatively, you can manually load it from within the CBEX main window.

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

To load and set up a directives file


1. Invoke CBEX in interactive mode using your directives file as described
in the procedure To invoke CBEX in interactive mode on page 238.
2. When the Login dialog box appears, enter the required information in it
and click Login.
The Login dialog box disappears and the CBEX main window appears,
which looks similar to the following:

3. To load a different directives file, do the following:


a. Choose Open from the File menu to display the file selection dialog
box.
b. Locate and then double-click the directives file you want to load.
This action inserts the information from the selected directives file into
the appropriate fields in the CBEX main window.

Building Your Project 247


Getting Ready to Use CBEX

4. Enable the modules you want to use:

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

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.

b. Highlight the module you want to include in the directives file.


c. Click the Add button.
This action places the module information in the Action Directives
List.
d. Repeat the preceding three substeps as necessary.
7. If you want to modify an existing module entry in the list or want to
create a new one that is based on an existing one, do the following:
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 above.
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.

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.

8. Repeat Step 7 as necessary.

Building Your Project 249


Getting Ready to Use CBEX

9. To save the information in the modified Action Directive List to the


current directives file, choose Save from the File menu.
10. To save the information in the modified Action Directive List to a new
directives file, use Save As from the File menu.

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

Using Action Directives List to Directly Specify


and Set Up Directives
It is not always a requirement that you have a directives file to set up
directives. You can also specify and set up directives “on the fly” directly in
the Action Directives list.

To specify and set up modules in the Action Directives List


1. If you want to delete any of current entries in the Action Directives list,
highlight them and click Delete.

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.

b. Highlight the module you want to include in the directives file.


c. Click the Done button.
d. Click the Add button.
This action places the module information in the Action Directives
List.
e. Repeat the preceding four substeps as necessary.
3. If you want to modify an existing module entry in the list or want to
create a new one that is based on an existing one, do the following:

Building Your Project 251


Getting Ready to Use CBEX

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.

Setting up a Directives File for Use in Command


Line Mode
When you want to use CBEX with a directives file in command line mode,
you enable and disable modules by editing the directives file.

To enable and/or disable form modules in a directives file


1. Open the directives file using a suitable text editor.
2. To enable a form module, remove the comment out character (‘) from the
beginning of the line that defines the module.
3. To disable a form module, insert the comment out character (‘) at the
beginning of the line that defines the module.

252 Chapter 13
Getting Ready to Use CBEX

Determining Which Form is Associated With a


Specific Form Module
At times you may want to modify the form layout and/or behavior. For this
you may need to modify both the source code in the form module and the
physical layout of the form. To facilitate this, CBEX provides for displaying
information about the form (or window) associated with a specific form
module.

To determine which form is associated with a form module


1. Highlight the target form module in the Action Directives List in the
CBEX main window.
2. Click the Forms button.
CBEX displays a Forms window similar to the following one that shows
information about the form associated with the selected (highlighted)
module.

Adding Comment Lines to a Directives File


You can provide spot documentation by adding comment lines to a
directives file.You can do this either in the CBEX window as outlined below
or you can edit the directives file and insert lines that start with the single
quote character (’).

To add comment lines to a directives file


1. In the CBEX window, click the Comments option button in the Type
options.
This action disables all text boxes except the Comments text box.
2. Enter suitable comments in the Comments text box.

Building Your Project 253


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-

Performing CBEX Operations-Global/Form


Modules
You can perform the following operations (one at a time) on any one or more
of the modules defined in the directives file:

NOTE: Unless noted otherwise, module(s) refer to both global and form module(s).

• Perform syntax check on selected modules


• Compile and import selected modules into the database
• Export selected module from the database to a local file
• Purge the selected modules from the database
• Export selected modules and then purge them in one operation

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.

Checking Syntax in Source Modules


When you compile and import source modules, CBEX first checks the syntax
in each source module. If CBEX encounters any syntax errors, it displays an
error message and then stops. However, if you specify the -syntax
command line option, CBEX only checks the syntax; it does not import the
modules into the database even if there are no errors in the source 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.

To perform syntax check in source modules in interactive mode


1. Edit your directives file to enable the module or modules you want to
check for syntax.
2. Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or UNIX prompt:

Building Your Project 255


Performing CBEX Operations-Global/Form Modules

cbex -syntax -dir directives_file


Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -syntax -dir MyDirFile
The above action posts the Session Login dialog box.
3. Enter the required information in the dialog box and click Login.
CBEX executes the command entered in the preceding step. If it
encounters syntax errors in any of the source modules enabled in the
directives file, CBEX displays the error message similar to the following:

4. If the preceding step displayed an error message, do the following:


a. If you want to recompile the module, open the source module file for
editing, edit it to fix the syntax problem, and then click the Recompile
button. Repeat this step as necessary.
b. If you want to discontinue processing the current directives file, click
Exit.

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:

d. If the preceding substep displayed the System Info window, click OK


to display any additional syntax error messages.
CBEX also writes the information displayed to the log file cbex.log.

To use command line to check syntax in a single global module


1. Enter the command in the following format:
cbex -batch -syntax -spec src_file -G clarify
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -syntax -spec MyGlobal.cbs -G clarify
The above action posts the Session Login dialog box.
2. Enter the required information in the dialog box and click Login.
CBEX executes the command entered in the preceding step and writes
the success or failure information about the operation to the cbex.log
log file.

To use command line to check syntax in a single form module


1. Enter the command in the following format:
cbex -batch -syntax -spec src_file -F FormID
UserVer
Refer to Table 13 on page 243 for description of command arguments.
Example:

Building Your Project 257


Performing CBEX Operations-Global/Form Modules

cbex -batch -syntax -spec jeff5050.cbs -F 550


jeff
The above action posts the Session Login dialog box.
2. Enter the required information in the dialog box and click Login.
CBEX executes the command entered in the preceding step and writes
the success or failure information about the operation to the cbex.log
log file.

To use command line to check syntax in multiple modules


1. Edit your directives file to enable the modules you want to check for
syntax.
2. Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or UNIX prompt:
cbex -batch -syntax -dir directives_file
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -syntax -dir MyDirFile.cbi
The above action posts the Session Login dialog box.
3. Enter the required information in the dialog box and click Login.
CBEX executes the command entered in the preceding step and writes
the success or failure information about the operation to the cbex.log
log file.

258 Chapter 13
Performing CBEX Operations-Global/Form Mod-

Compiling and Importing Modules into the


Database
You can compile/import modules into the database using CBEX in
interactive mode or the CBEX command line.

To import modules in interactive mode


1. In the CBEX window, load the directives file and enable the module or
modules you want to compile/import.
Refer to the procedure To load and set up a directives file on page 247 for
details.
2. Do one of the following:
• Click the Import button.
• Choose Import from the Actions menu.
If the compile/import operation is unsuccessful on any of the modules,
the System Info message box appears indicating the problem. Clicking
OK in the message box displays the next "unsuccessful" message, if any.
CBEX also writes this information along with any "successful"
information to the cbex.log log file.

To use command line to import a single form module


• Enter a command using the following format at the DOS prompt (in the
MS-DOS Prompt window) or the UNIX prompt:
cbex -batch [-imp] [-overwrite] -spec
src_file -F FormID UserVer
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -imp -overwrite -spec jeff5050.cbs -F
550 jeff
This example compiles the form module defined in the
jeff5050.cbs source file against Form 5050 user version jeff. It
then imports the module into the database.
Since -imp is the default, you can omit this option from the command
line. If you do not specify the -overwrite option and a module with
the same name already exists, CBEX displays a confirmation box that
prompts you to confirm the overwrite.

Building Your Project 259


Performing CBEX Operations-Global/Form Modules

To use command line to import a single global module


• Enter a command using the following format at the DOS prompt (in the
MS-DOS Prompt window) or the UNIX prompt:
cbex -batch [-overwrite] [-imp] -spec
src_file -G clarify
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -imp -overwrite -spec MyGlobal.cbs -G
clarify
This example compiles the global module defined in the
MyGlobal.cbs source file and then imports it into the database.
Since -imp is the default, you can omit this option from the command
line. If you do not specify the -overwrite option and a module with
the same name already exists, CBEX displays a confirmation box that
prompts you to confirm the overwrite.

To use command line to import multiple modules


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or UNIX prompt:
cbex -batch [-imp] [-overwrite] -dir
directives_file
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -imp -overwrite -dir MyDirFile.cbi
This command compiles all the enabled global and form modules (i.e.,
the modules that have not been commented out in the
MyDirFile.cbi file and imports them into the database. If a module
name already exists in the database, the command overwrites it. CBEX
writes the results of the operations to the cbex.log log file.
Since -imp is the default, you can omit this option from the command
line. If you do not specify the --overwrite option and a module with
the same name already exists, CBEX does not overwrite the module
and places a message to this effect in the cbex.log file.

260 Chapter 13
Performing CBEX Operations-Global/Form Mod-

Exporting Modules From the Database


You can export multiple modules from a database and save them to local
files.

To export form modules in interactive mode


1. In the CBEX window, load the directives file and enable the module or
modules to be exported.
Refer to the procedure To load and set up a directives file on page 247 for
details.
2. If you want to export the individual modules under their original names
to the current directory, continue with Step 4.
3. If you want to export the individual modules to different directories
under different names, do the following:
a. Highlight the module in the Active Directives List.
The name of the source code file for the module appears in the Code
File text box.
b. Delete the current entry in the Code File text box and then enter full
path for the file to which you want to save the module in the Code File
text box.
c. Enter or modify, as necessary, the comments in the Comments text box.
d. Click the Replace button.
The name of the source code file in the highlighted line in the Active
Directive window changes to the new name specified in the Code File
text box.
e. Repeat the preceding four substeps for each module to be exported.
4. Do one of the following:
• Click the Export button.
• Choose Export from the Actions menu.
If the export operation is unsuccessful on any of the modules, the System
Info message box appears indicating the problem. Clicking OK in the
message box displays the next "unsuccessful" message if any. CBEX also
writes this information along with any "successful" information to the
cbex.log log file.

Building Your Project 261


Performing CBEX Operations-Global/Form Modules

To use command line to export a single form module


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or UNIX prompt:
cbex -batch -exp -spec dest_file -F FormID
[ClarifyVer] UserVer
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -exp -spec jeff5050.cbs -F 550 jeff
This command exports the user form module “550 jeff” from the
database to the destination file jeff5050.cbs in the current directory.
If you wanted to export a module that was compiled against an earlier
CeFO version (e.g., 1.0), you would enter the above command as follows:
cbex -batch -exp -spec jeff5050.cbs -F 550 1.0
jeff

To use command line to export a single global module


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or UNIX prompt:
cbex -batch -exp -spec dest_file -G clarify
[subsystem] [-N label]
Refer to Table 13 on page 243 for description of command arguments.

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-

cbex -batch -exp -spec MyGlobal.cbs -G clarify


subsys_1 -N global_1

To use command line to export multiple modules


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or the UNIX prompt:
cbex -batch -exp -dir directives_file
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -exp -dir MyDirFile.cbi
This command exports all enabled modules (i.e., the modules that
have not been commented out in the MyDirFile.cbi file) from the
database to the current directory, i.e., the directory in which the CBEX
executable resides.
CBEX writes the result, successful or unsuccessful, of each operation to
the cbex.log log file.

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.

Purging Form Modules From the Database


You can purge, or delete, form modules from the database using the CBEX
window or the command line.

To purge form modules from the database in interactive mode


1. In the CBEX window, load the directives file and enable the module or
modules to be purged.
Refer to the procedure To load and set up a directives file on page 247 for
details.
2. Do one of the following:
• Click the Purge button.
• Choose Purge from the Actions menu.

Building Your Project 263


Performing CBEX Operations-Global/Form Modules

If the purge operation is unsuccessful on any of the modules, the System


Info message box appears indicating the problem. Clicking OK in the
message box displays the next "unsuccessful" message if any. CBEX also
writes this information to the cbex.log log file.

To use command line to purge a single form module


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or the UNIX prompt:
cbex -batch -pur -spec dest_file -F FormID
[ClarifyVer] UserVer
Refer to Table 13 on page 243 for description of command arguments.

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

To use command line to purge a global module


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or the UNIX prompt:
cbex -batch -pur -spec dest_file -G clarify
[subsystem] [-N label]
Refer to Table 13 on page 243 for description of command arguments.

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

To use command line to purge multiple modules


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or the UNIX prompt:
cbex -batch -pur -dir directives_file
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -pur -dir MyDirFile.cbi
This command purges all the enabled form modules (i.e., the modules
that have not been commented out in the directives.cbi file) from
the database.
CBEX writes the result, successful or unsuccessful, of each operation to
the cbex.log log file.

Building Your Project 265


Performing CBEX Operations-Global/Form Modules

Exporting and Purging Modules From the


Database
You can export modules from a database to local files and then purge them
from the database. You can do all this in a single operation.

To export and purge modules from the database in interactive mode


1. In the CBEX window, load the directives file and enable the module or
modules you want to export/purge.
Refer to the procedure To load and set up a directives file on page 247.
2. If you want to export the individual modules under their original names
to the current directory, continue with Step 4.
3. If you want to export the individual modules to different directories
under different names, do the following:
a. Highlight the module in the Active Directives List.
The name of the source code file for the module appears in the Code
File text box.
b. Delete the current entry in the Code File text box and then enter full
path for the file to which you want to save the module in the Code File
text box.
c. Click the Replace button.
The name of the source code file in the highlighted line in the Active
Directive List changes to the new name specified in the Code FIle text
box.
d. Repeat the preceding three substeps for each module to be exported.

266 Chapter 13
Performing CBEX Operations-Global/Form Mod-

4. Do one of the following:


• Click the Export/Purge button.
• Choose Export Purge from the Actions menu.
If the export/purge operation is unsuccessful on any of the modules, the
System Info message box appears indicating the problem. Clicking OK in
the message box displays the next "unsuccessful" message if any. CBEX
also writes this information along with any "successful" information to
the cbex.log log file.

To use command line to export/purge a single form module


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or the UNIX prompt:
cbex -batch -exp -pur -spec dest_file -F FormID
[ClarifyVer] UserVer
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -exp -pur -spec jeff5050.cbs -F 550
jeff
This command exports the user form module “550 jeff” to the
destination file jeff550.cbs in the current directory and then
purges the form module from the database.
If you wanted to export and purge a module that was compiled
against an earlier CeFO version (e.g., 1.0), you would enter the above
command as follows:
cbex -batch -exp -pur -spec jeff5050.cbs -F 550
1.0 jeff

Building Your Project 267


Performing CBEX Operations-Global/Form Modules

To use command line to export/purge a single global module


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or UNIX prompt:
cbex -batch -exp -pur -spec dest_file -G clarify
[subsystem] [-N label]
Refer to Table 13 on page 243 for description of command arguments.

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

To use command line to export/purge multiple modules


• Enter the CBEX command in the following format at the DOS prompt (in
the MS-DOS Prompt window) or the UNIX prompt:
cbex -batch -exp -pur -dir directives_file
Refer to Table 13 on page 243 for description of command arguments.
Example:
cbex -batch -exp -pur -dir MyDirFile.cbi
This command exports all the enabled form modules (i.e., the modules
that have not been commented out in the MyDirFile.cbi file) from
the database to the current directory, i.e., the directory in which the
CBEX executable resides. It then purges them from the database.
CBEX writes the result, successful or unsuccessful, of each operation to
the cbex.log log file.

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.

Building Your Project 269


Performing CBEX Operations-Global/Form Modules

270 Chapter 13
Chapter 14

Testing and Debugging

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.

Run-time error messages are generated by the underlying CeFO application.


The application does so when it encounters an illegal operation that is
specified in your CB code.

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.

This chapter provides general guidelines for eliminating the compile-time


and run-time errors. It also describes how to use the ClearBasic Debugger
and the Debug.Print statement.

272 Chapter 14
Fixing Compile-Time Errors

Fixing Compile-Time Errors


This section lists and explains some sample compile-time errors. To correct
these problems you will need to appropriately modify either the form using
the UI Editor or the CB source file or both. Then, you will need to reimport
the form module into the database.

A common source of compile-time errors is misspelled variables. You can


avoid this problem by using the OPTION EXPLICIT statement in one of
your global modules or in each form module.

When OPTION EXPLICIT is not used, ClearBasic creates variables on the


fly without checking whether the variable has been previously declared. If
OPTION EXPLICIT is used, compiler gives an error if it encounters an
undeclared variable in the code.

The following are some of the common compile-time error messages:


The form you specified does not exist ...
You have specified a wrong user version of the form against which you
are attempting to import the code into the database.
Failed to locate module file ‘global.cbs’
You have incorrectly spelled the globals file. It should be global.cbs.
Compile error on line nn of filename.cbs:
Encountered: string
Expecting: <identifier>
You have used a ClearBasic keyword (represented by string) as an
identifier. This is not legal.
Compile error on line nn of filename.cbs
Encountered: Token nnnn
Expecting: <statement>
You may have missed the beginning apostrophe (‘)on a comment line on
the flagged line.

Testing and Debugging 273


Fixing Run-Time Errors

Fixing Run-Time Errors


This section lists and explains some sample run-time errors. To correct these
problems you will need to appropriately modify either the form using the UI
Editor or the CB source file or both. Then, you will need to reimport the form
module into the database and re-run the application.

NOTE: To view run-time error messages in the format shown in this section, you
must start clarify with the -cbdebugger option.

You click a control and nothing happens


The control name you assigned in the form via the UI Editor and the
name of the corresponding event handler in your CB code do not match.
Or, you are compiling your CB code against an incorrect form version.
Runtime error in Form Module "nnnn,’nn’,nn’" at line nnn.
Sub or Function not found.
This error occurs whenever you inadvertently use the wrong syntax for a
method or property. It can also occur when you mistype the name of one
of your own variables.
Runtime error in Form Module "nnnn,’nn’,nn’" at line nnn.
The value "identifier" is not a valid number
Most likely you used a wrong data type for the identifier.
Runtime error in Form Module "nnnn,’nn’,nn’" at line nnn.
The Record object has an unknown RecordType. The
RecordType property must be set before performing this
operation.
Self-explanatory.
Runtime error in Form Module "nnnn,’nn’,nn’" at line nnn.
Index-1 is out of range for list (should be between 0 and
-1)
Self-explanatory

274 Chapter 14
Using the ClearBasic Debugger for Windows

Using the ClearBasic Debugger for Windows


The ClearBasic Debugger for Windows is a full-function debugger that you
can use to locate logic problems in your ClearBasic source code. The
debugger runs as a separate window in your ClarifyCRM eFrontOffice
process.

You can use the debugger to perform the following tasks:


• Set breakpoints in your code
• Step through your code line by line
• Watch the values of variables
• Modify the contents of variables
• View the current sequence of ClearBasic routine calls
• Edit your code during a debugging session and test your changes
The following sections provide more detailed information about how to use
the debugger and its features.

Starting the Debugger


To use the debugger, you must launch your ClarifyCRM eFrontOffice
application using the -cbdebugger command-line option. If you launch the
application from the MS-DOS prompt window, specify this option on the
command-line as follows:
clarify -cbdebugger

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.

To Enable the Debugger from Windows


1. Create a shortcut for the ClarifyCRM eFrontOffice application.
2. Open the Properties window for the shortcut by right-clicking the icon
and choosing Properties from the shortcut menu.

Testing and Debugging 275


Using the ClearBasic Debugger for Windows

3. In the Properties window, select the Shortcut tab.


4. In the Target text box, add the -cbdebugger option to the end of the
command line as shown in Figure 26.

Figure 26 Enabling the ClearBasic Debugger

5. Click OK to close the Properties dialog box.

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.

When you launch ClarifyCRM eFrontOffice with the -cbdebugger option,


the application proceeds as usual to the database login dialog. After you log
in to your database, the console window appears along with the ClearBasic
Debugger window (shown in Figure 27). You can use the debugger window
to set breakpoints and add watchpoints before performing any other actions
in the console. During your debugging session, use the debugger window to
control the execution of your ClearBasic code.

276 Chapter 14
Using the ClearBasic Debugger for Windows

Figure 27 The ClearBasic Debugger window

During debugging sessions, the ClearBasic Debugger normally disables


several caching features associated with ClarifyCRM eFrontOffice. The
debugger disables these caches to prevent conflicts when loading code
modules into the debugger window.

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.

Testing and Debugging 277


Using the ClearBasic Debugger for Windows

About the Debugger Toolbar


The debugger toolbar displays the tools you use to set breakpoints, add
watchpoints, and control the execution of code. Figure 28 shows the toolbar
and identifies each of its buttons.

Figure 28 The ClearBasic Debugger toolbar

Paste End Add Single Step


Copy Break Watch
Cut Start Procedure Step

Undo Calls
Toggle
Breakpoint

Cut Cuts the selected text from the


Editor tab.
Copy Copies the selected text from the
Editor tab.
Paste Pastes text from the clipboard to
the current insertion point in the
Editor tab.
Undo Undo the last operation.
Start Continues execution of code until
the next breakpoint.
Break Pauses the execution of the current
script.
End Terminates the execution of the
current script.
Toggle Adds a breakpoint at the selected
Breakpoint line of code.
Add Watch Adds a watchpoint for the selected
variable.
Calls Views the current call stack.

278 Chapter 14
Using the ClearBasic Debugger for Windows

Cut Cuts the selected text from the


Editor tab.
Single Step Steps into a procedure, or steps
over a single line of code.
Procedure Step Steps over a procedure, or steps
over a single line of code.

About the Debugger Window Tabs


The debugger window contains three main tabs and one additional tab for
modifying code at runtime. These tabs let you organize the information in
your current debugging session.
• The Debugger tab displays the toolbar and the code currently being
executed. Use this tab to step through code, set breakpoints in code, and
add watchpoints. Figure 27 on page 277 shows the debugger window
with the Debugger tab selected.
• The Breakpoints tab displays the current list of breakpoints. This tab lets
you set breakpoints at known subroutines and functions. This tab also
lets you remove and disable breakpoints. Figure 29 shows the
breakpoints tab.

Testing and Debugging 279


Using the ClearBasic Debugger for Windows

Figure 29 The Breakpoints tab

• 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

When the debugger encounters one of your breakpoints, it stops execution


of ClarifyCRM eFrontOffice and displays the code for the current breakpoint
in the debugger window. You can use the debugger to set watchpoints on
variables and step through the code line by line. You can also modify the
current breakpoints.

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.

To set breakpoints from the Breakpoints tab


1. Select the Breakpoints tab.
2. In the Module Name field, type the name of the global module or the ID
number of the form module.
For global modules, you must specify the complete name of the module.
3. In the Function/Line No field, type the complete name of the function or
subroutine you want to break at.
4. If you want to stop at a specific line of the function or subroutine, add a
forward slash (/) followed by the line number to the end of the function
name.
If you do not specify a line number, the debugger stops at the beginning
of the function or subroutine.
5. Click Set.

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.

To set breakpoints directly in your code


1. Select the Debugger tab.
2. Select the line of code where you want to set the breakpoint.
If no code is displayed in the Debugger tab, you must set your
breakpoint using the Breakpoints tab.

Testing and Debugging 281


Using the ClearBasic Debugger for Windows

3. Click the Add Breakpoint button in the toolbar.


The debugger stops the execution of your code at the beginning of the
line containing the breakpoint.

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.

Enabling and Disabling Breakpoints


New breakpoints are enabled automatically when they are created. During a
debugging session you can temporarily disable breakpoints that you do not
need now but may need later. When you disable a breakpoint, the debugger
does not stop at that breakpoint but it does save the breakpoint information
if you end the debugging session.

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

Using the SQL-Log tab


Stepping through ClearBasic code is not always enough to track down
problems in your application. In some cases, you may need to examine the
SQL statements generated during the session. Examining these statements
may show errors occurring in the transfer of information between your
application and the database.

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

Figure 30 The SQL-Log tab

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.

Testing and Debugging 283


Using the ClearBasic Debugger for Windows

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.

To add a new watchpoint


1. Set a breakpoint in one of your code modules.
See the section Setting Breakpoints on page 280 for more information.
2. Display the form that triggers that breakpoint.
3. Click the Add Watch button.
The debugger displays the Add Watch dialog (Figure 31).

Figure 31 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

Figure 32 A sample watchpoint

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.

Viewing and Modifying Variables


In the Debugger tab, you can view the value in any watched variable by
double-clicking its watchpoint entry. You can view the value of any type of
variable, including records and lists.

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.

To change the value of a variable


1. From the Debugger tab, select the desired variable in the watchpoint list.
If the variable does not have a watchpoint, create one as described in the
section Adding Watchpoints.
2. Press Enter to display the Modify Watch dialog.
3. Type a new value in the Value field.
4. Click OK.

Testing and Debugging 285


Using the ClearBasic Debugger for Windows

Using the Debugger Tools


In addition to setting breakpoints and watchpoints in your code, the
ClearBasic Debugger contains several tools that you use to control the
overall debugging session. The following sections describe these tools.

Controlling the Execution of Your Code


When the debugger reaches a breakpoint it stops execution of your code and
displays the code in the debugger window. After you have added any
breakpoints or watchpoints, you use the tools in the Debugger tab’s toolbar
to continue executing your code.

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.

Editing Code at Runtime


The ClearBasic Debugger incorporates functionality from ClearBasic
Exchange (CBEX) that allows you to import and export code modules to and
from the database. This feature allows you to modify a code module during
a debugging session and test your changes immediately.

To Edit a Form Module


1. In the debugger window, choose Export/Open from the File menu.
2. Enter the Form ID and Customer Version information for your form
module.
3. Click OK.
The debugger adds the Editor tab to the debugger window and selects
that tab.
4. Make the changes to your code in the Editor tab.
5. Select Import/Save from the File menu.

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.

Testing and Debugging 287


Using the ClearBasic Debugger for Windows

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.

Support for the Clipboard


The toolbar in the debugger window contains tools for cutting, copying and
pasting text. You can also access these functions from the debugger
window’s Edit menu.

Setting the Debugger Options


The ClearBasic Debugger contains settings for the formatting options used
to distinguish code elements. You can modify these settings and change the
color and font associated with the following elements:
• code comments
• normal text
• selected text
• other identifiers
• breakpoints
• the currently executing line
To modify these options, choose Options from the Preferences menu. The
debugger displays the Settings dialog as shown in Figure 33. Make any
desired changes and click OK to save them.

288 Chapter 14
Using the ClearBasic Debugger for Windows

Figure 33 The debugger settings dialog

Ending a Debugging Session


To end a debugging session, click the close box on the debugger window.
When you confirm that you want to exit the debugger, the debugger
window closes and ends the current session. In order to start a new
debugging session, you must restart the ClarifyCRM eFrontOffice
application.

NOTE: The debugger also shuts down automatically when you close the
ClarifyCRM eFrontOffice application.

If you want to continue testing your application without interruption from


the debugger, remove or disable all breakpoints and click the Start button in
the debugger toolbar. Without any breakpoints set, the debugger stays in
idle mode while you test your application.

Testing and Debugging 289


Using the ClearBasic Debugger for UNIX

Using the ClearBasic Debugger for UNIX


The ClearBasic Debugger for UNIX is a full-function debugger that you can
use to locate logic problems in your ClearBasic source code. You can use the
debugger to perform the following tasks:
• Set breakpoints at all or any specific modules
• Set breakpoints at discrete line numbers in the source code
• Debug the application by stepping through a procedure or function
(execute each statement one at a time) or stepping over a procedure
(execute all the statements in a procedure)
• Watch real-time values of simple variables or complex variables (records,
lists, etc.))
• Save the set breakpoints for later debug sessions
This section describes how to invoke the debugger, set breakpoints, trace
execution, and view variable values.

Invoking the Debugger


To use the debugger, you invoke the CeFO application with the option
-cbdebugger. In UNIX you enter the invocation command at the UNIX
prompt.

To invoke the ClearBasic debugger


1. Change to the directory that contains ClarifyCRM eFrontOffice.
2. Enter the following command at the UNIX prompt:
path/clarify -cbdebugger
path represents the location where the CeFO client software is
installed on your UNIX machine.

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.

3. Enter the required information in the various text boxes in the


dialog box and then click the Login button.
The Session Login dialog box disappears. The application window now
contains the Debugger Window and the ClearSupport window.

NOTE: At this point, the debugger, although invoked, is idle as indicated in


the title bar of the Debugger window.

Testing and Debugging 291


Using the ClearBasic Debugger for UNIX

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.

You can remove any previously set breakpoints.

IMPORTANT: Breakpoints set prior to running a module remain in effect as long as


the module is executing. You cannot remove these breakpoints or set new ones while
the module is running. This is true even though you seemingly can delete old or
add new breakpoints.

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:

3. Repeat Step 1 and Step 2 for setting any additional breakpoints.

Table 14 Setting breakpoints

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

Testing and Debugging 293


Using the ClearBasic Debugger for UNIX

Table 14 Setting breakpoints (Continued)

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

*The debugger does not support debugging of Form_Activate or Form_Deactivate event


handlers. The debugger skips over them. This is also true if you manually set breakpoints at
these event handlers.

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 set breakpoints during a debug session


1. While you are debugging a module and the debugger is displaying code
in the edit area of the Debugger window, position the cursor any where
in the line where you want to set the breakpoint.
2. Click the Toggle Breakpoint button on the toolbar.
The color of the characters on the selected line changes to red and the
new breakpoint setting appears in the Breakpoints Info area.
3. Repeat the preceding steps to set any additional break points as often as
you want.

NOTE: The manually set break points take immediate effect.

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

Debugging a Module in an Application


Once you have set the breakpoints in a module in your application, you can
begin debugging it. Debugging operations include the following:
• Run the application/module to be debugged in debug mode
• View and modify the contents of any supported variables in debug mode
In this context, variables of type string, integer, long, and float are
supported.
• Continue execution into a procedure in single-step mode
• Continue execution over a procedure
• Manually set breakpoints at selected line(s)
• Add watch variable
• View the call stack
To run an application or module in debug mode
1. Run the CeFO application with the debugger invoked.
Refer to the section Invoking the Debugger on page 290.
2. Check out the CeFO license:
a. Choose License from the File menu to display the CeFO License dialog
box:

b. Check the CeFO User License box and click OK.


3. Set the breakpoints in your application/module as described in the
section Setting Breakpoints on page 292.
4. From the Apps menu choose the CeFO application with which the
module to be debugged is associated.
5. From the Select menu, run the application or module to be debugged.
The application/module starts executing and stops when the debugger
encounters the first breakpoint.

Testing and Debugging 295


Using the ClearBasic Debugger for UNIX

To view and modify the contents of a variable


1. In the source code, select (highlight) the variable whose contents you
want to view.
You do this by double-clicking the variable or by dragging the mouse
cursor over it.

NOTE: You cannot directly view the contents of an entire variable of


User-defined Data Type (UDT). However, you can view individual fields in
the variable. Therefore, you must not select a variable of type UDT; instead,
you should select individual fields one by one. See note in Step 5 below.

2. Click the Add Watch button to display the Add Watch dialog box:

The selected variable appears in the Variable text 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.

NOTE: If the target variable is a Global or Public variable, select All


Procedures.

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.

6. To modify the contents of a supported variable, do the following:


a. In the watch pane, double-click the variable whose contents you want
to modify.
The Modify Variable dialog box similar to the following appears.

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.

7. To view the contents of a complex variable (such as records, lists,


controls, contextual objects, forms, etc.) double-click its address value in
the watch pane.
The debugger displays Quick Watch window showing various values in
the complex variable.

Testing and Debugging 297


Using the ClearBasic Debugger for UNIX

To continue the execution


1. If you want to continue the execution according to the previously set
breakpoints, click the Start button in the Debug window toolbar.
The execution stops at the next breakpoint if any. If the debugger does
not encounter any other breakpoint, the execution stops after
executing the rest of the CB code. Note, however, that if the module is
designed to display a form, the execution stops after displaying the
form. You then close the form by clicking the appropriate button,
which usually is the Done button.
2. If, from a breakpoint, you want to step through a procedure or function,
i.e., execute one statement at a time, click the Single Step button in the
Debug window toolbar.
You can view the contents of various variables, as described above, at any
time during single-step execution.

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

To view the call stack


• While the debugger is active, click the Calls button in the Debug window
toolbar.
The debugger displays the Calls list box that shows all the calls that have
been executed thus far. The most recent one is at the top of the list.

To stop the debugger


1. If you want to execute the entire application/module before stopping the
debugger, do the following:
a. Click the Start button in the Debug window toolbar.
The debugger execute the application/module code up to the next
breakpoint, where it pauses and awaits user interaction.
b. Repeat the preceding substep until the entire application code is
executed, which is indicated by the debugger gone Idle.

298 Chapter 14
Using the ClearBasic Debugger for UNIX

c. If the preceding step post any form, manually close it.


2. If you want to stop the debugger randomly, do the following:
a. Click the End button in the Debug window toolbar.
The execution of the application/module stops immediately and the
debugger goes idle.
b. If the preceding step post any form, manually close it.

Debugging Global Modules


The process for debugging global modules is somewhat different. It is
described in the following procedure.

To debug a global module


1. Invoke the ClearBasic debugger as described in the procedure To invoke
the ClearBasic debugger on page 290.
2. Set the breakpoint at the location where the global module or function is
called. For details about setting breakpoints, refer to the procedures To set
breakpoints on page 293 and To set breakpoints during a debug session on
page 294.
3. Click the Start button in the Debug window toolbar.
The debugger stops at the breakpoint set in Step 2 above.
4. Using the Single Step button step through the global module or function
and continue with the debugging process described in the section
Debugging a Module in an Application on page 295

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

Testing and Debugging 299


Using the Debug Window

To save the currently set breakpoints


1. Choose Exit from the File menu.
The debugger displays the following confirmation box:

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.

2. Click Save to save the breakpoints and exit the debugger.

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.

Using the Debug Window


Even if your code compiles correctly and you do not encounter any run-time
problems, your customized application may still not function as intended. In
such situations, you can use the Debug.Print statement to trace the problem.

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.

Using the SQL Log to Debug the Database


Viewing the ClearBasic code behavior is sometimes not enough to unit test
whether your customization was successful. You might want to do a final
check by examining the select, insert, and update SQL statements within the
SQL logfile. This guarantees that the right database interaction truly
happened.

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

In the above statement, SQLON and OVERWRITE_LOG are examples of


constants defined in one of the global modules. In the current command
both will have to be set to Boolean value of True.

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.

Testing and Debugging 301


Summary of Debugging

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

Handling Date and Time

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.

The Server Clock and Client Clock


Client clock. Each client machine has a clock that can be set by the user.
Client time is tied to the this clock on the client machine. Generally, the client
clock is set to the 'real' time of its location; for example, Pacific Time in
California.

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.

ClearBasic and Server/Client Clock Differences


ClearBasic supports the retrieval of both server time and client time, as
described later in this chapter. Equally importantly, ClearBasic automatically
adjusts for all server and client clock differences when retrieving server
times. When server time is retrieved, it is automatically adjusted to local
client times, using a number of mechanisms. One mechanism adjusts for
time zone differences, while another adjusts for the client/server clock
differences that are not caused by time zone differences.

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.

Manipulating Date and Time


You can use ClearBasic to get the current server date and time and to get the
date and time from a database record. However, you should be aware that
the values returned are always string values and must be converted to the
Date data type before you can manipulate them with the various Date
functions that are available.

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.

Handling Date and Time 305


Retrieving Server Date and Time

Retrieving Server Date and Time


You retrieve the current server date and time values using the App object
and the CurrentDate property. To get the current server time, adjusted and
expressed in local client time, use the CurrentDate method as follows:
Dim DateTimeStr as String
DateTimeStr = App.CurrentDate

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.

Retrieving Date and Time From Records


To retrieve date and time values from database records, you must retrieve
the desired records from the database, and then invoke the GetField method
(for the Record object) on the date and time fields, as follows:
Dim DateTimeStr as String
DateTimeStr = YourRecord.GetField("datetime_field")

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.

Converting DateTime Strings To Date Types


You must convert the CeFO datetime string to the Date data type in order to
manipulate the value with ClearBasic Date functions. The Date data type is
supported by ClearBasic and can be declared in local or global variables, as
follows:
Dim MyDate as Date

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.

Converting Date Data Types Back to String


To convert a Date data type back to a string, use the following call:
DateTimeStr = CStr(MyDate)

The above code converts the date type value back into a string that can be
displayed directly to the user.

Retrieving Client Time


To get the client time, use the Time function to return the time as a Date data
type, or the Time$function to return it as a string. These functions are
described in detail in the ClearBasic Language Reference.

Functions for Date and Time Manipulation


ClearBasic allows you to manipulate date and time values in a variety of
ways. Table 15 summarizes of the functions that currently can be used to
manipulate variables of the Date data type:

Table 15 Functions for manipulating date/time values

Function Description
DateAdd Add a number of date intervals to a date
DateDiff Subtract a number of date intervals from
a date

Handling Date and Time 307


Elapsed Time

Table 15 Functions for manipulating date/time values (Continued)

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

These functions are described in detail in the ClearBasic Language Reference.


These functions should allow for any necessary manipulation of datetime
values that are needed by a client application.

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.

DateTime Values in Database Records


Records can contain fields that have a data type of 'date and time'. That is,
they contain a single value consisting of date and time. These fields are
stored in the database in the native format of the RDBMS date and time, but
are automatically converted to equivalent displayable strings when
retrieved using the GetField method, as in the following example:
Dim DateTimeStr as String
DateTimeStr = YourRecord.GetField("datetime_field")

As noted previously, the date and time is automatically converted to a value


relative to the local client machine clock. For example, if the server is in
Boston and the client in California, then the value is adjusted by 3 hours
when retrieved from the database.

The datetime value retrieved from a Record can be converted to a Date


variable, and manipulated in the ways described previously. For example,
an elapsed time could be added to the date value, to give a resulting date
value that is, say, 8 hours advanced from the previous value.

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)

Handling Date and Time 309


Using Comparison Operators

Using Comparison Operators


You may be able to use the comparison operators like > directly on the Date
variables; however, this practice can lead to undesired results due to the
inaccuracy of this type of comparison. For example, you can have two date
and times that are slightly different (say, by a fraction of a second) and that
display as the 'same value' but a comparison of them may show them to be
different.

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

Accessing External Databases With


SQL

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.

This appendix describes what you need to do to connect, disconnect, and


send SQL statements.

Declaring a SQLDB Object


Before you can open a connection to a database, you must declare a SQLDB
object as follows:
dim YourSQLDB as new SQLDB

You can use this object to make one connection at a time.

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

Checking For a Valid Connection


After you connect to the database, you should check for a valid connection
using the Connected property.

Disconnecting From the Database


You should invoke this method when you are finished with a particular
connection. If you don’t, server and network performance can be adversely
affected.

To disconnect from a database, use the following syntax:


YourSQLDB.Disconnect

You cannot use this method to terminate the connection to the login
database.

Issuing a Non-Returning SQL Statement


If you want to issue a SQL statement that does not return any values, such as
update or delete, use the Execute method, with the following syntax:
YourSQLDB.Execute SQLStatement

where SQLStatement is a string variable containing the SQL statement you


want to issue. The statement cannot exceed 6144 characters.

Accessing External Databases With SQL 313


Issuing a Non-Returning SQL Statement

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

Issuing a SQL Select Statement


If you want to issue a SQL Select statement, use the Select method, with the
following syntax:
NumRecordsFound = YourSQLDB.Select (SQLStatement,
DestinationList, DestinationFields)
where SQLStatement is a string variable containing the SQL statement you
want to issue. (Make sure the statement begins with the verb "select"!) The
statement cannot exceed 6144 characters.

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"

Accessing External Databases With SQL 315


Invoking a Stored Procedure that Returns Values

SqlStatement = "select uId, site_id, ord_nr," & _


"description, convert(char(8),due_dt,1)," & _
"convert(char(8),notify_dt,1)," & _
"amount from order_tbl" & _
"where site_id='" & gSiteVal & "'"
toDB.Connect "MUGS", "cbforin", "sa", "sax"
toDB.Select SqlStatement, ordList
toDB.Disconnect
For Ind=0 to ordList.Count - 1
ordList.GetItemByIndex Ind,ordRecord
If (ordRecord.notify_dt = "01/01/00") Then
ordRecord.notify_dt = " "
ordList.ReplaceByIndex Ind, ordRecord
End If
Next
Cobj_ord_record.Fill ordList
End Sub

Invoking a Stored Procedure that Returns Values


You can invoke a stored procedure that requires a list of different types of
input values, for example, integers, strings, longs and that returns values.
You can do this using the ExecuteProc method. Any returned values must be
placed in the return parameter, which must be a user defined type.

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

First, an input list(InList) is filled with values required by the stored


procedure (Test1). Notice that the list is set to the type "variant." You must
use the list type of variant if the list contains values of different types, in our
example string and integer.

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

Accessing External Databases With SQL 317


Invoking a Stored Procedure that Returns Values

318 Chapter 16
Appendix A

The Former Default Global File

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.

The Default CeFO Global File


The former default CeFO Globals file included the following statements:
Global Const USE = 1
Global Const NEW_ONE = 2
Global Const SEL = 3
Global Const INV_LOC_CLASS = 0
Global Const CAP_GL_CLASS = 1
Global Const EXP_GL_CLASS = 2
Global Const FRONT_IF_UP = 1 'Form.Show option

'' Global variables and types needed for the


‘’ ClearLogistics GL interface

Global GLComTemplate as Record

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

Global gl_inv_mode as Integer


Global use_mode as Integer
Global location_obj as Record
Global parent as Form
Global bin_obj as Record
Global current_bin_obj as Record

Function Confirm_Changes(title as String, add_ctl as


Control, replace_ctl as Control, ByVal mb_type as
Integer)
'''''''''''''''''''''''''''''''''''''''''''''''''''
' This function posts a confirmation window with the
‘appropriate message

Dim dummy1 as GLSummary


Dim dummy2 as GLRun
Dim message as String
Dim default_label as String
If (add_ctl.Default = TRUE) Then

The Former Default Global File 321


Overview

default_label = "ADD"
Else
default_label = "REPLACE"
End If

message = "Window '" + title + "' has changed." +


Chr$(10) + "Do you wish to " + default_label +
" the item?"

Confirm_Changes = App.MsgBox(message, mb_type)


End Function

Sub Form_Save1(abc as BulkSave)


End Sub

Sub Form_Save2(abc as BulkSave)


End Sub

Sub Form_Save3(abc as BulkSave)


End Sub

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

Dim GLForm as New Form


GLForm.Show 522, FRONT_IF_UP
End Sub

The Former Default Global File 323


Overview

324 Appendix A
Appendix B

Writing Procedures for DDE Clients

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.

Table 16 DDE 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?

Table 16 DDE Messages (Continued)

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.

Writing Procedures for DDE Clients 327


Prerequisites

What is Supported by CeFO Applications?


Out of the messages listed in Table 16 on page 326, CeFO applications
supports only the following:
DDE_ACK
DDE_EXECUTE
DDE_INITIATE
DDE_TERMINATE

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.

Using DDE Protocols


To use the DDE protocols, you need to perform specific tasks on the CeFO
side and on the DDE client application side.

On the CeFO end, do the following:

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.

The above steps are illustrated in the following example.

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.

Let us assume the following:


• You want to run the GlobalProc procedure in the CeFO application
window whenever you press the Send button in the DDE client window.
• When done, you click the Close button to close the DDE link with the
DDE server.
• GlobalProc resides in the global module in the CeFO database.
• The DDE client window is a form called Form1.
To accomplish this you would write the following Visual Basic code and
compile it associating with Form1.
Sub Form_Load()

Writing Procedures for DDE Clients 329


A Usage Example

‘Enable the Send button


Send.Enabled = True
‘Disable the Close button
Close.Enabled = False
‘Assemble the application:topic string
‘txt.DDE refers to an edit box
‘The LinkTopic method is how Visual Basic
‘assembles an application:topic string. Your
‘lanaguage may use a different method.
Form1.txtDDE.LinkTopic = "ClarifyApp" & "|" & "Clarify"
‘Establish a cold link, or initiate conversation
‘This is equivalent to the DDE_INITITATE message
Form1.txtDDE.LinkMode = vbLinkManual
‘Insert error handler code here
...
End Sub

‘Functionality associated with the Send button


Sub Send_Click ()
‘Send the "execute comand string" message
‘This is equivalent to the DDE_EXECUTE message
‘P1-Pn represent the command parameters
Form1.txtDDE.Link_Execute = "GlobalProc, P1, P2,
...Pn"
End Sub

330 Appendix B
A Usage Example

‘Functionality assoociated with the Close button


Sub Close_Click ()
‘Terminate conversation
‘This is equivalent to the DDE_TERMINATE message
Form1.txtDDE.LinkMode = vbLinkNone
End Sub.

Writing Procedures for DDE Clients 331


A Usage Example

332 Appendix B
Appendix C

ClearBasic Pre-Defined Constants

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.
:

Table 17 ClearBasic constants

Usage Constant Associated Methods


MsgBox Options cbOK MsgBox
cbOKCancel
cbAbortRetryIgnore
cbYesNoCancel
cbYesNo
cbRetryCancel
MsgBox Return Values cbIdOK MsgBox
cbIdCancel
cbIdAbort
cbIdRetry
cbIdIgnore
cbYes
cbNo
Window Messaging cbCloseMessage Close
cbCloseChildren
cbRefreshMessage Refresh
cbFirstMessage
cbDefClosedWindow DoDefault
Passing Options cbByRef ChangeRecord
UpdateRecord
InsertRecord
DeleteRecord
GetRecordList
GetRelatedRecordList
cbByValue

334 Appendix C
Overview

Table 17 ClearBasic constants (Continued)

Usage Constant Associated Methods


Query Operators cbGreater AppendFilter method
cbGreaterorEqual
cbLess
cbLessOrEqual
cbEqual
cbNotEqual
cbLike
cbNotLike
cbSoundsLike
cbIn
Query Sorting Options cbAscending AppendSort method
cbDescending
DoDefault Options cbNoDefault DoDefault method
cbDefClosedWindow
Clipboard Format Options cbFormatText GetFormat method
cbFormatBitmap
Common Dialog Action cbCDOpen Action method
Options
cbCDSaveFile
cbCDPageSetup
cbCDDateTime
cbCDElapsedTime
cbCDReturnNone
Show Options cbFrontIfUp Show method
Record Copy Options cbChangeToNew Copy method
Boolean True/False

ClearBasic Pre-Defined Constants 335


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.

User Version Numbering for Forms


The UIEditor enables you to assign a user version number each time you
modify a form. This user-version is alpha-numeric. You should take great
care when modifying a form so that you retain control of the these version
numbers. We recommend the following methodology:
• When starting a new set of edits in the Development database, save the
form using a new user version number.
• During development, save updates under the same user version number.
• After development is complete and before exporting to any other
database, freeze the user version number, and new edits should be
applied to a new user version number.

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.

Parallel Development of Forms


If you are going to develop several user versions of a window in parallel,
then you will need extra precautions with the version numbering. For
example, consider a multinational implementation with German, French
and English versions of the screens. The version number should reflect the
language and the functionality, thus you might have version 1.1, f1.1, and
g1.1. Similarly, you may make parallel functional developments because
you have different functional groups within your organization which
require separate versions of the same screen; use a similar method to
identify the version. For example:

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.

Customization Methodology 339


Porting Customizations to Another Database

Porting Customizations to Another Database


The process flows in the preceding customization sections refer to the
process of porting the respective changes to the production database. You
should be aware of a few additional considerations when porting
customizations:

Recommended Order of Customizations


It is recommended that you use the following order for customizing:
1. Schema changes
2. UI changes
3. ClearBasic changes

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.

Porting Individual Customizations


When individually porting customized schema changes that involve adding
new database objects to object.sch (i.e. not porting the entire object.sch file),
there is the potential that the Type ID number from the source database is
already being used in the destination database by another table or view.

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.

Customization Methodology 341


Exporting Resource Configurations

Exporting Resource Configurations


If you use the UIEditor to export a resource config, it also exports all the
customized forms associated with the resource config, therefore, you do not
need to individually export/import each of the customized screens.

Exporting an Individual Form


When you export an individual form using the UIEditor, it not only exports
the objects associated with the form, but it also exports all the privilege
classes in the database as reference objects. Consequently, if you have
added a customized privilege class in the source database (e.g. the
development database) and have not added that same privilege class to the
destination database (e.g. the test database), when you use dataex to import
the custom form, you are apt to get the following error message:
% $CLARIFY_DIR/dbadmin/dataex -db_server CUSMS
-db_name cl40 -user_name sa -password sa0 -imp
610.dat
Initializing batch 4031/release/sybase/sun_server/
dbadmin/dataex...
Opening database 'cl40'... Done.
Reading data schema from database...
Checking relations...
Optimizing schema...
Done with schema
*** IMPORTING FROM file '610.dat' (log file is
'dataex.log')
*** FOUND 1 errors, 0 warnings.
Check file 'dataex.mes' for details...
sce_main_process_batch: could not import file '610.dat'
Import Error:
>> The object 'PRIVCLS_New_QA_Engineer' on line 597 could
not be located using the given fields
*** ERRORS ENCOUNTERED WITH BATCH commands; exiting...

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:

REFERENCE TYPE="privclass", NAME="PRIVCLS_CSR"


UNIQUE_FIELD=class_name
FIELDS
class_name ="CSR";
access_mask ="FFFFFFF FFFF FFFFTFFFFFF FF FF
FFFFFF FFF";
... other fields ...
remote_allowed=0;
END_FIELDS

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.

Customization Methodology 343


Testing and Debugging

Testing and Debugging


You must log into the CeFO application after the CB modules have been
successfully compiled, because Update Desktop does not currently re-cache
the form modules.

344 Appendix D
Accessing Data From Other Databases

Accessing Data From Other Databases


It is not uncommon for a feature to require data that is not stored in the
CeFO database. If that data is stored in a SQL database (Sybase, Oracle, or
SQL Server), it is possible to retrieve the data directly with ClearBasic.

The important points to remember are as follows:


• Read the SQL data into a List object (even if you know you only have one
result row being returned).
• Set the ItemType of the List so that CB knows what kind of list is being
returned. The type of the list will usually be a UDT.
• Either fill a contextual object with the list (if the contextual object will be
used for a Custom List), or extract the object from the list, and then assign
it to the contextual object (if you are putting the data into text fields, edit
fields…).

LIMITATION: Accessing data in another database requires that the other


database be on the same RDBMS and also on a compatible revision of that
RDBMS.

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 “%”.

Customization Methodology 345


Accessing Data From Other Databases

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

You might also like