Progress
Progress
Language Tutorial
for Windows
Progress software products are copyrighted and all rights are reserved by Progress Software Corporation.
This manual is also copyrighted and all rights are reserved. This manual may not, in whole or in part, be
copied, photocopied, translated, or reduced to any electronic medium or machine-readable form without
prior consent, in writing, from Progress Software Corporation.
The information in this manual is subject to change without notice, and Progress Software Corporation
assumes no responsibility for any errors that may appear in this document.
The references in this manual to specific platforms supported are subject to change.
Progress, Progress Results, Provision and WebSpeed are registered trademarks of Progress Software
Corporation in the United States and other countries. Apptivity, AppServer, ProVision Plus, SmartObjects,
IntelliStream, and other Progress product names are trademarks of Progress Software Corporation.
SonicMQ is a trademark of Sonic Software Corporation in the United States and other countries.
Progress Software Corporation acknowledges the use of Raster Imaging Technology copyrighted by
Snowbound Software 1993-1997 and the IBM XML Parser for Java Edition.
IBM Corporation 1998-1999. All rights reserved. U.S. Government Users Restricted Rights Use,
duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
Progress is a registered trademark of Progress Software Corporation and is used by IBM Corporation in the
mark Progress/400 under license. Progress/400 AND 400 are trademarks of IBM Corporation and are used
by Progress Software Corporation under license.
Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the
United States and other countries.
Any other trademarks and/or service marks contained herein are the property of their respective owners.
.
May 2001
Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Organization of This Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
How to Use This Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Typographical Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Syntax Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Example Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Progress Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Other Useful Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Development Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Reporting Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4GL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
DataServers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SQL-89/Open Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SQL-92 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
WebSpeed. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.
Welcome to Progress . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1
Progress Solves Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.1
A Classic Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2
The Progress Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3
About the Progress 4GL/RDBMS Product . . . . . . . . . . . . . . . . . . . . . . .
1.4
About the Relational Database Management System . . . . . . . . . . . . . .
1.4.1
Database Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xvii
xvii
xvii
xvii
xix
xx
xxi
xxiv
xxvi
xxviii
xxviii
xxix
xxx
xxxi
xxxii
xxxii
xxxii
xxxiii
xxxiv
xxxiv
xxxv
11
12
12
14
15
16
16
Contents
1.5
1.6
2.
3.
iv
1.4.2
About the Data Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
About the Application Development Language . . . . . . . . . . . . . . . . . . . .
1.5.1
About the Procedure Editor . . . . . . . . . . . . . . . . . . . . . . . . . . .
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
110
110
112
112
Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1
Preparing to Use This Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2
Accessing the Language Tutorial Sample Procedures . . . . . . . . . . . . . .
2.3
Starting Progress . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.1
Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.2
ADE Desktop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4
About the Procedure Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.5
Setting PROPATH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.6
Using Object Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.7
Using Mouse Functions, Key Functions, and Menus . . . . . . . . . . . . . . .
2.7.1
Basic Mouse Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.7.2
Basic Key Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.7.3
Menus and Menu Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.8
Text Entry and Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.8.1
Manipulating Blocks of Text . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.9
Edit Buffers and Procedure Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.10
Basic 4GL Constructs and Conventions . . . . . . . . . . . . . . . . . . . . . . . . .
2.11
The Progress Help System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.11.1 Accessing Help from the Procedure Editor . . . . . . . . . . . . . . . .
2.11.2 Using the Help Topics: Windows Help Topics dialog box . . . .
2.11.3 Getting Help on 4GL Language Elements . . . . . . . . . . . . . . . .
2.11.4 Accessing 4GL Language and 4GL Cross Reference Language
Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.12
Leaving the Procedure Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.13
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
22
22
22
22
23
24
25
26
27
27
28
29
212
214
215
218
219
219
221
223
31
32
32
35
38
312
314
316
316
328
330
333
341
224
227
228
Contents
3.5.1
Enabling and Disabling Widgets . . . . . . . . . . . . . . . . . . . . . . .
3.5.2
Viewing and Hiding Widgets . . . . . . . . . . . . . . . . . . . . . . . . . .
3.5.3
Accessing Widget Attributes and Methods. . . . . . . . . . . . . . . .
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
341
344
349
353
4.
41
42
42
44
44
44
46
47
47
48
48
49
411
412
412
412
414
415
417
417
419
420
422
423
423
424
425
5.
51
52
52
53
58
59
510
510
514
514
515
3.6
Contents
5.5
5.6
515
518
518
519
519
520
525
6.
61
62
62
66
68
610
610
611
617
621
622
623
624
624
626
629
631
632
632
633
637
7.
71
72
73
74
77
78
79
712
717
722
723
726
728
729
5.7
vi
Contents
7.4.2
Checked Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.4.3
Toggle Box Programming Example . . . . . . . . . . . . . . . . . . . .
Working with Radio Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.5.1
Radio Set Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.5.2
Radio Set Programming Example . . . . . . . . . . . . . . . . . . . . . .
Working with Sliders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.6.1
Slider Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.6.2
Slider Programming Example . . . . . . . . . . . . . . . . . . . . . . . . .
Working with Selection Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.7.1
Selection-list Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.7.2
LIST-ITEMS, NUM-ITEMS, and DELIMITER Attributes. . . . . .
7.7.3
ADD-LAST( ) and LOOKUP( ) Methods. . . . . . . . . . . . . . . . . .
7.7.4
Selection-list Programming Example . . . . . . . . . . . . . . . . . . .
Working with Combo Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.8.1
Combo Box Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.8.2
Combo Box Programming Example . . . . . . . . . . . . . . . . . . . .
Working with Editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.9.1
Editor Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.9.2
Editor Programming Example . . . . . . . . . . . . . . . . . . . . . . . . .
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
729
730
732
733
734
738
740
741
744
747
748
748
749
752
755
756
758
760
761
764
8.
81
82
84
87
812
818
820
823
824
832
838
840
844
849
849
850
851
852
865
9.
91
92
92
7.5
7.6
7.7
7.8
7.9
7.10
vii
Contents
9.2.1
Selecting with a WHERE Expression . . . . . . . . . . . . . . . . . . . .
9.2.2
Selecting with the USING Option . . . . . . . . . . . . . . . . . . . . . . .
9.2.3
Query and Selection Programming Example . . . . . . . . . . . . . .
Sorting Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.3.1
Sorting Records with the BY Phrase. . . . . . . . . . . . . . . . . . . . .
9.3.2
Sorting Records with the USE-INDEX Option. . . . . . . . . . . . . .
9.3.3
Querying and Sorting Example . . . . . . . . . . . . . . . . . . . . . . . . .
Relating Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.4.1
Understanding Table Relationships . . . . . . . . . . . . . . . . . . . . .
9.4.2
Relating Record Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.4.3
Relating with OF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.4.4
Relating with WHERE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.4.5
Inner and Outer Table Joins . . . . . . . . . . . . . . . . . . . . . . . . . . .
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
94
95
96
99
99
912
913
915
916
918
919
922
924
928
Creating Reports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.1
Report Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.1.1 Down Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.1.2 Text Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.1.3 Control Blocks and Output Statements . . . . . . . . . . . . . . . . . . .
10.1.4 Basic Report Demonstration . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2
Designing an Interface for Viewing Report Data . . . . . . . . . . . . . . . . . . .
10.3
Converting Widget Values to Report Data . . . . . . . . . . . . . . . . . . . . . . .
10.3.1 Printing Reports and the STREAM-IO Option. . . . . . . . . . . . . .
10.3.2 Formatting Long Text Strings . . . . . . . . . . . . . . . . . . . . . . . . . .
10.4
Generating Reports with Control Breaks and Aggregates . . . . . . . . . . .
10.5
Generating Reports from Multiple Tables . . . . . . . . . . . . . . . . . . . . . . . .
10.5.1 Reporting Information from One Table . . . . . . . . . . . . . . . . . . .
10.5.2 Reporting Information from Two Tables . . . . . . . . . . . . . . . . . .
10.5.3 Reporting Information from Multiple Tables . . . . . . . . . . . . . . .
10.6
Redirecting Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.6.1 OUTPUT TO and the Default Stream . . . . . . . . . . . . . . . . . . . .
10.6.2 Directing Output to a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.6.3 Directing Output to a Printer . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.6.4 Directing Output to Multiple Destinations . . . . . . . . . . . . . . . . .
10.7
Designing Frames for Reports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.7.1 Using Base Fields with the @ Option . . . . . . . . . . . . . . . . . . . .
10.7.2 Using the HEADER of a Frame for Running Page Heads . . . .
10.7.3 Using the HEADER of a Frame for Running Page Footers . . .
10.7.4 Programming Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.8
Using the PUT Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.8.1 Using PUT for Printer Control . . . . . . . . . . . . . . . . . . . . . . . . .
10.9
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
101
102
102
103
104
105
107
1011
1011
1012
1015
1019
1019
1020
1022
1024
1024
1026
1027
1028
1029
1029
1030
1032
1033
1036
1041
1044
9.3
9.4
9.5
10.
viii
Contents
11.
Building Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.1
Menu Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.2
Defining a Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.2.1 Defining a Submenu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.2.2 Defining a Menu Bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.2.3 Assigning a Menu Bar to a Window . . . . . . . . . . . . . . . . . . . .
11.2.4 Assigning Triggers to Menu Items . . . . . . . . . . . . . . . . . . . . . .
11.2.5 Menu Bar Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.3
Using Optional Menu Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.3.1 Disabled Menu Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.3.2 Toggle Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.3.3 Mnemonics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.3.4 Accelerators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.3.5 Programming Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.4
Menu Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.5
Design Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.6
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
111
112
113
114
116
118
118
1110
1114
1114
1115
1115
1116
1117
1119
1120
1121
12.
121
122
122
123
124
124
125
125
1210
1211
1211
1216
1219
1222
1227
1227
1228
1228
1229
13.
131
132
133
133
133
134
ix
Contents
13.6
13.7
13.8
13.9
13.10
13.11
13.12
Record Reading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Working with Large Data Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Multiple-window Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Dynamic Widgets and Direct Manipulation . . . . . . . . . . . . . . . . . . . . . . .
Graphical Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Internationalization and Localization . . . . . . . . . . . . . . . . . . . . . . . . . . . .
134
134
135
135
135
136
137
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Glossary1
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Index1
Contents
Figures
Figure 11:
Figure 12:
Figure 13:
Figure 14:
Figure 15:
Figure 21:
Figure 22:
Figure 23:
Figure 24:
Figure 25:
Figure 26:
Figure 27:
Figure 28:
Figure 31:
Figure 32:
Figure 33:
Figure 34:
Figure 41:
Figure 42:
Figure 43:
Figure 44:
Figure 45:
Figure 46:
Figure 47:
Figure 48:
Figure 49:
Figure 410:
Figure 411:
Figure 412:
Figure 61:
Figure 62:
Figure 63:
Figure 64:
Figure 65:
Figure 71:
Figure 72:
Figure 73:
Figure 74:
Figure 75:
Figure 76:
Figure 77:
Figure 78:
Figure 79:
13
15
17
18
19
23
24
210
220
221
222
222
223
33
34
313
334
43
47
410
412
413
414
416
418
418
420
422
423
63
65
67
69
611
77
722
726
728
732
738
744
753
758
xi
Contents
Figure 81:
Figure 82:
Figure 83:
Figure 84:
Figure 85:
Figure 86:
Figure 87:
Figure 88:
Figure 89:
Figure 810:
Figure 811:
Figure 812:
Figure 813:
Figure 814:
Figure 815:
Figure 816:
Figure 817:
Figure 818:
Figure 819:
Figure 820:
Figure 821:
Figure 91:
Figure 92:
Figure 93:
Figure 94:
Figure 95:
Figure 111:
Figure 121:
Figure 122:
Figure 123:
Figure 124:
xii
Data Locations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
Data Movement in Progress . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
Basic Database Access Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
How a Database Access Form Works . . . . . . . . . . . . . . . . . . . . . . . . .
86
Data Form with Navigation Buttons Enabled . . . . . . . . . . . . . . . . . . . .
812
Data Movement with the FIND Statement . . . . . . . . . . . . . . . . . . . . . . .
813
Data Movement with the DISPLAY Statement . . . . . . . . . . . . . . . . . . .
814
Data Movement with the GET Statement . . . . . . . . . . . . . . . . . . . . . . .
820
Database Access Form with Update Enabled . . . . . . . . . . . . . . . . . . . .
824
Data Movement with the ENABLE Statement . . . . . . . . . . . . . . . . . . . .
826
Data Movement with the ASSIGN Statement . . . . . . . . . . . . . . . . . . . .
827
Data Movement with the UPDATE Statement . . . . . . . . . . . . . . . . . . .
833
Data Movement with the RELEASE Statement . . . . . . . . . . . . . . . . . .
839
Data Movement with the CREATE Statement . . . . . . . . . . . . . . . . . . .
840
Data Movement with the DELETE Statement . . . . . . . . . . . . . . . . . . . .
844
Data Movement with the PROMPTFOR Statement . . . . . . . . . . . . . .
849
Data Movement with the SET Statement . . . . . . . . . . . . . . . . . . . . . . .
850
Data Movement with the INSERT Statement . . . . . . . . . . . . . . . . . . . .
851
Parts of a Read-only Browse Widget . . . . . . . . . . . . . . . . . . . . . . . . . .
852
Parts of an Updatable Browse Widget . . . . . . . . . . . . . . . . . . . . . . . . .
853
Database Access Form with a Browse Widget . . . . . . . . . . . . . . . . . . .
854
Table Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
916
One-to-one Relationship . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
917
One-to-many Relationship . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
917
Inner Join . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
926
Left Outer Join . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
927
Example of a Window with a Menu Bar . . . . . . . . . . . . . . . . . . . . . . . .
113
Flat Structure of an Event-driven Application . . . . . . . . . . . . . . . . . . . .
122
A Modeless Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1217
A Modal Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1218
QUESTION Alert Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1221
Contents
Tables
Table 21:
Table 22:
Table 23:
Table 24:
Table 25:
Table 26:
Table 27:
Table 31:
Table 32:
Table 33:
Table 34:
Table 41:
Table 42:
Table 43:
Table 44:
Table 45:
Table 46:
Table 47:
Table 48:
Table 51:
Table 52:
Table 53:
Table 54:
Table 55:
Table 56:
Table 57:
Table 58:
Table 61:
Table 62:
Table 71:
Table 72:
Table 73:
Table 74:
Table 75:
Table 76:
28
29
212
213
215
216
220
314
329
332
332
48
411
413
415
416
419
421
424
53
510
511
512
513
513
514
517
66
631
72
75
78
714
733
739
748
748
754
759
815
825
855
xiii
Contents
Table 84:
Table 91:
Table 92:
Table 93:
Table 101:
Table 102:
Table 111:
Table 112:
Table 113:
Table 114:
Table 115:
Table 116:
Table 121:
Table 122:
Table 123:
xiv
857
93
99
919
1015
1025
114
115
117
1119
1119
1120
126
1214
1220
Contents
Procedures
lt-03-01.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-03-02.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-03-03.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-03-04.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-03-05.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-03-06.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-03-07.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-03-08.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-03-09.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-03-10.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-05-01.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-05-02.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-06-01.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-06-02.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-06-03.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-06-04.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-06-05.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-01.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-02.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-03.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-04.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-05.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-06.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-07a.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-08.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-09.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-07-10.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-08.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-f1.i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-01.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-02.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-03.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-04.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-05.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-06.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-07a.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-08-07b.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-09-01.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-09-02.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-09-03.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-09-04.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-09-05.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lt-10-01.p . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
310
319
321
323
325
339
343
348
351
57
522
616
616
616
628
635
711
716
721
725
731
735
742
751
757
762
89
811
817
822
829
837
843
847
862
863
97
912
914
922
924
106
xv
Contents
lt-10-02.p
lt-10-04.p
lt-10-05.p
lt-10-06.p
lt-10-07.p
lt-10-08.p
lt-10-09.p
lt-10-10.p
lt-10-11.p
lt-10-12.p
lt-10-13.p
lt-11-mn.i
lt-11-01.p
lt-11-02.p
lt-12-01.p
lt-12-04.p
xvi
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
.............................................................
109
1014
1018
1019
1021
1022
1026
1034
1038
1039
1042
1111
1113
1118
129
1226
Preface
Purpose
This book introduces the basic concepts of the Progress 4GL and programming model and
provides opportunities for hands-on experience designing applications and user interfaces.
Audience
This book is intended for the person with some programming experience who wants to start
developing applications in Progress.
xviii
Preface
Problem 5-1
lt-05-s1.p
Using a FOR EACH block, increase all customer credit limits by 10%. Display the
customer name, old credit limit, and new credit limit.
You can access the sample solutions on-line. Refer to the Example Procedures section later
in this Preface for the specific details to access this information.
The best advice for success is to set a pace for yourself that makes the tutorial fun and gives you
plenty of time to practice what you learn.
xix
Typographical Conventions
This manual uses the following typographical conventions:
New terms
Monospaced typeface
indicates:
Code examples
System output
Small capitals are used for Progress key functions and generic keyboard keys.
END-ERROR, GET, GO
ALT, CTRL, SPACEBAR, TAB
When you have to press a combination of keys, they are joined by a dash. You press and
hold down the first key, then press the second key.
CTRLX
When you have to press and release one key, then press another key, the key names are
separated with a space.
ESCAPE H
ESCAPE CURSOR-LEFT
xx
Preface
Syntax Notation
The syntax for each component follows a set of conventions:
Uppercase words are keywords. Although they are always shown in uppercase, you can
use either uppercase or lowercase when using them in a procedure.
In this example, ACCUM is a keyword:
SYNTAX
ACCUM aggregate expression
Italics identify options or arguments that you must supply. These options can be defined
as part of the syntax or in a separate syntax identified by the name in italics. In the
ACCUM function above, the aggregate and expression options are defined with the
syntax for the ACCUM function in the Progress Language Reference.
You must end all statements (except for DO, FOR, FUNCTION, PROCEDURE, and
REPEAT) with a period. DO, FOR, FUNCTION, PROCEDURE, and REPEAT
statements can end with either a period or a colon, as in this example:
Square brackets ([ ]) around an item indicate that the item, or a choice of one of the
enclosed items, is optional.
In this example, STREAM stream, UNLESS-HIDDEN, and NO-ERROR are optional:
SYNTAX
DISPLAY
STREAM stream
] [
UNLESS-HIDDEN
][
NO-ERROR
In some instances, square brackets are not a syntax notation, but part of the language.
xxi
, constant
] ...
Braces ({ }) around an item indicate that the item, or a choice of one of the enclosed
items, is required.
In this example, you must specify the items BY and expression and can optionally
specify the item DESCENDING, in that order:
SYNTAX
BY expression
DESCENDING
]}
In some cases, braces are not a syntax notation, but part of the language.
For example, a called external procedure must use braces when referencing arguments
passed by a calling procedure. In these cases, normal text braces ( { } ) are used:
SYNTAX
{ &argument-name }
xxii
EACH
FIRST
LAST
record-phrase
Preface
In this example, you must select one of logical-name or alias:
SYNTAX
CONNECTED (
logical-name
alias
Ellipses (...) indicate that you can choose one or more of the preceding items. If a group
of items is enclosed in braces and followed by ellipses, you must choose one or more of
those items. If a group of items is enclosed in brackets and followed by ellipses, you can
optionally choose one or more of those items.
In this example, you must include two expressions, but you can optionally include more.
Note that each subsequent expression must be preceded by a comma:
SYNTAX
MAXIMUM ( expression , expression
, expression
] ...
In this example, you must specify MESSAGE, then at least one of expression or SKIP,
but any additional number of expression or SKIP is allowed:
SYNTAX
MESSAGE
expression
SKIP
(n)
] } ...
In this example, you must specify {include-file, then optionally any number of
or &argument-name = "argument-value", and then terminate with }:
argument
SYNTAX
{ include-file
argument
&argument-name = "argument-value"
] ...
In some examples, the syntax is too long to place in one horizontal row. In such cases,
optional items appear individually bracketed in multiple rows in order, left-to-right and
top-to-bottom. This order generally applies, unless otherwise specified. Required items
also appear on multiple rows in the required order, left-to-right and top-to-bottom. In cases
where grouping and order might otherwise be ambiguous, braced (required) or bracketed
(optional) groups clarify the groupings.
xxiii
[
[
ACCUM max-length
][
STREAM-IO ]
CENTERED
] [ expression DOWN ]
] [ SIDE-LABELS ]
n COLUMNS
In this example, ASSIGN requires one of two choices: either one or more of field, or one
of record. Other options available with either field or record are grouped with braces
and brackets. The open and close braces indicate the required order of options:
SYNTAX
ASSIGN
{{ [
{
FRAME frame
field
]
] }
]
= expression
[ WHEN expression
} ...
| { record [ EXCEPT field ... ] }
}
Example Procedures
This manual provides numerous example procedures that illustrate syntax and concepts.
Examples use the following conventions:
If they are available online, the name of the procedure appears above the left corner of the
box and starts with a prefix associated with the manual that references it, as follows:
Progress External Program Interfaces, for example, e-ddeex1.p
e-
lt-
p-
r-
If the name does not start with a listed prefix, the procedure is not available online.
xxiv
Preface
If they are not available online, they compile as shown, but might not execute for lack of
completeness.
You must first create all subdirectories required by a library before attempting to extract files
from the library. You can see what directories and subdirectories a library needs by using the
PROLIB -list command to view the contents of the library. See the Progress Client Deployment
Guide for more details on the PROLIB utility.
Extracting source files from a procedure library involves running PROENV to set up your
Progress environment, creating the directory structure for the files you want to extract, and
running PROLIB.
1 From the Control Panel or the Progress Program Group, double-click the Proenv icon.
2 The Proenv Window appears, with the proenv prompt.
Running Proenv sets the DLC environment variable to the directory where you installed
Progress (by default, C:\Program Files\Progress). Proenv also adds the DLC
environment variable to your PATH environment variable and adds the bin directory
(PATH=%DLC%;%DLC%\bin;%PATH%).
3 Enter the following command at the proenv prompt to create the prodoc directory in your
Progress working directory (by default, C:\Progress\Wrk):
MKDIR prodoc
MKDIR prodoc\langref
5 To extract all examples in a procedure library directory, run the PROLIB utility. Note that
you must use double quotes because Program Files contains an embedded space:
xxv
Progress Messages
Progress displays several types of messages to inform you of routine and unusual occurrences:
Compile messages inform you of errors found while Progress is reading and analyzing a
procedure prior to running it (for example, if a procedure references a table name that is
not defined in the database).
Startup messages inform you of unusual conditions detected while Progress is getting
ready to execute (for example, if you entered an invalid startup parameter).
xxvi
Continues execution, subject to the error-processing actions that you specify, or that are
assumed, as part of the procedure. This is the most common action taken following
execution messages.
Returns to the Progress Procedure Editor so that you can correct an error in a procedure.
This is the usual action taken following compiler messages.
Halts processing of a procedure and returns immediately to the Procedure Editor. This
does not happen often.
Preface
Progress messages end with a message number in parentheses. In this example, the message
number is 200:
** Unknown table name table. (200)
Use Progress online help to get more information about Progress messages. Many Progress
tools include the following Help menu options to provide information about messages:
Choose Help Recent Messages to display detailed descriptions of the most recent
Progress message and all other messages returned in the current session.
Choose Help Messages, then enter the message number to display a description of any
Progress message. (If you encounter an error that terminates Progress, make a note of the
message number before restarting.)
xxvii
xxviii
Preface
Progress Master Index and Glossary for Windows and Progress Master Index and Glossary for
Character (Hard copy only)
Platform-specific master indexes and glossaries for the Progress hard-copy documentation
set.
Progress Startup Command and Parameter Reference
A reference manual that describes the Progress startup commands and parameters in
alphabetical order.
Welcome to Progress (Hard copy only)
A booklet that explains how Progress software and media are packaged. An icon-based
map groups the documentation by functionality, providing an overall view of the
documentation set. Welcome to Progress also provides descriptions of the various services
Progress Software Corporation offers.
Development Tools
Progress ADM 2 Guide
A guide to using the Application Development Model, Version 2 (ADM 2) application
architecture to develop Progress applications. It includes instructions for building and
using Progress SmartObjects.
Progress ADM 2 Reference
A reference for the Application Development Model, Version 2 (ADM 2) application. It
includes descriptions of ADM 2 functions and procedures.
Progress AppBuilder Developers Guide (Windows only)
A programmers guide to using the Progress AppBuilder visual layout editor. AppBuilder
is a Rapid Application Development (RAD) tool that can significantly reduce the time and
effort required to create Progress applications.
Progress Basic Database Tools (Character only; information for Windows is in online help)
A guide for the Progress Database Administration tools, such as the Data Dictionary.
Progress Basic Development Tools (Character only; information for Windows is in online help)
A guide for the Progress development toolset, including the Progress Procedure Editor and
the Application Compiler.
xxix
xxx
Preface
Progress Results Users Guide for Windows and Progress Results Users Guide for UNIX
Platform-specific guides for users with little or no programming experience that explain
how to query, report, and update information with Results. Each guide also helps advanced
users and application developers customize and integrate Results into their own
applications.
4GL
Building Distributed Applications Using the Progress AppServer
A guide that provides comprehensive information about building and implementing
distributed applications using the Progress AppServer. Topics include basic product
information and terminology, design options and issues, setup and maintenance
considerations, 4GL programming details, and remote debugging.
Progress External Program Interfaces
A guide to accessing non-Progress applications from Progress. This guide describes how
to use system clipboards, UNIX named pipes, Windows dynamic link libraries, Windows
dynamic data exchange, Windows ActiveX controls, and the Progress Host Language Call
Interface to communicate with non-Progress applications and extend Progress
functionality.
Progress Internationalization Guide
A guide to developing Progress applications for markets worldwide. The guide covers
both internationalizationwriting an application so that it adapts readily to different
locales (languages, cultures, or regions)and localizationadapting an application to
different locales.
Progress Language Reference
A three-volume reference set that contains extensive descriptions and examples for each
statement, phrase, function, operator, widget, attribute, method, and event in the Progress
language.
Progress Programming Handbook
A two-volume handbook that details advanced Progress programming techniques.
xxxi
SQL-89/Open Access
Progress Embedded SQL-89 Guide and Reference
A guide to Progress Embedded SQL-89 for C, including step-by-step instructions on
building ESQL-89 applications and reference information on all Embedded SQL-89
Preprocessor statements and supporting function calls. This guide also describes the
relationship between ESQL-89 and the ANSI standards upon which it is based.
xxxii
Preface
Progress Open Client Developers Guide
A guide that describes how to write and deploy Java and ActiveX applications that run as
clients of the Progress AppServer. The guide includes information about how to expose
the AppServer as a set of Java classes or as an ActiveX server.
Progress SQL-89 Guide and Reference
A user guide and reference for programmers who use interactive Progress/SQL-89. It
includes information on all supported SQL-89 statements, SQL-89 Data Manipulation
Language components, SQL-89 Data Definition Language components, and supported
Progress functions.
SQL-92
Progress Embedded SQL-92 Guide and Reference
A guide to Progress Embedded SQL-92 for C, including step-by-step instructions for
building ESQL-92 applications and reference information about all Embedded SQL-92
Preprocessor statements and supporting function calls. This guide also describes the
relationship between ESQL-92 and the ANSI standards upon which it is based.
Progress JDBC Driver Guide
A guide to the Java Database Connectivity (JDBC) interface and the Progress SQL-92
JDBC driver. It describes how to set up and use the driver and details the drivers support
for the JDBC interface.
Progress ODBC Driver Guide
A guide to the ODBC interface and the Progress SQL-92 ODBC driver. It describes how
to set up and use the driver and details the drivers support for the ODBC interface.
Progress SQL-92 Guide and Reference
A user guide and reference for programmers who use Progress SQL-92. It includes
information on all supported SQL-92 statements, SQL-92 Data Manipulation Language
components, SQL-92 Data Definition Language components, and Progress functions. The
guide describes how to use the Progress SQL-92 Java classes and how to create and use
Java stored procedures and triggers.
xxxiii
xxxiv
Preface
Welcome to WebSpeed! (Hard copy only)
A booklet that explains how WebSpeed software and media are packaged. Welcome to
WebSpeed! also provides descriptions of the various services Progress Software
Corporation offers.
Reference
Pocket Progress (Hard copy only)
A reference that lets you quickly look up information about the Progress language or
programming environment.
Pocket WebSpeed (Hard copy only)
A reference that lets you quickly look up information about the SpeedScript language or
the WebSpeed programming environment.
xxxv
xxxvi
1
Welcome to Progress
Welcome, and congratulations for choosing Progress as your development product for database
applications. Progress has a rich array of features and options, all contributing to an application
development environment that allows you to deliver complete database applications quickly
and easily. This tutorial couldnt possibly cover all the features of Progress, but it does cover
those features that you need to begin coding right away.
The tutorial focuses on teaching you the Progress application development language. Youll use
the demonstration database that comes with Progress to jump past database development and
into code development. Youre ready right now to discover why programming in the Progress
4GL is the best way to turn your ideas into robust applications.
Before you begin the tutorial, make sure that your hardware is set up correctly and that Progress
is installed and ready to go. For complete installation and setup instructions, see the Progress
Installation and Configuration Guide Version 9 for Windows or Progress Installation and
Configuration Guide Version 9 for UNIX.
This chapter introduces you to some fundamental concepts and terminology. After you read this
chapter, youll be ready to begin working with the software in Chapter 2, Getting Started.
This contains information on:
1.1
1.1.1
A Classic Problem
Heres what happens during a typical sales order, using All Around Sportss paper-based sales
and inventory system:
12
1.
Second Skin Scuba calls All Around Sports to place orders for its annual Deep Savings
Sale. Before the sales representative (sales rep) can take the order, she needs to retrieve
the file on Second Skin Scuba from the customer filing cabinets. Once she finds the folder,
she copies the billing and shipping addresses from the folder onto an order form.
2.
The sales rep writes down the name, quantity, and price of each item that Second Skin
Scuba wants. Referring to a typed list, the sales rep quotes prices and calculates the grand
total. After hanging up, the sales rep copies all the information neatly onto the order from.
3.
The sales rep now needs to walk to the inventory filing cabinet, make sure the items are in
stock, and subtract the newly sold items from the inventory sheets. Finally, the sales rep
stores the order form where the Finance and Shipping departments can make copies.
Welcome to Progress
Figure 11 shows the All Around Sports paper-based ordering process.
Customers
1 Check
Customer
Account
Information Folder
Orders
Order Form
2 Complete
Order Form
Item
Qty
Buoyancy Vests 12
Wet Suits
12
Price
27.50
50.00
Total
330.00
600.00
Inventory
Inventory Sheet
3 Update
Inventory
Figure 11:
ITEM
Buoyancy Vests
Fins
Swim Goggles
Wet Suits
QTY
100
110
200
104
92
88
Although the sales rep carried out her job correctly and in quick order, she has a surprise waiting
for her when she returns to her desktwo more customers called while she was completing the
paperwork on the Second Skin Scuba order.
13
1.2
Move the business information from paper to an electronic form that can be stored in a
computer. This step involves:
a.
Gathering together the relevant business information, called data, and analyzing the
relationships among the data. At All Around Sports, the relevant data is in the
customer, order, and inventory filing cabinets.
b.
Designing and creating an electronic storage structure for the data. The electronic
storage structure is called a database. A database that allows users to organize data
so that its easy to define relationships is called a relational database.
Progress provides the tools that let you easily design, create, and maintain relational
databases.
2.
14
b.
c.
Creating computer programs that run with an overall look and feel and are easy to
learn and use.
Welcome to Progress
Progress provides the tools that let you create and maintain procedures quickly. When you
use Progress, you dont have to program the low-level data-access routines that move data
around and take care of the database. This functionality is present and ready for you to tap
into from the very first Progress 4GL statement that you write.Your computer
instructionsalso called codecan concentrate on displaying and manipulating the data
in the database.
The database and procedures that you create with Progress form an applicationa complete
solution to a business problem. The first business problem that All Around Sports wants to
tackle is speeding up the sales and inventory process. To do this, it needs a sales and inventory
application. In other words, it needs a database for the sales and inventory data and procedures
to perform the business tasks associated with the sales and inventory process.
The bottom line is that Progress allows you to create complete solutions to business problems
quickly and easily. All Around Sports agrees and joins the fast growing list of Progress
application developers.
1.3
Data Dictionary
Relational Database
Application Language
Procedure Editor
Figure 12:
Store data
Define tasks
Write code and verify language
syntax
15
1.4
1.4.1
Database Basics
The computer professionals that All Around Sports brings in to evaluate the sales and inventory
system take note of how All Around Sports stores its files. All Around Sports keeps each type
of filesuch as customer information files, order files, and inventory filesin a separate filing
cabinet. It also stores all these related filing cabinets together in one room. This strategy of
grouping related information is also the basic strategy behind the structure of a database.
A database, which you can think of as an electronic filing system, stores all related information
together in a structure called a table. A table is equivalent to a filing cabinet at All Around
Sports. A collection of related tables makes up a database. A database is the equivalent of the
room of filing cabinets at All Around Sports.
16
Welcome to Progress
Figure 13 illustrates the relationship of the sales and inventory paper filing system to a
database.
Paper
Tables
Customer
Information
Folders
Customer
Database
Order Forms
Order
Inventory
Sheets
Item
Figure 13:
A database table is similar to a data table you might create with graph paper. A paper table
consists of rows and columns. The intersection of each row and column contains one specific
piece of data. In a database table, each row contains all the individual pieces of information
about one member. A database row is called a record. In the paper filing system, each folder in
a filing cabinet contains the equivalent of a row or record. For example, the customer filing
cabinet contains one folder for Second Skin Scuba and another for Off the Wall Sports. When
All Around Sports creates its database, the Customer table will contain one record for Second
Skin Scuba and another for Off the Wall Sports.
17
Database
Table
Table
...
...
Record
Table
Table
=
Record
Field
=
Figure 14:
Name
Data
Name
Data
...
Structure of a Database
The last component of an electronic filing system is an index. When you open the drawer of a
filing cabinet and thumb through the tabs on the folders, youre using a kind of index. Whats
on the paper tab is normally a copy of a piece of information found in the folder. For example,
youd expect the tabs in the customer filing cabinet to contain the name of the customer whose
information is in that folder. Similarly, an electronic index is a component that serves as the
basis for searching, sorting, or otherwise processing the records in a particular table.
18
Welcome to Progress
In a database, an index is a list that contains a value for each record in the table. When you define
an index, you choose the field or fields used to derive the index value for each record. For
example, if you choose the Name field as an index, Progress creates an index for the Customer
table that consists of a list of customer names, just like the list of tabs in the paper filing system.
A simple index is based on the value of one field, while a compound index is based on two or
more fields. Figure 15 shows an example of a simple and a compound index.
Simple Index
02176
Jan
Last
Abbot
Street
City
Grovewood
State
MA
ZIP Code
02176
37771
02176
01130
Compound Index
Abbot, Jan
Jan
Last
Abbot
Street
City
Grovewood
State
MA
ZIP Code
02176
Figure 15:
Bishop, Jose
Bishop, Fred
Abbot, Jan
Depending on your needs, you can define more than one index per table. When you are coding
applications, youll be able to use indexes for faster processing.
19
1.4.2
The tool you use to create databases is the Data Dictionary. The Data Dictionary lets you move
step by step through defining each table, field, and index that makes up your database. The Data
Dictionary also provides an easy way to view and change the configuration of an existing
database.
Each table, field, and index has a variety of properties that you can modify. Many of these
properties affect Progresss behavior. When you begin programming Progress procedures,
youll also start exploring databases with the Data Dictionary to change properties and make
Progress work more effectively for you.
Application Defaults
A major part of your applications work involves presenting database fields for end users to
view and manipulate. Each time you access and display a field, you wont have to write lots of
codeyou can rely on Progress to use default information stored in the Data Dictionary to
properly present the data. Progress stores these defaults in a Progress database:
Default display information for fields, such as display formats and help messages
Default data access behavior for both fields and tables, such as data input checking
routines and default values
This ability to store defaults in the database saves time for developers. Using defaults makes it
easier to enforce data-access rules and reduces error-checking code, default value generation,
and display-formatting code in your procedures.
See Chapter 4, Understanding the Database Environment, for more information about the
Data Dictionary and Progress databases.
1.5
110
Provides powerful statements that perform the work of multiple 3GL statements
Employs a highly readable syntax that is succinct and much closer to natural English
Welcome to Progress
Besides giving you the complete flexibility of a general-use programming language, the
Progress 4GL allows you to do two main tasks: access and manipulate data in a database, and
present that data for user inspection and interaction.
Look at this Progress code:
FOR EACH Customer:
DISPLAY Customer.
END.
This compact loop, where Customer is the name of a database table, performs these functions:
Reads the contents of each Customer table record, beginning with the first record
Accesses the default display format for each field in the record
Pauses and waits for the user to signal when to display more information
Each of these tasks would require many lines of 3GL code. The Progress 4GL executes these
tasks implicitly.
Progress also makes useful assumptions about what you want, relieving you from the tedious
task of coding every tiny detail. For example, notice that the DISPLAY statement in the
example does not offer any detail about how to format the output. Progress constructs a default
output format by combining default formatting information for each database field with default
output algorithms. This intuitive handling of defaults is called default behavior. This advantage
does not come at the expense of customization. Every Progress statement includes options that
allow you to override default behavior.
Youll find yourself relying on default behavior in the beginning of a project so that you can
quickly create a prototype. Later, youll get more involved with programming options to fine
tune your application.
111
1.5.1
The Progress 4GL/RDBMS also provides you with the Procedure Editor. From the Procedure
Editor, you create, compile, and run Progress procedures. The Procedure Editor also provides
extensive facilities for checking syntax, managing multiple procedure files, and customizing
your environment.
In the next chapter, youll learn to use the Procedure Editor. It wont take you long to master the
Procedure Editor and customize its environment. For the rest of the tutorial, the Procedure
Editor will be your base for trying out example code and creating your own code.
1.6
Summary
First, you learned how Progress can solve tough business problems. A computerized solution to
a business problem is called an application. An application consists of a database and Progress
procedures. Heres a summary of important points about databases:
A database is an electronic filing system for organizing and storing data that relates to a
broad subject area, like sales and inventory.
A database that lets you organize data so you can easily define and exploit relationships
among data is called a relational database.
At the top level, a database is made up of tables. A table is a collection of records about a
specific subject, like customers.
A record is a collection of pieces of information, called fields, about one thing, like a single
customer.
An index uses data from a field or fields as the basis for searching, sorting, or otherwise
processing records.
Progress procedures are collections of statements that let you define tasks. Here are some
important points about Progress procedures:
112
You create procedures with the Progress fourth generation language (4GL).
A 4GL is much easier to use than a third generation language (3GL) because 4GL
statements perform the work of many 3GL statements and use default behavior to relieve
you from programming every tiny detail.
Welcome to Progress
You also learned about the Progress tools for creating and maintaining applications:
You can also use the Data Dictionary to store display and data-access defaults, which help
cut down on redundant coding.
The Procedure Editor lets you create, edit, and run procedures. The Procedure Editor also
lets you check the syntax of your code.
113
114
2
Getting Started
This chapter teaches you the essentials of starting Progress and using the basic tools.
Specifically, this chapter covers:
Starting Progress
2.1
Confirm that the Progress Data Dictionary, Procedure Editor, and Application Compiler
are properly installed on your system.
2.
Create a directory named mytut. The mytut directory will be your working directory for
all tutorial exercises.
3.
Create a subdirectory of mytut named sports. The sports subdirectory will contain
procedures that are part of the Progress demonstration database. The tutorial uses the
demonstration database, named sports, as the basis for programming examples and
exercises.
4.
Extract the example source programs from the prodoc.pl procedure library according to
Section 2.2 below. The procedures in this book assume that your program examples are in
a working directory called Progress\Wrk\prodoc\langtut.
If you run into problems with these tasks, consult the Progress Installation Notes, your
operating system documentation, or your system administrator.
2.2
2.3
Starting Progress
The procedure you use to start Progress on Windows depends on the operating system on which
you are running Progress. This section describes how to access Progress from the platforms
specified.
2.3.1
Windows
Click the Start button on the taskbar and choose Programs Progress Desktop. Click on the
Progress Desktop program option to display the ADE Desktop.
22
Getting Started
2.3.2
ADE Desktop
From the ADE Desktop, you launch Progress development tools. When you exit a tool that you
started from the desktop, you return to the desktop.
Figure 21 presents the ADE Desktop and identifies its parts.
Figure 21:
Menu bar The menu bar is a horizontal list of menu titles. A menu is a collection of
related options. Youll learn how to use menus later in this chapter.
Tool buttons Tool buttons are images that you click to start a tool. There are seven tool
buttons on the ADE Desktop. From left to right, the tool buttons representing these tools:
Data Dictionary
Procedure Editor
AppBuilder
Results
Report Builder
Application Debugger
Translation Manager.
When you are running Progress either on Windows 95 or on Windows NT 4.0, the labels
do not automatically display. Pause your mouse pointer over each tool button to display a
ToolTip that identifies each icon by its tool name. A ToolTip is a brief text message that
defines various user interface elements on Windows 95 or on Windows NT 4.0.
NOTE:
If you are running Progress on Windows NT 3.51, each tool button has a permanent
label displayed.
23
2.4
Status area
Figure 22:
24
Getting Started
The main display of the Procedure Editor contains several features:
2.5
Title bar Shows the name of the current edit buffer. An edit buffer is a temporary work
area for procedures under construction in the Procedure Editor. The Procedure Editor
allows you to have several buffers open simultaneously. If a buffer has no name assigned,
it appears as Untitled followed by a number to make the name unique (for example,
Untitled:1).
Menu bar Allows you to access and execute tasks. Each item on the menu bar is a
menu title. A menu provides access to menu options. Menu options perform tasks.
Insertion point Marks the location where text appears when you start typing.
Procedure area The visible part of the current edit buffer. This is where you type and
edit Progress procedures.
Status area The one line panel at the bottom of the window where Progress displays
helpful information for the user.
Setting PROPATH
Progress contains an environmental variable called PROPATH which contains a list of
directories that Progress searches to find procedures. In order to access your example programs
without having to enter the complete path each time, you must add your prodoc directories to
the PROPATH as follows:
25
2.6
1 Enter the name of the on-line demonstration program. Because you have modified the
PROPATH, you do not have to enter the entire absolute address. The following example
shows how to enter this command on Windows:
RUN widget.p.
26
Getting Started
Button widgets
4 Follow the instructions you see on your display. You can press ESC at any time to end the
on-line tutorial, and ESC again to return to the Procedure Editor.
2.7
2.7.1
A mouse, or other pointing device, gives you flexibility that you dont get with a keyboard. By
using mouse buttons in different ways, you can accomplish many tasks more quickly than you
can with a keyboard.
27
2.7.2
The Procedure Editor responds to several keystrokes that perform editor functions. Tool
functions that map to a keystroke are called key functions and are common throughout the
Progress toolset. Progress uses a keyword like HELP or GO to represent a key function because
the actual keystroke that performs the function may vary across operating systems. Many key
functions in the Procedure Editor execute menu options available from the Procedure Editor
menu bar. These keystrokes provide a quick and easy way to get things done.
Table 21 lists the most commonly used key functions.
Table 21:
Key
Function
28
Description
HELP
F1
GO
F2
GET
F3
PUT
F6
CLOSE
F8
ENTER-MENUBAR
ALT
END-ERROR
ESC
Getting Started
2.7.3
Most of the tools in the Progress toolset have a menu bar. The menu bar appears at the top of
the tool display and provides access to most of the functionality in the tool. Table 22 provides
a short description of the functionality available on each menu in the Procedure Editor.
Table 22:
Menu
File
Create new edit buffers; open text files that contain Progress language
statements; save the contents of an edit buffer to a text file; print the
current buffer; escape to the operating system; exit the Procedure Editor.
Edit
Search
Search and replace text in the current edit buffer; go to a specified line
position in the current edit buffer.
Buffer
Compile
Run, compile, and check the syntax of the Progress code contained in the
current buffer.
Tools
Options
Help
Get information about the current tool, system messages, the 4GL, and the
Progress system.
29
Figure 23:
You can execute menu options using your cursor keys. For example, to exit the Procedure
Editor, you can choose the Exit menu command from the File menu. The following information
explains how to choose the Exit option with the cursor keys:
210
Getting Started
Another way to execute a menu option is to use mnemonics. A mnemonic is a character
associated with a menu or menu option. If the menu bar is active, you can type a mnemonic to
display a menu or to execute a menu option. All menus and menu options in the Progress toolset
have a mnemonic. The mnemonic is the underlined character from the label of the menu option
and must be unique within a menu or the menu bar. For example, the mnemonic for the Help
menu is the character H.
The following steps describe how to choose the Exit option from the File menu using
mnemonics:
The menu option that exits a tool is always the last menu option on the first menu.
A Help menu is available on all menu bars in the Progress toolset and is always the last
menu on the menu bar.
Some menu options have symbols that provide information about how they work. Menu
options that do not use symbols are commands and simply execute the function that they
represent.
211
Menu Symbol
Description
menu option
Indicates that the menu option is a submenu. When the user chooses
a submenu from a menu, additional menu options appear next to the
original pull-down menu.
menu option . . .
Indicates that the menu option requires additional user input. When
the user chooses a menu option with this symbol, a dialog box
appears. Progress uses dialog boxes to prompt users for additional
input before executing the function.
menu option
Indicates that the menu option is a toggle for a tool setting. When the
symbol is present, the setting is active or in the ON state.
The Progress documentation set uses the following notation to represent a menu option.
File Exit
This notation is a shorthand representation of the Exit option on the File menu.
2.8
212
Getting Started
Table 24 presents basic keys available in the Procedure Editor that help you move around and
edit text in the current buffer.
Table 24:
Key Function
Common
Keyboard
Mapping on Windows
(1 of 2)
Description
CURSOR-UP
CURSOR-DOWN
CURSOR-LEFT
CURSOR-RIGHT
BACKSPACE
BACKSPACE
BACK-TAB
SHIFT-TAB
DEL
DEL
LEFT-END
HOME
NEXT-WORD
CTRL-CURSOR-RIGHT
PAGE-DOWN
PAGE-DOWN
PAGE-UP
PAGE-UP
PREV-WORD
CTRL-CURSOR-LEFT
RETURN
ENTER
213
Key Function
(2 of 2)
Common
Keyboard
Mapping on Windows
Description
RIGHT-END
END
TAB
TAB
The next section describes more advanced text editing techniques in the Procedure Editor.
2.8.1
The Procedure Editor allows you to define and manipulate blocks of text. A block of text can
be a set of contiguous characters, a whole line, several contiguous lines in a buffer, or an entire
procedure.
Follow these basic steps to manipulate a block of text:
214
Getting Started
Table 25 lists the set of keys that allow you to define a block and execute a text-block operation
on Windows.
Table 25:
Key
Function
Common
Keyboard
Mapping on
Windows
Description
COPY
CTL+C
CUT
CTL+X
Cut the current text block into the cut/paste buffer. This
key function is the same as Edit Cut.
PASTE
CTL+V
With this functionality, you can cut and paste code from one position to another in the current
edit buffer. You can also cut and paste between edit buffers.
2.9
215
Although you can open multiple buffers in the Procedure Editor, you can open only
one buffer for each operating system file.
Table 26 summarizes the Procedure Editor features that help you create and manage buffers.
Table 26:
Task
216
Menu Option
(1 of 2)
Description
File New
File Open
Close a buffer.
File Close
File New
Procedure Window
File Save
File Save As
File Print
Buffer List
Getting Started
Table 26:
Task
Menu Option
(2 of 2)
Description
Buffer Next
Buffer
Buffer Previous
Buffer
Display detailed
information about a
buffer.
Buffer
Information
Modify fonts.
Buffer Font
Buffer
Information
Compile Run
Compile Check
Syntax
217
2.10
This procedure contains the following Progress language constructs and elements:
Phrases A phrase is a collection of keywords and values that modify the way Progress
executes a statement. In the code above, the keyword WITH begins a frame phrase in the
DISPLAY statement. Phrases can contain options and values.
Options An option is like a phrase, only smaller. Options usually consist of a single
keyword and a possible accompanying value. Options also modify the way Progress
executes a statement. In the code above, the keyword AS is an option of the DEFINE
VARIABLE statement and the keyword CENTERED is an option in the frame phrase of
the DISPLAY statement.
Progress is a block-structured languagethat is, you can group statements together into blocks.
Procedures are the largest block structures in Progress. Later in the tutorial, youll learn about
other types of blocks that can exist inside a procedure block.
218
Getting Started
A repeat block is similar to the repeat loop, which is found in many 3GLs) The following code
fragment shows a repeat block:
Procedure
block
Repeat block
Block structures within a procedure normally begin with a block-header statement and end with
an END statement. You can use these block structures to apply processing services to a group
of statements.
You will learn about more Progress language constructs and blocks as you proceed through this
tutorial. To learn more about the syntax of the Progress language, see the Progress Language
Reference or the Progress On-line Reference module in the Progress help system.
2.11
2.11.1
There are two ways to access help information from the Procedure Editor:
Press HELP to get information about the current window or dialog box. This is known as
context-sensitive help. Most dialog boxes in the Progress toolset also have a Help button
you can choose to get information about the dialog box.
Use the Help menu from the menu bar to access information about the current tool or to
display reference information.
219
Figure 24:
Help
220
Messages...
Recent Messages...
Keyboard...
Getting Started
2.11.2
The Progress help system organizes information into discrete units called help topics. An
individual help topic typically contains information about one thing, such as a particular dialog
box in the Progress Procedure Editor or a 4GL language element. When you access the help
system from a tool, you can display related help topics as they are organized under the various
tabs that display on the Help Topics: Windows Help Topics dialog box. Figure 25 shows the
Help Topics: Procedure Editor Help dialog box that displays when you access help from the
Procedure Editor.
NOTE:
The Help Topics: Windows Help Topics dialog box title changes to reflect the
specific help that is displayed. The title change can help keep you oriented as to
which part of the help system you are currently using. For example, when you
display help from the Procedure Editor, the title bar in the dialog box reads Help
Topics: Procedure Editor Help. However, when you display help from the Data
Dictionary, the title bar in the dialog box reads Help Topics: Data Dictionary Help.
Figure 25:
A Help Topics: Windows Help Topics dialog box includes three tabs: Contents, Index, and
Find. The order in which these tabs display will vary because the most recently displayed tab
appears on top. However, clicking on a given tab will always put the tab on top and available
for you to use.
The Contents Tab, displayed in the on top position in Figure 25, acts as a table of contents for
all the topics associated with a specific tool. Click on a book icon on the Contents Tab to display
the specific help topics associated with each defined category.
221
Figure 26:
Index Tab
The Index Tab allows you to enter a word or phrase in the top field. As you type, help attempts
to match your entry with keywords defined in the help system. For example, in Figure 26 the
user entered the word buffer. As you can see, the help system provided an initial match and
highlighted it; the user can choose to click on the suggested match or scroll to a different entry.
It is possible that a search will not find any keywords to match an entry. If this situation occurs,
the keyword display area does not scroll to display a match; the informational window shown
in Figure 27 displays when you click on the Display button.
Figure 27:
222
Informational Window
Getting Started
The Find Tab allows you to search for specific words or phrases in a database that comprises
the actual words used in the help files. Figure 28 shows the Find Tab.
Figure 28:
Find Tab
The first time you access the Find Tab, the help system prompts you to create the database. Once
you have compiled your database, it is available for you to perform word searches. To perform
each word search, enter a word in the top field and the help system provides the values displayed
in the second and third fields. Note that you can refine your search using these fields and the
buttons on the right-hand side of the Find Tab. If a search does not find any suitable matches,
the second and third fields are blank and the phrase 0 Topics Found displays in the lower
left-hand corner of the dialog box.
2.11.3
There is a way to get help information about Progress language elements without having to
search for it through the Help Topics: Window Help Topics dialog box. Simply highlight a
Progress keyword in the Procedure Editor and press the HELP key function (F1).
When you press HELP, the Help Topics: Window Help Topics dialog box opens to the specific
information you need in the Progress On-line Reference, or the Index Tab dialog box appears
listing the topics that most closely match the highlighted text. From this dialog box, you can
choose the correct topic and display it.
223
2.11.4
The Progress Language Reference provides a comprehensive alphabetical list of all the
language elements in the Progress 4GL. In contrast, the Progress 4GL Cross Reference
organizes language elements by type and use. It is worth noting the variety of information that
you can easily and quickly obtain through the on-line help system. You will find this part of the
on-line help system an important tool for learning the 4GL.
Follow these steps to access the Progress On-line Reference and 4GL Cross Reference
Language information:
Exercise
224
1.
Choose Help Help Topics from the Procedure Editor menu bar. The Help Topics:
Procedure Editor Help dialog box displays with the Contents Tab on top.
2.
On the Contents Tab, click on the book icon associated with the Procedure Editor Interface
Reference. Then, click on the Procedure Editor Window.
Getting Started
3.
In the Notes section of the Procedure Editor Window topic, click on the Progress
Language Reference link to display the Progress Language Reference help window:
225
226
Click on the Progress 4GL Cross Reference information link defined on the Progress
Language Reference topic to display the Progress 4GL Cross Reference:
Getting Started
2.12
When you exit the Procedure Editor, the editor checks the open buffers for unsaved changes. If
there are buffers with unsaved changes, the following dialog box appears:
If you choose the Yes button to save modified buffers, the Save Buffers with Changes dialog
box appears:
The box around a buffer name indicates that the buffer is selected. To toggle the selection of a
buffer in the list, click the buffer name. This dialog box presents three options:
Save the selected buffers in the buffer list by choosing the Save Selected button.
Opt not to save any buffers and exit the Procedure Editor by choosing the Save None
button.
Cancel the exit and save operations and return to the Procedure Editor display by choosing
the Cancel button.
227
2.13
Summary
Before you finish this chapter, take a moment to review your progress on these topics.
Starting Progress:
To start Progress on Windows NT 3.51, double-click the Progress Desktop icon to display
the ADE Desktop. Then, to start the Procedure Editor, double-click on the Procedure
Editor tool button.
To start Progress on Windows 95 or Windows NT 4.0, click the Start button on the taskbar
and choose Programs Progress Desktop. Click on the Progress Desktop program to
display the ADE Desktop. Then, to start the Procedure Editor, double-click on the
Procedure Editor tool button.
The Procedure Editor is a text text editor that you can use to create, compile, and run
Progress procedures. A procedure is a series of Progress language statements that performs
a desired data processing task.
A key function is an event in Progress that describes a behavior that occurs when you use
a particular keystroke or key combination. Some common key functions are HELP,
ENTER-MENUBAR, and GO. However, the keyboard mappings for specific keys may vary
depending on the console you are using and the platform on which Progress is running.
Many functions of the Procedure Editor are accessible from the menus and menu
commands on the Procedure Editor menu bar.
The computer displays that enable a user to accomplish tasks are called the user interface.
In Progress, interfaces are made up of objects, called widgets, that can be controls,
representations of data, decorations, or containers. Widgets also serve as receptors for user
input and application output.
228
The Procedure Editor supports the basic editing keystrokes that are standard to most text
editors and word processors.
You can define blocks of text to cut, copy, and paste in an edit buffer or between edit
buffers.
Getting Started
Edit buffers and procedure files:
A procedure file is a text file that contains one or more Progress procedures. By
convention, procedure files have a .p file extension.
The Procedure Editor provides menu commands that allow you to edit and manage
multiple edit buffers and open and save procedure files.
Phrases and options consist of keywords and values and alter the way Progress executes a
statement.
Press HELP to access information about the current display or dialog box.
Use the Help menu to access information about the current tool.
You can access these sample procedures on line in the procedure libraries prodoc.pl and
prohelp.pl in the src directory where Progress is installed.
The File Exit menu option allows you to exit the Procedure Editor and return to the
operating system or the tool that called the Editor.
229
230
3
Programming the Progress Way
So far youve learned what Progress is about and youve had a chance to work with the
Procedure Editor. Now its time to begin working with the 4GL. This chapter covers what is
fundamental to every Progress application. First, the chapter presents the underlying concepts
and techniques of the Progress 4GL. Second, the chapter examines the components of a
Progress procedure. By the end of the chapter, you will be able to recognize a well-structured
Progress procedure and understand the function of its constituent parts.
Specifically, youll learn about:
In this chapter, youll see examples of complete Progress procedures. For now, your goal isnt
to master all the language elements introduced. Instead, your goal is to become familiar with
and comfortable with the major components of a Progress procedure.
3.1
Make the application developer more productive by minimizing the amount of code
needed to create complete and powerful applications.
Isolate the developer from as many portability issues as possiblelet Progress handle
platform-specific issues during compile time or run time.
Provide flexible and intelligent features that allow the end user to work intuitively and
productively with highly responsive Progress applications.
Chapter 1 discussed the nature of the 4GL and how it streamlines application development by
providing more functionality with less code. The second philosophy, easy portability, allows
you to focus on developing one application, using one programming language and one program
structure. Then, when you move your application to other platforms, youll see the benefits of
Progresss portability philosophy:
The third philosophy, providing the end user with intuitive and responsive applications, takes a
little more time to present. Creating responsive applications requires a certain style of
codingwhat Progress calls the Progress programming model. To use the programming model
effectively requires looking at the process of user and application interaction in a certain way.
The rest of this section discusses the concepts, terminology, and language elements that make
up the basic Progress programming model.
3.1.1
User Interfaces
To begin, look at the application screen shown in Figure 31. Its simply three fields arranged
on a computer screen. This simple screen helps illustrate some of the important concepts and
terms of the Progress programming model:
32
The keyboard and the mouse are the users mechanism for communicating with your
application.
Fill-in fields
Figure 31:
Before continuing, its important to distinguish between two types of user interfaces: character
interface and graphical user interface, or GUI. These user interfaces are distinct from one
another in appearance and behavior. The primary reason for their differences is the fact that
these interfaces run on different operating systems that support different functionality.
For example, lets look at Figure 31, a character interface. A character interface supports a
text-based data display that is presented in a single fixed-width font. The display occurs within
a single, fixed-sized default window. A character interface accepts ASCII keyboard characters
as input, and it can support limited mouse capabilities such as basic text selection and
navigational activities. Some advantages associated with character interfaces are speed and
portability.
In contrast, Figure 32 presents a GUI that is comparable to the graphical interface that
Windows supports. This figure shows how this same simple Progress procedure looks when you
run it on Windows 95, a GUI system. A GUI supports not only text-based presentations with
multiple font types and sizes and fixed and proportional spacing, but it can also feature
high-resolution graphics such as images and buttons. A programmer working in a graphical
interface has the opportunity to create and control multiple windows, manipulating the
properties associated with each unique window. Also, the graphical interface supports a wide
range of mouse activities, expanding beyond simple selection and navigational activities into a
broader range of editing capabilities. Due to its emphasis on visual presentation and the
numerous mouse-supported point and click interactive opportunities, many users and
programmers feel this interface is easier to learn and use.
33
Progress supports a character client that runs in DOS only when DOS is running on
Windows. However, when a character client is running in this manner, the interface
that displays on both of these platforms is a character interface, not a graphical one.
Window
Fill-in Fields
Figure 32:
When you are working with a character interface, you will be working with what the Progress
programming model refers to as the default window. (If you were to recompile your code on a
GUI platform, Progress would run your application in the default GUI window.)
Now, look again at the contents of the window shown in Figure 32. The window contains three
data fields. Instead of thinking of them as fields, however, think of them as a collection of
individual objects. Each object has capabilities for communicating with and receiving input
from the user. In this example, the field objects, called fill-in fields , display the current contents
of three variables. (A variable is a temporary data location in memory.) The user can choose a
fill-in field object and change the contents of that object, thereby changing the value of the
underlying variable.
34
3.1.2
User Input
Any type of interaction a user can have with a Progress application is called an event. Each user
action, like pressing a mouse button, is a separate event. For example, typing new data into a
fill-in field is actually a series of events. Each individual keystroke is a separate event.
When you program in Progress, think of the user interface as a tool for displaying data and
receiving user events. Progress processes the user events and notifies your application so that
your code can respond to the events.
Considering the number and combinations of ways that a user can interact with an interface, the
task of receiving and responding to those events must seem daunting. However, the Progress
programming model significantly simplifies this task for you. First, the low-level computer
tasks of receiving events from a keyboard or mouse and notifying your application occur
automatically with Progress. Second, sorting through the stream of events becomes easier once
you understand that certain events go naturally with certain widgets. For example, while it
makes perfect sense to type characters in a fill-in field widget, it does not make sense to type
characters to a button widget. Therefore, fill-in fields accept keyboard character events and
button widgets do not.
This widget-event pairing leads to the question: how do you know which widget is receiving
events? The user can tell which widget receives events because of the cursor location or other
visual cues that Progress and the operating system provide. Since you cannot predict the order
in which the user will interact with your widgets, your code must be ready to respond to many
events.
How does your code know which widget is receiving events? To begin with, a widget can
receive events only after the application has enabled it to receive input. Of all the widgets that
are enabled at any time, only one can receive events. When a widget is the current event
receptor, it has input focus. The application or the user can designate a widget to have input
focus. The application can assign input focus to an enabled widget programmatically. The user
can assign input focus by selecting the desired widget. The concept of input focus is absolutely
crucial to a Progress application.
35
1 From the Procedure Editor, open the lt-03-01.p procedure. (Use the Open option on the
File menu.) Dont worry about trying to understand the code right now.
2 Choose Compile Run. You now see the basic interface you saw in Figure 32:
Input focus
Notice that the cursor is positioned in Field1. This cursor illustrates two points:
The user is normally aware of which widget has input focus by the visual cues
provided automatically by Progress and the underlying operating system.
3 Press TAB to move input focus among the fields. These actions illustrate the last important
point about input focus: after startup, the location of input focus is normally controlled by
the user. In other words, users can enter data into the fill-in fields in any order.
36
4 Move input focus to Field3 and press RETURN to end the procedure.
5 Press SPACEBAR to return to the Procedure Editor.
Because the user has more control of input focus, the user has more control of the application.
The applications job is to respond to the users events in a way that correctly interprets the
users desires. Because of this reliance on events, this type of programming model is called
event-driven programming.
Parts of a Progress Procedure
Now, examine the code for the procedure you just ran:
lt-03-01.p
/*1*/
/*2*/
/*3*/
/*4*/
The first part of a Progress procedure defines widgets. The three DEFINE VARIABLE
statements create three new variables for text data (AS CHARACTER) and initialize them
with a string (INITIAL " "). Progress displays variables or database fields as fill-in fields
by default.
2.
The second part of a Progress procedure creates the user interface. The DISPLAY
statement creates an interface that consists of the default window, blank lines (SKIP),
fill-in fields, and labels for the fields (SIDE-LABELS). This DISPLAY statement also
centers the widgets within the default window (CENTERED) and suppresses the default
border that surrounds the widgets (NO-BOX).
3.
The third part of a Progress procedure enables the widgets of the user interface. The
ENABLE statement turns on the widgets. By default, the first widget listed in an ENABLE
statement gets initial input focus. Assigning input focus to Field1 means that Field1
receives events at startup.
37
The fourth part of a Progress procedure blocks execution. Now that you have
presented a complete interface and enabled it for the user, you have to pause the execution
of the procedure to allow the user to interact with the interface. This process is called
blocking. If you did not block, Progress would execute the code to the end of the file and
end the procedure.
The WAIT-FOR statement is your primary tool for blocking execution. With it, you
establish the condition that signals that the user has finished working with the current
interface. In this case, if the user presses RETURN (WAIT-FOR RETURN) while input
focus is in Field3 (OF Field3), then the procedure completes.
Every Progress procedure that interacts with the user follows this basic four-step process:
1.
Define widgets.
2.
Display widgets.
3.
Enable widgets.
4.
Block execution.
You explicitly code these four steps. Progress provides much of the additional functionality
required to make this interface flexible and responsive to the user. For example:
Progress takes care of the normal events associated with a widget. For example, the user
might want to type new text into the fields. Progress handles these events by default.
3.1.3
Responding to Events
For every widget, there is always a default response for each possible event. The default
response for pressing TAB with most widgets is to move input focus to the next enabled widget.
The default response for pressing a character key when a fill-in field has focus is to display that
character in the field.
The default response for many events is no response. As mentioned earlier, some keystrokes
with certain widgets dont make sense. Therefore, Progress ignores these events. Remember
that for every widget-event pair, Progress executes the default response, even though that
response may be no response.
38
Using Triggers
Follow these steps to create a trigger:
1 Open lt-03-02.p.
2 Choose Compile Run.
3 Click Field3. Notice the message that now appears at the bottom of the window:
Message
39
Notice the new language element in the example, the ON statement. The ON statement sets up
the trigger. In the example, ENTRY is the event and Field3 is the widget. (ENTRY is an event
that occurs when the user or the application gives input focus to a widget.) The MESSAGE
statement is the trigger that occurs when Field3 receives the ENTRY event.
NOTE:
By default, window widgets reserve space at the bottom of the window to display
messages from Progress and your application. The MESSAGE statement
automatically outputs text enclosed in quotes to the message area.
This is a partial syntax for the ON statement. (For complete syntax descriptions, see the
Progress Language Reference or access the On-line Language Reference module of the help
system.)
SYNTAX
ON event-list
310
OF widget-list
OR event-list OF widget-list
trigger-block
] ...
Components
Description
event-list
widget-list
OR
Use the OR phrase to create another widget-event pair that can execute
the code in the trigger block.
trigger-block
Defining triggers is part of the basic Progress code template. Adding triggers to the basic
template gives you this new coding template:
1.
Define widgets.
2.
Display widgets.
3.
Enable widgets.
4.
Define triggers.
5.
Block execution.
311
3.1.4
So far youve learned that the user interacts with an application through an interface made up
of widgets. The user responds to the interface with events. A widget responds to an event by
executing the programmed response, if one exists, followed by the Progress default response.
There is one more important development in the cycle of events and responses: you need a way
to suppress default responses. Most of the time, youll want to keep the default response, but
youll also encounter instances when you want to replace the default response with a
programmed response.
To suppress a default response, you include the Progress statement RETURN NO-APPLY just
before the END statement of your trigger. Later in the tutorial, youll see examples of using
RETURN NO-APPLY. The tutorial introduces it here because it is an important part of the
event-response cycle, which Figure 33 illustrates.
312
User Interface
Input Devices
Input
Focus
Event
No
Field1:
H ello
Field2:
Progress
Field3:
World!
Widgets
Yes
Programmed Response
TRIGGER
ON event OF widget
DO:
Programmed Response
END.
Default Response
No
Yes
Done
Figure 33:
2.
When you create the interface (define, display, and enable widgets), Progress automatically
provides all the default behavior the user needs as they interact with that interface. The real work
that your application does normally occurs as a response to a specific event from the user. That
means that much of your functionality resides inside triggers. A good way to visualize this
structure is to think of the code outside of the triggers as the code that creates and controls your
interface. The code inside your triggers performs the tasks for which you created the
application. The ON statement is the connection between the interface and the functionality
inside the trigger.
3.2
Widgets
Since widgets make up the part of your application with which the end user interacts, its
important to thoroughly understand how to use each widget. Table 31 provides a brief
description of each type of widget.
Table 31:
Widget
314
Widget Types
(1 of 2)
Use
Fill-in field
Displays and accepts any kind of data. When you display a variable or
database field, the fill-in field is the default widget.
Text
Displays any kind of data as read-only text. The text widget is useful for
creating lists, reports, or labels.
Selection list
Combo box
Like a selection list, a combo box presents a list of value choices for a
character variable or database field. The value list of a combo box is only
visible after a user chooses the button next to the combo box. When the
user selects a value, the combo box closes and displays only the selected
value.
Editor
Widget Types
(2 of 2)
Use
Radio set
Displays and accepts data that has a limited number of possible values.
Use radio sets to display options where the user understands that only one
option can be true at a time.
Toggle box
Browser
Slider
Displays and manipulates integer data. When the user moves the pointer
on the trackbar inside the slider, the value changes proportionally to the
move.
Rectangle
Image
Button
Explicitly executes tasks. Use a button to allow the user to execute triggers
or control the interface.
Frame
Dialog box
Creates a frame that overlays the current interface. The main interface is
disabled until the user is done working with the dialog box. A dialog box
notifies the user of important information or requests more information. A
dialog box is a container for other widgets.
Menu bar
Pull-down
menu
(submenu)
Menu item
Since the goal of this section is to introduce widgets in general, youll work with just four
widgets: fill-in fields, text widgets, rectangle widgets, and button widgets. The tutorial covers
other widgets in later chapters.
315
3.2.1
Widget Categories
All widgets fall into one of five categories that describe general function. These categories are:
Window Widgets Window widgets are workspace for your application. A window
contains all other widgets. Character interfaces use one window, while graphical
interfaces can use multiple windows.
Container Widgets Container widgets allow you to organize data, action, and graphic
widgets. Container widgets include frames and dialog boxes.
Data Widgets Data widgets are the widgets you use to represent data from fields and
variables. Data widgets include fill-in fields, text, editors, selection lists, combo boxes,
radio sets, toggle boxes, sliders, and browse widgets.
Action Widgets Action widgets allow the user to direct the operation of your
application. Menus provide groups of related processing options while buttons execute a
single option. Buttons, menu bars, submenus, and menu items make up action widgets.
Graphic Widgets Graphic widgets help you decorate your interface. Use rectangles to
make different kinds of borders. Images, which are available on graphical interface
systems, allow you to include high-resolution graphics in your interface.
3.2.2
Defining Widgets
This section discusses the basic 4GL syntax that you use to define widgets. First, youll learn
how to represent a database field or a variable as a data widget. Next, youll learn how to define
buttons and rectangles. Finally, youll see how to use a frame to arrange your widgets inside a
window.
Defining Data Representations
Recall that Progress represents database fields and variables in an interface as a data widget. The
widget and the field or variable are separate. You can think of a data widget as a suit of clothes
that a database field or variable can put on or change out of as the need arises. In other words,
in one part of your application you might represent a particular field or variable as a fill-in field,
while in another part you might use an editor widget.
316
[ INITIAL constant ]
[ LABEL string ]
The following table describes the components:
Component
Description
variable-name
datatype
INITIAL
constant
LABEL string
Specifies a label that Progress uses when it displays the widget. If you
do not specify a label, the variable name is the default label.
So, the DEFINE VARIABLE statement defines a variable and allows you to define the default
data representation for that variable. The Progress language element for specifying data widgets
is the VIEW-AS phrase. This is the general syntax.
SYNTAX
VIEW-AS widget-type [ options ]
317
Description
Specify the Progress keyword that indicates the appropriate data
representation. The keywords are:
FILL-IN
TEXT
SELECTION-LIST
COMBO-BOX
RADIO-SET
TOGGLE-BOX
EDITOR
SLIDER
options
Specific widgets have options that let you define functional and display
characteristics.
Note that VIEW-AS is a phrase, not a statement. This means that VIEW-AS can be attached to
certain Progress statements to expand the function of the statement. When you attach the
VIEW-AS phrase to a DEFINE VARIABLE statement, you are defining the default data
representation of the variable as shown in this brief code example:
DEFINE VARIABLE Field1 AS CHARACTER VIEW-AS TEXT.
Whenever Progress displays Field1, it displays the variable as a text widget. (Text widgets are
typically used for labels and reports.) If you do not use a VIEW-AS phrase in the DEFINE
VARIABLE statement, Progress displays the variable as a fill-in field.
You dont have to stick with the default data representation, however. You can override the
default widget for a variable or a database field by attaching the VIEW-AS phrase to a run-time
screen output statement, like this DISPLAY statement shows:
DISPLAY Field1 VIEW-AS FILL-IN.
318
NOTE:
When you run the lt-03-03.p procedure, you see a fill-in field because the VIEW-AS phrase
on the DISPLAY statement overrides the default VIEW-AS phrase of the DEFINE VARIABLE
statement.
Defining Buttons
Button and rectangle widgets differ from data representations in that they are exclusively user
interface components and are not related to database fields or variables. The button allows the
user to execute a function directly and the rectangle is an interface decoration.
This is a partial syntax for the DEFINE BUTTON statement.
SYNTAX
DEFINE BUTTON button-name LABEL string
Typically, you associate a button with a trigger in your code. The button then becomes a tool
that lets a user explicitly execute a trigger.
319
1 Open lt-03-04.p.
Exercise
2 Choose Compile Run. The interface, shown below, contains two buttons, Display Data
and Exit:
3 Choose the Display Data button. The trigger executes on the CHOOSE event of the button
widget, and displays Field1 as a text widget.
4 Choose Exit to end the procedure.
5 Press SPACEBAR to return to the Procedure Editor.
320
The Exit button does not have a trigger associated with it. Thats because the procedure uses the
CHOOSE event of btn-Exit to signal the unblocking response. Since this is a default response,
the procedure doesnt require a trigger and a programmed response.
Defining Rectangles
The basic syntax for defining a rectangle lets you decide the size of the rectangle, whether its
filled or empty, and how wide the edge is.
This is a partial syntax for the DEFINE RECTANGLE statement.
SYNTAX
DEFINE RECTANGLE rectangle-name SIZE width BY height
[
[
NO-FILL
EDGE-CHARS width
321
1 Open lt-03-05.p.
Exercise
2 Choose Compile Run. The interface, shown below, contains two buttons:
Display Rectangle and Exit:
322
As shown at point 1, the size of the rectangle is 12 columns (width) by 8 rows (height). The
NO-FILL option makes the rectangle empty. The EDGE-CHARS option specifies a border
thats two characters wide. The trigger executes on the CHOOSE event of the btn-Rect widget,
and displays a rectangle.
Defining Frames
A frame is a container for widgets. Frames allow you to organize data, action, and graphic
widgets. Data, action, and graphic widgets that can be placed in a frame (or dialog box) are
called field-level widgets.
You cannot place widgets in a window unless they are first contained in a frame widget. (One
exception: menu bars go directly into the window.) If you dont specify a frame, Progress
creates one for you. This frame is called the default frame.
323
1 Open lt-03-06.p.
Exercise
2 Choose Compile Run. The interface you see is the same Hello Progress World!
interface, except that a graphic border surrounds the fill-in fields. The graphic border
shows the area of the default frame follows:
Default frame
graphic border
3 Move input focus to Field3 and press RETURN to end the procedure.
4 Press SPACEBAR to return to the Procedure Editor.
Here is the code that created the display:
324
lt-03-06.p
DEFINE VARIABLE Field1 AS CHARACTER INITIAL "Hello".
DEFINE VARIABLE Field2 AS CHARACTER INITIAL "Progress".
DEFINE VARIABLE Field3 AS CHARACTER INITIAL "World!".
DISPLAY SKIP(1) Field1 SKIP(1) Field2 SKIP(1) Field3
/*1*/
WITH SIDE-LABELS CENTERED THREE-D.
ENABLE Field1 Field2 Field3.
ON ENTRY OF Field3
DO:
MESSAGE "Press Return in Field3 to exit the procedure.".
END.
WAIT-FOR RETURN OF Field3.
In the code you saw earlier, the DISPLAY statement included the NO-BOX option, which
suppressed the default frame border. Since the option is not included here, as shown at point 1,
the border appears.
The DEFINE FRAME statement allows you to name a frame and list the field-level widgets it
contains. You also have several options for controlling the arrangement of the widgets within
the frame, such as the SKIP option, which you have already seen.
Here is a partial syntax.
SYNTAX
DEFINE FRAME frame-name
form-item
...
[
WITH
[
[
[
SIDE-LABELS
NO-BOX
CENTERED
]
The following table describes the elements of the DEFINE FRAME statement:
325
Component
Description
form-item
Form items can include database fields, variables that have been
previously defined, buttons, rectangles, and SKIP options.
Frame phrase
(WITH)
The options shown at the bottom of the syntax diagram make up what is
called the frame phrase. The frame phrase, which begins with WITH, lets
you specify options that affect the frame itself or all the widgets in the
frame as a group.
The frame phrase has other important applications outside of the DEFINE FRAME statement.
The frame phrase can be attached to statements that output data to the screen to:
326
[
[
[
SIDE-LABELS
NO-BOX
CENTERED
In the following example, the DISPLAY statement uses a frame phrase to alter the
characteristics of a default frame:
DISPLAY Field1 WITH SIDE-LABELS NO-BOX CENTERED.
When you use a frame phrase without specifying a frame name, Progress applies the phrase to
the default frame.
Defining Frame Families
A parent is a widget that contains or owns other widgets. In addition to parenting frames to
windows, as described in the previous section, you can also parent frames to other frames. When
you parent a frame to another frame, you create a frame family. A frame that is parented by
another frame is called a child frame and a frame that parents another frame is called a parent
frame. Frames that are parented to the same frame, in the same generation, are called sibling
frames.
By defining a frame family, you create a relationship among the descendant frames that is
different from that of frames parented to the same window. For example, you can:
Control the hiding and viewing of child frames through the parent, or independently
Use default or cancel buttons from any other frame in the same family
Child frames behave like field-level widgets of the parent frame. Child frames must be
positioned physically within the parent frame. When you specify a location of a child frame, the
options you specify are with respect to the parent frame, not the window. However, the
field-level widgets of child frames are not controlled by the parent frame. You must explicitly
display, enable, and disable field-level widgets of child frames.
327
You can use frame families to create useful interactions among frames, but they do carry some
restrictions that are important to remember. For example:
Child frames cannot be down frames. (Down frames are frames that display multiple
records, one per line, one after another.)
Child frames must appear within the display area of their parent frame.
3.2.3
Widget Attributes
Each widget has a set of values that Progress uses to define the widget and change it during run
time. These attributes define all the characteristics of a widget that you can read or set in your
procedures. Attributes define the widgets:
Appearance
Functionality
When you first create a widget, Progress automatically determines many of the attributes.
Progress defines or changes other attributes during run time.
328
Attribute
Data Type
(1 of 2)
Description
HANDLE
WIDGET-HANDLE
VISIBLE
LOGICAL
HIDDEN
LOGICAL
SENSITIVE
LOGICAL
SCREEN-VALUE
CHARACTER
329
Attribute
Data Type
(2 of 2)
Description
ROW
DECIMAL
COL
DECIMAL
FIRST-CHILD
WIDGET-HANDLE
NEXT-SIBLING
WIDGET-HANDLE
Typically, the default attribute values assigned implicitly by Progress statements provide the
appearance and functionality you want in your widgets. Later, youll learn how to read and set
attributes directly.
3.3
Event Types
Earlier, the tutorial defined any user input as an event. All keystrokes are events. All mouse
interactions are events. Its time to expand the definition of events. Progress recognizes two
types of events: event actions and event functions. An event action is any simple user
interaction, like a single keystroke or a simple mouse interaction. An event function is an
abstraction of one or more event actions.
For example, on some platforms F1 invokes the help system. On other platforms F2 invokes the
help system. F1 and F2 are both event actions, but both invoke the same function (in this
example). Instead of writing code for the event action, you can write equivalent code using the
Progress keyword that specifies the function. In this case, the keyword is HELP. HELP is an
event function:
330
ON F1 OF widget-name
DO:
/* Code */
END.
ON HELP OF widget-name
DO:
/* Code */
END.
The first trigger relies on the event action, while the second trigger relies on the event function.
For any particular widget, you can write a trigger for either the event action or the event
function, but not for both. However, you should write your triggers for event functions wherever
possible because:
Your code is more portable. In the example above, writing a trigger for F1 would not work
on some platforms. Writing a trigger for HELP works everywhere.
Execute a trigger
Youve already seen the syntax for the ON statement, which handles events that execute trigger
code. Now, examine this partial syntax for the WAIT-FOR statement.
SYNTAX
WAIT-FOR event-list OF widget-list
OR event-list OF widget-list
] ...
The WAIT-FOR statement translates to on this widget-event pair, unblock execution. The
result is that the user moves into another part of the procedure or completes the procedure.
331
Function
Description
ENTRY
Any action by the user or the application that gives a widget input focus.
LEAVE
Any action by the user or the application that takes input focus from a
widget.
GO
Any action that signals Progress to accept new data and continue
processing.
CHOOSE
Event Categories
There are literally hundreds of events, so the Progress documentation uses some terms to refer
to groups of related events. Table 34 describes the categories.
Table 34:
Event Categories
Category
332
Description
Universal key
functions
Navigation key
functions
These events are the keystrokes that let you move input focus in an
interface, like TAB or BACK-TAB.
Field-editing key
functions
These events are the keystrokes that let you manipulate text inside a
widget, like BACKSPACE or DELETE.
High-level Progress
event functions
3.4
2.
Define frames.
3.
Define triggers.
4.
Display widgets.
5.
Enable widgets.
6.
Block execution.
7.
333
Buttons that launch the major sections of the application (for now, Customer, Order Entry,
and Inventory)
Figure 34:
A Simple Interface
Now that youve envisioned the interface, you can start coding the sections of the procedure to
make it a reality.
334
/*2*/
/*3*/
/*4*/
/*5*/
These notes explain how field-level widgets serve various functions in this application:
1.
Use the rectangle widget to create a large (SIZE-CHARS 40 BY 7) empty (NO-FILL) box
with a one-character wide edge (EDGE-CHARS). The box makes the application title
stand out.
2.
Create two variables to hold the application title. The FORMAT "x(19)" option specifies
how many characters of display space Progress should allow the text widgets to occupy.
The default is 8. You define these variables as text widgets because you are using the
values as a title. The variables are read-only text.
3.
Create another variable to hold the initials of the user. Here, you need a fill-in field, but
you dont have to specify it as such because fill-in field is the default.
4.
Create three buttons that launch various functions of a sales and inventory application.
5.
NOTE:
Keep in mind that you can access online help information about a Progress keyword
by highlighting the keyword and pressing the HELP key function (F1).
335
Previously
defined
widgets
21
31 NO-LABEL
31 NO-LABEL
34
With the DEFINE FRAME statement, you list the widgets you want contained in each frame.
In the first frame, you want precise placement of each widget. The AT phrase allows you to
place a widget at a specific ROW and COLUMN within the frame, not the window. Here, you
place the title variables inside the rectangle widget and you place the fill-in field below the
rectangle. In the second frame, the default spacing works fine, so you dont need to use the AT
phrase.
Define Triggers
You only need one trigger for now. When the user chooses any of the function buttons, you want
to display the message Sorry, that function is not yet implemented. Here is the code:
ON CHOOSE OF btn-Cust, btn-Order, btn-Inv
DO:
HIDE MESSAGE NO-PAUSE.
MESSAGE "Sorry, that function is not yet implemented.".
END.
As you can see, one ON statement can apply to many widgets. It can also apply to many events.
The HIDE MESSAGE NO-PAUSE statement clears the default message area without pausing.
Its a good habit to always use this statement before sending a new message.
336
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
The DISPLAY statement displays the title variables without labels (NO-LABEL). Next it
displays the fill-in field. Finally, by using the frame phrase (WITH FRAME), you tell
Progress to use a frame youve already defined.
2.
Only the fill-in field in the frame is meant to have user interaction, so you enable it.
3.
You block execution until the user presses RETURN in the fill-in field.
4.
When the user presses RETURN, the application executes the code that follows the
WAIT-FOR statement. Here, you disable the fill-in field from receiving further input.
5.
This statement serves to more precisely illustrate the function of the DISPLAY statement.
As you can see, you do not need a DISPLAY statement to make the buttons
appear-enabling the buttons makes them appear. Basically, you use the DISPLAY
statement with data widgets to display both the widget and the underlying value of the
variable or database field that the widget represents. If you had skipped the DISPLAY
statement for the first frame, the values of the text widgets, All Around and Sports,
would not appear.
The ALL keyword tells Progress to enable all the widgets in the defined frame.
6.
You establish the condition that signals the end of the applicationwhen the user chooses
the Exit button.
337
1 Open lt-03-07.p.
Exercise
338
339
Practice Problems
If you feel like you need some practice creating interfaces, complete the exercise below. The filename
listed next to the problem contains a sample solution. You can load the file into the Procedure Editor.
Problem 3-1: lt-03-s1.p
The procedure you just worked with, lt-03-07.p, creates a complete interface that follows the Progress
programming model. Using the same techniques, you should be able to duplicate the interface shown
below.
340
3.5
3.5.1
As youve seen in previous examples, you use the ENABLE and DISABLE statements to turn
widgets on and off. Typically, when you present an interface, you enable all the widgets in that
interface. At other times, some widgets dont have to be enabled unless special conditions are
met.
341
1 Open lt-03-08.p.
Exercise
2 Choose Compile Run. The interface shown below appears. Note that buttons #1 and
Exit are enabled, and #2 is disabled:
3 Choose the first button. The second button becomes enabled and the first becomes
disabled.
4 Choose the second button. The first button becomes enabled again and the second button
becomes disabled. You can repeat this process as many times as you like.
5 Choose Exit to end the procedure.
6 Press SPACEBAR to return to the Procedure Editor.
342
**********/
The effect of the ENABLE and DISABLE statements at points 1 and 2 is that only one of the
buttons can be active at a time. By selectively enabling and disabling parts of the interface, you
help the user focus on the parts of the interface that are important at a given moment.
This is a partial syntax for the ENABLE statement.
SYNTAX
ENABLE
{[
ALL
[ (n) ] |
]}
SKIP
frame-phrase
widget-list }
ALL
widget-list
}{ [
frame-phrase ]
343
Description
ALL
frame-phrase
Specifies the frame where the targeted widgets exist. Even when Progress
does not require it, it is good programming practice to specify the frame.
3.5.2
Theres some important default Progress behavior that determines when widgets are visible and
when they are not. This section outlines Progresss default behavior so you know when to rely
on it. This section also introduces the VIEW and HIDE statements, which allow you to control
the display of widgets.
Default Viewing and Hiding
When you use DISPLAY and ENABLE statements, Progress takes care of making the
appropriate widgets visible. When you DISPLAY any widget, all the widgets in the widgets
frame become visible. When you ENABLE a widget, all the widgets in the frame become
visible, although Progress only enables the widget you specified. Progresss default viewing and
hiding behavior concentrates on displaying and hiding frames of widgets, not individual
widgets.
Viewing and Hiding Widgets
You can explicitly view and hide frames or view and hide widgets within frames by using the
VIEW and HIDE statements. This is a partial syntax for the VIEW statement.
SYNTAX
VIEW widget-list
344
widget-list
| MESSAGE |
ALL
] [
NO-PAUSE
Description
MESSAGE
You can also use the HIDE statement to hide the contents of the default
message area.
NO-PAUSE
To hide or view a frame, substitute the keyword FRAME and frame name for widget-list:
VIEW FRAME Frame1.
HIDE FRAME Frame2.
To hide or view one or more widgets in a frame, specify a list of widgets and, if necessary,
append the IN FRAME frame-name syntax to individual widget references:
VIEW Widget1 IN FRAME Frame1 Widget2 IN FRAME Frame2.
HIDE Widget1 IN FRAME Frame1 Widget2 IN FRAME Frame2.
Up to now you used the frame phrase, which begins with WITH, to specify a frame. Here you
use the IN FRAME syntax. The difference is that WITH is used to create or modify a frame and
its attributes, while IN FRAME merely references an existing frame.
One very important thing to remember about using VIEW and HIDE is that they do not affect
the enabled status of a widget. If a widget is enabled when you hide it, it will still be enabled
when you view it again. Enabling and viewing are separate functions.
345
1 Open lt-03-09.p.
Exercise
2 Choose Compile Run. The visible interface consists of buttons and a small frame with
its border showing and a widget within the frame. All the HIDE and VIEW statements will
operate on this small frame and the widget within it:
346
347
348
When you display the default border of a frame, you can use the TITLE option to give the
whole frame a label.
The first trigger views the frame. You must include the keyword FRAME or Progress will
attempt to find a field-level widget with the specified name.
3.
As with VIEW, the HIDE statement only requires a valid frame reference.
4.
Here, you are viewing a widget within a frame. You need to specify the widget and the
frame reference with IN FRAME.
5.
Hiding a specific widget also requires both widget and frame references.
3.5.3
Usually, the default attribute values assigned implicitly by Progress statements provide the
appearance and functionality you want in your widgets. However, Progress also supports a
syntax that lets you access attribute information directly. This syntax is shown below.
SYNTAX
ASSIGN widget-name:attribute-name
You can also assign widget attribute values to variables, as long as the variable is of the same
data type, using the following syntax.
SYNTAX
ASSIGN var-name = widget-name:attribute-name
To set an attribute, you assign the new value to the attribute, but you must also specify the frame
in which the widget resides. You use the IN FRAME phrase to identify the containing frame.
Here is the syntax.
SYNTAX
ASSIGN widget-name:attribute-name IN FRAME frame-name = value
349
1 Open lt-03-10.p.
Exercise
2 Choose Compile Run. You see a fill-in field with the label Is Rectangle Visible? and
the value no.
3 Choose the Show Rectangle button. A rectangle becomes visible and the value of the fill-in
field becomes yes, as shown below:
350
When you first create a widget, the VISIBLE attribute is set to YES by default. However,
a field-level widget is not visible until its frame is visible. Therefore, when a frame
becomes visible, all the widgets in it are visible by default. In this statement, you set the
VISIBLE attribute to NO. When the frame displays, you wont see the rectangle.
2.
3.
When the user chooses the button, the trigger changes the value of the VISIBLE attribute
to YES, making the widget visible, since its frame is currently visible.
4.
5.
The DISPLAY statement outputs the new value of Field1 to the screen.
351
2.
3.
Assign the result of the method call to a variable of the same data type.
Heres an example:
ASSIGN variable-name = widget-name:method-name(parameter-name).
The later chapters of the tutorial discuss some of the most useful methods.
352
3.6
Summary
The Progress programming model is a way of programming that creates highly responsive
interfaces. A user interface is made up of a keyboard, or other input device such as a mouse, and
whatever the user sees on the screen.
A window is an object that contains your applications workspace. Character interfaces use only
one window. Graphical interfaces, such as Windows 95 or Windows NT, can have multiple
overlapping windows on the screen.
Progress interfaces are made of objects called widgets. An interface is a tool for displaying data
and receiving events. A particular interface can receive events when it is enabled for input and
the procedure or the user designates that widget as the event receiver. A widget so designated
is said to have input focus.
Each widget responds to each possible user event (keyboard or mouse action) with a default
response. You can program a widget to have a response in addition to the default response using
triggers. A trigger is a block of code following an ON statement. The code executes when the
widget specified in the ON statement receives the user event specified in the ON statement.
The parts of a Progress procedure include:
Widget definition
Frame definition
Trigger definition
Interface creation
Interface enabling
Execution blocking
Interface disabling
Window Widgets Window widgets are workspace for your application. A window
contains all other widgets. Character interfaces use one window, while graphical
interfaces can use multiple windows.
Container Widgets Container widgets allow you to organize data, action, and graphic
widgets. Container widgets include frames and dialog boxes.
353
Data Widgets Data widgets are the widgets you use to represent data from fields and
variables. Data widgets include fill-in fields, text, editors, selection lists, combo boxes,
radio sets, toggle boxes, sliders, and browse widgets.
Action Widgets Action widgets allow the user to direct the operation of your
application. Menus provide groups of related processing options while buttons execute a
single option. Buttons, menu bars, submenus, and menu items make up action widgets.
Graphic Widgets Graphic widgets help you decorate your interface. Use rectangles to
make different kinds of borders. Images, which are available on graphical interface
systems, allow you to include high-resolution graphics in your interface.
354
DISPLAY displays widgets and the data contained in the associated fields.
WAIT-FOR blocks execution and establishes the condition that unblocks execution.
DEFINE FRAME creates a frame, including the field-level widgets that it contains.
4
Understanding the Database Environment
This chapter introduces you to the Data Dictionary, a tool that you use to create, modify, and
view the properties of a database. The chapter covers:
Generating reports
For additional information about the Data Dictionary, see the Progress Basic Development
Tools on-line help. For a discussion of designing and creating effective databases, see the
Progress Database Design Guide.
4.1
To illustrate how the Data Dictionary and application defaults work, youll create and use your
own copy of the sports database.
4.2
42
1.
From the ADE Desktop, click the Data Dictionary tool button.
2.
If you havent connected a database, Progress displays a series of dialog boxes to let you
specify one. The next section describes how to use these dialog boxes.
If you have connected a database, Progress loads the schema of that database into the Data
Dictionary and displays the Data Dictionary main display, as shown in Figure 41.
Connected
database
Figure 41:
Note that while you work with the Data Dictionary, you cannot work with the tool you started
the Data Dictionary from (the Desktop or the Procedure Editor), although it remains open.
43
4.3
This dialog box permits you to save or discard all changes you have made to the current database
during the current Data Dictionary session. Choose Yes to keep your changes and No to discard
them. This dialog box also appears when you switch between databases in the Data Dictionary.
While you work with this tutorial, always choose No when this dialog box appears. The
exercises in the tutorial depend on the sports database schema remaining the same.
4.4
4.4.1
Creating a Database
Follow these steps to access the Data Dictionary and create a new database.
When you start the Data Dictionary without having connected a database, the Dictionary
Startup dialog box appears, as shown below:
This dialog box prompts you to connect an existing database, create a new database, or
continue with no database.
44
2 Choose Create a New Database and then OK. The Create Database dialog box appears as
shown below:
A Copy of Some Other Database You can specify another Progress database to
copy.
5 Activate the Replace If Exists toggle box. In this case, the Replace If Exists toggle box
represents a YES/NO question. (Do you want the new database to replace any existing
database of the same name in the current directory?)
6 Choose OK to create a copy of the sports database.
7 Once you create a Progress database, you must connect the database to access the data in
it. When you choose OK in the Create Database dialog box, the Database Connect dialog
box appears to help you connect the sports database. Choose Cancel for now. The next
section describes how to access this dialog box directly.
The main Data Dictionary display appears.
45
4.4.2
Connecting a Database
When you connect a database with the Data Dictionary, you make the database available to all
Progress tools and applications. In other words, if you exit the Data Dictionary without
explicitly disconnecting a connected database, the database is still available to other Progress
tools and applications. From within the Data Dictionary, connecting a database also means that
you have access to view or modify the database schema.
Follow these steps, to connect a database:
Exercise
1 In several cases, the Data Dictionary displays the Database Connect dialog box
automatically. To access it directly, choose Database Connect from the Data Dictionary
main display. The dialog box appears, as shown below:
The Connect Database dialog box allows you to specify how you want to connect to a
database. For specifics on database connection parameters, see the Progress Startup
Command and Parameter Reference.
3 Choose OK to connect to the new sports database and return to the Data Dictionary
display. The Data Dictionary display confirms the database connection. The Databases
selection list now lists the sports Database.
You can connect several databases, but you can only work with one at a time in the Data
Dictionary. If you have several connected, choose the one you want to work with from the
Databases selection list.
46
4.4.3
Disconnecting a Database
When you disconnect a database, that database is no longer available to other Progress tools and
applications and the schema is no longer available in the Data Dictionary.
Follow these steps to disconnect a database:
Exercise
1 Choose Database Disconnect. Progress displays a dialog box and prompts you to verify
that you want to disconnect:
2 Choose Yes. The Databases selection list no longer lists the sports database.
3 Reconnect the sports database so that it is available for the next exercise.
4.5
Menu bar
Mode buttons
Selection list of
database objects
Action buttons
Figure 42:
The rest of this section provides information on using the different interface components.
47
4.5.1
Using Menus
While the rest of the Data Dictionary interface widgets allow you to work with objects, the
menus on the menu bar allow you to control the application and work with whole databases.
There are also some menu options that duplicate the function of other widgets in the main
display. Table 41 provides a brief description of the menus available in the Data Dictionary.
Table 41:
Menu
Description
Database
Create, connect, and disconnect databases; create schema reports; exit the
Data Dictionary.
Edit
Delete or view properties for the current database object; commit or undo
all actions since your last save or when you last opened the Data
Dictionary. This menu is not available until you connect a database.
Create
View
Options
Rename fields globally and renumber fields in a table. This menu is not
available until you connect a database.
Tools
Help
4.5.2
The Data Dictionary interface allows you to quickly access the schema of a database object. As
mentioned before, the schema consists of properties that define a database object or properties
that establish an application default for a database object. A property, then, is an individual
schema element. The paradigm of the Data Dictionary is to provide a simple point and click
interface that lets you quickly select an individual database object and bring up a dialog box that
organizes and displays all the properties associated with that type of object. These dialog boxes
are known as property sheets.
48
Select the type of database object that you want to work with by choosing the appropriate
mode button.
The Data Dictionary displays the correct selection lists and action buttons that go with that
object. In other words, the Data Dictionary has a different mode for each of the four
database objects.
2.
Select an individual database object from the selection list. For fields and indexes, you
select the correct table and then the correct field or index object.
3.
The Create button creates a new object and brings up a new property sheet.
The Properties button brings up the property sheet for the selected object. You can
view and change properties from this dialog box.
The Delete button removes the selected object from the database.
4.5.3
Although the property sheets for each object type are different, they all work similarly. Follow
the steps below to view the property sheet for the Cust-Num field of the Customer table:
Exercise
49
5 The property sheet for the Cust-Num field appears, as shown in Figure 43.
Properties
Bring up dialog
boxes for other
properties
Action buttons
Figure 43:
The data widgets on the property sheet each correspond to a single database property. The first
set of buttons on the property sheet access dialog boxes that let you define more complex or
additional properties. The bottom of all property sheets contains a row of standard action
buttons that let you control the property sheet:
410
Choose OK to save the changes you have made and close the property sheet.
Choose Save to save the changes and keep the property sheet open.
Choose Cancel to close the property sheet and discard all changes made.
Choose the left arrow button (<) to clear the property sheet and show the properties of the
object that immediately precedes the current object in the selection list. If you have made
changes, the Data Dictionary asks you to save or discard those changes before moving to
the next object.
Choose the right arrow button (>) to clear the property sheet and show the properties of
the object that immediately follows the current object in the selection list.
4.6
Customer
Invoice
Item
Local-Default
Order
Order form information, such as order date, shipping date, and postal
carrier.
Order-Line
Ref-Call
Customer call information, such as call number and reason for call.
Salesrep
State
As you can conclude from these descriptions, this database holds the information necessary for
All Around Sports to take orders, process orders, bill for orders, and keep inventory information
up to date.
411
4.7
4.7.1
Defining Tables
Figure 44:
All you really need to define a table is a unique name. The rest of the table definition is actually
the definition of the field and index objects that make up the table.
4.7.2
Defining Fields
A field is a particular item of information that helps describe the subject of a table. For example,
the name of a customer, the address, and the credit limit are information items that help define
a customer.
412
Figure 45:
Two properties make up the essential definition of a field object: the field name and the data
type.
Field names may be up to 32 characters long and can consist of alphabetic characters (AZ,
az), digits (09), and the special characters $, &, #, %, -, and _. A field name must begin with
an alphabetic character.
The data type defines what type of data a field can store. Table 43 describes the Progress data
types.
Table 43:
Data Type
Data Types
(1 of 2)
Description
CHARACTER
Character fields contain any type of data (letters, numbers, and special
characters). Some character fields in the Customer table are Name,
Address, and Phone.
INTEGER
413
Data Types
Data Type
(2 of 2)
Description
DECIMAL
DATE
Date fields contain dates. The Invoice-Date field in the Invoice table
is a date field.
LOGICAL
4.7.3
Defining Indexes
An index is a field or combination of fields from one table that Progress uses as the basis for
searching, sorting, or otherwise processing the records of that table. As an example of index
properties, access the property sheet for the Comments index of the Customer table as shown in
Figure 46.
Properties of
selected index
Figure 46:
An index is defined by several important properties. First, the index must have a unique name.
If it is a simple index, based on one field, then name the index the same as the field component.
If it is a compound index, based on several fields, give the index a descriptive name that
describes the components of the index.
414
Index Properties
Property
Description
Primary
The primary index is the one that Progress uses by default. Each table has
one and only one primary index. Progress uses the primary index when
retrieving records or ordering records for a list (like a report) if you dont
specify another index. You want your primary index to reflect the most
common or natural sort order.
Unique
A unique index is one where each index value must be different. For
example, each customer needs a unique number to identify them. Thus, the
Cust-Num index is a unique index. When you define an index as unique,
Progress will not allow you to enter an index value thats already in use.
Active
An active index is one that Progress updates when you create, delete, or
modify a record. If the index were inactive, you could still find the
definition of the index in the Data Dictionary, but Progress would not
update it until you made it active again.
Word
A word index is one based on a character field where each distinct word in
the data becomes a separate index entry. Word indexes allow you to search
character fields quickly for key words.
4.7.4
Defining Sequences
A sequence is an algorithm for creating an incremental number series. Sequences can generate
sequential values within any integer range with either positive or negative increments. The
database holds the sequence definition and keeps track of the next available value. However,
you use sequences programmatically. That is, when you create a new record, your procedures
can use sequences to provide automatically generated sequential values for fields.
415
Figure 47:
Sequence properties include a unique name and properties that provide a number of ways to
alter the basic sequential algorithm. Table 45 describes the properties.
Table 45:
Property
416
Sequence Properties
Description
Initial Value
The starting value of the sequence. You can enter any positive or
negative integer.
Increment by
The value used to determine the next sequence number. You can use a
positive or negative integer.
Upper Limit
The highest acceptable number for the sequence. You can use any
positive or negative integer.
Cycle at Limit
4.8
Cycling Sequence A sequence that begins at an initial value and increments in one
direction until it reaches a designated limit. On reaching the limit, the sequence restarts
with the initial value. You must provide a value for the Initial Value property, the
Increment by property, and the appropriate limit property. Cycle at Limit must be YES. A
cycling sequence does not provide unique values.
Validation
Display formatting
4.8.1
Validation is the process of checking criteria before allowing the user to take an action. There
are two types of validation: table validation and field validation. Table validation allows you to
establish criteria that must be met before a user can delete a record. For example, you wouldnt
want to delete a customer record if that customer has unpaid bills.
417
Figure 48:
Field validation allows you to establish what is and is not an acceptable entry for a field. For
example, you can check to make sure an entry falls with high and low numeric limits.
To see an example of field validation, access the property sheet for the Credit-Limit field of the
Customer table and choose the Validation button. The dialog box shown in Figure 49 appears.
Figure 49:
Both of these dialog boxes have an editor widget where you can define the validation criteria
using Progress 4GL statements. This code is known as the validation expression.
The fill-in widget contains text that Progress displays to the user when a user action fails the
validation expression. This message is known as the validation message.
418
4.8.2
In Chapter 3, you learned about events and triggers. These triggers and events are called
user-interface events and user-interface triggers. Tables and fields in a Progress database can
receive a different type of event known as database events. Tables and fields respond to these
events with a different type of trigger known as a database trigger.
When discussing database triggers, its also important to distinguish two types: schema triggers
and session triggers. A schema trigger is a database trigger stored in the schema of a database.
A session trigger is a database trigger used in code.
There are five database events, as described in Table 46.
Table 46:
Event
Database Events
Object Type
Description
CREATE
Table
DELETE
Table
FIND
Table
WRITE
Table
ASSIGN
Field
419
Figure 410:
The tutorial doesnt cover how to write and implement database triggers. Still its important to
know about them. Database triggers give 4GL programmers the ability to define custom default
behaviors and business rules for your data. The database then becomes a central storage place
for these rules.
For information on using the controls of the Table or Field Triggers dialog boxes, see the
Progress Basic Development Tools manual.
4.8.3
Field Formats
The format of a field describes the way that Progress displays data on your screen and in printed
reports. The format is a string made up of literals and symbols. Literals are extra characters that
you want to display with data and symbols are place holders for data. When you create a field
in the Data Dictionary, Progress supplies a default format string for the particular data type. If
that format string doesnt suit your needs, then you can specify another.
420
Symbol
Description
>
Designates zero suppression. That is, Progress replaces > with a number,
as long as its not a leading zero. If its a leading zero, Progress replaces >
with a blank.
To create a format string, just put together the symbols to describe how to display the data. For
example, if a character field contains the word Wonderful, one format string could be
AAAAAAAAA. If you want the data to display in uppercase, change the format string to
!!!!!!!!!. If the field can contain numbers too, change the format string to NNNNNNNNN.
If the field can contain any number, letter, or character, including blanks, then use the format
string, XXXXXXXXX.
Instead of typing long strings of symbols, you can use this shortcut:
1.
2.
421
Figure 411:
While the format strings help display existing data, they also limit user input. For example, if a
field has a format string that converts all data to uppercase, then when the user enters data, it
will be converted to uppercase. Similarly, a format string that specifies numeric data prevents a
user from entering letters and special characters into the field.
4.8.4
VIEW-AS Phrases
As you learned in the last chapter, the default data widget for a database field is a fill-in field.
If you dont plan to display a particular field as a fill-in field, consider using the VIEW-AS
property to establish a different default data widget. For example, if you want a particular
database field to hold notes and miscellaneous information in sentence form, then a fill-in field
would be a poor data representation for that field. It would be better to define it as an editor
widget.
422
Figure 412:
The selection list contains the data widgets that are legal for the field. When you select a widget
type, the editor displays a syntax diagram for in the bottom editor, which you can copy into the
editor at the top of the dialog box.
4.8.5
Labels
When you display a field, the field name is the default screen label. You can specify a different
label using the Label property on the field property sheet. Typically, you want your default label
to be more descriptive than the field name, which most programmers like to keep short. You can
also specify a different label in the Column Label field for use when Progress displays data in
columns. Both the label and column label can consist of any text, including blanks.
To keep the default label (field name), enter ? in the label fields.
4.8.6
Help Text
The field property sheet also contains the Help Text property. Progress displays the text entered
here in the default status area of the window when the field gets input focus. You can specify
any text you like. Consistently providing help text for database fields significantly reduces the
burden of programming help messages.
423
4.9
Generating Reports
As youre coding, it helps to have hard copy reports of database properties for reference. The
Data Dictionary Reports menu has a variety of options, which you can use to output reports to
the screen or to a printer. Table 48 lists and describes the Reports menu options.
Table 48:
Menu Option
424
Description
Detailed Table
Quick Table
Quick Index
Quick Field
SQL View
Sequence
Trigger
User
Table Relations
4.10
Summary
The Data Dictionary is a tool that you use to create, view, and modify the properties of a
database and database objects: tables, fields, indexes, and sequences. Database properties
include those that define database objects and those that establish application defaults.
Collectively, database properties are referred to as schema.
Databases have two names:
The physical database name is the operating system filename of the database.
The logical database name is the internal Progress name of the database. Procedures
reference the logical name. If you dont specify a logical name, Progress uses the physical
name by default.
The Data Dictionary allows you to connect databases. When a database is connected, any
Progress tool or application can access the data or schema of the database.
Table objects are defined with a unique name. The definitions of constituent fields and indexes
make up the bulk of a table definition.
Field objects are defined with a unique name and by specifying a data type. Data types
determine what kind of data a field can store:
Index objects are defined by specifying a name and the component fields. Other index properties
define how the index works:
An active index is one that Progress keeps updated and ready for use.
A word index is an index of a character field that allows you to search for words within
the field.
425
Terminating sequences start at an initial value and increment in one direction toward a
limit. Upon reaching the limit, a terminating sequence ceases to generate new values.
A cycling sequence starts at an initial value and increments in one direction toward a limit.
Upon reaching the limit, the sequence starts over at the initial value.
Tables and fields have a validation property, which allow you to check criteria before allowing
record deletions in a table or new values in a field. The validation property is made up of:
A validation expression that establishes the logic that allows or disallows record deletions
in a table or new values in a field.
A validation message that informs the user that an action failed a validation check.
Databases have special events for which you can write triggers:
A WRITE event occurs when Progress writes a record back to the database.
An ASSIGN event occurs when Progress writes new data to an individual field.
The database trigger property allows you to add default behaviors to a database, eliminating the
need to code the behaviors in your procedures.
Field formats are symbols that tell Progress how you want to display data by default. Formats
do not affect the actual data, just the display of the data.
426
5
Working with Expressions
This chapter discusses different ways to represent and manipulate values. A value can be a
variable or a database field, as youve already seen. A value can also be the result of an
arrangement of language elements. An arrangement of language elements that represents a
single value is known as an expression.
Specifically, this chapter contains information on:
Understanding expressions
Using operands
Using operators
Using functions
5.1
Understanding Expressions
An expression is a combination of 4GL language elements that results in a single value. At a
minimum, an expression consists of one operand, but can include multiple operands, operators,
and functions.
An operand is a language element that represents a value. Operands include:
Variables A location in memory that holds a value that may change during the
execution of a procedure.
Widget attributes A value that describes a characteristic of a widget like its width,
height, and so on.
Constants A value that does not change during the execution of a procedure.
An operator is a language element that represents an action carried out on one or more operands.
The successful combination of operands and operators, called an operation, always returns a
value. For example, the equal sign (=) is a 4GL operator that assigns the value from the right
side of the operator to the field or variable on the left side of the operator. The plus sign (+) is
another operator that adds the operands on either side of the operator and returns the result.
A function is a prewritten program that performs a specific task and returns a value. A function
is like an operand in that it represents a value, but it is also like an operator in that it represents
an action. You can think of a function as a prepackaged solution to a task that can be used in an
expression. Because the code already exists, either as a pre-defined function or one that you
create as a user-defined function, it offers a shortcut to providing a programmed solution to a
coding task or problem.
Progress supports pre-built Progress-supplied functions and user-defined functions. The 4GL
contains many functions that perform a wide range of common tasks. For example, the
ASC(character) function returns the ASCII integer code for a supplied character. Also, you can
use the FUNCTION statement to create specific functions that suit your programming needs.
The sections that follow provide more information about expression components.
5.2
Using Operands
Operands are values. They are the raw material that operators and functions act on to determine
the final result of an expression. This section provides the information you need to successfully
use operands in expressions.
52
5.2.1
Using Variables
A variable is a temporary storage place for data. The value contained in a variable may change
during the execution of the program that contains it. Typically, variables contain data from the
user, copies of database fields or other variables, or the results of expressions.
Defining Variables
The partial syntax for the define statement below contains more options than you encountered
in Chapter 3.
SYNTAX
DEFINE VARIABLE variable-name
{ AS datatype | LIKE field }
[ EXTENT n ]
[ FORMAT string ]
[ LABEL string [ , string ] ]
[ INITIAL { constant | [ constant [ , constant ] ... ] } ]
Table 51 describes the new syntax components of the DEFINE VARIABLE statement:.
Table 51:
Component
(1 of 2)
Description
AS datatype
Specifies the data type of the variable. Valid data types include:
CHARACTER, INTEGER, DECIMAL, DATE, LOGICAL and
WIDGET-HANDLE
LIKE
EXTENT
FORMAT
53
Component
(2 of 2)
Description
LABEL
Specifies the display label for the variable. For arrays, if you specify
a single label, then every element of the array uses that label. You can
also specify a different label for each element of the array using a
comma-separated list of labels after the keyword.
INITIAL
Gives the variable an initial value. For arrays, if you specify a single
value, then every element of the array has that initial value. You can
also specify a different initial value for each element using a
comma-separated list of values enclosed in brackets.
Using LIKE
When defining a variable, you must specify either the data type or a database field or another
variable whose format and attributes you want to copy to the new variable. When you specify
the LIKE option, the new variable acquires the format, label, and initial value attributes of the
referenced field or variable. You can override an inherited attribute by using the FORMAT,
LABEL, and INITIAL options.
NOTE:
To use a LIKE phrase that references a database field, you must be connected to the
database that contains the field you want to copy.
/*2*/
/*3*/
54
1.
2.
Your second variable is identical to the first; that is, New-Name2 has the same value,
format, and label that you specified in the New-Name1 definition.
3.
In this statement, you create a third variable that inherits many of the attributes of a
database field. Notice the general syntax for making a specific reference to a database
field: table-name.field-name. The period separates the table and field names.
Keep in mind that you can access on-line help information about a Progress keyword
by highlighting the keyword and pressing the HELP key function (F1).
Using Arrays
Arrays are fields or variables that contain multiple data elements. The extent of an array is the
number of elements it contains.
To define a field or variable as an array, specify the extent. If you want to define a database field
as an array, use the extent option in the Data Dictionary. To define a variable as an array, use
the EXTENT option in the DEFINE VARIABLE statement.
To initialize the array with values, you can use the INITIAL option with the values listed
between square brackets as shown in the following code:
DEFINE VARIABLE Letters AS CHARACTER EXTENT 3 INITIAL ["a", "b", "c"].
DEFINE VARIABLE Numbers AS INTEGER EXTENT 5 INITIAL [1, 2, 3, 4, 5].
If you do not supply enough values to fill up the elements of the array, Progress copies the last
specified value into the remaining elements of the array. If you supply too many values,
Progress returns an error message.
Within a procedure, you can:
Refer to all the elements in the array at once. Simply specify the array name.
Refer to a specific array element. Specify the array name and the element number, called
the index, enclosed in square brackets. For example: Letters[2]. Note that the index value
of the first array element is 1.
55
1 Open lt-05-01.p and run it. The interface shown below appears:
Exercise
The array of 12 elements contains the number of days in each month. Each element has an
individual label that corresponds to the name of the month.
2 Press TAB to move through the array elements. Notice the message area of the window. As
you enter each element, the message references the label, data, and index of the element.
3 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
56
NOTE:
The DEFINE VARIABLE statement with the EXTENT option defines the array.
2.
To give each element an individual label, use a comma-separated list of strings after the
LABEL keyword.
3.
To initialize the elements, use a bracketed, comma-separated list of values after the
INITIAL keyword.
57
5.
Here, you use the array variable name (Months) as a reference to the whole array. If the
user enters a fill-in field associated with any of the elements, the trigger executes.
6.
The SELF keyword is called a system handle. The LABEL, SCREEN-VALUE, and
INDEX keywords are widget attributes. A system handle is a global variable that holds a
widget handle. The system maintains system handles for you. SELF is a system handle that
holds the widget handle of the current widget (a widget that has input focus or a widget for
which a trigger is firing). SELF is a convenient way of referring to an individual array
element without having to keep track of the index. Youll learn more about SELF later in
the tutorial.
The LABEL attribute holds the widget label. The SCREEN-VALUE attribute holds the
value shown on the screen, which may not be the same as the value in the underlying
variable. (Perhaps the user changed the screen value or the procedure changed the field
value.) The tutorial covers screen values and field values more thoroughly later. Finally,
the INDEX attribute holds the index value of the array element where the cursor currently
resides. If you need to know explicitly where the cursor is, as opposed to relying on SELF,
the INDEX attribute is your tool.
5.2.2
Before you can reference a database field, you must connect the database that contains it. To
reference a field in your code, specify its name. You may also need to specify the table name
that contains the field if more than one table in the database contains a field of the same name.
To avoid ambiguity, add the table name and a period before the field name.
SYNTAX
table-name.field-name
In many cases, programmers feel that supplying both the table and field name makes the code
more readable, even if it is not required.
58
5.2.3
Since a widget attribute is a value, it can be an operand in an expression. For some widget
attributes, you can assign the result of an expression to a widget attribute, thereby changing that
characteristic of the widget. For example, you could move a widget over five columns by adding
five to the current value of the COL attribute.
This is the syntax for referencing a widget attribute value.
SYNTAX
widget-name:attribute-name
IN FRAME frame-name
You only need the IN FRAME option when two or more frames have a widget of the same
name. Heres an example of using a widget attribute in an expression:
Mywidget:COL IN FRAME Myframe = Mywidget:COL IN FRAME Myframe + 5.
59
5.2.4
Using Constants
A constant is a value that does not change. A constant can be of any data type: Numeric
(DECIMAL or INTEGER), CHARACTER, DATE, or LOGICAL.
Table 52 shows how to represent constants.
Table 52:
Data Type
Constant Example
CHARACTER
My-variable =
Numeric
My-variable =
5000:
DATE
Myvariable =
12/31/93:
LOGICAL
Myvariable =
TRUE:
Myvariable =
T:
Myvariable =
YES
Myvariable =
As you can see for LOGICAL values, TRUE, T, YES, and Y all represent the TRUE state.
Similarly, FALSE, F, NO, and N all represent the FALSE state.
5.3
Using Operators
An operator is a language element that represents an action carried out on one or more operands,
resulting in the return of a value. Operator categories include:
510
Numeric
Comparison
Date
Character
Logical
Numeric Operators
Name
Operator
Unary Negative
Description
Reverses the sign of a numeric expression.
Variable1 =
Unary Positive
Credit-Limit.
Division
+ (Credit-Limit - Balance).
Multiplication
Subtraction
* Quantity.
Addition
/ Quantity.
+ Variable1.
511
Comparison Operators
Name
Less Than
Operator
<
or
LT
Description
Returns TRUE if the first expression is
less than the second.
FOR EACH Customer WHERE Balance
LT
Credit-Limit:
Less Than or Equal To
<=
or
LE
LE
Credit-Limit:
Greater Than
>
or
GT
>
credit-limit:
Greater Than or Equal To
>=
or
GE
>=
credit-limit:
Equal To
=
or
EQ
EQ
"Finland":
Not Equal To
<>
or
NE
"France":
512
<>
Date Operators
Name
Date Subtraction
Operator
Description
Date Addition
promise-date.
+ 30.
Character Operator
You use the character concatenation operator to combine two character expressions. Table 56
describes the operator.
Table 56:
Name
Concatenation
Character Operator
Operator
+
Description
Produces a character value by joining, or
concatenating, two character strings or
expressions.
DISPLAY "ATTN: "
+ contact.
513
Logical Operators
Operator
NOT
Description
Returns a TRUE value if an expression is false, and FALSE if an
expression is true.
IF
AND
AND
country = "Japan":
OR
50000:
5.4
Using Functions
A function is a prewritten program that performs a specific task and returns a value. Functions
enable code to be defined once but re-used repeatedly. Some functions require input values.
Progress supports two kinds of functions:
Pre-defined function
User-defined function
The following sections provide more details about each of these kinds of functions.
5.4.1
Pre-defined Functions
The Progress 4GL provides numerous pre-defined functions that provide shortcuts for
accomplishing many common programming tasks. For example, Arithmetic functions (such as
RANDOM or EXP) perform mathematical operations on numeric values and Character
functions (such as LENGTH and SUBSTRING) manipulate character strings or expressions.
514
Here, 9 is the input parameter and the SQRT function returns 3, the square root. You could write
code with Progress to calculate square roots, but using the prebuilt function is far more
convenient.
For more information about pre-defined functions, see the function entries of the Progress
Language Reference.
5.4.2
User-defined Functions
As its name implies, a user-defined function is a function that you can create based on a
programming task that you want to solve. Like the pre-defined function, the value of a
user-defined function is that you can write the code once and reuse it. You define user-defined
functions using the FUNCTION statement. Youll learn more about the FUNCTION statement,
its syntax, and its role in relationship to other parts of the Progress program in Chapter 6.
5.5
515
Progress evaluates functions first. So, Progress executes the ASC functions, which return
the ASCII integer code for a supplied character as shown in the following code:
2.
Progress has predefined levels of operator importance based on the laws of mathematics
and logic. These levels of precedence define which operators Progress executes first.
Table 58, which follows this description, shows the levels of precedence. Operators with
a higher number are executed first. In this example, the division operator has the highest
level of precedence:
Among operators of equal precedence, Progress evaluates them from left to right.
4.
var1 <= 20
5.
516
Finally, the less than or equal to operator remains. Since this is a logical operator, the final
result of the expression will be TRUE or FALSE. In this case the final value is TRUE.
Operator Precedence
Level
7
Operator
Symbol
Unary Negative
Unary Positive
Modulo
MODULO
Division
Multiplication
Date Subtraction
Subtraction
Date Addition
Concatenation
Addition
MATCHES
MATCHES
Less Than
LT or <
LE or <=
Greater Than
GT or >
GE or >=
Equal To
Not Equal To
<>
BEGINS
BEGINS
Not
NOT
And
AND
Or
OR
517
5.6
Using Expressions
To help you learn the rules of writing expressions, the tutorial looks at several of the most
common uses of expressions, including:
Calculating values
Evaluating conditions
5.6.1
Calculating Values
When you calculate a value, you usually need to save the calculation result. In other words, you
need a way to assign a new value to a variable or a field. In Progress, the assignment operator
is the equal sign as shown in the following code:
A = 2 + 2.
When you use the assignment operator in this way, it is a complete Progress statement. Now
suppose you need to make several calculations such as those shown in this code:
A = 2 + 2.
B = A + 10.
C = A + B.
Youve created three Progress statements to perform three calculations. Progress can perform
any number of assignments using the ASSIGN statement. This is a partial syntax for the
ASSIGN statement.
SYNTAX
ASSIGN
expression
] ...
518
5.6.2
Evaluating Conditions
You can think of a conditional expression as an expression that Progress ultimately evaluates to
either TRUE or FALSE. Conditional expressions make up the heart of conditional branching
statements, like the IF statement and the CASE statement. (Youll learn about conditional
statements in the next chapter.) The conditional expression is the test that determines how a
conditional statement branches. Conditional expressions do not make up separate statements,
but are usually part of another statement. Here are some examples using the IF statement:
/*1*/
/*2*/
/*3*/
IF A = 2 + 2 THEN . . .
IF B > A THEN . . .
D = B > A.
2.
This second expression uses the greater than operator: Is B greater than A?
3.
This example is a statement, not a conditional expression. Here, you are assigning the
result of the B > A test to a LOGICAL variable named D.
5.6.3
Conditional expressions used to select particular records from a database table or tables are
called the selection criteria. Progress has many options for specifying selection criteria, but the
most commonly used is the WHERE phrase. Youll learn about selecting records in later
chapters. This chapter shows you how to create the expressions youll use with WHERE. This
is the general syntax for WHERE.
SYNTAX
WHERE
expression
519
So, as Progress cycles through the Customer records, it displays information from only those
records where the customer number is greater than 30.
5.6.4
Widgets have many attributes that you can access and change even when the widget is visible
on screen. By changing attributes, you can change the appearance or function of the widget. For
example, you might want to:
520
Move a widget by manipulating the ROW and COL attributes. You can actually create
simple animation by incrementing these values.
Change the size of a widget by manipulating the WIDTH and HEIGHT attributes.
2 Experiment by choosing from the Up, Down, Left, Right button group. The Reset button
moves. You can move the button around within the frame, but cant move the button
beyond the borders of the frame. The ROW and COL attributes, which the buttons
manipulate, position a widget within a frame.
3 Choose the Reset button to move it back to its starting location.
4 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
521
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
522
Choosing the Reset button moves the widget back to its starting location. The trigger
assigns the constant values that correspond to the original coordinates to the ROW and
COL attributes.
2.
This trigger moves the Reset button up one row by decrementing ROW.
3.
This trigger moves the Reset button down one row by incrementing ROW.
4.
This trigger moves the Reset button right one column by incrementing COL.
5.
This trigger moves the Reset button left one column by decrementing COL.
523
Practice Problems
If you feel like you need some practice writing expressions, complete the exercises below. The filename
listed next to each problem contains a sample solution. You can load the file into the Procedure Editor.
Problem 5-1
lt-05-s1.p
Using a FOR EACH block, increase all customer credit limits by 10%. Display the customer name, old
credit limit, and new credit limit.
Problem 5-2
lt-05-s2.p
Display all customer names and balances where the balance is $5000 or more.
Problem 5-3
lt-05-s3.p
Display all orders that were placed between 1/14/93 and today.
Problem 5-4
lt-05-s4.p
Display all orders that have not been shipped within five days of the promised date.
Problem 5-5
lt-05-s5.p
Based on todays date, display the number of the month, weekday, and year.
Problem 5-6
lt-05-s6.p
Define an array of dates called Holidays. Initialize the array with the dates you get off from work. Label
each element with the holiday name. Display the result.
524
5.7
Summary
An expression is a combination of 4GL language elements that results in a value. At a minimum,
an expression consists of one operand, but can include multiple operands, operators, and
functions.
An operand is a language element that represents a value. Operands include:
Variables A location in memory that holds a value that may change during the
execution of a procedure.
Widget attributes A value that describes a characteristic of a widget like its width,
height, and so on.
Constants A value that does not change during the execution of a procedure.
An operator is a language element that represents an action carried out on one or more operands.
An operation, is the successful combination of operands and operators that results in a value.
A function is a prewritten program that performs a specific task and returns a value. There are
two types of functions in Progress: pre-defined functions that Progress provides and
user-defined functions that you can create.
Arrays are fields or variables that contain multiple data elements. The extent of an array is the
number of elements it contains.
525
526
6
Working with Control Structures
In Chapter 3, Programming the Progress Way, you learned about the parts of a Progress
procedure that define and enable an interface. This chapter discusses the various Progress
components that make up the functional part of an applicationwhats going on behind the
interface. The discussion describes both the structures you can use for containing code and the
structures you can use to manage flow of control within a procedure.
Specifically, the chapter discusses:
Sharing information
6.1
6.1.1
Using Procedures
Minimize your application development time. You dont have to retype a sequence of
statements each time you need those statementsyou call the subprocedure as many times
as you like.
Maintain your application easily. If you want to change code, you can change the one
subprocedure that contains it, instead of correcting the code in many different areas of the
main procedure.
To run a procedure from within another procedure, you use the RUN statement. Heres a partial
syntax of the RUN statement.
SYNTAX
RUN procedure-name
62
main.p
Main Procedure
.
.
.
ON CHOOSE OF btn-1
DO:
RUN sub1.p.
END.
ON CHOOSE OF btn-2
DO:
RUN sub2.p.
END.
.
.
.
Subprocedures
/* Perform Task #1 */
.
.
.
Figure 61:
sub1.p
sub1.p
/* Perform Task #2 */
.
.
.
In the example shown in Figure 61, each procedure file contains one procedure. The RUN
statement references the procedure filename to access the procedure contained within the file.
When you store a subprocedure in a separate procedure file, it is called an external procedure.
Progress also allows you to store subprocedures with the main procedure in one procedure file.
These subprocedures are called internal procedures. You can have many internal procedures in
a procedure file.
63
[ PROCEDURE ].
By convention, you store internal procedures at the bottom of a procedure file, after the main
procedure. Internal procedures do not require a file extension (.p). You access internal
procedures in exactly the same way as external procedureswith the RUN statement.
64
main.p
/* Define Widgets */
/* Define Frames */
/* Define Triggers */
Main Procedure
ON CHOOSE OF btn-1
DO:
RUN sub1.p.
END.
ON CHOOSE OF btn-2
DO:
RUN sub2.p.
END.
/* MAIN LOGIC */
ENABLE btn-1 btn-2 ...
WAIT-FOR ...
PROCEDURE sub1:
Internal Procedure
(Subprocedure)
/* Perform Task #1 */
END PROCEDURE.
PROCEDURE sub2:
Internal Procedure
/* Perform Task #2 */
END PROCEDURE.
Figure 62:
All procedures define resources like variables, widgets, frames, and triggers. By default, the
main procedure cannot use the resources defined in an internal or external subprocedure. Also,
an external procedure cannot use the resources defined in the main procedure. An internal
procedure can use the resources defined in the main procedure. This feature is the major
advantage that internal procedures have over external procedures.
Now that you know the difference between internal and external procedures and how each of
these procedures relates to the main procedure, lets resume the topic of user-defined functions
that was introduced in Chapter 5, Working with Expressions..
65
6.1.2
When you define a function using the FUNCTION statement, the statement is treated like an
internal procedure. The FUNCTION statement can use the resources defined in the main
procedure, helping you to simplify the actual statement that you need to code. However,
user-defined functions differ from internal procedures because the function can return a value,
and the function can be called from within a Progress expression. In addition, user-defined
functions have certain restrictions such as you cannot define work tables, temporary tables or
shared variables in a user-defined function.
Heres a partial syntax of the FUNCTION statement.
SYNTAX
FUNCTION function-name
[ RETURNS ] data-type
[ ( param [ , param ] ...
Component
Description
function-name
data-type
Describes the data type of the value returned from the function.
param
The FUNCTION statement offers you the advantages of defining an internal procedure while
also returning a value, a capability supported by a function. A function applies the logic that
defines the function to the values that are passed to it, and provides a single return value to the
calling procedure (that is, the procedure that contacted it to perform its function).
NOTE:
66
You cannot define temp-tables, work-tables, shared variables, shared frames, shared
browses or streams within a user-defined function.
main.p
DEFINE VAR for_tax AS INTEGER.
User-defined
Function Definition
/* Define Function */
FUNCTION compute RETURNS INTEGER
(INPUT hrs AS INTEGER,
INPUT rate AS INTEGER,
OUTPUT tax AS INTEGER).
tax = 1.
RETURN (hrs * rate).
END FUNCTION.
/* Invoke Function */
First Invocation
DISPLAY
"Info1 hrs = 3,rate = 3".
DISPLAY (compute (3,3,for_tax)).
/* end of function */
/* Invoke Function */
Second Invocation
DISPLAY
"Info2 hrs = 7,rate = 5".
DISPLAY (compute (7,5,for_tax)).
/* end of function */
Figure 63:
This example shows an extract of a main procedure in which the user-defined function compute
is defined and then used, or invoked, in two separate instances. In this example, the function
accepts input and output parameter details for each function call, and substitutes the actual
parameters to perform its defined operation. As you can see from the two invocations of the
function, the values passed to the function are different, but the functions defined operation is
applied in the same way; within the function definition, the value for hours that is supplied from
the calling procedure is multiplied by the value supplied for rate from the same calling
procedure. The single return value derived is returned to the calling procedure. The parameters
67
6.1.3
68
proc1.p
proc2.p
DEFINE . . .
DEFINE . . .
DEFINE . . .
DEFINE . . .
DEFINE FRAME . . .
DEFINE FRAME . . .
Duplicate
Code
DISPLAY . . .
ENABLE . . .
WAIT-FOR . . .
dis-cust.i
Include File
proc1.p
proc2.p
DEFINE . . .
DEFINE . . .
DEFINE . . .
DEFINE . . .
DEFINE FRAME . . .
DEFINE FRAME . . .
{dis-cust.i}
Include
Reference
DISPLAY . . .
ENABLE . . .
WAIT-FOR . . .
Figure 64:
{dis-cust.i}
DISPLAY . . .
ENABLE . . .
WAIT-FOR . . .
69
6.2
Define shared variables to make a variable and its value available to other procedures
When you run internal procedures from a main procedure, the variables defined in the main
procedure are always available to the internal procedure. Therefore, the information-sharing
techniques listed above are not usually necessary for internal procedures.
6.2.1
When you define a variable in one procedure, you can only use it in that procedure or the
internal subprocedures of that procedure. This kind of variable is known as a local variable. If
you want more than one procedure to use a variable, then you need to use a shared variable. To
defined a shared variable, use the DEFINE VARIABLE statement.
SYNTAX
DEFINE
{ AS
[[
NEW
SHARED
VARIABLE variable-name
When you use a shared variable, only one procedure can own the shared variable. That
procedure creates it, and when that procedure ends, so does the availability of the shared
variable. The owner procedure must use the two keywords NEW SHARED in the DEFINE
VARIABLE statement, as in this example:
DEFINE NEW SHARED VARIABLE Field1 AS CHARACTER.
Any other procedure that uses the shared variable must also define it, but without the keyword
NEW:
DEFINE SHARED VARIABLE Field1 AS CHARACTER.
Note that any format phrase option, such as a label or format string, specified in the original
definition (NEW SHARED), does not apply to the variable in subsequent definitions
(SHARED). You can specify different options for the variable in different procedures.
610
proc1.p
DEFINE NEW SHARED
VARIABLE shareinfo
AS CHARACTER.
.
.
.
RUN proc2.p
.
.
.
proc2.p
.
.
.
RUN proc3.p
.
.
.
proc3.p
DEFINE SHARED
VARIABLE shareinfo
AS CHARACTER.
.
.
.
Shared Variable
shareinfo
Figure 65:
6.2.2
Shared Variables
Shared variables are one way that procedures share information, although perhaps not the best
way. It may not be clear to other programmers who read your code what relationship each
procedure has to the shared variable. Another way of sharing values is to pass parameters. A
parameter is a variable in a called procedure whose function is to accept an input value from
the calling procedure, output a value to the calling procedure, or both. For example, you can use
a parameter with an internal procedure to create something like a function that accepts input
values and outputs return values. If you define such a procedure, you can use it many times in
the main procedure.
611
PARAMETER parameter
The statement options are similar to the options you used with the DEFINE VARIABLE
statement. The parameter types are:
INPUT A parameter defined in a called procedure that receives a value from the calling
procedure.
OUTPUT A parameter defined in a called procedure that returns a value to the calling
procedure.
INPUT-OUTPUT A parameter defined in the called procedure that can receive a value
from the calling procedure and return a value back to it.
All procedure and function parameters (that is, pre-defined and user-defined functions) are
passed by value. This means that for any INPUT-OUTPUT or OUTPUT parameter, the field or
variable that receives the output value is not set by the called procedure until and unless the
procedure returns without error.
To call a procedure that contains parameters, place a comma-separated list of parameters
enclosed in parentheses at the end of the RUN statement. You can specify a type for each
parameter in the list. Similarly, to call either type of function, you also define a
comma-separated list of parameters enclosed in parentheses within a statement that invokes the
function.
Parameters Used in the RUN Statement
The following syntax shows where to define parameters used within a RUN statement.
SYNTAX
RUN procedure-file
[([ {
612
INPUT
OUTPUT
INPUT-OUTPUT
expression ] , ... )
If you do not specify the parameter type keywords in the RUN statement, Progress assumes that
the parameters are INPUT parameters. The number and type of parameters in the called
procedure must match the number and type of procedures in the RUN statement:
DEFINE INPUT-OUTPUT PARAMETER Param1 AS CHARACTER.
DEFINE INPUT PARAMETER Param2 AS CHARACTER.
DEFINE OUTPUT PARAMETER Param3 AS CHARACTER.
.
.
.
DISPLAY Param1 Param2 Param3 WITH FRAME Frame1.
The called procedure matches the values passed by the RUN statement by associating the first
value to the first defined parameter and so on.
Parameters Used in the FUNCTION Statement
The following is a partial syntax of the FUNCTION statement. It presents the syntax that you
can use to define parameters for a user-defined function using the FUNCTION statement.
SYNTAX
FUNCTION function-name
[ RETURNS ] data-type
{ { [ INPUT ] | OUTPUT |
INPUT-OUTPUT
param-name AS data-type
}
The FUNCTION statement matches parameters by associating the first value to the first defined
parameter, the second value to the second defined parameter, and so on. The number and type
of parameters in the calling procedure must match the number and type of procedures in the
FUNCTION statement.
613
lt-06-01.p
lt-06-02.p
lt-06-03.p
614
The code in procedure lt-06-03.p creates this display, but the value Paris originates in
the main procedure lt-06-01.p, passes through lt-06-02.p, and arrives safely for use in
the display.
615
/*2*/
RUN lt-06-02.p
lt-06-02.p
/*3*/
/*4*/
/*5*/
lt-06-03.p
/*6*/
/*7*/
NOTE:
These notes explain the code and trace the value through the three procedures:
616
1.
The main procedure creates a new shared variable and gives it an initial value.
2.
The main procedure calls the second procedure. Note that the RUN statement uses no
parameters.
3.
For this procedure to access the shared variable, it too must define it.
This local variable passes on the value as a parameter. It is not necessary, because a shared
variable can also be a parameter. The point here is to show how to pass the value of a local
variable.
5.
This RUN statement calls the next procedure and specifies the local variable London as a
parameter. Note the parentheses.
6.
The final procedure defines one parameter. During run time, Progress checks to make sure
that both the calling and called procedures specify the same number of parameters.
7.
Because of the defined parameter, you can use Paris as a valid reference anywhere you can
use a variable name.
NOTE:
6.2.3
For more information about the keywords associated with this procedure and any
other procedures that you work on in Progress, simply highlight the keyword and
press the HELP key function (F1).
While parameters allow you to pass values to accomplish a run-time task, arguments allow you
to pass literals to allow code to compile. For example, you can use arguments to change a
procedure that works with only one database table to one that works with any database table.
The following code creates a report of all customer names in the Customer table:
FOR EACH Customer:
DISPLAY Name.
END.
You can modularize this code to work for any table and field name pair by replacing the literals.
Literals are programming symbols, such as table names, field names, or variable names. An
argument passes a literal, not a value. To create a procedure that accepts arguments, replace the
literals with argument references, as shown:
FOR EACH {1}:
DISPLAY {2}.
END.
Progress cannot compile this code because {1} is not a table name and {2} is not a field name.
However, if you place any valid table name at {1} and any valid field name at {2}, the procedure
could compile. Once the procedure compiles, the table and field name become valid references
to actual data, and the procedure runs.
617
Customer is argument 1 and Name is argument 2. To reference the arguments in the called
procedure, enclose the argument number in braces { } as shown in the following code:
FOR EACH {1}:
DISPLAY {2}.
END.
Now the external procedure can compile by substituting the argument references for the
arguments. Remember, you are literally passing the argument specified in the RUN statement,
not the value of the argument. In this case, arguments turn out to be very useful because now
you have a procedure that can create a report for any valid table and field pair.
You can also use variables in the RUN statement, if the values of the variables are valid literals
for the called procedure, as shown in the following code:
DEFINE VARIABLE Table-Name AS CHARACTER.
DEFINE VARIABLE Field-Name AS CHARACTER.
ASSIGN Table-Name = "Customer"
Field-Name = "Name".
RUN proc2.p Table-Name Field-Name.
The drawback to using arguments is that you cannot compile the external procedures that
contain them until run time, which may slow your application down. In many cases, you can
achieve the same kind of modularity by using parameters or shared variables. In other words,
use arguments as a last resort.
Using Arguments with Include Files
Although arguments may not be the best way to modularize external procedures, they work well
with include files. When Progress encounters an include file in a procedure, it retrieves the
contents of the include file, substitutes the arguments, and compiles the statements as part of the
main procedure. Therefore, Progress resolves all include file references to arguments at compile
time.
618
You reference the arguments in the include file the same way you reference arguments in called
procedures, as shown in this example:
DISPLAY {1} {2} WITH FRAME Frame1.
619
Practice Problems
This problem gives you some practice modularizing code and using parameters.
Problem 6-1:
First, duplicate the interface shown below with a DEFINE FRAME statement. Cost and Cancellation
should be text widgets. All the widgets should be enabled on startup except for Refund Sent.
620
6.3
About Blocks
The Progress 4GL is a block-structured language. A block is a series of 4GL statements grouped
together and treated as a single unit. Blocks are important because Progress bases many default
behaviors on blocks. For example, earlier you learned about the default frame. If you dont
define a frame, Progress creates one for you (the default frame) when you display widgets.
Actually, each block in your procedure can have a default frame; default frame behavior is
based on blocks.
There are several types of blocks that you can use within your application. They include:
Procedures
Internal procedures
Triggers
Control blocks:
DO
REPEAT
FOR EACH
Here are some general statements about blocks, although youll learn about some exceptions in
the sections that follow:
Most block types come with implicitly defined services called block properties. Default
frame allocation, for example, is a service, or block property, of many blocks. In the
tutorial, youll work with these block properties: looping, record reading, and frame
allocation.
Many blocks have syntax options that allow you to define services explicitly, either to
override implicit services or to add new services.
621
You can name blocks by adding a label and a colon before the block header as shown in
the following code:
Block Label
Block Header
Cust-Loop:
FOR EACH Customer:
DISPLAY Name.
END.
6.3.1
Procedure Block
Every procedure includes a procedure block, whether the procedure is a main procedure or an
external or internal subprocedure. The procedure block encompasses the entire procedure file
(a .p file). You can include any Progress 4GL statement inside the procedure block, and you can
also nest other blocks inside the main procedure block. However, the main procedure block
cannot be enclosed in another block. The procedure block does not have a block header
statementProgress automatically starts a new procedure block when you run a new procedure
file. The procedure block does not require or allow an END statement to terminate itthe end
of the procedure file marks the end of the procedure block.
Quite literally, the procedure block encompasses all the code in a procedure file. However, only
the statements that are not part of another block belong to the procedure block. The procedure
block is also characterized by these features:
Although you can place internal procedures anywhere in a procedure file, by convention,
you usually place them at the very end of the procedure file.
A typical event-driven procedure contains definitions, triggers, and main logic. The task of
blocking the interface with the WAIT-FOR statement usually falls to the procedure block,
because it is the outermost block. Blocks within the procedure block normally work with the
interface created and blocked for input in the procedure block.
The procedure block has implicit frame allocation, that is, any screen I/O statements in the
procedure block that do not explicitly use a defined frame perform their functions in a default
frame owned by the procedure block.
622
6.3.2
Trigger Blocks
The trigger header statement is the ON statement. You enclose the trigger block statements
between DO and END as shown in the following code:
Block Header
ON CHOOSE OF btn-Exit
DO:
RUN proc1.p.
END.
[ TO
widget-phrase ]
Note that the event name in an APPLY statement is enclosed in quotation marks, which is not
the case for the ON statement.
In general, you should avoid using APPLY because too many APPLY statements make your
code hard to follow and also because APPLY is not a very efficient way to execute triggers. If
you have code in a trigger and want to execute the same code from another location, move the
trigger code into an internal or external procedure. Then, you can access the code with a RUN
statement from inside a trigger or anywhere else.
623
6.4
DO
REPEAT
FOR EACH
6.4.1
You use the DO block to group statements together and treat them as a single unit. DO has no
implicit block properties. However, you can add explicit looping and frame allocation
properties to the DO block by using the syntax shown below.
SYNTAX
label:
DO
[ WHILE expression ]
{ [ frame-phrase ] } :
END
624
To provide explicit services to another block. For example, triggers have implicit frame
allocation, but do not have the frame phrase option on the header statement. So, if the
statements in your trigger operate with a frame other than one Progress expects, you can
nest a DO block within the trigger block. As shown in the following code, this technique
eliminates having to specify the frame on every screen-output statement in the trigger:
ON CHOOSE OF btn-New
DO:
DO WITH FRAME Frame2:
ASSIGN Cost = Price + Tax.
DISPLAY Price Tax Cost.
END.
END.
To provide looping with an incrementing variable using the TO syntax as shown in this
code:
DO i = 1 TO 31:
ASSIGN Total = Total + January[i].
END.
To provide conditional looping with the WHILE syntax. WHILE allows you to specify an
expression. On each iteration, the block evaluates the WHILE expression and then
executes the block, if the expression evaluates to TRUE. Review the WHILE expression
in this code:
ASSIGN i = 1.
DO WHILE(i < 32):
ASSIGN Total = Total + January[i]
i = i +1.
END.
Its important to note that the DO and END syntax of a trigger block does not make it a DO
block. As described in this section, DO is a control structure that has no block properties unless
you specify them with optional syntax. The trigger block DO has no explicit syntax options.
625
6.4.2
The REPEAT block provides implicit looping and frame allocation, as well as syntax options
for explicit looping and frame allocation. This is the syntax for the REPEAT block.
SYNTAX
]
REPEAT [ variable = expression1
[ WHILE expression ]
{ [ frame-phrase ] } :
label:
TO expression2
END
Like the DO block, the REPEAT block can define the iterations of the block by incrementing a
variable to a desired value or by specifying a WHILE expression. If the block contains neither
of these options, then the REPEAT block loops continuously. In other words, there is no implicit
terminating condition.
Progress provides the user with an implicit method of ending the iterations of a REPEAT block:
the END-ERROR key. This feature makes REPEAT useful for coding repetitive tasks, especially
where you cannot predict how many iterations of the task the user will want to complete. The
terminating condition is in the hands of the user. By default, Progress displays a message
instructing the user to press END-ERROR to end the block.
You can also programmatically control the end of a REPEAT block using the LEAVE
statement. The LEAVE statement is useful when you want to evaluate a condition within a
REPEAT block and exit the block based on the outcome. After Progress encounters the LEAVE
statement, it continues execution with the first statement after the end of the block.
626
As soon as the interface displays, the letters of the alphabet quickly fill the Alphabet field.
Of course, if you have a very fast computer, you may only see the end result of the
loopthe entire alphabet.
627
DEFINE FRAME
Frame1
**********/
SKIP(1)
SIDE-LABELS NO-BOX CENTERED THREE-D.
The ASC function returns the integer code for a single character. (The integer value is
interpreted from the current character set)
2.
The CHR function returns the character equivalent of an integer code. Applying a
character to a fill-in field is equivalent to a user typing that character.
3.
When the loop reaches z, the LEAVE statement terminates the loop.
628
Can use explicit looping with either the TO or WHILE syntax. Using either of these
options creates a loop with an explicit terminating condition.
Can use a frame other than the default by specifying one with the frame phrase.
6.4.3
The FOR EACH block has implicit looping, frame allocation, and record reading block
properties. FOR EACH is an essential structure for moving through the records of a database
table. Each iteration of the block reads a new record from the table. When no records are left,
the block ends. While the FOR EACH header reads a record, the statements inside the FOR
EACH block typically work with the data of that record. Therefore, the main use of this
structure is to move through and process the data of a database table. Chapter 8, Using
Database Records, and Chapter 9, Selecting, Sorting, and Relating Records, extensively
describe the use of FOR EACH as a record-reading tool. This section introduces the properties
of the FOR EACH block.
This is the basic syntax of FOR EACH.
SYNTAX
END
This simple example of FOR EACH shows the implicit block properties:
/*1*/
/*3*/
/*2*/
The record phrase defines the implicit looping of a FOR EACH block. The actual number
of iterations of the FOR EACH statement is the sum of all records of all tables referenced
in the record phrase. However, the FOR EACH statement does not necessarily execute the
statements inside the block for each record of the database table. FOR EACH executes
these statements when the current record matches the criteria specified in the record
phrase. In this example, the statements execute for every record, since no selection criteria
exist.
2.
The record phrase is a Progress language structure that lets you specify options for
selecting, sorting, and relating records. In the last chapter, you learned how to create
record-selection expressions using the WHERE syntax. Youve also seen that specifying
a table name, as in this example, selects all the records of the table. Both of these
techniques are uses of the record phrase.
629
This statement performs screen output, so Progress creates a default frame for the FOR
EACH block to use.
The WHERE expression in the record phrase restricts the number of records that execute
the statement of the block body. Although Progress reads every record and compares it to
the WHERE expression, Progress executes the block statements for only those records
where the Balance field is less than 1000. On the other hand, the default implicit record
reading property executes the block for every record.
2.
The frame phrase here names a frame for use with the screen-output statements of the
block. Frame3 could be either a previously defined frame or a new frame created for the
block.
Although the TO and WHILE syntaxes for explicit looping are valid with FOR EACH,
they are not commonly used.
630
6.5
Block Properties
FOR
EACH
Property
REPEAT
Looping
Implicit
Implicit
Explicit:
WHILE
TO
Explicit:
WHILE
TO
Explicit:
WHILE
TO
None
Implicit
None
Record
reading
DO
Procedure
Internal
Procedure
Trigger
None
None
None
None
None
None
Implicit
Implicit
Implicit
Explicit:
Record
Phrase
Frame
allocation
Implicit
Implicit
Explicit:
Explicit:
WITH
FRAME
WITH
FRAME
Explicit:
WITH
FRAME
631
Practice Problems
These problems give you some practice with blocks.
Problem 6-2:
Using a FOR EACH block and a DO block, loop through all the customer records and count the number
of customers whose credit limit is greater than $15,000. Display the customer number, name, and credit
limit.
Problem 6-3:
lt-06-s3.p
Using the REPEAT block, increment a counter by 1 up to 10 times and display the counter. Once the
counter has a value of 10 leave the REPEAT block.
6.6
Conditional Processing
Conditional processing structures are those that allow the flow control within a procedure to
branch based on a condition. There are two statements that allow you to test conditions and
define what code to execute under what circumstances: the IF statement and the CASE
statement.
6.6.1
The IF statement allows you to test for a condition and then execute code if the expression is
TRUE. The ELSE option allows you to specify a second block of code to execute if the
expression is FALSE. This is the syntax.
SYNTAX
IF expression THEN
{
[
632
block
ELSE
| statement }
{ block | statement } ]
The block at point 1 executes when the expression is TRUE, while the block at point 2 executes
when the expression is FALSE.
6.6.2
Another means of conditional control is the CASE statement. Use the CASE statement when
you want to test the result of an expression against several values. You could use nested IF
statements, but the CASE statement is much clearer.
This is the syntax for CASE.
SYNTAX
CASE expression :
WHEN value
THEN
block
} ...
[ OTHERWISE {
END [ CASE ]
OR WHEN value
statement
block
] ...
statement
}]
633
1 Open lt-06-05.p and run it. The display shown below appears:
Exercise
The selection list allows you to choose a chapter. A short description of the chapter then
appears in the editor widget.
634
635
2.
This DEFINE VARIABLE statement sets up the selection list using the VIEW-AS phrase.
3.
This syntax makes the screen value of the selection list the conditional expression of the
CASE statement.
4.
For each value of the selection list, the branches of the CASE statement assign an
appropriate value to the editor widget.
Practice Problems
These problems give you some practice with conditional processing.
Problem 6-4:
lt-06-s4.p
Using the IF statement, identify the number of customers that have BBB for their sales rep, the number
of customers that have the sales rep SLS, and the number of customers that have any other sales rep. Use
the Customer.Sales-Rep field.
Problem 6-5:
lt-06-s5.p
Do the same thing as in Problem 6-4, except use the CASE statement.
636
6.7
Summary
This chapter discussed those features of the Progress 4GL that allow you to control the flow of
execution within your application. Heres a summary of what youve learned.
Procedures and Include Files
In the Progress programming model the main procedure can access modules stored in separate
subprocedures. A subprocedure can be either an internal or external procedure:
The main procedure accesses an internal procedure with the RUN statement.
An internal procedure is a procedure file that is stored with the main procedure in one
procedure file.
A user-defined function is like an internal procedure that has some additional capabilities.
It can return a value and the function can be called from within a Progress expression. You
use the FUNCTION statement to create a user-defined function.
An include file is a text file that contains Progress source code. When you reference
include files in your procedures, Progress replaces the reference with the contents of the
include file at compile time.
Using shared variables Shared variables are specially defined variables that more than
one procedure can use.
Using arguments to pass literals Literals are programming symbols, such as table
names, field names, or variable names. You can replace the literals with argument
references in your procedure to make your code more generic. Arguments let you pass
literals that allows code to compile.
637
Procedure blocks Encompass the entire procedure file (a .p file), but only those
statements that dont belong to another block actually belong to the procedure block.
Internal procedure blocks Begin with the PROCEDURE header statement and are
accessed with the RUN statement.
Trigger blocks Allow the user to control an application by directing processing with
events.
Control blocks Have specific implicit properties that affect: loping, frame allocation,
and record reading.
DO Groups statements together for execution as a single unit. It has no implicit block
properties.
REPEAT Provides implicit looping and frame allocation. It has no explicit terminating
condition, but Progress allows a user to end a REPEAT block with the END-ERROR key,
or you can end it programmatically with the LEAVE statement.
FOR EACH Provides implicit looping, frame allocation, and record reading. Each
iteration of the block reads a new record from a database table.
638
The IF statement lets you test for a condition and then execute code if the expression is
TRUE. The ELSE option lets you specify a second block of code to execute if the
expression is FALSE.
The CASE statement lets you test the result of an expression against several values.
7
Representing Data with Widgets
Using the right data widget with a particular variable or database field makes all the difference
in the world to your end users. The nature of many widgets suggests the kind of data they
contain and the ways that users can interact with them. For example, when users see a slider
widget, they know that they are working with numeric data. On the other hand, some widgets,
like the fill-in field, can work with several data types, so a user relies on other cues in your
interface to determine the expected input.
First, this chapter introduces you to some common widget issues. Then the chapter discusses the
syntax, events, attributes, and programming techniques used with:
Fill-in fields
Text widgets
Toggle boxes
Radio sets
Sliders
Selection lists
Combo boxes
Editors
7.1
Programming Widgets
Before you work with each individual widget, its important to understand the programming
concepts and structures that support your ability to define and modify the characteristics of a
widget. Table 71 organizes these concepts and structures around the life span of a widget.
Table 71:
Stage
Widget definition
Description
For variables, the DEFINE VARIABLE statement supports the
VIEW-AS phrase. This phrase enables you to specify a widget
type and define its major characteristics.
For fields, the Data Dictionary supports properties that match all
the options of the DEFINE VARIABLE statement.
Container definition
When you define your frames and dialog boxes, you specify the
widgets found in the containers. After each widget reference,
there are several 4GL options you can specify to further define
the characteristics of the widget. Collectively, these options are
referred to as the format phrase.
The DEFINE FRAME statement supports the frame phrase,
which you use to define the characteristics of the frame widget.
Some frame phrase options modify the characteristics of the
widgets contained in the frame.
Before display
After display
72
7.1.1
The VIEW-AS is a programming structure for associating a data widget with a variable or
database field. The syntax below shows the VIEW-AS phrase at the simplest level.
SYNTAX
VIEW-AS widget-phrase
The widget phrase consist of a keyword that identifies the widget type and the options that go
with that particular type. This chapter covers each widget phrase in detail.
You can specify a VIEW-AS phrase at several points as noted in the following list:
1.
Data Dictionary
2.
3.
4.
Format phrase on a screen I/O statement (DISPLAY, ENABLE, UPDATE, SET, and
PROMPT-FOR)
73
7.1.2
Throughout the tutorial, youve seen the appearance of widgets affected by programming
options included in a DEFINE FRAME statement or on a screen I/O statement. These options
are part of a Progress language structure called the format phrase. Not to be confused with the
FORMAT option, the format phrase is a collection of options that you can specify after a field,
variable, or expression reference in a DEFINE FRAME statement or screen I/O statement.
This simplified syntax for the DEFINE FRAME statement shows how the format phrase fits
into the definition of a frame.
SYNTAX
DEFINE FRAME frame-name
frame-item
format-phrase
format-phrase
] ] ...
A frame item can be a constant, a database field, or a variable. After each, you can specify one
or more options from the format phrase to affect, for example, the label, format, or position of
the frame item. The partial syntax below shows the most frequently used options of the format
phrase.
SYNTAX
[
[
[
[
[
[
[
74
at-phrase
COLON n
LABEL string
HELP string
TO n
NO-LABELS]
COLUMN-LABEL string
FORMAT string
|
]
view-as-phrase
Option
Use
Example
at-phrase
COLON n
field1 COLON 40
TO n
field1 TO 40
LABEL string
NO-LABELS
field1 NO-LABELS
COLUMN-LABEL
FORMAT string
HELP string
view-as-phrase
VALIDATE
(condition,
string
msg-expression)
75
2.
Also, you can specify format phrase options for an expression in a screen I/O statement, but not
in a DEFINE FRAME statement. Note the following code example:
DISPLAY (A + B) LABEL "Sum of A and B" WITH FRAME Frame1.
Note that the LABEL, COLUMN-LABEL, FORMAT, and VIEW-AS phrase options are also
available on the DEFINE VARIABLE statement.
76
7.1.3
Positioning Widgets
From Table 72, you saw that you have three options for positioning a widget in a frame: AT,
COLON, and TO. You can think of these options as left, center, and right alignment options for
widgets. Figure 71 contrasts the three positioning options.
Positioned with:
AT ROW x COLUMN
Column 40
Positioned with:
COLON 40
Positioned with:
TO 40
Figure 71:
As you might surmise from Figure 71, the COLON option is very useful for aligning columns
of fields.
77
7.1.4
The frame phrase is the major structure for defining the characteristics of a frame. However,
some of the frame phrase options affect the contents of the frame. In this respect, the frame
phrase is also a structure for defining the characteristics of widgets. In some cases, it may be
more convenient to use a frame phrase option rather than specifying a similar option for each
individual widget. The partial syntax below shows the most frequently used options of the frame
phrase that affect widget characteristics.
SYNTAX
WITH
[
[
[
[
SIDE-LABELS
]
n COLUMNS ]
USE-TEXT ]
NO-LABELS
Use
SIDE-LABELS
COLUMNS
NO-LABELS
USE-TEXT
78
2.
3.
A frame phrase that occurs later in the execution of a procedure overrides one that occurs earlier.
7.1.5
The characteristics of the fill-in field widget in this example are either default
characteristics or characteristics defined with the DEFINE VARIABLE statement.
79
2 Choose the second button. The new display shows the same variable with a new set of
characteristics established by the format phrase and frame phrase in a DEFINE FRAME
statement.
3 Choose the third button. This display shows the variable with another set of characteristics.
A format phrase and frame phrase on a screen I/O statement (ENABLE) defined these
characteristics.
Now, pause your mouse pointer over the Exit button. Notice a small piece of text that
displays. It is called a ToolTip. A ToolTip is a brief text piece that you can optionally
define for any of the widgets that will be presented in this chapter. Youll hear more about
ToolTips throughout the chapter and see a few more examples of how to use them.
710
/*2*/
/*3*/
/*4*/
/*5*/
711
The DEFINE VARIABLE statement establishes the default characteristics and the
optional characteristics of the widget associated with the variable.
2.
3.
This DEFINE FRAME statement alters the characteristics of the widget with both the
format and frame phrases.
4.
This run-time screen I/O statement defines a new frame and alters the characteristics of the
widget with both the format and frame phrases.
5.
Because Progress creates one of the frames used in this procedure at run time, the trigger
definitions that reference that frame must follow the run-time frame definition.
NOTE:
7.1.6
The TOOLTIP attribute noted in the code example is ignored when this code is run
on a character client.
Referencing Widgets
A field or variable name is both a valid reference to the value associated with the field or
variable and to the widget associated with the field or variable. For example, in the first
statement below, referencing Field1 and Variable1 in an expression manipulates their values. In
the second and third statements, referencing the names in a screen I/O statement manipulates
the widgets associated with them. Review these statements in the following code:
New-Total = Field1 + Variable1.
ENABLE Field1 Variable1 WITH FRAME Frame1.
HIDE Field1 IN FRAME Frame1 Variable1 IN FRAME Frame1
This example also demonstrates the difference between using the frame phrase or IN FRAME
to make an unambiguous reference to a widget. A single screen I/O statement can only work
with the widgets in one frame. Thus the reference to the frame in the frame phrase creates an
unambiguous reference to all widgets in the frame. On the other hand, you can append the
IN FRAME syntax to any widget reference in any other statement to make a single widget
reference unambiguous.
712
You append the IN FRAME syntax to the widget attribute reference to make the reference
unambiguous, as follows:
SYNTAX
widget-name:attribute-name IN FRAME frame-name
For example, the assignment statement below assigns an attribute value to a variable:
Myvar = Mywidget:ROW IN FRAME Myframe
Like a function, a method always returns a value. For methods, that value is usually LOGICAL
and indicates whether or not Progress successfully applied the method to the widget. Methods
also may use input and output parameters like a function.
Later in the chapter youll see programming examples that use methods.
Using Widget Handles
Using the field or variable name as a reference to both value and widget is convenient and makes
readable code. At times, you may need to specifically reference the widget and not its associated
field or variable. In these cases, you need to provide the widget handle. A widget handle is a
unique internal identifier for a widget. Every widget has an attribute named HANDLE that
contains the widget handle for that widget.
713
You may also want to save the handle of a widget in a variable. Since Progress supports widget
handles as a separate data type, you need to specify the WIDGET-HANDLE data type in your
DEFINE VARIABLE statements as this shows:
DEFINE VARIABLE Myhandle AS WIDGET-HANDLE.
Progress maintains several global variables that contain widget handles. These variables are part
of a group of language elements known as system handles. System handles allow you to access
information about the system. Table 74 describes the system handles that you can use to access
information about widgets.
Table 74:
714
System Handle
Description
DEFAULT-WINDOW
CURRENT-WINDOW
FOCUS
Contains the handle of the widget that currently has input focus.
SELF
2 Press TAB or use the mouse to move input focus or choose a button. Notice that the
variables at the top of the screen keep track of your actions.
3 Choose Exit and press SPACEBAR to return to the Procedure Editor.
715
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
716
1.
The first frame contains the text widgets that track the users actions.
2.
This trigger executes when any of the four buttons receive the ENTRY event. Notice the
IN FRAME syntax for specifying the location of the widgets.
4.
The ENTRY event occurs before Progress actually moves input focus. This APPLY
statement forces Progress to fully move focus to the new widget. Notice the SELF system
handle. No matter which button executes the trigger, Progress evaluates this statement
using the correct button.
5.
You can access an attribute of FOCUS or SELF exactly as you would with an explicit
widget reference.
6.
On this screen I/O statement, the frame phrase option specifies the correct frame.
7.
8.
Again, you access the system handle attribute exactly as you would a named widget.
7.1.7
There is one very important case when you want to make a distinction between the field a widget
represents and the widget itself. When you display a value and enable a widget for input, the
value in the field and in the widget are the same. From that point forward, however, the user can
change the value in the widget, which is also known as the screen value.
When users manipulate screen values, they are not manipulating the underlying field or variable
values. Your code has to explicitly assign changes in the widget to the field or variable. There
are two ways to do this.
1.
This form of the ASSIGN statement can be interpreted as write the screen values of these
widgets to their associated fields or variables.
2.
717
Validating Input
You saw earlier that the format phrase has a VALIDATE option. You can use this option to
establish validation criteria for variables or to change default validation for database fields.
Although you can use this option instead of the corresponding Data Dictionary properties, it is
far more valuable to use the Data Dictionary as a central source for validation information.
To use the VALIDATE option, specify a condition and a message expression, as shown in this
example:
DEFINE FRAME Frame1
Var1 VALIDATE(Var1 > 0, "Entry must be greater than zero.")
WITH SIDE-LABELS
718
2 Type a new value for CharField that does not begin with the letter A.
3 Try to move input focus with TAB or the mouse. An alert box appears telling you that the
entry must begin with the letter A.
4 Choose OK. You return to the main display with input focus on CharField. You cannot
move from this field until you make a valid entry.
5 Type a new value for CharField that does begin with A and move input focus. This time
you can.
6 Try the same experiment with IntField using a number less than 100.
7 Now that you have changed the screen values, choose Reset. The original values appear.
719
8 Type new valid entries in the fields and choose Save and then Reset. As you can see, your
new values are now also the values stored in the variables.
9 Choose Exit and press SPACEBAR to return to the Procedure Editor.
720
The VALIDATE option of the format phrase establishes a condition that will allow only
input that begins with the letter A.
2.
Here the VALIDATE option establishes a condition that disallows input less than 100.
721
7.2
3.
This trigger moves the screen values into the associated variables.
4.
The IF statement checks the MODIFIED attribute of the widget to see if any changes were
made, and thus whether it is necessary to write a new value.
5.
This trigger copies the values of the variables to the screen with the DISPLAY statement.
Current Value
Label
Figure 72:
The fill-in field is the all-purpose data representation. Think of the fill-in field as the data widget
you use unless another data widget is better. Since the fill-in field is the default data widget, you
dont need to write a VIEW-AS phrase when you want a fill-in field, unless you want to be
explicit. This is the syntax for specifying a fill-in field.
SYNTAX
VIEW-AS FILL-IN
size-phrase
][
TOOLTIP tooltip
The size phrase is a standard Progress way of describing how much room a widget should
occupy. Normally, the size phrase uses this syntax.
SYNTAX
SIZE-CHARS width BY height
722
When Progress defines this variable, it uses the default format string of x(8) for
CHARACTER variables, the default data widget (fill-in field), and creates a default size
for the widget based on the format string. (The default size is the width of eight
average-width characters.)
2.
In this example, x(8) is not adequate, so the FORMAT option overrides the default and
makes it x(20). Progress still determines the default size (20 average-width characters)
based on the new FORMAT option.
3.
This statement uses a format string of x(40). However, 40 characters take up too much
room on the display, so the size phrase shortens the display area to 20 characters. Now the
widget displays 20 characters, but can accept up to 40. When a user types beyond the 20th
character, the data in the field scrolls to allow the extra input.
7.2.1
When an enabled fill-in field appears on screen, it can accept a whole range of events. The
fill-ins default response to most events will be exactly what you intend, requiring no
programming on your part. The fill-in field:
Accepts input focus by way of the navigation key functions (like TAB) or the mouse
723
Allows the user to move the text cursor within the field with the cursor keys or the mouse
Allows the user to edit the field with the standard field editing keys of the native
environment
2 Press TAB. Notice the message that appears in the message area. A trigger attached to
ENTRY displays this message.
724
3 Press TAB again. Another message appears: Hey, wheres the tip! A trigger attached to
LEAVE displays this message.
4 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
Here is the code that created this interface:
lt-07-04.p
/********** DEFINE WIDGETS **********/
DEFINE VARIABLE Field1 AS CHARACTER INITIAL "Home"
FORMAT "x(10)" LABEL "Start".
DEFINE VARIABLE Field2 AS CHARACTER INITIAL "Joes Deli"
FORMAT "x(10)" LABEL "Destination".
DEFINE BUTTON btn-Exit LABEL "Exit".
/********** DEFINE FRAMES **********/
DEFINE FRAME Frame1
SKIP(2) Field1 SPACE (10) Field2 SKIP(2)
btn-Exit
WITH NO-BOX CENTERED SIDE-LABELS THREE-D.
/********** DEFINE TRIGGERS **********/
ON ENTRY OF Field2
DO:
MESSAGE "Can I take your order, please?".
END.
/*2*/ ON LEAVE OF Field2
DO:
MESSAGE "Hey, wheres the tip!".
END.
/*1*/
As you can see at points 1 and 2, simple triggers on ENTRY and LEAVE are all that you need
to extend the functionality of the widget.
NOTE:
LEAVE does not execute when you switch focus between windows or on high-level
event functions, such as GO or menu mnemonics.
725
7.3
Label
Figure 73:
Current Value
Text widgets take up less screen space on many platforms and print more compactly,
making them valuable for printed reports.
You can easily switch between fill-in fields and text widgets. The new widget inherits
many of the attributes of the old widget, such as format and label options.
You can use text widgets to display static text in your interface display without creating a
variable to hold the data.
TOOLTIP tooltip
726
The USE-TEXT option on the screen I/O statement converts the fill-in fields in the frame to text
widgets. The USE-TEXT option does not affect any other type of widget.
Static Text without Variables
To include text as part of a frame without first storing the text in a variable, simply place the
text between quotes in a DEFINE FRAME or screen I/O statement. Progress creates a text
widget to contain the string. You can then apply the options of the format phrase to the constant
as this code example shows:
DEFINE FRAME Frame1
Field1 SKIP
"Constant Text String" TO 50
Button1 Button2
WITH SIDE-LABELS THREE-D.
.
.
.
DISPLAY Field1 "More Text" AT ROW 9 COLUMN 30 WITH FRAME Frame1.
Practice Problems
Youve covered quite a bit of new material so far in this chapter. Its time to cement your new knowledge
in place by putting it to use.
Problem 7-1:
lt-07-s1.p
Create a procedure that accepts input for the List Price, Discount, and Tax Rate with fill-in fields. Using
a LEAVE trigger on the Tax Rate field, calculate the adjusted Price, Tax, and Total with text widgets.
727
7.4
TRUE Marker
Label
Toggle Box
Figure 74:
Instead of relying on textual value pairs like TRUE/FALSE or YES/NO, the toggle box
graphically represents the value of a single logical field. A filled or checked box indicates a
positive choice and is said to be activated. An empty box indicates a negative choice and is said
to be deactivated.
This is the syntax for defining a toggle box.
SYNTAX
VIEW-AS TOGGLE-BOX
TOOLTIP tooltip
As mentioned earlier in this chapter, the TOOLTIP attribute allows you to optionally define a
text message string that automatically displays when the mouse pointer pauses over the toggle
box.
728
7.4.1
Toggle-box Events
Accepts input focus by way of the navigation key functions (such as TAB) or the mouse
7.4.2
Checked Attribute
The toggle box has an additional attribute thats useful: CHECKED. The CHECKED attribute
holds a logical value. The value is TRUE when the on-screen state of the widget is solid or
checked. Its FALSE when the on-screen state is empty. Although you can use either, using
CHECKED instead of SCREEN-VALUE with toggle boxes creates more readable code. The
following examples are equivalent, assuming that the solid state of the widget corresponds to
YES:
IF Mywidget:SCREEN-VALUE = "YES" THEN . . .
IF Mywidget:CHECKED = YES THEN . . .
729
7.4.3
2 Only the toggle box and Exit button are sensitive. Activate the toggle box. A
VALUE-CHANGED trigger calculates the tax and new total.
Note that if you pause your mouse pointer over the toggle box a ToolTip is displayed.
3 Deactivate the toggle box. The VALUE-CHANGED trigger executes again and calculates
the total without the tax.
4 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
730
/*3*/
731
2.
USE-TEXT converts the fill-in fields to text widgets without affecting other widgets.
3.
Whenever you change the screen value of the widget, VALUE-CHANGED executes,
forcing the appropriate calculation and update.
NOTE:
7.5
The TOOLTIP attribute noted in the code example is ignored when this code is run
on a character client.
Label
Figure 75:
You can use the radio-set widget with a CHARACTER, INTEGER, DECIMAL, LOGICAL, or
DATE field or variable. This is the syntax for defining a radio set with the VIEW-AS statement.
SYNTAX
VIEW-AS RADIO-SET
[
[
HORIZONTAL
size-phrase
| VERTICAL ]
]
732
TOOLTIP tooltip
label, value
] ...
Component
Description
HORIZONTAL
VERTICAL
size-phrase
You probably wont use the size phrase for radio sets-Progress radio
sets use the native look and spacing of your platform.
label, value
For each radio button, specify the screen label and the corresponding
value. Enclose strings in quotes.
TOOLTIP tooltip
NOTE:
7.5.1
Keep in mind that you can access on-line help information about a Progress keyword
by highlighting the keyword and pressing the HELP key function (F1).
Accepts input focus by way of the navigation key functions (such as TAB) or the mouse
Moves input focus among the radio buttons with the cursor keys
733
7.5.2
4 Press RETURN or SPACEBAR or click to choose a radio button. Note that the Product Code
field updates after each selection.
5 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
734
/*3*/
735
For each label-value pair, Progress creates a radio button. In this case, the screen labels
describe a product and the values represent an internal code. A radio set has vertical
orientation by default. The keyword HORIZONTAL in the VIEW-AS phrase changes the
orientation.
2.
The INITIAL option sets the value of the P-code variable to "11".
3.
Whenever you select a different radio button, the VALUE-CHANGED event executes and
Progress concatenates and reassigns the values of the radio-set variables to P-code.
NOTE:
736
The ToolTip attribute noted in the code is ignored when this code is run on a
character client.
Practice Problems
Youve now added two more widgets to your repertoire. Use the problem below to practice what youve
learned about the widgets.
Problem 7-2:
lt-07-s2.p
Duplicate this display using variables as the basis for the widgets. Use a VALUE-CHANGED trigger to
update the Package Code field. The first three digits come from the index of the radio sets. The last three
digits are "1" if the corresponding toggle box is TRUE and "0" if it is FALSE. (HINT: Use the online help
system to look up the IF... THEN... ELSE function.)
737
7.6
Tic Marks
Trackbar
Figure 76:
Pointer
Parts of a Slider
The slider shows the current value and the range of acceptable values for an INTEGER field or
variable. This is the VIEW-AS syntax for defining a slider widget.
SYNTAX
VIEW-AS SLIDER
MAX-VALUE max-value MIN-VALUE min-value
[
[
[
[
HORIZONAL
VERTICAL
LARGE-TO-SMALL
NO-CURRENT-VALUE
TIC-MARKS
size-phrase
738
RIGHT
BOTH
TOOLTIP tooltip
NOTE:
LEFT
A slider works best with a mouse. If your environment does not support the mouse,
your users may prefer another data widget.
Slider Syntax
Element
MAX-VALUE
(1 of 2)
Description
MIN-VALUE
HORIZONTAL
VERTICAL
NO-CURRENTVALUE
LARGE-TOSMALL
The default is to display the current value for a given position on the
slider s trackbar. The NO-CURRENT-VALUE option allows you to
override this default behavior to indicate that the slider will not
automatically display its current value.
The default numeric range that a slider displays is small (minimum)
to large (maximum). The LARGE-TO-SMALL option allows you to
override this default behavior as follows:
When the slider is positioned horizontally, the left most position on
the trackbar displays the maximum value and the right most position
displays the minimum value.
When the slider is positioned vertically, the bottom most position on
the trackbar displays the maximum value and the top most position
displays the minimum value.
739
Slider Syntax
Element
(2 of 2)
Description
TIC-MARKS
FREQUENCY
This option is used only with the TIC-MARKS option to indicate how
often tic marks will display. For example, if you indicate a frequency
of 5, a tic mark displays in every fifth position along the track bar.
size-phrase
The size phrase has a few different syntaxes. The tutorial uses the
most portable syntax:
SIZE-CHARS width BY height
where width and height are integer constants.
If the slider has horizontal orientation, the height has to accommodate
the trackbar, pointer, and labels. For character interfaces, the width
should be a multiple or factor of the range to ensure that the pointer
moves in even increments.
If the slider has vertical orientation, the width has to accommodate the
label. The height should be a multiple or factor of the range to ensure
that the pointer moves in even increments.
TOOLTIP tooltip
7.6.1
Slider Events
740
Accepts input focus by way of the navigation key functions (such as TAB) or the mouse
Moves the slider pointer with either the cursor keys or when a user drags it with a mouse
7.6.2
2 To change the value, drag the pointer located in the trackbar. At each increment, the value
changes, a trigger executes, and the X character moves.
3 Press TAB to move to the second slider, or just click on the pointer in the second slider.
4 Use the cursor keys to move the pointer. At each increment, the value changes, a trigger
executes, and the X character moves.
5 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
741
742
1.
The first slider is horizontal and displays the X coordinate of the character that moves
within the area of the sliders. Tic marks are defined for every fifth position in the range
and the tic marks display on the bottom of the slider. The NO-CURRENT-VALUE option
indicates that the current value of a position on the slider will not automatically display.
2.
The second slider is vertical and displays the Y coordinate of the character. This slider also
has tic marks defined for every numeric position in the defined range. The tic marks
4.
The ROW and COL attributes specify the location of the widget within a frame.
NOTE:
Keep in mind that ToolTip information can be added to a slider widget. Refer to the
code examples in either the Toggle Box Programming Example or the Radio Set
Programming Example presented earlier in this chapter that show how to define the
TOOLTIP option.
743
7.7
Label
List Item
Figure 77:
You can use the selection list widget with a CHARACTER field or variable. The choices in a
list are always CHARACTER strings and the values returned to the procedure from the widget
are CHARACTER strings. (You can effectively create a selection list of a different data type by
using the data conversion functions on the returned CHARACTER string.)
Selection lists are valuable for restricting values to a predefined set. Selection lists are also
valuable for creating indexes to data sets. For example, suppose you needed to search through
several records. As you search, each record displays-thats a lot of work on the computers part.
Instead, you could create a selection list that contains a key field in a record, such as Name in
the Customer table. You can then search more quickly through the selection list and use the
result to display the whole record. This technique of creating a run-time selection list from a data
set is called populating a selection list.
744
SINGLE | MULTIPLE
LIST-ITEMS item-list
[ DELIMITER character ]
[ SCROLLBAR-HORIZONTAL ]
[ SCROLLBAR-VERTICAL ]
{ size-phrase | INNER-CHARS
[ SORT ]
[TOOLTIP tooltip ]
(1 of 2)
Description
SINGLE
MULTIPLE
The SINGLE and MULTIPLE options allow you to specify whether the user
can select a single value from the list or multiple values. Normally, selection
lists have single selection and that is the default. For more information about
MULTIPLE lists, see the Progress Programming Handbook.
item-list
DELIMITER
After the keyword DELIMITER, you can specify a character other than the
comma to use as the separator in the item list. This option is necessary when
your data could contain commas.
745
(2 of 2)
Element
Description
SCROLLBAR-HORIZONTAL
SCROLLBAR-VERTICAL
If the selection list has more items than the confining rectangle can show,
then the selection list automatically scrolls the values as the user accesses
the top and bottom values in the selection rectangle. Despite this behavior,
specifying a vertical scrollbar with the SCROLLBAR-VERTICAL option
makes it explicit to your users that the selection list contains more items than
they can see.
Specify a horizontal scrollbar with the SCROLLBAR-HORIZONTAL
option when the selection list items are longer than the confining rectangle.
Scrollbars only appear if Progress cannot fit all the items in the display
rectangle.
size-phrase
INNER-CHARS
INNER-LINES
After the keyword INNER-LINES, specify the number of list items you
want to appear in the rectangle of the selection list. Progress will then
determine the height of the widget.
SORT
This option sorts and displays the list items in alphabetical order. This
option is especially valuable when populating selection lists at run time.
TOOLTIP tooltip
You can optionally define a text message string that automatically displays
when the mouse pointer pauses over the selection list.
746
7.7.1
Selection-list Events
Accepts input focus by way of the navigation key functions (such as TAB) or the mouse
Moves input focus among the list items with the cursor keys or the mouse
Responds to alphanumeric keys by moving the cursor to the first list item that begins with
that letter.
DEFAULT-ACTION Event
A default action is an interaction with a widget that signals the widget to perform a task
associated with the widget. For example, issuing a default action with a selection list might
make the display update with new information about the selection. The default action for a
selection list is to press ENTER or RETURN after selecting a list item or to double-click the
desired list item. When a user issues the default action, the DEFAULT-ACTION event occurs,
making this event the one to use for associating tasks with widgets that support a default action.
747
7.7.2
Three attributes are important for use with selection lists, as shown in Table 78.
Table 78:
Attribute
Description
LIST-ITEMS
This attribute contains all the list items in a selection list. The attribute
is formatted as a comma-separated list of CHARACTER strings. The
list does not require quotes around the list items.
NUM-ITEMS
DELIMITER
This attribute defines the character that separates the items in the
LIST-ITEMS attribute. By default, it is a comma. However, since data
frequently contains commas and would therefore corrupt the format
of the LIST-ITEMS attribute, you can use the DELIMITER attribute
to select a different delimiter.
7.7.3
The selection list supports a variety of methods to give you greater flexibility during runtime.
Table 79 defines two important methods.
Table 79:
Attribute
748
Description
ADD-LAST(list-item)
Adds a new list item to the bottom of the selection list. This
method returns TRUE if the method successfully added the
item to the selection list and FALSE if it failed.
LOOKUP(list-item)
7.7.4
Although the selection list is valuable for presenting a list of known choices to a user, it becomes
essential as a way to display acceptable choices that arent known until run time. The process
of filling the list of choices at run time is known as populating. Populating involves two major
steps:
1.
Use the VIEW-AS phrase without the LIST-ITEMS option. This allows the Progress
compiler to define the widget for use at runtime.
2.
Define the list items of the widget before you display it.
All Around Sports is a growing business, and the responsibilities of its sales people are changing
to meet the new challenges. The sales director asks you to design a simple interface so that she
can quickly view and change sales representative assignments.
Exercise
2 Click an item to choose it. The form does not update. If the trigger in the procedure used
VALUE-CHANGED, it would have.
749
3 Double-click a sales representative name, Progress accesses the appropriate record from
the sports database and displays some of the fields. The double-click event executes the
DEFAULT-ACTION trigger for the selection list.
4 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
750
751
Note that the initial definition of the selection list does not include the LIST-ITEMS.
2.
By using DEFAULT-ACTION, the fields in the form do not update until the user
double-clicks a list item or presses RETURN or SPACEBAR. The FIND statement, which
youll learn about in the next chapter, accesses the appropriate sales representative record.
3.
Since the names in the Salesrep table may contain commas, you have to set the
LIST-ITEM delimiter to some character that wont be in the data. You choose the asterisk.
4.
The FOR EACH block cycles through each record in the Salesrep table.
5.
The ADD-LAST( ) method adds the current Salesrep name to the bottom of the list. Since
the SORT option is also employed, Progress will sort the list items before you display the
widget.
6.
This FIND statement accesses a record so that some data appears at startup.
NOTE:
7.8
Keep in mind that ToolTip information can be added to any selection list widget.
Refer to the code examples in either the Toggle Box Programming Example or the
Radio Set Programming Example presented earlier in this chapter that show how to
define the TOOLTIP option.
752
A SIMPLE combo-box widget with a read/write edit control and a selection list that is
always visible. This widget is supported in graphical interfaces only, and only in
Windows. If you specify a SIMPLE combo-box widget in a character interface, Progress
treats it as a DROP-DOWN-LIST combo-box widget.
A DROP-DOWN combo-box widget with a read/write edit control and a selection list that
appears when you click the drop-down button. This option is supported in graphical
interfaces only, and only in Windows. If you specify a DROP-DOWN combo-box widget
in a character interface, Progress treats it as a DROP-DOWN-LIST combo-box widget.
Position to the value in the drop-down list using the scroll bar and click on the value in the
drop-down list using the SELECT mouse button.
Enter text in the fill-in and allow the edit control to complete keyboard input to the
combo-box, based on a potential or unique match, by searching through the items in the
drop-down list.
Position to the value in the drop-down list using the arrow keys and press SPACEBAR or
RETURN to confirm the selection.
Active State
Inactive State
Label
Fill-in Field
Button
Current Value
List Item
Drop-Down List
Figure 78:
753
[
[
[
[
[
[
| LIST-ITEM-PAIRS item-pair-list ]
] [ size-phrase ] [ SORT ]
LIST-ITEMS item-list
INNER-LINES lines
TOOLTIP tooltip
SIMPLE
]
| DROP-DOWN-LIST ]
]
[ UNIQUE-MATCH ] ]
DROP-DOWN
MAX-CHARS characters
AUTO-COMPLETION
Element
754
(1 of 2)
Description
LIST-ITEMS
LIST-ITEM-PAIRS
INNER LINES
Specify the number of entries that the drop-down list can display.
If you set INNER-LINES to less than the actual number of
entries, the user can scroll through the drop-down list.
size-phrase
SORT
TOOLTIP tooltip
SIMPLE
DROP-DOWN
Element
(2 of 2)
Description
DROP-DOWN-LIST
MAX-CHARS
AUTO-COMPLETION
UNIQUE-MATCH
7.8.1
Accepts input focus by way of the navigation key functions (such as TAB) or the mouse
Moves input focus among the drop-down list items with the cursor keys
755
7.8.2
This example creates a simple combo box to represent a variable that lists U.S. time zones.
Follow these steps to view the combo box:
Exercise
1 Open lt-07-09.p and run it. The display shown below appears:
This application calculates the correct local arrival time of a U.S. domestic flight.
2 Choose the button for the Departure Time Zone combo box. The drop-down list appears.
You select a value as you do with a selection list.
3 Select a value for the Arrival Time Zone combo box.
4 Enter a value for Departure Time and Flight Time.
5 Choose the Calculate button. The application displays the local arrival time.
6 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
756
This DEFINE VARIABLE statement sets up the first combo box with the VIEW-AS
phrase.
2.
This DEFINE VARIABLE statement uses the LIKE option to inherit the characteristics of
the first combo box. The other options override specific inherited characteristics.
3.
This expression uses departure time and flight time to calculate arrival time. It also uses
the LOOKUP method of the combo box to determine the index values of the selected time
zones. The expression uses these values to adjust the arrival time to the arrival time zone.
Finally, the MOD operator keeps the result in 24 hour format.
757
7.9
Keep in mind that tooltip information can be added to a combo box widget. Refer to
the code examples in either the Toggle Box Programming Example or the Radio Set
Programming Example earlier in this chapter that show how to define the TOOLTIP
option.
Label
Text Area
Figure 79:
Parts of an Editor
The editor serves as a means to display and update lengthy CHARACTER data. However, you
could also use the editor widget as the basis for a word processor. This section sticks to the basic
functionality, which is essential for many applications. See the Progress Programming
Handbook for information on the sophisticated applications of the editor widget.
This is the VIEW-AS syntax for creating a simple editor.
SYNTAX
VIEW-AS EDITOR
{
[
[
[
[
[
[
[
758
size-phrase
BUFFER-CHARS chars
BUFFER-LINES lines
LARGE
]
]
MAX-CHARS chars
SCROLLBAR-VERTICAL
NO-WORD-WRAP
TOOLTIP tooltip
SCROLLBAR-HORIZONTAL
]]
Editor Syntax
Component
size-phrase
(1 of 2)
Description
You might want to use the size phrase with an editor to
fit an editor into a particular area of a display. In this
case, use this syntax:
SIZE-CHARS WIDTH cols HEIGHT rows
Where cols and rows are integer constants.
INNER-CHARS
INNER-LINES
BUFFER-CHARS
BUFFER-LINES
LARGE
MAX-CHARS
759
Editor Syntax
(2 of 2)
Component
Description
SCROLLBAR-VERTICAL
NO-WORD-WRAP
SCROLLBAR-HORIZONTAL
TOOLTIP
7.9.1
tooltip
Editor Events
Accepts input focus by way of the navigation key functions (such as TAB) or the mouse
Moves the text cursor with the arrow keys or the mouse
For information about the attributes and methods associated with more sophisticated editors, see
the Progress Programming Handbook.
760
7.9.2
1 Open lt-07-10.p and run it. The display shown below appears:
Exercise
2 Select the editor widget. The text cursor appears in the widget.
3 Type some comments. Notice the word-wrap behavior.
4 Press RETURN to enter a manual line break.
5 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
761
Simply by defining the size with the INNER-CHARS and INNER-LINES options at point 1,
Progress creates an editor with the text-handling behavior the user expects.
NOTE:
762
Keep in mind that ToolTip information can be added to an editor widget. Refer to the
code examples in either the Toggle Box Programming Example or the Radio Set
Programming Example presented earlier in this chapter that show how to define the
TOOLTIP option.
Practice Problems
The problem below gives you some practice with sliders, selection lists, combo boxes, and editors.
Problem 7-3:
lt-07-s3.p
It seems that All Around Sports needs to add another display to its on-line questionnaire application. It needs
widgets to record customer responses to these questions.
A. What percentage of your business is in sports equipment?
B. What percentage of your business is in sports supplies?
C. What percentage of your business is in sports apparel?
D. Of the following categories, which best describes your business?
Department store, general sports retailer, specialty sports retailer, secondary distributor, mail order
distributor, sports club
E. What is your best sales season of the year?
F. Do you have any suggestions for All Around Sports?
Create the display All Around Sports needs, using these directions.
1.
2.
3.
Use an editor capable of holding 25 lines of 60 characters to implement question F. However, make the editor
small enough to fit in the same display as the other widgets.
763
7.10
Summary
This chapter covered the language elements used to define general widget characteristics as well
as the specific elements used to define data widgets.
Defining Widget Characteristics
Progress provides different methods for determining the characteristics of widgets. When you
can use the different methods depends of the stage of the widget:
Widget definition For variables, the DEFINE VARIABLE statement supports the
VIEW-AS phrase and other options to define the major characteristics of a widget. For
database fields, the Data Dictionary supports properties which correspond to all the
options of the DEFINE VARIABLE statement.
Container definition When you define your frames and dialog boxes, you specify the
widgets found in those containers and define the characteristics of the widget with the
format phrase. The DEFINE FRAME statement also supports the frame phrase, which has
options that modify the characteristics of the widgets contained in the frame.
Before display Progress screen I/O statements support both the format phrase and the
frame phrase.
After display After a widget appears on screen, you access widget attributes directly
to redefine widget characteristics.
Programming Widgets
Data widgets are representation of database fields or variables. The data widgets include:
764
Fill-in field The default widget representation for all fields and variables. It presents
data as modifiable text.
Text widget Basically a fill-in field for read-only data. Text widgets are useful because
they take up less room than fill-ins on some operating platforms and in reports.
Radio set A graphical representation of a field or variable that has a limited number of
possible values. Only one value can be true at a time.
Selection list Presents the user with a scrolling list of possible values for a
CHARACTER field or variable.
Editor A large rectangular area for displaying and editing long text.
You can create ToolTip information for all of the data widgets previously listed.
765
766
8
Using Database Records
Up to this point, youve learned about interfaces and procedure without learning much about
database access. The tutorial uses this approach because database access techniques make more
sense in the context of fully functional procedures. In this chapter, youll learn complete
database access techniques that draw on what you already know about interfaces and
procedures.
Specifically, this chapter describes:
Retrieving data
Using queries
Modifying data
Releasing records
Creating records
Deleting records
8.1
Database
Figure 81:
Record Buffer
Screen Buffer
Data Locations
These data locations are important to understand because they relate to three fundamental rules
of data movement in Progress. The following list describes these rules of data movement:
82
1.
Your procedure cannot interact with data until the procedure copies the data from the
database to a record buffer. Once in the record buffer, the procedure can manipulate that
data.
2.
End users cannot interact with data until your procedure copies the data from the record
buffer to the screen buffer. Once in the screen buffer, the data is visible on screen.
Progress does not automatically copy changes made in a screen buffer or a record buffer
to the related buffer. For example, if a copy of a particular field exists in both a record
buffer and a screen buffer, changing the data in the screen buffer does not change the data
in the record buffer. Your procedure programmatically controls the movement of data
between buffers.
Think of the data locations as stops along a two-way street. To display a database record,
Progress must first move it to a record buffer and then into a screen buffer. Similarly, Progress
cannot write new screen buffer data to a database without first writing it to a record buffer.
Figure 82 shows how data moves in Progress.
Database
Record Buffer
Screen Buffer
Database
Record Buffer
Batch Manipulation
Figure 82:
Screen Buffer
User Input
User Manipulation
83
8.2
Figure 83:
84
Displays key data so users know that they are interacting with the correct record
Separates update mode from display mode and lets users decide whether to save or cancel
their changes on a record-by-record basis
Lets users create new records and lets the user decide whether to keep or discard the new
record
Allows users to delete records, but asks for confirmation before deleting the record
85
Field: Data
PREV Trigger
Field: Data
Field: Data
ON CHOOSE OF b-prev
DO:
FIND PREV record.
DISPLAY record.
END.
Field: Data
Field: Data
Prev
Next
Update
UPDATE Trigger
ON CHOOSE OF b-update
DO:
UPDATE record.
END.
Add
Delete
CREATE Trigger
ON CHOOSE OF b-add
DO:
CREATE record.
UPDATE record.
END.
Field:
Data
Field:
Data
Field:
Data
Field:
Data
Field:
Data
Field:
Data
Figure 84:
86
Exit
ON CHOOSE OF b-next
DO:
FIND NEXT record.
DISPLAY record.
END.
DELETE Trigger
ON CHOOSE OF b-del
DO:
verify request.
DELETE record.
END.
OK
NEXT Trigger
Cancel
NO
8.3
record-phrase-options
][
statement-options
87
FOR statement
DO PRESELECT statement
It is a good rule of thumb to use field lists only when you are referencing less than 90% of the
record. When you are referencing more than 90%, it makes more sense to fetch the entire record.
Also keep in mind these rules when you use field lists:
88
Specify all the fields you plan to reference in your field lists.
Specify the entire database record if you are updating or deleting the record. Otherwise, if
you delete or update a record from a Progress database, Progress rereads the complete
record before completing the transaction.
NOTE:
89
This FOR statement uses the FIELDS option to specify a field list instead of fetching the
entire record.
2.
The Sales-Rep and Region fields of the Salesrep table are also referenced in the
application, but they do not appear in the field list because they are referenced outside of
the FOR statement.
Progress flags all ambiguous references at compilation time. Many programmers always specify
the full reference to avoid ambiguity and make more readable code.
Referencing Database Fields
After you retrieve a record, youll want to work selectively with some of the fields in the record
buffer. To avoid ambiguity at this level, use the syntax shown below.
SYNTAX
database-name.table-name.field-name
It is also important to remember that the expanded reference to a database field is also a
reference to the widget that represents it. In most cases, Progress knows from the context of your
code whether you are working with the record buffer (database value) or screen buffer (widget
screen value).
810
The frame in this code fragment is the main display for the database access form. Notice how
the database references here refer to the widgets associated with the database fields. You can
think of this frame as a formatted representation of the screen buffer.
About Queries
A query is a request for database data that results in one or more records. A results or results list
is the record or set of records defined by a query. Some Progress statements query the database
directly. Other statements work with the results list of a predefined query to query the database.
A results list points to all the records that satisfy a predefined query. For example, the FIND
statement queries the database directly, while the GET statement queries through the results list
of a predefined query.
In general, the Progress documentation uses query to refer to a predefined query created with
the DEFINE QUERY and OPEN QUERY statements.
811
8.3.1
The first step in implementing the database access form, shown in Figure 85, is to let users
move through, or navigate, the records of a database table. In this example, when the procedure
starts, it finds the first record in the Item table and displays data from that record. Choosing the
Next button finds and displays the next Item record. The Prev button finds and displays the
previous Item record. The Next and Prev buttons implement the navigation and display
functions of the form.
Figure 85:
812
The FIND statement retrieves an individual record and is the basis for the triggers associated
with the navigation buttons. FIND copies a record from a database to a record buffer, as shown
in Figure 86.
Database
Figure 86:
Record Buffer
FIRST
NO-ERROR
NEXT
PREV
LAST
CURRENT
record-phrase
When you think about it, there are four records that you search for most often in database
applications. They are the first record, the record next after the one currently in the record
buffer, the record previous to the one currently in the record buffer, and the last record. Progress
supports four keywords for the FIND statement to specify these records: FIRST, NEXT, PREV,
and LAST.
With just these four keywords, you have enough context to create an application that
interactively searches one by one through the records of a database table. The record phrase only
has to specify a table name to complete a valid statement, as shown below:
FIND FIRST Item.
The FIND statement uses the primary index of the database table to determine which record is
first and last. In the next chapter, youll learn how to navigate through the records in different
orders.
813
The NO-ERROR option suppresses the normal error messages and default behavior that the
RDBMS executes if the FIND attempt fails. Use NO-ERROR when you want to handle error
conditions in your procedure. The programming example at the end of this section demonstrates
error handling.
Once you have a record in the buffer, you can display that record. Youve already seen the
DISPLAY statement several times. The function of the DISPLAY statement is to move data
from a record buffer into a screen buffer, and thus make the data visible to the user, as shown
in Figure 87.
Record Buffer
Figure 87:
Screen Buffer
As you learned in Chapter 3, Programming the Progress Way, a widget and the data it
represents are two different things. DISPLAY manipulates the data in a widget. But, if the
widget that contains the data is not already visible when Progress executes DISPLAY, Progress
makes the widget visible. After a widget is visible, you can use the DISPLAY statement
repeatedly to update the data in the screen buffer, which refreshes the widget with the most
current data. Remember, when data changes in the record buffer, Progress does not update the
associated data in the screen buffer. If you want your user to see the current data, use another
DISPLAY statement.
814
expression
format-phrase
| SPACE [ ( n ) ]
| SKIP [ ( n ) ]
] ...
{ [ frame-phrase ] }
This is an alternate syntax (partial) of the DISPLAY statement for displaying whole records.
SYNTAX
DISPLAY record
Component
Description
expression
SPACE ( n )
SKIP ( n )
frame-phrase
EXCEPT
Specify fields from the record to not display with the record.
815
1 Open lt-08-01.p and run it. The Database Access Form appears.
2 Choose the Next button several times and notice the changes to the Item No. field. The
procedure navigates through the records starting with the lowest item number and moving
to the highest. FIND uses the Item-Num field for the navigation order because it is the
primary index of the Item table.
3 Choose Prev until the form displays item number 1. Now choose Prev again. Normally,
trying to find the previous record of the first record would be an error. This procedure,
however, defines the LAST record as the PREV record of the FIRST record. The
procedure also defines the NEXT record of the LAST record as the FIRST record.
4 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
816
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*9*/
/*2*/
**********/
This statement includes the file that contains the frame and button definitions that make
up the interface.
2.
The first FIND statement (in the Main Logic section) creates the Item buffer and copies
the first record from the database to the record buffer. The NO-ERROR option is not
necessary here. As long as the table contains one record, Progress will find a record that
satisfies the request. If the RDBMS encounters any other errors, then you want the default
messages and behaviors to execute.
3.
This trigger executes when the user chooses the Prev button. It finds the previous record,
which is the record that comes before the current record according to the primary index. If
the current record is the first record (no previous record exists) it finds the last record.
817
8.4
4.
This FIND statement clears the Item buffer, locates the previous record, and copies it to
the Item buffer. The NO-ERROR option suppresses the normal error response. Normally,
if Progress cannot find the previous record, the RDBMS sends a message to the user and
the procedure stops execution of the current code block, which is the trigger. With the
NO-ERROR option, the user gets no error message and the procedure continues executing
the code block. However, because Progress clears the Item buffer during the FIND
request, there is no current record. Any attempt to access the buffer later results in an error.
5.
This IF statement checks the Item buffer with the AVAILABLE function. This test allows
you to handle error conditions. If there is no record in the Item buffer, then the FIND
statement failed. If it failed, then it probably failed because the user tried to find the
previous record of the first record. In this situation, finding the last record puts data into
the empty buffer.
6.
The DISPLAY statement refreshes the form with the new data in the record buffer.
7.
This trigger executes when the user chooses the Next button. It finds the next record,
which is the record that comes after the current record according to the primary index. If
the current record is the last record (no next record exists) it finds the first record.
8.
This FIND statement copies the next record to the Item buffer.
9.
This IF statement defines the normal behavior for trying to find the next record of the last
recordfind the first record.
818
1.
Established the query with the DEFINE QUERY statement at the top of the procedure in
the definitions section.
2.
Initialize the results list with the OPEN QUERY statement at the beginning of your main
code block.
Navigate through the results list with the GET statement, or by using a browse widget, but
not with both.
4.
Release the query resources with the CLOSE QUERY statement at the end of your main
code block.
To start with, the DEFINE QUERY statement lets you name your new query and requires you
to list all the tables that the query uses. This is a partial syntax for the DEFINE QUERY
statement.
SYNTAX
DEFINE QUERY query-name FOR table-name
[
[
, table-name
SCROLLING
] ...
Use the SCROLLING option if you plan to use a browse widget or the REPOSITION statement
with the query. SCROLLING is almost always necessary for an interactive database procedure.
Next, you need to initialize the results list with the OPEN QUERY statement. This is a partial
syntax for the OPEN QUERY statement.
SYNTAX
OPEN QUERY query-name FOR EACH record-phrase
Each instance of the FIND statement uses a record phrase. With a defined query, the record
phrase does its work up front in the OPEN QUERY statement. Therefore, the GET statement
has no need to support the record phrase.
Now, youre ready to navigate through the results list. The next few sections of this chapter
show you how to do this.
Finally, when you finish working with a query, you should close it. This is the syntax for the
CLOSE QUERY statement.
SYNTAX
CLOSE QUERY query-name
819
8.5
Database
Figure 88:
Record Buffer
As you can see, GET accomplishes the same thing as the FIND statement. While FIND goes
directly to the database, GET works through the results list. GET manipulates the cursor of the
results list. The cursor is an agreement between the query results list and the database about
which record is the current one. When GET moves the cursor of the results list, Progress updates
the associated record buffer. So, the position of the cursor always indicates which record is in
the record buffer. This is the syntax for the GET statement.
SYNTAX
GET
FIRST
NEXT
PREV
LAST
CURRENT
query-name
As with FIND, the four keywords specify which record you are trying to get. Following the
keyword, you provide the name of the query, not the actual table name:
GET FIRST My-Query.
820
The function takes the query name as a string and returns TRUE if the cursor is off either the
top or bottom end of the results list. Here is a code example using this query function:
IF QUERY-OFF-END ( "My-Query" ) THEN GET FIRST My-Query.
1 Open lt-08-02.p and run it. The database access form appears.
2 Choose the Prev and Next buttons and notice the changes to the Item No. and Name fields.
The code works precisely the same as the FIND statement version.
3 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
821
/*4*/
/*5*/
/*2*/
/*3*/
/*6*/
822
1.
2.
OPEN QUERY at the beginning of the main code block initializes the results list that
defines the matching subset of records. You cannot use GET until after you open the
query.
3.
The GET statement creates a record buffer and copies a record to the buffer from the
database using the query results list.
4.
This trigger performs the retrieve next or retrieve first record logic, exactly as in the
FIND example. Here, the GET statement replaces the FIND statement and the
QUERY-OFF-END function replaces the AVAILABLE function.
This trigger performs the retrieve previous or retrieve last record logic, exactly as in the
FIND example.
6.
The CLOSE QUERY statement after the WAIT-FOR statement releases the resources
used by the query.
Practice Problems
The basic form used in the programming examples can quickly be refitted for use with any other table.
Use the Customer table with the problems below to practice what you have learned so far.
Problem 8-1:
lt-08-s1.p
Using the FIND and DISPLAY statements, create a procedure that lets you review records in the
Customer table.
Problem 8-2:
lt-08-s2.p
Make a copy olist:f the procedure you created in Problem 8-1. Replace the FIND statements with
DEFINE QUERY and GET statements.
8.6
Modifying Data
Earlier, this chapter defined a good database access form as one that separates navigation and
display of data from update of data. Separating the two functions into different modes makes
clear to the user whats going on and helps prevent unintended changes. This statement isnt
necessarily true in all cases. In some cases, you may want to use the display form as your update
form.
This section describes two techniques for changing data: one that uses the main form as the
display form and one that uses a separate dialog box as the update form.
823
Figure 89:
8.6.1
When you worked with variables in previous chapters, you used this technique, as summarized
below:
1.
Use a DISPLAY statement to copy data from the variable to the widget that represents that
variable.
2.
Use an ENABLE statement to let the user interact with the widget and the screen value.
3.
On some event, use an ASSIGN statement to copy the screen value back to the variable.
Using the form in Figure 89, you could follow the same sequence of steps to change database
data. Choosing the Update button will be the event that copies the current screen buffer to the
record buffer and eventually to the database.
To use this basic technique with database records, you need to learn more about locks,
ROWIDs, ENABLE, and ASSIGN.
824
2.
Only one user at a time can access a record to change the data.
When a user retrieves a record, Progress puts the users copy of the record in one of three lock
states. A lock is a description on the users freedom to use the record. Progress has three
keywords that describe the lock states, as shown in Table 82.
Table 82:
Locks
Lock
Description
NO-LOCK
The user can only view the data. Progress puts the users record
in this state if the NO-LOCK keyword is included in the record
phrase.
SHARE-LOCK
EXCLUSIVE-LOCK
To let the greatest number of users successfully access a particular record, it makes sense to
keep the record in NO-LOCK state. The application should only upgrade the lock to
EXCLUSIVE-LOCK during the act of changing data. This means that the record is tied up for
the shortest possible period of time.
825
This code fragment shows how to retrieve and store a ROWID for later use:
DEFINE VARIABLE Current-Record AS ROWID
.
.
.
FIND FIRST Item.
Current-Record = ROWID(Item).
.
.
.
The programming example at the end of this section demonstrates how to use ROWIDs and how
to take specific control over locks. First, you need a more in-depth look at the ENABLE and
ASSIGN statements.
ENABLE Statement
You saw in the last section that the DISPLAY statement moves data from the record buffer to
the screen buffer. ENABLE allows users to enter data directly into the screen buffer, as shown
in Figure 810.
Screen Buffer
Figure 810:
826
User Input
{[
ALL
EXCEPT widget
frame-phrase
... ] |
field
... }
]}
Use the EXCEPT widget syntax to enable all the widgets in a frame, except for those you
specify.
ASSIGN Statement
You also have encountered the ASSIGN statement. ASSIGN moves data from the screen buffer
to the record buffer, as shown in Figure 811.
Screen Buffer
Record Buffer
Figure 811:
Once you move changes from the screen buffer to the record buffer, or make changes directly
to the record buffer, Progress understands that you want those changes written to the database.
Progress does not immediately write the changes to the database. When the write occurs is based
on other factors. The next section describes how Progress handles database writes.
This is the syntax for the ASSIGN statement.
SYNTAX
ASSIGN
{{
field
record
field = expression
EXCEPT field
} ...
] ...
}
You can assign fields or the entire record. The EXCEPT syntax is also valid with ASSIGN.
827
Using the DISPLAY, ENABLE, and ASSIGN technique does not automatically
invoke the validation behaviors stored in the Data Dictionary. To force the validation
routines to run, you can query the VALIDATION attribute of a widget or frame. For
more information, see the Progress Programming Handbook. The other techniques
described in this section do invoke Data Dictionary validation.
1 Open lt-08-03.p and run it. Note that the form now uses fill-ins instead of text widgets.
2 Select a record and change some of the fields.
3 Choose the Next followed by the Prev button. The record does not contain the new data.
This procedure does not save your changes unless you choose the Update button.
4 Select a record, change some of the fields, and choose Update.
5 Choose the Next followed by the Prev button. The new data is now permanent.
6 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
828
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
/*1*/
/*2*/
**********/
ON CHOOSE OF btn-Update
DO:
Current-Record = ROWID(Item).
FIND FIRST Item WHERE ROWID(Item) = Current-Record EXCLUSIVE-LOCK.
IF AVAILABLE(Item) THEN
ASSIGN Item.Item-Name Price On-Hand Allocated Re-Order
On-Order Cat-Page Cat-Description.
ELSE DO:
FIND FIRST Item WHERE ROWID(Item) = Current-Record NO-LOCK.
MESSAGE "Record in use. Unable to update."
VIEW-AS ALERT-BOX WARNING BUTTONS OK Title "Update Error".
END.
END.
/********** MAIN LOGIC **********/
OPEN QUERY Item-Query FOR EACH Item NO-LOCK.
GET FIRST Item-Query.
DISPLAY Item.Item-Num Item-Name Price On-Hand Allocated Re-Order
On-Order Cat-Page Cat-Description WITH FRAME Frame1.
ENABLE Item.Item-Name Price On-Hand Allocated Re-Order On-Order
Cat-Page Cat-Description btn-Prev btn-Next btn-Update btn-Exit
WITH FRAME Frame1.
WAIT-FOR CHOOSE OF btn-Exit.
CLOSE QUERY Item-Query.
In the main code block, the OPEN QUERY statement contains the NO-LOCK option. This
means that navigating through the records or leaving the application running will not
impede other users.
2.
3.
This variable will hold the current ROWID when trying to upgrade a lock.
4.
This include file contains the navigation triggers which you have already studied.
829
Once the user chooses Update, this trigger executes. Here, the trigger saves the ROWID
of the current Item record.
6.
Recall that FIND retrieves an individual record. This trigger uses FIND to get a copy of
the record with the EXCLUSIVE-LOCK option. The FIND statement does not affect the
defined query.
7.
If any other user has EXCLUSIVE-LOCK or SHARE-LOCK, the FIND will fail, which
is why this IF statement checks the record buffer. If the record is there, the users changes
are saved with the ASSIGN statement.
8.
If the FIND failed, then refind the record with a NO-LOCK and inform the user.
One way to keep data accessible to all users is to keep the data in NO-LOCK and let the user
change it. When it is time to assign the changes, use the FIND CURRENT or GET CURRENT
statement to get a fresh copy of the record that the user has been modifying with an
EXCLUSIVE-LOCK. Then, use the CURRENT-CHANGED function to test for changes to the
record while the user was working with it. If the record was changed by another user, you can
send a message to the user and display the updated record. If the record is unchanged, you can
assign the changes.
830
831
8.6.2
A separate mode for updating data protects data from unintended changes. The technique shown
in this section relies on a statement normally reserved for application-driven programs and a
special type of frame. To understand the technique, you need to learn about the UPDATE
statement and the dialog box.
UPDATE Statement
To put it succinctly, the UPDATE statement is a powerful statement that does the work of the
DISPLAY, ENABLE, ASSIGN, and WAIT-FOR statements. The procedure below is a
complete application that does much of the work of the last programming example:
FIND FIRST Item.
REPEAT:
UPDATE Item WITH 2 COLUMNS.
FIND NEXT Item.
END.
832
1.
2.
Assigns changes after receiving the GO event function. (Pressing F2 executes GO.
After finishing with each record, the user presses F2 to move on to the next record.)
3.
4.
Iterates until it encounters an error condition: either no more records exist or the user
issues the ENDKEY (F5) event function. If the user issues ENDKEY, any changes made
to the current record are discarded.
Record Buffer
Screen Buffer
Record Buffer
Screen Buffer
Figure 812:
User Input
field
| SPACE [ ( n ) ]
| SKIP [ ( n ) ]
} ... { [ frame-phrase ] }
833
834
Exercise
1 Open lt-08-04.p and run it. The display appears as shown below, with the fields on the
form represented as text widgets:
835
Note that you cannot move focus to any widget outside the dialog box.
3 Change the data and choose Cancel. The dialog box disappears and the main form remains
unchanged.
4 Choose Update again, change some data, and Choose OK. The dialog box disappears and
the main form shows your changes.
5 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
836
**********/
/*2*/
/*3*/
/*4*/
/*1*/
**********/
ON CHOOSE OF btn-Update
DO:
Current-Record = ROWID(Item).
FIND FIRST Item WHERE ROWID(Item) = Current-Record
EXCLUSIVE-LOCK.
IF AVAILABLE(Item) THEN DO:
UPDATE Item.Item-Name Price On-Hand Allocated Re-Order
On-Order Cat-Page Cat-Description btn-OK btn-Cancel
WITH FRAME Dialog1.
DISPLAY Item-Num Item-Name Price On-Hand Allocated Re-Order
On-Order Cat-Page Cat-Description WITH FRAME Frame1.
END.
ELSE DO:
FIND FIRST Item WHERE ROWID(Item) = Current-Record NO-LOCK.
MESSAGE "Record in use. Unable to update."
VIEW-AS ALERT-BOX WARNING BUTTONS OK Title "Update Error".
END.
END.
/********** MAIN LOGIC **********/
OPEN QUERY Item-Query FOR EACH Item NO-LOCK.
GET FIRST Item-Query.
DISPLAY Item.Item-Num Item-Name Price On-Hand Allocated Re-Order
On-Order Cat-Page Cat-Description WITH FRAME Frame1 USE-TEXT.
ENABLE btn-Prev btn-Next btn-Update btn-Exit WITH FRAME Frame1.
WAIT-FOR CHOOSE OF btn-Exit.
CLOSE QUERY Item-Query.
837
8.7
1.
In the main code block, the NO-LOCK option lets all users have complete access.
2.
3.
4.
Again, if the lock upgrade fails, refind the record with NO-LOCK and notify the user.
Releasing Records
When you make changes to a record buffer, Progress knows that those changes are intended for
the database. Progress does not, however, write changes to the database as it receives them in
the record buffer.
Progress makes the changes to the database only when your procedure is done with the record.
Progress understands when you are finished with a record because the rules that determine how
long a record stays in a record buffer are enforced by the 4GL. The life span of a record in a
record buffer is called the scope of the record. When the scope of a record ends, Progress
releases the record and surrenders it to the RDBMS. The RDBMS has its own rules for
determining when it is safe and efficient to write the record to the database.
The basic rule for determining the scope of a record is that the scope lasts from the moment the
record is retrieved until:
As a general rule, you could say that a records scope ends on a new record request or an END
statement. That statement is subject to many exceptions and some special situations where
Progress allows you to bend the rules. As you work through this tutorial, the general rule of
thumb holds. When you finish working with the tutorial, you can read more about record
scoping in the Progress Programming Handbook.
Earlier in the tutorial, you learned that Progress can create and maintain a separate record buffer
for each database table. Actually, each block that can own a record buffer can have a separate
record buffer for the same database table. Blocks that can have buffers include:
838
Procedures
FOR EACH
If a block is not capable of owning its own buffer then it uses the buffer of the block in which
it resides. So, unless you have heavily nested blocks, the block uses its own buffer or the main
procedure blocks buffer.
The idea of multiple buffers is important because it means your procedures can work on more
than one record from a table at a time.
Explicit Release
You can end the scope of a record prematurely by forcing Progress to release it with the
RELEASE statement.
This is the syntax for the RELEASE statement.
SYNTAX
RELEASE record
Database
Figure 813:
Record Buffer
839
Practice Problems
Problem 8-3:
lt-08-s3.p
Make a copy of your solution to Problem 8-2. Now, add the ability to update the fields of your customer
review program using the UPDATE statement and a dialog box.
8.8
Creating Records
When you create a record, you are directly manipulating the database. Progress creates a new
empty record and copies that record to the record buffer in EXCLUSIVE-LOCK state. The new
record may not be entirely empty, however. Depending on your database schema, some of the
fields may have default initial values or values generated by sequences and database triggers.
Figure 814 shows the data movement of CREATE.
Database
Figure 814:
Record Buffer
As soon as you create a record, youll want to fill it with data. One way to acquire new data for
the record is to use a dialog box with an UPDATE statement.
840
1 Open the file named lt-08-05.p and run it. The following display appears:
Exercise
841
2 Choose Add, enter data in the update dialog box, shown below, and choose OK:
842
**********/
**********/
ON CHOOSE OF btn-Add
DO:
/*1*/
CREATE Item.
/*2*/
UPDATE Item.Item-Name Price On-Hand Allocated Re-Order
On-Order Cat-Page Cat-Description btn-OK btn-Cancel
WITH FRAME Dialog1.
/*3*/
DISPLAY Item-Num Item-Name Price On-Hand Allocated Re-Order
On-Order Cat-Page Cat-Description WITH FRAME Frame1.
END.
/********** MAIN LOGIC **********/
OPEN QUERY Item-Query FOR EACH Item NO-LOCK.
GET FIRST Item-Query.
DISPLAY Item.Item-Num Item-Name Price On-Hand Allocated Re-Order
On-Order Cat-Page Cat-Description WITH FRAME Frame1 USE-TEXT.
ENABLE btn-Prev btn-Next btn-Update btn-Add btn-Exit
WITH FRAME Frame1.
WAIT-FOR CHOOSE OF btn-Exit.
CLOSE QUERY Item-Query.
The CREATE statement establishes the record and interacts with the schema to get default
values.
2.
Since the record has EXCLUSIVE-LOCK, you can move right to an UPDATE statement.
3.
The DISPLAY statement refreshes the main form with the new data.
843
8.9
Deleting Records
The process for deleting records is simple. The following list identifies the steps in the delete
process:
1.
2.
Upgrade to an EXCLUSIVE-LOCK.
3.
Figure 815 shows the data movement for the DELETE statement.
Database
Figure 815:
Record Buffer
The figure may seem nonsensical. The DELETE statement doesnt copy data to the database.
What it does do is mark the record for deletion and release the record to the RDBMS for
eventual removal from the database. You could say that DELETE sends instructions, not data,
back to the database.
Again, the syntax is simple, although delete has a new useful option. This is the syntax for the
DELETE statement.
SYNTAX
DELETE record
The VALIDATE function accepts an expression and a message to check and make sure that the
deletion is allowable according to your business rules.
844
2 Choose the Prev button to get one of the records you created in the last exercise. Since the
new records were created with high customer numbers, they appear last in the record list.
(Cust-Num is the primary index.)
3 Choose Delete Customer. An alert box appears, as shown:
An alert box is a sophisticated alternative for sending messages to the status area. The
status area is an extension of the window widget and so is the alert box.
845
846
847
A special VIEW-AS syntax on a MESSAGE statement reroutes a message from the status
area to an alert box. The UPDATE option and variable captures the users response to the
question.
2.
3.
4.
5.
Reopening the query rebuilds the results list without the newly deleted record.
6.
7.
Practice Problems
Problem 8-4:
lt-08-s4.p
Make a copy of your solution to problem 8-3. Add the ability to create new customer records and to delete
customer records using the techniques covered in this chapter.
848
8.10
8.10.1
The PROMPT-FOR statement accepts data from the keyboard to the screen buffer, as shown in
Figure 816.
Screen Buffer
Figure 816:
User Input
field
| SPACE [ ( n ) ]
| SKIP [ ( n ) ]
} ... { [ frame-phrase ] }
Like UPDATE, PROMPTFOR has implied application blocking.
849
8.10.2
SET works like a PROMPT-FOR followed by an ASSIGN statement. Figure 817 shows the
data movement with SET.
Record Buffer
Figure 817:
Screen Buffer
User Input
You use SET when you dont need to execute any tasks between the time that the data is in the
screen buffer and moves to the record buffer. This is a partial syntax for the SET statement.
SYNTAX
SET
field
| SPACE [ ( n ) ]
| SKIP [ ( n ) ]
} ...
{ [ frame-phrase ] }
SET also has implied application blocking.
850
8.10.3
The INSERT works like a combined CREATE and UPDATE statement. Typically, you use
INSERT only when you are creating a lot of records, like when you create a new database from
scratch. Figure 818 shows the data movement of the INSERT statement.
Database
Figure 818:
Record Buffer
Screen Buffer
Record Buffer
Screen Buffer
User Input
EXCEPT field
... ] { [
frame-phrase
]}
851
8.10.4
The data widgets youve used so far represent a single variable or database field. The browse
widget goes beyond that and represents the results list of a defined query. Basically, you can
think of a browse widget as a selection list of database records. Instead of listing a single value
on each line of the list, browse widgets let you list values from several fields.
You can use a browse widget to display or update record values. When you use a browse for
display only, it is called a read-only browse. Figure 819 describes the parts of a read-only
browse widget.
Column Labels
Viewport
Highlight Bar
Record
Figure 819:
852
Selectable
Column Labels
Row Marker
Selected Row
Figure 820:
Like the other widgets youve used so far, the browse widget is a screen object. You can
manipulate the browse widget in many of the same ways you manipulate the other widgets. The
browse widget is a ready-made navigable interface to a query.
853
Figure 821:
To completely understand browse widgets, you need to understand how to work with the screen
object and how to work with the associated query.
NOTE:
854
The type of row marker indicator that displays can vary depending on the platform
on which you are running the Progress character client.
The mouse cannot be used to select and access records from either a read-only or an
updatable browse widget when the browse widget is displayed in character client
mode on Windows platforms. You must use the keyboard features.
{
[
[
expression
format-phrase
browse-enable-phrase
browse-options-phrase
][
LABEL label
] } ...
]
]
Table 83 defines some of the elements of the DEFINE BROWSE statement syntax.
Table 83:
Element
browse-name
query-name
To specify the name of the query with which the browse is associated.
expression
To specify the field or expression for each column. You can include a
format phrase and LABEL option for each field reference.
format-phrase
LABEL
enable-phrase
options-phrase
855
856
Key Function
(Space Bar)1
(Space Bar)
(1 of 3)
Description
Edit mode:
Enters a space or zeroes numeric data in the
focused cell.
Row mode:
Fires the VALUE-CHANGED event.
CURSOR-LEFT
Edit Mode:
Moves the cursor one character to the left in
the cell.
(Does not leave the cell.)
Row mode:
Scrolls the browser widget horizontally one
column to the left.
CURSOR-RIGHT
Edit mode:
Moves the cursor one character to the right
in the cell.
(Does not leave the cell.)
Row mode:
Scrolls the browser widget horizontally one
column to the right.
CURSOR-DOWN
Edit mode:
Moves focus down to the next cell in the
column.
Row mode:
Moves focus down one row.
CURSOR-UP
Edit mode:
Moves focus up to the previous cell in the
column.
Row mode:
Moves focus up one row.
857
Key Function
BACK-TAB
(2 of 3)
Common
Keyboard
Mappings on
Windows
CTRL-U
Description
Edit mode:
Moves focus to the previous enabled cell in
the browse
(right to left; bottom to top).
Row mode:
No function.
EDITOR-TAB
CTRL-G
Edit mode:
Moves focus to the next enabled cell in the
browse
(left to right; top to bottom).
Row mode:
No function.
END
END
Edit mode:
Moves focus to the last cell in the current
column.
Row mode:
Moves focus to the last row in the browse
widget.
HOME
HOME
Edit mode:
Moves focus to the first cell in the current
column.
Row mode:
Moves focus to the first row in the browse
widget.
PAGE-DOWN
PAGE-DOWN
Edit mode:
Pages down one full page of data.
Row mode:
Pages down one full page of data.
PAGE-UP
PAGE-UP
Edit mode:
Pages up one full page of data.
Row mode:
Pages up one full page of data.
858
Key Function
REPLACE
CTRL-ALT-R
(3 of 3)
Description
Edit mode:
Changes the browser to row mode, with
selection set to the currently focused row.
Row mode:
Changes the browser to edit mode and places
focus in the first enabled cell
of the currently focused row.
If you define the browse with the
NO-ROW-MARKERS option, REPLACE
has no effect.
RETURN
ENTER
Edit mode:
Moves focus to the next cell in the current
column.
Row mode-Fires the DEFAULT-ACTION
event.
TAB
TAB
Note that Progress has no key function identifier for the space bar. In code, you reference a character string
containing a single space (" ")
859
Accepts input focus by way of the navigation key functions (such as TAB) or the mouse.
Moves input focus among the records with the arrow keys.
ENTRY Occurs when the user enters the named column in the focused row.
LEAVE Occurs when the user leaves the named column in the focused row.
START-SEARCH Occurs when the user chooses a column label and enters search
mode.
END-SEARCH Occurs when the user selects a row or starts to edit a browse cell after
a START-SEARCH has occurred.
860
ROW-LEAVE Occurs when the user or system moves focus away from a row.
1 Open lt-08-07.p and run it. The Database Access Form appears.
2 Select an item using the row marker to the left of the row.
3 Click on a cell other than the Item Number. Make a change in the Item-Name, Price,
On-hand, or Cat-Description field.
4 Move focus to another row. Notice that Progress saved your changes to the updated field.
5 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
861
/*2*/
/*3*/
/*4*/
These notes explain the highlights of the first part of the programming example:
862
1.
To use a browse with a query, include the SCROLLING option on the DEFINE QUERY
statement.
2.
This statement defines the browse widget, the fields it displays, and the number of rows it
shows at one time. The ENABLE option defines this as an updatable browse where all
fields except Item-Num can be changed.
3.
These statements define the widgets and frames for the procedure.
4.
These notes explain the highlights of the second half of the programming example.
1.
This DO statement executes when changing focus from a row in browse Item-Browse. For
new records, the IF...THEN statement updates the browse.
2.
The INPUT BROWSE option of the ASSIGN statement writes the new information to the
database.
3.
4.
This statement displays the Item-Num assigned to a new record by the database.
5.
863
864
Moving columns
Locking columns
Calculated fields
Searching
8.11
Summary
Primarily, you work with three data locations:
Databases
Memory used to store records that the procedure is working with, called record buffers
Memory used to store data that is visible on the screen, called screen buffers
Progress creates and maintains buffers for you, but you programmatically control the movement
of data between buffers. Some rules about data and buffers:
Procedures cannot interact with data until the data is copied to the record buffer from the
database.
End users cannot work with data until it is copied from the record buffer to the screen
buffer.
Changes made to one buffer do not automatically affect the other buffer.
To make an unambiguous reference to a database field, specify the database name, table name,
and field name using this syntax: database.table.field
The following list summarizes the data handling statements:
GET Copies data from the database to the record buffer. You use GET with a defined
query. Progress has three statements that control defined queries:
OPEN QUERY Uses the record phrase to define the records that are part of the
query.
DISPLAY Moves data from the record buffer to the screen buffer.
ASSIGN Moves data from the screen buffer to the record buffer.
RELEASE Prematurely releases a record from the record buffer to the RDBMS.
865
CREATE Adds a new record to the database and copies the empty record to the record
buffer.
DELETE Marks a record for deletion and releases the record to the RDBMS for
eventual removal from the database.
PROMPT-FOR Allows user input from the user to the screen buffer.
When working with records, your procedures should handle the basic error processing
associated with not finding a record. Using the NO-ERROR option suppresses the Progress
default error response. Use the AVAILABLE function to test the record buffer before
attempting to use the buffer.
The PROMPT-FOR, SET, UPDATE, and INSERT statements all have implied blocking
properties. These statements block execution until the user issues either a GO event or an
ENDKEY event. Because of this behavior, these statements must never be mixed with
WAIT-FOR statements.
To facilitate the GO and ENDKEY events more easily, you can associate buttons with the
events using the AUTO-GO and AUTO-ENDKEY options in a DEFINE BUTTON statement.
The length of time a record stays in the record buffer is called the scope of the record. As a very
general rule of thumb, a records scope ends when a new record is requested or the block in
which the buffer was created ends.
Alert boxes are extensions to the window widget that provide important information to users
and disable the rest of the interface until the user responds to the alert box.
A browse widget is a specialized selection list for displaying data from database tables:
866
The most common event function for the browse widget is VALUE-CHANGED.
VALUE-CHANGED executes every time you change the row focus of the browse
widget from one row to another.
9
Selecting, Sorting, and Relating Records
This chapter describes the important options of the record phrase and how to use them in the
context of an interactive database form. The options contribute to your ability to select a record
or set of records, to sort records, and to relate records from different tables.
Specifically, the chapter covers:
For more information on the record phrase and database access techniques, see the Progress
Programming Handbook.
9.1
The FIND statement locates an individual record. The record phrase options help specify
the record.
The FOR EACH block is most valuable in batch applications where records are processed
linearly. The options of the record phrase help select which records are executed with the
statements inside the block. You can also sort and relate records with the FOR EACH
block.
The OPEN QUERY statement establishes a results list of records. Record phrase options
help select, sort, and relate the records to form the results list.
To continue the focus on interactive database applications, this chapter teaches record phrase
options in the context of a defined query. Notes along the way point out any significant
differences in the use of an option with FIND or FOR EACH.
9.2
Selecting Records
Record selection is the process of distinguishing which records are part of the set you want to
work with and which are not. In a defined query, the results list represents the set of records you
want to work with. With the results list established, you can ignore all the other records in the
table. For example, you might want to select just those customers who have a balance due, or
those items that are on order. This section describes the two main options for selecting records.
As a refresher, this is the basic syntax for the OPEN QUERY statement.
SYNTAX
OPEN QUERY query-name FOR EACH record-phrase
92
[
[
WHERE expression
USING
AND
[
[
FRAME frame
FRAME frame
]
]
field
field
] ...
]
Table 91 introduces the record phrase selection options.
Table 91:
Component
Description
record-name
WHERE
USING
93
9.2.1
Any valid Progress expression can be used with WHERE to select records. The code fragment
below shows an example:
OPEN QUERY My-Query FOR EACH Customer WHERE Customer.Country = "USA".
In addition to the expressions you learned about in Chapter 5, Working with Expressions,
WHERE supports operators that make working with CHARACTER data easier:
BEGINS
MATCHES
CONTAINS
This example of BEGINS finds any record where the field reference begins with the same letters
as specified in the option:
OPEN QUERY My-Query FOR EACH Customer WHERE Customer.Name BEGINS "Smith".
The output from this selection criteria includes Smith, Smithers, Smithy, and so on.
This example of MATCHES finds any record where there is an exact match between the
supplied string and the database field reference:
OPEN QUERY My-Query FOR EACH Customer WHERE Customer.Name MATCHES "Tim".
This example finds Tim. However, MATCHES is very slow compared to using BEGINS. In
most cases, substituting the = operator is far more efficient than using MATCHES.
You can use two wildcards with the MATCHES options, and this is the only use where
MATCHES has an advantage over the other comparison operators. Use asterisk (*) to take the
place of many characters and period (.) to take the place of a single character as shown in the
following example:
OPEN QUERY My-Query FOR EACH Customer WHERE Customer.Name MATCHES "T.m".
94
When a field is defined as a word index in the database schema, you can use the CONTAINS
option. CONTAINS checks whether the supplied string is contained anywhere in the field
reference. Review the following code example that presents the CONTAINS option:
OPEN QUERY My-Query FOR EACH Customer WHERE Customer.Comments CONTAINS
"volleyball".
9.2.2
The USING option allows you to match a screen value for a database field with records that
have that value. In this example, the new query will build a results list of Customer records that
have the same postal code as the current screen value of Postal-Code:
OPEN QUERY My-Query FOR EACH Customer USING Postal-Code.
In this example, the new query will build a results list of Customer records that have the same
postal code and the same country name as the current screen value of Postal-Code and Country:
OPEN QUERY My-Query FOR EACH Customer USING Country AND Postal-Code.
The examples assume that a user has entered a value for Postal-Code and Country. Progress
attempts to match these values to database records.
You can code similar functionality by prompting the user to enter a value into a variable, then
using that variable in a WHERE clause, as shown below:
OPEN QUERY My-Query FOR EACH Customer WHERE Cust-Num = My-Variable.
95
9.2.3
2 Choose the first Query button. The following browse widget appears with the results of
the query. In the status area, notice the message that shows the selection syntax used in the
particular OPEN QUERY statement:
96
97
These notes help explain the code, describing how to query and use the browse widgets:
98
1.
Even though the procedure makes several queries, each query uses the same table (Item)
and only one query is active at a time. Therefore, you need only one defined query.
2.
Similarly, although the procedure uses the browse widget to display several queries, only
one is displayed at a time.
3.
The first query uses a WHERE expression to display all the inventory items with item
numbers greater than 45.
4.
The second query uses a WHERE BEGINS query to list all the items with names that
begin with "ski".
5.
The third query uses a WHERE MATCHES query to see if any of the item names end with
"ball".
6.
The fourth query uses the USING option to allow the user to define the query. The USING
item accepts a screen value for a table field, then finds the records that have that value.
9.3
Sorting Records
This is the syntax for using the OPEN QUERY statements sorting options.
SYNTAX
OPEN QUERY query FOR EACH record-phrase
BY expression
record-name
DESCENDING
USE-INDEX index
] ] ...
]
Component
Description
BY expression
ASCENDING
DESCENDING
Ascending sorts begin with the lowest value and go to the highest
value (A, B, C, D). Descending sorts start with the highest value and
go toward the lowest value (Z, X, Y, W). By default, sorting is always
ascending, so you dont need to specify the ASCENDING keyword.
To use descending order, you must specify the DESCENDING
keyword in the BY phrase.
USE-INDEX
9.3.1
You use the BY option to sort by a field that is not indexed. The other sort options work
efficiently with indexed fields, but work less efficiently with non-indexed fields. BY can work
with either, which makes it the most useful sorting option.
There are three basic techniques to sorting with BY:
BY field
BY expression
99
The first example selects all United States-based companies and sorts the records by postal
code, which is the ZIP code. This code could be used with an envelope-printing procedure to
meet the sorting requirements of the U. S. Postal Service.
You can use multiple BY phrases in the same query as this example shows:
FOR EACH Customer BY Country BY Postal-Code
The first BY option is the primary sort order, and the second is the secondary sort order, and so
on. In other words, this code first sorts the customers by their base country. Records within each
country group are then sorted by postal code. With just a little more code, youve
internationalized your envelope application.
Using Expressions with BY
The BY option can accept more than just database fields. You can also create expressions based
on fields and sort by the results. See Chapter 5, Working with Expressions, for more
information on valid expressions.
For example, suppose you need to code a browse widget to show the insurance charge for
shipping a particular item. Insurance costs either $1 or 1% of the list price, whichever is higher.
You can calculate the insurance based on the Price database field. If you sort the records in the
browse descending by the insurance charge, then the sales representatives can quickly see which
items have an insurance charge of more than $1.
910
As you can see, for each record, the procedure calculated the cost of shipping insurance.
Since this is a descending list, you can quickly pick out which items cost more than $1 to
insure.
911
/*2*/
NOTE:
In the widget definition statement, you include space for a calculated field (Price / 100),
which is a temporary new field based on the value of other fields.
2.
In the OPEN QUERY statement, you use the expression that corresponds to the calculated
field in order to sort the calculated field. The descending option places those products with
higher insurance charges at the top of the list.
9.3.2
The USE-INDEX option of the record phrase allows you to choose the defined index by which
you want to access the selected records. Usually, its more efficient to use BY and let Progress
pick the indexes for you. Since FIND does not support BY, USE-INDEX comes in handy with
this statement. Review the following code example that presents the USE-INDEX option:
OPEN QUERY My-Query FOR EACH Item WHERE Price > 50 USE-INDEX Item-Name
In this example, the records for all items over $50 are sorted by product name.
912
9.3.3
Follow these steps for a demonstration of combining sorting options with selection options:
2 Choose the BY ASCENDING Price button. A browse widget appears with the results of
the query. In the status area, notice the message that shows the selection and sorting syntax
used in the OPEN QUERY statement.
3 Choose the next two buttons.
4 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
913
914
The BY phrase sorts the selected records by a non-indexed field, Price. The sort is
ascending by default.
2.
This BY phrase also sorts the selected records by Price, but the DESCENDING option
forces a descending sort.
3.
The USE-INDEX option makes clear to the query which of the defined indexes to use for
the sort order. Again, this sort is ascending by default.
Practice Problems
Problem 9-1:
The code for the first example, lt-09-01.p, provides a nice shell for creating your own queries. Make a
copy of the procedure and use it to experiment with querying. Use the different selection and sorting
techniques. Also try using a different database table.
9.4
Relating Records
Imagine that a sales manager at All Around Sports discovers that a shipment of a best-selling
product is a month late from the manufacturer and may be delayed for another three weeks. The
sales manager wants to write to the affected customers about the delay. All Around Sports asks
you to come up with a quick computer solution. You decide to write a procedure to generate a
letter for each customer. However, the information you need for this project is in different
tables. You need to:
In a paper system, finding related data in different tables would be a tedious manual task. In
some databases, youd also have a hard time accomplishing this task. You need to use a
relational database to put together data from related files, and youve got one with Progress.
This process is also called joining tables or creating a join. For more information on joins, see
the section on inner and outer joins later in this chapter.
915
9.4.1
The most powerful advantage an electronic filing system has over a paper filing system is the
ability to process data based on the relationships of the database tables to each other. When a
database uses table relationships in this way, it is called a relational database.
Database table relationships are called relations. Two records from different database tables are
said to have a relation if each contains a field with identical data, as shown in Figure 91.
Customer Record
Relation
Order Record
Customer No.
Customer No.
Name
Order No.
10
11/23/93
Street
79 Farrar Ave
Promised...
City
Yuma
Shipping Date
State
AZ
Terms
Net30
ZIP Code
85369
Shipped?
Not Shipped
Figure 91:
Table Relations
Two fields in two different tables contain the same data. Although the field names in Figure 91
are identical, they dont have to be to form a relation. Relations are the result of good database
design. When you read the Progress Database Design Guide, youll find a lot of information
about normalization through the development of relations. Normalization is the database design
principle that seeks to eliminate redundant data. In Figure 91, notice that the Order record does
not contain the name or address of the customer. It doesnt need to because that information is
already stored in the Customer record. However, you do need one field to associate this
particular order with a particular customer. The Customer Number field serves this purpose.
Now youve minimized the redundant data and established a common link between the two
tables.
Its important to understand that normalizing your database in this manner does not create
relationships. Relationships are created programmatically. However, good database design sets
the preconditions for effective relationships.
916
Order-Line
Figure 92:
Item
One-to-one Relationship
When one record can relate to many records in another table, it is called a one-to-many
relationship. For example, each customer can have several orders. In other words, each
customer number can occur only once in the Customer table, but can occur many times in the
Order table. This relationship is shown in Figure 93.
Customer
Figure 93:
Order
One-to-many Relationship
You may also suspect that there is a many-to-one relationship. However, a many-to-one
relationship is just an inverted one-to-many relationship. In other words, instead of saying one
customer can have many orders, you can say many orders relate to one customer. Both
statements define a one-to-many relationship.
917
9.4.2
Your tools for creating relationships among tables are the same statements that youve been
working with throughout this chapter. Instead of working with a single table, you can use the
same statements to work with more than one. This section introduces the new options that help
with this task.
This is the relevant FOR EACH syntax.
SYNTAX
FOR EACH record-phrase
, EACH record-phrase
, EACH record-phrase
] ...
918
OF table
] [
WHERE expression
] ...
Component
Description
Allows you to relate two tables. You can use OF only when the two
tables share an identical field and that field is indexed in at least one
of the tables.
OF table
WHERE
Relates two tables in the same way OF does. With WHERE, however,
the fields do not need to be indexed and they dont have to have the
same name.
expression
EACH
record-phrase
9.4.3
Relating with OF
Relating records in a query means that you are building a meaningful data set with data from
more than one table. The examples for the rest of this chapter display the data sets you build in
browse widgets, but the task of combining data for reports is also a very important one. Chapter
10, Creating Reports, discusses this important topic.
One of the sales reps asks you to write a browse procedure that shows all the outstanding orders
for each customer. That way, when a customer calls about an order, the customer doesnt
necessarily have to have the order number.
The name of each customer is in the Customer table in the Name field. The order number is in
the Order table in the Order-Num field. To put the data set together, you need to search for and
compare records from two tables in one process. You cant make the search and comparison
unless there is a key between the two tables. A key is a field that holds common data.
919
For the OF keyword to properly detect a relationship between two tables, only one
such relationship is allowed. If there are two or more fields in two tables with the
same name and at least one of each is indexed, a relationship will not be detected.
The OPEN QUERY statements youve seen so far search through one table. You need to search
through two. So, it makes sense that you need two search phrases as the following code example
shows:
OPEN QUERY My-Query FOR EACH Customer, EACH Order
This is where you use the EACH phrase. Each EACH searches a different table. But, this syntax
still doesnt relate the tables. You have to use OF as the following code example shows:
OPEN QUERY My-Query FOR EACH Customer, EACH Order OF Customer
OF relates the second EACH back to the first EACH. The result is that the first Customer record
is found. Next, Progress finds every Order record that has the same Cust-Num as the first
Customer record.
920
2 Scroll through the records. The browse lists only Customers with current orders, and lists
every order number for customers with multiple orders.
3 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
921
/*2*/
Since you need to work with more than one table, you have to list the tables in the DEFINE
QUERY statement.
2.
This code searches for and does an implicit comparison on the Cust-Num key field.
9.4.4
You can also relate tables with WHERE. There are two scenarios where you must use WHERE:
In both of these cases, you may want to reconsider your design. Consider adding an index or
changing the name of the field.
922
OF implicitly compares the keys, while WHERE explicitly compares the keys. At compile time,
Progress turns an OF into a WHERE expression. For that reason, you should consider OF a
shortcut and use WHERE most of the time.
Follow these steps for a demonstration of the last exercise reworked to use WHERE:
1 Open lt-09-05.p and run it. The same display as in the last exercise appears:
Exercise
923
2 Scroll through the records. As you can see, the same data is present.
3 Choose Exit, then press SPACEBAR to return to the Procedure Editor.
Here is the code that created the display:
lt-09-05.p
/********** DEFINE QUERIES **********/
DEFINE QUERY New-Query FOR Customer FIELDS (Name Cust-Num),
Order FIELDS (Order-Num Cust-Num).
/********** DEFINE WIDGETS **********/
DEFINE BROWSE New-Browse QUERY New-Query
DISPLAY Name SPACE(3) Order-Num WITH 12 DOWN.
DEFINE BUTTON btn-Exit LABEL "Exit".
/********** DEFINE FRAMES **********/
DEFINE FRAME Frame1
New-Browse AT ROW 1 COLUMN 2
btn-Exit
AT ROW 1 COLUMN 50
WITH NO-BOX CENTERED THREE-D.
/*1*/
As shown at point 1, you still need the additional EACH to search through the second table. The
WHERE expression causes an explicit mathematical comparison between key values.
9.4.5
You have learned that you can refer to multiple tables in a single statement using a join. A join
is a binary operation that selects and combines the records from multiple tables so that each
result in the results list contains a single record from each table. A join combines the records
from one table with those from another table or a previous join.
When you specify a join, you also specify conditions that determine how one table relates to
another. These are called join conditions. Join conditions control which records selected from
one table join with the records in the other table.
924
Inner join Supported in all statements capable of reading multiple tables, including the
FOR, DO, REPEAT, and OPEN QUERY statements. An inner join returns the records
selected for the table (or join) on the left side of the join with the related records selected
from the table on the right side of the join. If a value in the left table does not have a
corresponding value in the right table, Progress does not return that value or a result for
the results list. This is an example of an inner join with the FOR statemen:.
In this join, Table1 is on the left side of the join and Table2 is on the right, and
Field1 = Field3 is a join condition. For any records not selected from Table2, the join
returns no records from either the Table1 or Table2. Only records that are selected from
both tables are returned for an inner join.
Left outer join Supported only in the OPEN QUERY statement. An outer join returns
the same set of records selected for an inner join. However, outer joins also return all the
records from the left table. When a value from the left table does not have a corresponding
value in the right table, Progress returns the left-table value with an unknown value (?)
from the right table. This is an example of a left outer join with the OPEN QUERY
statement:
In this join, Table1 is on the left side and Table2 is on the right, and Field1 = Field3 is a
join condition.
925
Table1
Field1 Field2
Join
Where
Field1 = Field3
Table2
Field3 Field4
Join12
Field1 Field2 Field3 Field4
Figure 94:
926
Inner Join
Table1
Field1 Field2
Join
Where
Field1 = Field3
Table2
Field3 Field4
Join12
Field1 Field2 Field3 Field4
Figure 95:
927
Practice Problems
Using a copy of procedure lt-09-04.p as a starting point, figure out the correct syntax for these queries:
Problem 9-2:
lt-09-s2.p
Display the customer name and the sales representative for each customer. What kind of relationship is
this?
Problem 9-3:
lt-09-s3.p
For each customer, list all the product names currently on order. What type of relationship is this?
9.5
Summary
This chapter explained how to select, sort, and relate records from different tables.
Selection Options
These options allow you to specify which records to retrieve:
928
The WHERE option uses any valid Progress expression to select records. WHERE
supports options that allow you to specify how to select CHARACTER data:
BEGINS finds records where the field begins with a particular string.
MATCHES finds records where the field matches a string, but should only be used
with wildcards, since the = operator is much more efficient for full string matches.
The BY phrase allows you to sort by one or more fields (these dont have to be indexed)
or by expressions based on fields.
Relating Records
Database tables have a relationship if they have a field with identical data in common. There are
two kinds of relationships between tables:
A one-to-one relationship occurs when one record in a table relates to only one record in
another table.
A one-to-many relationship occurs when one record can relate to many records in another
table.
The field with identical data that is held in common between two tables is called the key.
Three options allow you to establish relationships between database tables:
The OF option allows you to relate tables in a search by specifying the key field. The key
must be an indexed field in at least one of the tables.
The WHERE option relates tables in which the key is not an indexed field, or the key field
doesnt have the same name in both tables.
929
930
10
Creating Reports
A database management system provides information that helps an organization run efficiently.
A reportwhether printed on paper, viewed on a workstation, or stored on mediais a
common tool for distributing database information.
This chapter introduces you to the 4GL statements that you can use to generate reports, both
simple and complex. Specifically, it discusses these topics:
Report basics
10.1
Report Basics
The event-driven model provides a highly flexible environment for interactive applications.
Reports collect and organize static data without interaction from the user, so traditional
top-down programming techniques work better for this task. Typically, you can integrate a
report-generating procedure into an event-driven application using a trigger with a RUN
statement attached to a button or menu command (covered later).
The components of a basic report procedure include:
A special type of frame, called a down frame, that can hold more than one iteration of data
Text widgets
An output statement
10.1.1
Down Frames
Like an interactive display, a frame is the data container for reports. However, unlike a display
frame, a report usually contains more than one iteration of data. A frame that can contain more
than one iteration of data is known as a down frame. (Sometimes a frame with a single iteration
of data is called a one-down frame.)
Early on, you learned that a frame is a container for field-level widgets (data widgets, action
widgets, graphic widgets). Actually, its a bit more complicated than that. All the widgets
included in a one-down frame are contained in a special widget called a field-group widget. The
frame contains the field-group widget. When you display several iterations of data, the widgets
of each iteration belong to a single field-group widget, and the frame contains the set of field
group widgets.
The behind-the-scenes work of the field-group widget is rarely something that you need to track.
The explanation above simply serves to explain the mechanics of a down frame in terms of the
programming model.
102
Creating Reports
The default frame of an iterating control block, like FOR EACH, is a down frame. You can also
specify a down frame with the DOWN keyword of the frame phrase. DOWN used alone
indicates that you want Progress to fit as many iterations in the frame as the screen can hold.
Here is an example:
DEFINE FRAME Frame1
sports.Customer.Name
WITH DOWN CENTERED THREE-D.
Specifying an integer before DOWN indicates the maximum number of iterations the frame can
hold. Here is an example:
DEFINE FRAME Frame1
sports.Customer.Name
WITH 12 DOWN CENTERED THREE-D.
10.1.2
Text Widgets
The text widget displays textual data without the decorations native to your windowing system.
This means that data displays more compactly, so more iterations fit in a single display or
printed page.
If you are working with fields or variables that use the fill-in field as the default data widget,
then the USE-TEXT option of the frame phrase quickly converts the fill-in fields to text
widgets. Here is an example:
DEFINE FRAME Frame1
sports.Customer.Name
WITH DOWN USE-TEXT CENTERED THREE-D.
If the default data widget is anything other than a fill-in field or text widget, you need to use the
VIEW-AS TEXT option of the format phrase on each widget to convert the widget to a text
widget. Here is an example:
DEFINE VARIABLE Bal-due AS LOGICAL LABEL "Balance Due?"
VIEW-AS TOGGLE-BOX.
DEFINE FRAME Frame1
sports.Customer.Name /* default is a fill-in field */
Bal-due VIEW-AS TEXT /* default is a toggle box */
WITH DOWN USE-TEXT CENTERED THREE-D.
103
10.1.3
Compiling a report usually involves a straightforward process of moving through a set of table
records, calculating data, and outputting results. A control block best handles the
report-generating process. Most reports use the FOR EACH block because of its record-reading
properties. Here is an example:
FOR EACH Customer FIELDS (Name) WITH FRAME Frame1:
IF BALANCE > 0 THEN Bal-due = YES.
ELSE Bal-due = NO.
DISPLAY Name Bal-due.
END.
104
Creating Reports
10.1.4
Follow the steps below for a demonstration of Progress behavior when displaying a report to
your screen:
Exercise
1 Open lt-10-01.p and run it. Progress creates a down frame that occupies all the vertical
space it can and fills the frame with iterations of data, as shown below:
Notice the message at the bottom of the screen. Progress pauses to allow you to view the
first frame of data.
2 Press SPACEBAR. Progress clears the down frame and fills it with a new set of iterations.
3 Press END-ERROR and then SPACEBAR to return to the Procedure Editor.
105
NOTE:
106
1.
The default data widget for this LOGICAL variable is a toggle box, making the VIEW-AS
TEXT phrase necessary to convert it to a text widget.
2.
The frame phrase of the DEFINE FRAME statement contains two key options: DOWN
and USE-TEXT. The DOWN keyword specifies a down frame that automatically expands
to fit as many iterations as the screen can hold. Specifying an integer before DOWN sets
the maximum number of iterations the frame can hold. USE-TEXT converts all fill-in
fields into text widgets for a compact display.
3.
Since the great majority of reports compile and manipulate table data, the FOR EACH
statement is the most common control block used for report procedures. The frame phrase
here replaces the default down frame with the named down frame defined earlier.
4.
The DISPLAY statement is the most commonly used output statement. As youll see later,
DISPLAY can output to terminals, printers, or files.
Creating Reports
The type of report display created by procedure lt-10-01.p does not fit well with the
event-driven model because the user:
The next section describes a technique for viewing reports that better suits the event-driven
model.
10.2
A dialog box to contain the output. Therefore, you wont need to leave room on your main
display for the report data.
2.
An OK button in the dialog box to let the user dismiss the report.
3.
A temporary file to contain the report data. Having the control block output to a temporary
file eliminates the pausing behavior.
4.
An editor widget with scrollbars to read the file into. The scrollbars let the user navigate
the report in two directions.
107
108
Creating Reports
The report data appears in an editor that you can scroll through.
109
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
/*7*/
/*8*/
1010
Creating Reports
These notes explain the new code techniques used in this example:
1.
2.
The OUTPUT TO statement is your tool for directing output. This example directs output
to the named file. This chapter covers directing output more fully in a later section.
3.
This FOR EACH uses the default down frame, and the STREAM-IO option reduces all
widgets to textual data without decorations. Using the STREAM-IO option is a
requirement when outputting to any destination other than the screen.
4.
Once you direct output to a destination, you need to close the output stream to return
output to the default destination, which is the screen.
5.
This ASSIGN statement manipulates three editor attributes and one method to set up the
dialog box. The READ-ONLY attribute prevents changes to the report content. The
SENSITIVE attribute enables the editor, making the scrolling functions available. The
TITLE attribute contains the dialog box title text. The READ-FILE method takes a valid
filename and returns YES or NO to indicate if Progress successfully read the file contents
into the editor.
6.
You only want to bring up the dialog box if the logical variable stat equals YES, which
means that Progress successfully read the file into the editor.
7.
If you use a WAIT-FOR statement in a dialog box, you must use the HIDE statement to
dismiss the dialog box.
8.
On all platforms that Progress supports, the output font designated by 3 is always a
monospaced font, which are frequently used in printed reports. Assigning this font makes
the editor contents mimic a printed report.
1011
10.3
Using the STREAM-IO option of the frame phrase to convert all data widgets in a frame
to text widgets
Using the editor for formatting long text strings as blocks of text
10.3.1
For toggle boxes, radio sets, sliders, combo boxes, and selection lists, trying to output the widget
to any other device besides the screen yields nothing. Neither the widget nor the value it
contains appears in files or printed reports.
Rather than tack a VIEW-AS TEXT phrase onto every widget, you can use the STREAM-IO
option of the frame phrase to reduce every widget to textual data. Here is an example:
DEFINE VARIABLE Bal-due AS LOGICAL LABEL "Balance Due?"
VIEW-AS TOGGLE-BOX.
DEFINE FRAME Frame1
sports.Customer.Name
Bal-due
WITH DOWN STREAM-IO CENTERED THREE-D.
You must use the STREAM-IO option on every output frame intended for a destination other
than the screen.
Although primarily a tool for sending data to files and reports, the STREAM-IO option also
reduces all widgets to textual data for screen output. This exercise demonstrates the effects of
the STREAM-IO option on screen data. Perform the following steps:
Exercise
1 Open lt-10-03.p and run it. This report is the same as the one from the last exercise, but
without the special interface.
2 Press END-ERROR and then SPACEBAR to return to the Procedure Editor.
1012
Creating Reports
3 Remove STREAM-IO from the frame phrase and run the procedure again.
Note that the Bal-Due variable displays as a disabled toggle box in the iterations.
10.3.2
The remaining problem for simple output is how to handle long text strings. A text widget that
contains a long string may cause formatting problems such as skipping to a new line or
truncating. For screen design, you saw earlier that the editor widget is a good choice for holding
long text strings. The editor is also the solution for reports. With the editor, you can output text
in blocks.
For example, the Comments field in the Customer table has a format of x(60). Reserving 60
spaces takes up most of a line in a standard printed report. You can override this default behavior
by specifying a VIEW-AS EDITOR phrase for the Comments field. When you output a field or
variable value as an editor widget, Progress uses the INNER-CHARS attribute of the editor to
format and wrap the text into a block. The INNER-LINES syntax sets the minimum number of
lines the block occupies. If there is enough data to fill more lines than specified by
INNER-LINES, then Progress provides the extra room.
1013
2 Choose Report. The report dialog box appears as shown in the following screen:
As you scroll through the editor, notice the blocks of Comments text.
3 Choose OK, then Exit, and then press SPACEBAR to return to the Procedure Editor.
1014
Creating Reports
Here is the code:
lt-10-04.p
{lt-10-in.i} /* Common Interface Setup Code */
/********** DEFINE TRIGGERS **********/
ON CHOOSE of b-rep
DO:
OUTPUT TO "tut-temp.txt".
FOR EACH Customer WITH STREAM-IO:
DISPLAY Name SPACE(5) Comments VIEW-AS EDITOR
/*1*/
INNER-LINES 3 INNER-CHARS 20.
END.
OUTPUT CLOSE.
ASSIGN Rep-Editor:READ-ONLY IN FRAME Dialog1 = YES
Rep-Editor:SENSITIVE IN FRAME Dialog1 = YES
FRAME Dialog1:TITLE = "Report Output"
Stat = Rep-Editor:READ-FILE("tut-temp.txt") IN FRAME Dialog1.
IF Stat THEN DO:
ENABLE Rep-Editor b-ok WITH FRAME Dialog1.
WAIT-FOR GO OF FRAME Dialog1.
HIDE FRAME Dialog1.
END.
END.
/********** MAIN LOGIC **********/
ENABLE ALL WITH FRAME Frame1.
WAIT-FOR CHOOSE OF b-exit.
INNER-LINES reserves at least three lines per iteration of the report. INNER-CHARS sets the
length of the text block at 25 characters.
INNER-LINES reserves at least three lines per iteration of the report. INNER-CHARS sets the
length of the text block at 20 characters.
This section concludes the basic discussion on creating a reporting procedure. The next few
sections concentrate on the techniques for populating reports with more complex data.
1015
10.4
A control break separates sorted data into meaningful groups. Breaking sorted data by Sales-rep
separates each sales reps customers into a separate break group. Break groups allow you to
calculate summary data on subsets of data. For example, you could total the number of
customers that each sales rep serves.
The BREAK option of the record phrase sets up your data for control breaks, as shown in this
block header statement:
FOR EACH Customer BREAK BY Sales-Rep:
Once youve set up the control break, you can use the aggregate phrase on an output statement
item to calculate summary information. The diagram below shows the syntax of the aggregate
phrase.
SYNTAX
aggregate-option
] ... [
BY break-group
] ...
Aggregate Option
1016
(1 of 2)
Description
AVERAGE
SUB-AVERAGE
COUNT
Creating Reports
Table 101:
Aggregate Option
(2 of 2)
Description
SUB-COUNT
Counts the number of items in the break group, but does not
calculate the overall count.
MAXIMUM
SUB-MAXIMUM
MINIMUM
SUB-MINIMUM
TOTAL
SUB-TOTAL
For example, in the code below, Sales-rep is the control break, Balance is the expression, and
the aggregate phrase with the TOTAL option appears in parenthesis immediately after the
expression in the DISPLAY statement:
FOR EACH Customer FIELDS (Balance Sales-Rep) BREAK BY Sales-rep:
DISPLAY Customer Balance (TOTAL BY Sales-Rep).
END.
The TOTAL aggregate option totals the balances for each break group. Each time the value of
Sales-rep changes in the sorted data, Progress creates another break group, and the TOTAL BY
aggregate function calculates and outputs the total of customer balances for that sales reps
customers. Finally, at the end of the report, the TOTAL option calculates and outputs the total
balances of all the break groups.
1017
2 Choose Report. The report dialog box appears as shown in the following screen:
The members of each break group all have the same Sales-rep value. Notice that the report
separates each break group with white space and outputs the result of the aggregate phrase
options immediately following the break groups.
If you scroll to the bottom of the report, you can see the aggregate values for all the break
groups.
3 Choose OK, then Exit, and then press SPACEBAR to return to the Procedure Editor.
1018
Creating Reports
Here is the code for this procedure:
lt-10-05.p
{lt-10-in.i} /* Common Interface Setup Code */
/********** DEFINE TRIGGERS **********/
ON CHOOSE of b-rep
DO:
OUTPUT TO "tut-temp.txt".
/*1*/
FOR EACH Customer BREAK BY Sales-rep WITH STREAM-IO:
DISPLAY Sales-rep Name
/*2*/
Balance (COUNT TOTAL AVERAGE BY Sales-rep).
END.
OUTPUT CLOSE.
ASSIGN Rep-Editor:READ-ONLY IN FRAME dialog1 = YES
Rep-Editor:SENSITIVE IN FRAME Dialog1 = YES
FRAME dialog1:TITLE = "Report Output"
Stat = Rep-Editor:READ-FILE("tut-temp.txt") IN FRAME Dialog1.
IF Stat THEN DO:
ENABLE Rep-Editor b-ok WITH FRAME Dialog1.
WAIT-FOR GO OF FRAME Dialog1.
HIDE FRAME Dialog1.
END.
END.
/********** MAIN LOGIC **********/
ENABLE ALL WITH FRAME Frame1.
WAIT-FOR CHOOSE OF b-exit.
The BREAK option of the record phrase sets up the control break.
2.
The aggregate phrase after the Balance expression contains three aggregate options.
1019
10.5
Sort information
The reports you have seen so far display data from a single table (the Customer table) and
demonstrate one or two reporting features. Real world reports, however, frequently do a little
bit of everything as they strive to organize lots of information and calculate useful summary
information.
For example, suppose the All Around Sports accounting department needs to analyze
delinquent accounts. To do their jobs, the accountants need information on customers, orders,
and inventory. To get all the data they need, the report requires information from four tables:
the Customer, Order, Order-line, and Item tables. The rest of this section builds a report that
gathers and organizes information from these four tables and performs some summary
calculations on the data.
10.5.1
First, the accounting department needs to sort out which customers have exceeded their credit
limits or those who are close to exceeding the limits. All Around Sports wants accounting to
look at all customers that have balances equal to or greater than 85 percent of their credit limits.
All of this information is in the Customer table.
A single FOR EACH with a WHERE clause is what you need to gather this information. The
code fragment below from lt-10-06.p shows this structure:
lt-10-06.p
.
.
.
FOR EACH Customer FIELDS (Balance Credit-Limit Name Contact)
WHERE Balance >= (Credit-Limit * .85)
WITH STREAM-IO:
DISPLAY Name FORMAT "x(20)" Contact FORMAT "x(15)"
Balance Credit-Limit WITH NO-BOX.
END.
.
.
.
1020
Creating Reports
The WHERE clause selects just the customers over the 85 percent threshold, and the DISPLAY
statement outputs the key information about these customers. Running this procedure yields the
output shown below:
10.5.2
The next step is to look at the orders for each selected customer. This information is in the Order
table. Another FOR EACH inside the first accomplishes this task. For each iteration of the outer
block, the inner block finds all the related information. The WHERE clause establishes the
relationship between the two tables.
1021
The output from this procedure (following) shows how the related information ends up grouped
together:
Notice that for a single iteration of the Customer data, there may be several iterations of Order
data. Earlier you learned that the default frame of an iterating control block is a down frame.
When you nest control blocks, only the innermost block uses a down frame. The other blocks
1022
Creating Reports
execute one iteration at a time. This default behavior lets the related information group together
naturally with the iteration of the blocks.
10.5.3
Each order has one or many order lines, each of which relates to a single inventory item.
Accounting needs to pull information from the Order-Line and Item tables to get specific
information about what was ordered. One more FOR EACH block, inside the existing block,
completes the structure.
Once the procedure gathers all the information, accounting needs the procedure to calculate
total prices. Nested FOR EACH blocks create sorted groups of information similar to break
groups. Therefore, you can use the aggregate phrase to calculate total prices.
This code fragment comes from lt-10-08.p and shows the completed structure of nested FOR
EACH blocks:
1023
lt-10-08.p
.
.
.
FOR EACH Customer FIELDS (Balance Credit-Limit Contact Cust-Num)
WHERE Balance >= (Credit-Limit * .85)
WITH STREAM-IO:
DISPLAY Name FORMAT "x(20)" Contact FORMAT "x(15)"
Balance Credit-Limit WITH NO-BOX.
/*1*/
/*2*/
/*3*/
/*4*/
END.
END.
.
.
.
1024
Creating Reports
These notes explain the code highlights:
1.
The WHERE clause of the third FOR EACH relates the Order-Line table back to the Order
table.
2.
For each Order-Line, there is a single Item record that contains information about the
ordered item. A simple FIND statement retrieves this information.
3.
Here, the report totals the result of an expression. Notice the absence of the BY break
group syntax.
4.
The FORMAT option here specifies a fairly complex format string. The result displays a
leading dollar sign ($), suppresses the leading zeroes (z), and displays the credit symbol
(CR) when the result is a negative value.
1025
10.6
Redirecting Output
A report procedure outputs to the screen by default and takes control of the application by
building reports and pausing one screen at a time. Since this behavior takes control away from
the user, you also learned to create a more user friendly interface for reports based on the
OUTPUT TO statement. Essentially, report output gets redirected from the screen to a
temporary file, and then the procedure reads the report results into an editor in a dialog box. This
section discusses the OUTPUT TO statement and shows you how to send report output to text
files and printers. Other uses include sending reports to text tables or UNIX devices. See the
Progress Language Reference for more information about these uses of the OUTPUT TO
statement.
10.6.1
A stream is a path for data movement. In this case, a stream is a path for output to a named
destination. Every Progress procedure has one unnamed default output stream that writes data
to the screen. The OUTPUT TO statement is your tool for redirecting the default stream to
another destination. Once you use OUTPUT TO to change the output destination in a procedure,
the output goes to that destination until you close it with the OUTPUT CLOSE statement, or
until you name a new output destination.
This is a partial syntax for the OUTPUT TO statement.
SYNTAX
OUTPUT
STREAM stream
TO
PAGED
PRINTER
opsys-file
opsys-device
1026
STREAM stream
CLOSE
Creating Reports
Table 102 describes the OUTPUT statement syntax components.
Table 102:
Component
Description
STREAM
Specifies a named output stream. Omit this syntax when using the
default stream.
PRINTER
opsys-file
opsys-device
PAGED
1027
10.6.2
To direct output to a file, use the OUTPUT TO statement followed by the name of the
destination file enclosed in quotes. The destination can include the path, or just the filename. If
you do not provide a path, Progress writes the file to the current directory. If the file does not
exist, Progress creates it. If the file does exist, Progress overwrites its contents.
The following code example is simply the report from the last exercise, removed from the
interface code:
lt-10-09.p
/*1*/
OUTPUT TO "tut-temp.txt".
FOR EACH Customer FIELDS (Balance Credit-Limit Name Contact Cust-Num)
WHERE Balance >= (Credit-Limit * .85)
WITH STREAM-IO:
DISPLAY Name FORMAT "x(20)" Contact FORMAT "x(15)"
Balance Credit-Limit WITH NO-BOX STREAM-IO.
FOR EACH Order FIELDS (Cust-Num Order-Num Order-Date Ship-Date
Promise-Date) WHERE Order.Cust-Num = Customer.Cust-Num
WITH STREAM-IO:
DISPLAY Order-Num Order-Date Ship-Date
Promise-Date SKIP(1) WITH 2 COLUMNS STREAM-IO.
FOR EACH Order-Line FIELDS (Order-Num Item-Num Qty)
WHERE Order-Line.Order-Num =
Order.Order-Num WITH STREAM-IO:
FIND Item WHERE Item.Item-Num = Order-Line.Item-Num.
DISPLAY Qty Order-Line.Item-Num
Item-Name FORMAT "x(13)"
Item.Price LABEL "Unit Price"
Item.Price * Qty (TOTAL)
LABEL "Price" FORMAT "$zzz,zz9.99 CR"
WITH NO-BOX STREAM-IO.
END.
/*2*/
END.
END.
OUTPUT CLOSE.
You can see from the highlighted points that the OUTPUT TO and OUTPUT CLOSE
statements control the stream. Also note that the STREAM-IO option must appear in each
output frame phrase.
1028
Creating Reports
Try running lt-10-09.p and then opening tut-temp.txt in the procedure editor; as you can
see from the figure below, the content of the file matches what the interface showed in the last
exercise:
10.6.3
To direct output to your default printer, use the OUTPUT TO statement with the PRINTER
option. Remember to use the STREAM-IO option in your frame phrases. STREAM-IO removes
all graphical characteristics of the widgets, leaving just the textual data.
You probably also want to use the PAGED option of the OUTPUT TO statement to create neat
page breaks.
Try modifying lt-10-09.p to send the report to a printer, if you have one available. Alternately,
add the PAGED option to the OUTPUT TO statement, run the report, and open tut-temp.txt
in the Procedure Editor.
Notice that Progress redisplays the labels for the current frame after a page break.
To direct output to a printer other than the default printer, use the Printer (-o) startup parameter
to designate a specified printer for the Progress session. For more information, see the reference
entry for the Printer (-o) startup parameter in the Progress Startup Command and Parameter
Reference.
1029
10.6.4
Progress lets you specify multiple output destinations in a single procedure. You can use
OUTPUT TO several times in a single procedure to direct the output to different destinations.
You can also define named streams so you can output to several destinations.
First, you use the DEFINE STREAM statement to create the streams you need. This is a partial
syntax for DEFINE STREAM.
SYNTAX
DEFINE STREAM stream-name
To output to the stream, you reference it in your output statement with the keyword STREAM,
as shown in the following example:
/*1*/
/*2*/
/*3*/
OUTPUT TO PRINTER.
OUTPUT STREAM To-File TO "tut-temp.txt".
/*4*/
/*5*/
/*6*/
/*7*/
1030
1.
When the procedure starts, it has a default unnamed stream that outputs to the screen by
default. This statement establishes a second stream that also outputs to the screen by
default. Both streams are now available for the life of the procedure.
2.
This OUTPUT TO statement redirects the unnamed stream to the the default printer.
3.
4.
5.
6.
This OUTPUT CLOSE statement redirects the default stream back to the screen.
7.
This OUTPUT CLOSE statement redirects the named stream back to the screen.
Creating Reports
10.7
10.7.1
You cannot place an expression in a DEFINE FRAME statement because no values exist at
compile time for Progress to format. Since you often need to put derived data in frames, you
need a way to handle expressions. One solution is to create variables to hold the values. Another
solution provides more flexibility: create variables with the characteristics of the expression
results (data type, formatting, and label) as base fields. You can include the base fields in the
frame definition and then replace the base field with any compatible expression result at run
time using the @ option of the DISPLAY statement.
1031
The example above compiles a phone list of customer and contact names. If no contact is on
file, No Contact appears in the report.
10.7.2
A frame can contain three distinct sections: body, HEADER, and BACKGROUND. Until now,
everything you placed in a frame became part of the frame body. Using the keywords HEADER
and BACKGROUND, you can also define two additional sections for your frames. The code
fragment below shows how a DEFINE FRAME statement with these sections would look:
DEFINE FRAME f-example
body-item1 /* Can be field, variable, constant, image,
body-item2
or rectangle. */
body-item3
HEADER
header-item1 /* Can be field, variable, constant, EXPRESSION,
header-item2
image, or rectangle. */
header-item3
BACKGROUND
background-item1 /* Can be field, variable, constant, EXPRESSION,
background-item2
image, or rectangle. */
background-item3
WITH SIDE-LABELS.
1032
Creating Reports
Frame backgrounds are typically used for placing a logo (image) or other graphic device in the
background of a display frame. However, you cannot print graphics from the Progress 4GL. For
more information, see the Progress Language Reference and the Progress Report Builder
Users Guide. The rest of this section concentrates on the HEADER part of the frame.
The HEADER has a couple of special properties that allow you to implement running page
heads and footers:
Progress suppresses field and variable labels in a header frame. If you want labels, you
supply text strings in the frame definition.
If a HEADER frame contains an expression, field, or variable, the frame definition must take
place in the context where Progress can provide new values. In other words, for an iterating
report procedure, move the DEFINE FRAME statement from the top of your procedure into the
FOR EACH block. Think of a HEADER frame as an executable statement. Just like a
DISPLAY statement inside a FOR EACH block, the HEADER section of the DEFINE FRAME
statement executes on every iteration of the FOR EACH block.
Also, note that a frame does not have to have a bodyit can consist of a header only. You can
modularize your report design with three frames: one each for page header, body, and page
footer. This approach lets you adopt standard headers and footers.
Assume that All Around Sports wants a standard page header on every page of its reports. This
is the information they want to include in the page header:
Date: mm/dd/yy
Title
sales-rep
Page: xxx
This code defines the first part of a procedure that implements the three-frame design:
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/
/*6*/
1033
The PAGE-SIZE option of the OUTPUT statement sets the default size for a report page.
2.
The HEADER option tells Progress to place the specified items in the header section at the
top of the frame.
3.
The TODAY function returns the current system date, and constitutes an expression.
4.
The Sales-rep initials come from the database and represent another part of the HEADER
that Progress must evaluate.
5.
6.
The PAGE-TOP FRAME f-hdr further defines what kind of HEADER the frame is.
PAGE-TOP specifies where to place the frame and makes the frame a running page head.
10.7.3
You can also use the HEADER section to create running page footers. The only difference is
that you specify PAGE-BOTTOM in the frame phrase instead of PAGE-TOP. Heres how All
Around Sports wants their footers to look:
Customer Report continued on next page
Once again, the report needs a DEFINE FRAME statement with the HEADER option as this
code shows:
DEFINE FRAME f-ftr
HEADER
"Customer Report"
"continued on next page"
/*1*/
WITH FRAME f-ftr PAGE-BOTTOM CENTERED STREAM-IO.
The PAGE-BOTTOM option tells Progress to display the frame at the bottom of each page.
PAGE-TOP and PAGE-BOTTOM frames are activated based on DISPLAY or VIEW
statements. They are deactivated when the block to which the frames are scoped iterates or ends,
which is why they have to be viewed in every iteration.
1034
Creating Reports
10.7.4
Programming Example
Notice the header info at the top of each page. As you scroll through, you can see footers
as well.
3 Choose OK, then Exit, and then press SPACEBAR to return to the Procedure Editor.
1035
1036
Creating Reports
The following notes summarize the techniques shown in this chapter:
1.
The body frame, which has no HEADER section, appears in its normal position, at the top
of the file with other definitions.
2.
3.
The use of the control break changes the report output from one report into a series of
smaller reports-one for each sales rep.
4.
5.
6.
7.
8.
The VIEW statements force Progress to evaluate the two HEADER frames on each
iteration of the block.
9.
Here, the report creates an address string and uses the @ option to place the result at the
Holder variable.
10. The LAST-OF function is for checking for the end of a break group, allowing you to
perform special tasks. In this case, the procedure suppresses the page footer because this
break group report is complete. It also uses the PAGE statement to start a new page for the
next break group report.
1037
10.8
[
[
] [ UNFORMATTED ]
expression [ FORMAT string ]
[ AT expression | TO expression ]
| SKIP [ ( expression ) ]
| SPACE [ ( expression ) ]
] ...
STREAM stream
One common task that the PUT statement can help with is mailing labels. Since mailing labels
must conform to a compact physical layout and be uniform, using PUT is a good idea. Suppose
that the All Around Sports accounting department wants to send notices to customers with large
balances. They need a procedure that creates mailing labels for the notices.
1038
Creating Reports
Follow these steps to demonstrate the PUT statement:
The editor shows the mailing list as it appears in a text file. Note that the output is not
perfect:
For simple addresses, there is a blank line between the street address line and the city,
state, postal-code line. Some addresses need this blank line for extra information.
There is too much space between the state and postal code.
3 Choose OK, then Exit, and then press SPACEBAR to return to the Procedure Editor.
1039
1040
1.
The OUTPUT TO statement directs the output from this procedure to a text file named
tut-temp.txt.
2.
You can use the PUT statement in addition to the DISPLAY statement when sending data
to a file or to a printer (any destination other than the screen).
Creating Reports
To improve this procedure, you can:
Remove the blank line from simple addresses that do not use the extra space
If you run lt-10-12.p, you can see the modified version of this procedure. Here is the code for
that version:
lt-10-12.p
{lt-10-in.i} /* Common Interface Setup Code */
/********** DEFINE TRIGGERS **********/
ON CHOOSE of b-rep
DO:
OUTPUT TO "tut-temp.txt".
FOR EACH Customer FIELDS (Balance Postal-Code Contact Name Address
Address2 City St) WHERE Balance >= 1400 BY Postal-Code
WITH STREAM-IO:
PUT Contact SKIP
Name SKIP
/*1*/
Address SKIP.
/*2*/
/*3*/
/*4*/
END.
/********** MAIN LOGIC **********/
ENABLE ALL WITH FRAME Frame1.
WAIT-FOR CHOOSE OF b-exit.
1041
The following notes help explain the techniques used in the procedure:
1042
1.
The first PUT statement outputs and formats the part of the mailing label that is common
to all labels.
2.
The first IF statement determines whether the second address line has data. If it does, it
outputs the data.
3.
When you create a character expression, like the one in this PUT statement, Progress
removes trailing blanks from the fields. So this output tightens up the extra white space
that showed up in the first mailing list example.
4.
Finally, the second IF statement determines whether there is second address line data. If
not, the PUT statement sends a blank line at the end of the address. This statement keeps
the label data together and keeps the individual labels correctly spaced from each other.
Creating Reports
10.8.1
When you send output to a printer, you may want to modify the way the printer generates that
output. Many printers have a set of control sequences you can use to specify different print
characteristics. You might, for example, want to change the number of printed characters per
inch.
When you write a procedure that sends output to a printer, you can include printer control
sequences within that procedure. Many control sequences involve special characters that can be
represented by their octal (base 8) equivalent. To distinguish these octal codes, you precede the
three octal digits by an escape character. Progress then converts the octal number to a single
character.
On UNIX, the escape character is a tilde (~) or a backslash (\).
The PUT statement with the CONTROL option allows you to specify a control sequence to send
to the printer. This is a partial syntax for this version of the PUT statement.
SYNTAX
PUT
STREAM stream-name
...
The control sequences you send to the printer have no effect on the current line, page counters,
and positions maintained within Progress. Assume you want to print a report on your Brand X
printer, using compressed-print mode.
1043
NOTE:
1044
This procedure works only if you have a printer connected to your system. Not all
printers support compressed printing.
Creating Reports
These notes help to explain the code:
1.
The start-compress variable contains the four-character sequence that puts the printer into
compressed-print mode. These four characters are octal 033 (decimal 27) followed by left
bracket ([), 3, and w.
2.
The variable stop-compress takes the printer out of compressed print mode.
3.
When the user selects btn-normal, Progress runs the report in normal mode.
4.
When the user selects btn-compressed, Progress runs the report in compressed mode.
1045
10.9
Summary
This chapter showed how to write Progress procedures that produce both simple and
sophisticated reports.
Generating Simple Reports
You can use the DISPLAY statement to generate a simple report output to the screen from a
single table or from multiple related tables. You can easily format a report to group records and
include calculations with the CONTROL BREAKS option and aggregate functions.
Redirecting Output
The STREAM-IO option allows you to redirect the output of a report-generating procedure to
a printer or text file. This option removes the graphical components of your data. You can also
redirect output to multiple destinations, and you can define multiple streams.
Generating Reports of Data Represented by Widgets
The widgets that deal with text-fill-in field and text widgets-pose no special problems when you
generate reports. However, you must make certain adjustments for widgets that represent data
graphically. There are two ways to handle these widgets in reports:
Use the PUT statement instead of DISPLAY. PUT suspends default frame-based
formatting.
Customizing Reports
You can customize your reports by:
1046
11
Building Menus
Menus add flexibility to an interface. A menu provides choices and options for end users that
give them more control over how they use an application. Through menus, users can access the
different functions of an application in the order that best suits them.
In this chapter, you learn about building and customizing menus. Specifically, you learn about:
Menu basics
Menu attributes
Design conventions
11.1
Menu Basics
Menus are an important part of an event-driven programming model, since menus allow users
to control the flow of an application. Progress defines a menu as a widget containing a list of
commands or options available to users. In Progress, a menu is always associated with another
widget. In the tutorial, you learn about the most common type of menu: the menu bar. A menu
bar is a horizontal bar displayed at the top of a window. The menu bar is always associated with
a window widget. To learn about other types of menus, see the Progress Programming
Handbook.
A menu bar consists of submenus. A submenu is a vertical list of commands and options
available to a user. So, the menu bar form of menu is a collection of lists of commands and
options. The titles of the submenus are listed across the menu bar. To a user, a menu bar is a
collection of pull-down menus. To a Progress programmer, a menu bar is a collection of
submenusthe menu bar is syntactically the menu. This slight distinction in terminology is
important to help make the discussion in this chapter clear. The terms submenu and pull-down
menu are analogous, and the terms menu and menu bar are analogous.
A submenu consists of menu items. A menu item is an individual command or option, or even
another submenu. When a submenu is a menu item of another submenu, it is known as a nested
submenu. Nested submenus appear to the side of the main submenu when chosen.
When complete, the menu bar you present to a user is a hierarchical structure consisting of a:
Menu widget
The widgets that make up the complete menu bar are related to each other. For example,
submenus on the menu bar are children of the parent menu bar. Each of the menu bar
submenus are siblings to each other. Similarly, menu items are children of a parent submenu,
and so on. When you code a complete menu bar, you build it from the bottom up. The
lower-level widgets must exist before you can relate them to the higher-level widgets.
The menu widget itself does not have a parenta menu is always owned by one widget. In the
case of the menu bar, the window widget owns it. Each Progress window can own one menu bar.
112
Building Menus
Figure 111 shows a menu bar with two menu titles, File and Edit. When you choose Edit, a
pull-down menu with three menu items appears below Edit. When you choose the menu item
Add, a pull-down menu with four menu items appears to the side of Add. The arrow to the right
of Add indicates that there is a nested submenu.
Menu titles
Menu bar
Submenu with
menu items
Nested
submenu
Figure 111:
11.2
Defining a Menu
A complete menu bar consists of a menu bar, submenus, and menu items. When you define a
menu bar in the Progress 4GL, you start at the lowest level, then build the top-level structure.
You need to:
1.
2.
3.
The following sections explain how to define submenus and menu items, how to add them to a
menu bar, and how to assign the menu bar to a window.
113
11.2.1
Defining a Submenu
When you assemble a menu, you first define the pull-down submenus and their associated menu
items with the DEFINE SUB-MENU statement. This is the basic syntax for the DEFINE
SUB-MENU statement.
SYNTAX
DEFINE SUB-MENU submenu-name
LIKE menu
menu-element-descriptor
... }
The LIKE menu option is useful when you want to duplicate an already existing menu. The
menu-element-descriptor allows you to customize the submenu. This is the syntax for the
menu-element-descriptor phrase.
SYNTAX
SUB-MENU submenu-name
[
|
|
|
DISABLED
][
LABEL label
RULE
SKIP
menu-item-phrase
}
Table 111 explains the relevant components of the syntax.
Table 111:
Component
114
(1 of 2)
Description
SUB-MENU
Names a submenu that displays when the user chooses this menu item.
The specified submenu must already be defined.
DISABLED
Disables the menu item initially. When you use this option, the user
cant choose the menu item.
LABEL
Defines the text descriptor that the user sees on the menu. If you omit
LABEL, Progress displays the submenu name by default.
RULE
Inserts a rule (line) at this point on the menu. Use rules to visually
group related commands.
Building Menus
Table 111:
Component
(2 of 2)
Description
SKIP
menu-item-phrase
Names a menu-item widget and specifies details about the item. See
the following table for more information.
The menu-item-phrase lets you customize both how the menu item displays and how the user
can access it. This is the syntax for the menu-item-phrase.
SYNTAX
MENU-ITEM item-name
[
[
[
[
ACCELERATOR keylabel
TOGGLE-BOX
DISABLED
LABEL label
MENUITEM Options
Component
(1 of 2)
Description
MENU-ITEM
Specifies a unique name for the menu item. This name doesnt have
to be previously defined.
ACCELERATOR
TOGGLE-BOX
Displays the menu item with a toggle box that the user can toggle on
or off.
115
MENUITEM Options
Component
(2 of 2)
Description
DISABLED
Disables the menu item. This means that the user cannot choose this
item.
LABEL
Specifies the text descriptor that the user sees in the submenu. If you
omit LABEL, Progress displays the item name by default.
You can include an ampersand (&) within the label to indicate that the
following letter acts as a mnemonic (shortcut key) for the menu item.
For example, "E&xit" specifies x as the mnemonic.
Note that in this code fragment, which is an example of a complete submenu definition, only the
final MENU-ITEM phrase has a period:
DEFINE SUB-MENU sm-Reports
MENU-ITEM mi-Labels
MENU-ITEM mi-Names
RULE
MENU-ITEM mi-Balances
MENU-ITEM mi-Today
The next step in building a menu is to define a menu bar and add submenus and items to it.
11.2.2
Once youve defined the contents of each submenu, you need to define a menu bar and associate
the submenus to it. The DEFINE MENU statement defines a menu, and the MENUBAR phrase
makes the menu a menu bar. This is the syntax for the DEFINE MENU statement.
SYNTAX
DEFINE
116
Building Menus
Table 113 explains the relevant components of the syntax.
Table 113:
MENU Options
Component
Description
NEW SHARED
SHARED
MENU
MENUBAR
LIKE
menu-element-descriptor
LABEL "Tables"
LABEL "Reports"
LABEL "Help".
First, the DEFINE MENU statement creates the menu bar and names it mbar. Then it assigns
each of the previously defined submenus to it. The LABEL option once again lets you provide
titles for the menu items. The order in which you list the submenus is importantProgress
places the menu titles of the submenus on the menu bar starting with the first listed submenu.
117
11.2.3
The last step in building a menu is assigning the menu bar to a window. You accomplish this by
setting the windows MENUBAR attribute equal to the menus widget handle. For example, if
you are using the default window, you can refer to it with the DEFAULT-WINDOW system
handle, as follows:
ASSIGN DEFAULT-WINDOW:MENUBAR = MENU mbar:HANDLE.
In graphical systems, you can create multiple windows. So, to assign a menubar to a window
other than the default window, use the widget handle variable you use in the CREATE
WINDOW statement, as shown in the following example:
ASSIGN Mywindow:MENUBAR = MENU mbar:HANDLE.
11.2.4
To associate functionality with menu items, you use triggers. As with buttons, the key event to
attach a trigger to is CHOOSE. Typically, the content of a trigger for a menu item is a RUN
statement calling an internal or external procedure, as shown in the example below:
/********** DEFINE TRIGGERS **********/
ON CHOOSE OF MENU-ITEM mi-Labels IN MENU sm-Reports
DO:
RUN Display-Labels.
END.
Another typical function found on a menu is the Exit command. Throughout the tutorial, youve
used a button labeled Exit and used the CHOOSE event of the Exit button as the condition
that satisfies the WAIT-FOR statement. When the user chooses Exit, the flow of control goes
past the WAIT-FOR. If the WAIT-FOR is the last statement in the procedure, the procedure
ends.
118
Building Menus
You can easily replace this functionality with an Exit command on the menu bar. By
convention, the Exit command is always the last menu item on the first submenu of a menu bar.
If you add this menu item to your menu bar, then you could use the following WAIT-FOR
statement to block the application:
/********** MAIN LOGIC *********/
WAIT FOR CHOOSE OF MENU-ITEM mi-Exit IN MENU mbar.
In reality, closing down an application often requires some clean up. While still using the
CHOOSE event of the Exit command as your WAIT-FOR condition, you can write a trigger for
the same event to do your clean-up. Then, as a last step, you could close the window and end
the application, as shown in the following example:
/********** DEFINE TRIGGERS *********/
ON CHOOSE OF MENU-ITEM mi-Exit IN MENU mbar
DO:
/* Clean up Code */
APPLY "CLOSE-WINDOW" TO DEFAULT-WINDOW.
END.
CLOSE WINDOW is a Progress event function that executes for any event that equates to
dismissing a window.
For a complete discussion of triggers and trigger programming techniques, see the Progress
Programming Handbook.
Referencing Menus
Each menu and submenu must have a unique name. To reference the menu or submenu, precede
the reference with the keyword MENU. To reference a menu item, precede the reference with
the keyword MENU-ITEM. Menu items do not have to have unique names. In situations where
ambiguity arises, you must extend the menu item reference to include the IN MENU option.
119
11.2.5
Youve learned all the basics, so now you can put it all together. This example implements
enough of a menu bar to demonstrate what youve learned. Perform these steps:
Exercise
2 Choose Tables from the menu bar and browse through the submenu and the nested
submenu.
3 Choose the Reports and Help submenus and browse through them.
4 Choose Reports Mailing Labels. The editor in the window displays the list of customer
mailing labels.
5 Choose Tables Exit.
6 Press SPACEBAR to return to the Procedure Editor.
1110
Building Menus
First, look at the code that sets up the menu structure:
lt-11-mn.i
/*1*/
/*2*/
/*3*/
**********/
LABEL "&Customer"
LABEL "&Order".
LABEL "O&pen"
LABEL "E&xit".
LABEL "H&elp".
LABEL "&Tables"
LABEL "&Reports"
LABEL "&Help".
1111
1112
1.
The DEFINE SUB-MENU statement defines one pull-down menu and the menu items of
that pull-down menu. The ampersand (&) in the label, establishes the mnemonic for the
menu item (covered later).
2.
This submenu appears as a menu item in the next DEFINE SUB-MENU statement, so its
definition must come first.
3.
The Exit menu item is always the last menu item of the first submenu on the menu bar.
4.
Use RULE to provide a graphic divider between groups of menu items. Use SKIP to add
space between menu items.
5.
The DISABLED option disables this menu item on startup (covered later).
6.
The TOGGLE-BOX option makes the menu item a toggle (covered later).
7.
The DEFINE MENU statement defines a Progress menu. The MENUBAR phrase makes
the menu a menu bar and associates submenus with it.
8.
This critical step makes the window the owner of the menu bar. In this case, the owner is
the default window.
Building Menus
Next, look at the following code, which uses the previous menu structure to implement the
mailing list report you saw in the last section:
lt-11-01.p
/*1*/
/*2*/
/*3*/
/*5*/
1113
11.3
1.
2.
Choosing the Exit menu item ends the application by closing the window.
3.
Like most menu items, choosing this item executes a RUN statement to an internal or
external procedure. Here, the internal procedure runs a report.
4.
The Exit command of the menu bar satisfies the WAIT-FOR condition by closing the
application window.
5.
Toggle boxes
Mnemonics
Accelerators
11.3.1
You can enable and disable menu items when it is appropriate to do so based on the users
previous action. An enabled item is a valid selection; a disabled item is not, and the user cannot
choose it.
This is the syntax for the DISABLED option.
SYNTAX
MENU-ITEM menu-item DISABLED
1114
Building Menus
11.3.2
Toggle Boxes
Toggle boxes let you represent selectable menu items as logical values. You can then program
the menu item to trigger a different event based on the value of the toggle box which changes
each time the user selects the menu item. The application can examine the CHECKED attribute
for the menu item to determine whether the item is currently checked or unchecked. You can
also initialize or change the condition of the menu item by setting the CHECKED attribute in
the program.
When the user toggles a toggle-box item, Progress sends the VALUE-CHANGED event to the
menu item. Therefore, by defining a trigger on that event, you can take immediate action when
the user toggles the value.
This is the syntax for the TOGGLE-BOX option.
SYNTAX
MENU-ITEM menu-item TOGGLE-BOX
11.3.3
Mnemonics
A mnemonic provides a way to access menu items from the keyboard. The user can use
mnemonics to navigate through a menu by first activating the menu bar, then typing the
mnemonic character. Progress indicates the mnemonic character by underlining it in the menu.
For example, suppose the menu bar contained these elements: File, Edit, and Reports. Once the
menu bar is active, the mnemonic to access the File menu is f, the Edit menu is e, and the
Reports menu is r. By default, Progress assigns the first character in the item label as the
mnemonic. However, you can also define it yourself by inserting an ampersand (&) before the
letter in the label.
This code fragment defines the mnemonic for the Exit menu item:
DEFINE SUB-MENU sm-Open
SUB-MENU sm-Table LABEL "Open"
MENU-ITEM mi-Exit LABEL "E&xit".
1115
11.3.4
Accelerators
An accelerator is a key or key combination that executes an item from a pull-down menu
without the user having to pull down the menu. You can define an accelerator for a menu item
with the ACCELERATOR option in the menu-item description. This is the syntax for the
ACCELERATOR option.
SYNTAX
ACCELERATOR keylabel
In this syntax, the value keylabel must be a character-string constant that evaluates to a valid
Progress key label. You can modify the keylabel by specifying one or more of these
keys-SHIFT, CONTROL, ALT. For example, you can specify "ALT-F8", "PAGE-UP", etc.
Progress automatically displays the specified accelerator key label next to the menu item label,
so the user knows what key is the accelerator. The user can then choose a menu item by pressing
the specified keys.
For more information on key labels, terminals, and how they are specified in the
PROTERMCAP file, see the Progress Client Deployment Guide.
For more information on keyboard events and keyboard event precedence, see the chapter on
handling user input in the Progress Programming Handbook.
1116
Building Menus
11.3.5
Programming Example
1 Open lt-11-02.p and run it. The display shown below appears:
Exercise
2 Display the Reports pull-down menu. The third and fourth items are disabled, so you cant
choose them.
3 Choose Mailing Labels. The mailing label frame appears.
4 Choose Output to Printer from the Reports menu.
5 Choose Mailing Labels again. An alert box appears informing you that the report printed.
Choose OK to dismiss the alert box.
6 Browse through the various submenus. Notice that a letter in each submenu or menu item
is underlined. The underlined letter is a mnemonic.
7 Choose Tables Exit, then press SPACEBAR to return to the Procedure Editor.
1117
1118
Building Menus
These notes help explain the code:
11.4
1.
The CHECKED attribute applies only to toggle boxes and toggle box menu items. You
can check it at any time to determine the on screen state of the menu item. If you wanted
to write a trigger for the toggle box menu item, you would normally use the
VALUE-CHANGED event function.
2.
Here, the CHECKED attribute determines whether to read the report output file into the
editor or to let the user know that the output went to the default printer.
Menu Attributes
Progress maintains attributes for menu widgets. Table 114, Table 115 and Table 116 list the
specific attributes for menus, submenus, and menu items. For more information about these
attributes, see the Progress Language Reference.
Table 114:
Attribute
Menu Attributes
Type
Default
Readable
Setable
FIRST-CHILD
WIDGET-HANDLE
LAST-CHILD
WIDGET-HANDLE
OWNER
WIDGET-HANDLE
TITLE
CHARACTER
TYPE
CHARACTER
Table 115:
Attribute
MENU
Submenu Attributes
Type
Default
Readable
Setable
FIRST-CHILD
WIDGET-HANDLE
LAST-CHILD
WIDGET-HANDLE
PARENT
WIDGET-HANDLE
TYPE
CHARACTER
SUB-MENU
1119
Table 116:
Attribute
Type
Default
Readable
Setable
CHECKBOX
LOGICAL
FALSE
CHECKED
LOGICAL
LABEL
CHARACTER
SUBTYPE
CHARACTER
TYPE
CHARACTER
MENU-ITEM
11.5
Design Conventions
There are common practices to consider when designing menus. Following these guidelines
gives your menus a common look and makes them predictable so that users can navigate
unfamiliar applications more quickly. Here are some useful design conventions:
1120
Group menu items in submenus by task. Order the tasks by frequency of use, as well as
the order in which they are used. Place the most frequently used menu items where users
can easily access themin general on the left and close to the top.
Keep any destructive menu item (like delete) away from frequently used menu items.
When possible, provide alternate methods for accessing menus, like mnemonics and
accelerator keys.
Use an ellipsis (...) to indicate menu items that require further user input.
Each menu bar should contain at minimum these three items: File, Edit, and Help.
Building Menus
Place the Exit option as the last menu item on the first menu.
Limit submenus to three levels or less, because multiple levels of submenus clutter the
screen and make the menu difficult to use.
Practice Problems
To practice defining menu bars, submenus, and menu items, design a basic menu system for an application you
plan to develop.
1.
2.
3.
Now that you have a basic menu worked out, experiment by adding some advanced features, such as disabled
menu items, mnemonics, and toggle boxes.
11.6
Summary
Menus create an interface that allows your application to take full advantage of the event-driven
programming model. The user controls which tasks are accomplished and the order in which
theyre accomplished.
A menu consists of three parts:
A menu bar at the top of the window is the highest level of the menu.
Submenus open below the menu bar and offer the user additional submenus or items to
choose from.
1121
2.
3.
Once youve assembled the menu, you can assign functionality to it by adding triggers that
execute when the user chooses the menu items.
Advanced Menu Features
Progress menus include the following features to make the menus easier to navigate:
Disabled menu items let the user know which options are not available to them at certain
points in the application.
Toggle boxes can keep track of the users decision regarding a certain option.
Mnemonics provide keys that the user can use as shortcuts to choosing a menu item.
Accelerator keys allow users to select items from a menu that is not displayed.
1122
12
Managing Your Application
When you begin your own application development cycle, youll reach a point where you have
all your functionality and interface code stored in procedure files. Together, these procedure
files make up the complete application. Your final task will be to make sure it all works
smoothly together.
This chapter discusses the issues that arise when putting together a large-scale application. It
summarizes many techniques you already know about in the context of application
management. The chapter also covers several new techniques and language elements that are
important in managing your application.
Specifically, the chapter covers:
Sharing resources
Managing interfaces
12.1
Managing Procedures
Organizing your procedure files and how they work together is the first step in managing your
application development. This section describes the typical organization of an event-driven
application and how to work around some common problems with larger applications.
12.1.1
An event-driven application typically has a flat structure. There is a main procedure that creates
the main user interface and presents the user with functionality choices in the form of buttons
and menu commands. Normally, each button or menu command links to a trigger in the main
procedure that runs an external procedure file. The procedure files are all very modular,
performing a single task.
As your application grows, your tendency will be to define all resources that the individual
procedures use in the main procedure file, including:
Triggers
Internal procedures that represent functionspieces of common code that more than one
external procedure relies on.
External
Procedures
External
Procedures
Main Procedure (.p)
.p
.p
.p
Figure 121:
122
.p
.p
.p
.p
.p
12.1.2
What you need is a technique for modularizing the content of the main procedure. For example,
suppose you have a collection of internal procedures in the main procedure that acts as a
function library for the external procedures. If you move those internal procedures into a
separate procedure file and then call that procedure from the main procedure during startup,
what happens?
Progress scopes all resources defined in a procedure to that procedure. The sum of the interface
objects, data structures, and internal procedures is called the context of the procedure. The
context of the procedure is only available during the life of the procedure. So, when the
procedure of internal procedures mentioned above finishes executing, all the resources it
defines are unscoped.
Progress has another type of procedure that creates a context that lasts beyond the execution of
the procedure. This type of procedure is known as a persistent procedure. The context of a
persistent procedure lasts until you explicitly delete it.
Persistent procedures promote modularity of application functionality. For example, you could
have several persistent procedures that contained related groups of internal procedures. This
technique essentially lets you have loadable and unloadable libraries of functions. This ability
gives you the modularity you need and allows you to manage your system resources.
Later in the chapter, youll learn the specifics of programming persistent procedures. For now,
heres a quick description of how they work. First, you instantiate a procedure context by using
the PERSISTENT option of the RUN statement. You can provide the RUN statement with a
HANDLE variable to hold a pointer to the context. A procedure context created in this way is a
self-contained context. Your code manages the communication between this module and any
other modules currently running. The HANDLE variable is the bridge between contexts.
123
12.2
Sharing Resources
A large application has many resources that are potentially reusable by several modules of the
application. This section describes different approaches to sharing resources with modules.
12.2.1
In the tutorial, you learned about SHARED variables. SHARED variables allow you to set aside
an area in memory that is accessible by each procedure that defines the SHARED variable. The
SHARED variable is available to all of these procedures, as long as the procedure context that
initially created the SHARED variable is still available.
Progress provides the SHARED option for most resources. You can have SHARED variables,
frames, buffers, queries, and streams. To implement a SHARED resource, see the Progress
Language Reference for the appropriate syntax.
The advantage of SHARED resources is that they promote sharing resources and
communicating data between application modules. SHARED resources also take a little less
time to resolve at startup.
The disadvantage of SHARED resources is that they are not explicit and therefore not very
portable. Since SHARED resources are available for both input and output operations, it may
not be immediately clear to another programmer how a particular module interacts with the
shared resource.
124
12.2.2
In the tutorial, you also saw how to define input and output parameters and supply values when
calling runnable modules. Progress supports these types of data structures as parameters:
variables, buffers, and handles.
Parameters are more precise in their use of resources and more readily understandable since
they specify whether they are input, output, or both.
For most applications, and especially where resource concerns are an issue, parameters are the
most common and important technique for sharing among modules.
12.2.3
The persistent procedure is different from parameters and SHARED resources, in that it makes
an entire procedure context available to other modules.
It is important to remember that persistent procedures instantiate separate, individual
contextsnot one large context in which each context becomes a part of the whole. By using
the procedure HANDLE your code can make the separate procedures interact with each other.
The point of the persistent procedure is that what is available to be shared between modules is
now under your control. The resources in a persistent procedure can be loaded and unloaded in
bulk.
Persistent Procedure Syntax
The first step in creating a persistent procedure, is to define a HANDLE variable to hold the
context reference as the following code fragment shows:
DEFINE VARIABLE proc-handle AS HANDLE.
The next step is to run an external procedure with the PERSISTENT option of the RUN
statement. The diagram below shows the relevant RUN statement syntax.
SYNTAX
RUN extern-procedure
PERSISTENT
SET handle
]] [
runtime-parameters
Progress sets the HANDLE variable you supply to the handle for the procedure context.
125
When you are through with a procedure, you need to delete it. This is the syntax for the
DELETE PROCEDURE statement.
SYNTAX
DELETE PROCEDURE proc-handle
There are some other 4GL language elements that help you manage persistent procedures. Table
121 describes them.
Table 121:
126
(1 of 2)
Description
SESSION:FIRST-PROCEDURE
SESSION:LAST-PROCEDURE
handle:FILE-NAME
handle:PRIVATE-DATA
(2 of 2)
Description
handle:NEXT-SIBLING
handle:PREV-SIBLING
VALID-HANDLE
THIS-PROCEDURE
127
1 Open lt-12-01.p and run it. The display shown below appears:
2 Choose Run Procedure 2. An alert box appears informing you that the context for
procedure 2 is available. This alert box represents the body of an internal procedure stored
in an external procedure file. The internal procedure was accessed and run from the main
procedure after the execution of the external procedure was already complete.
3 Choose Check Contexts. The filenames of all persistent procedures appear in the display.
4 Choose Delete Context 2 and then choose Check Contexts again. The deleted context
disappears from the list.
5 Choose Exit, and then press SPACEBAR to return to the Procedure Editor.
128
129
12.3
1.
2.
This IF statement prevents the user from establishing many separate contexts for each
procedure.
3.
The PERSISTENT option asks Progress to save the procedure, and the SET option
provides the handle to the procedure.
4.
5.
This RUN statement uses the IN handle syntax to access and run an internal procedure in
the persistent procedure context.
6.
7.
This trigger runs through the current chain of persistent procedures and records the
filenames of each in a string.
8.
The exit trigger makes sure the procedures are destroyed before exiting the procedure.
Because you stored the procedure HANDLE when you ran the procedure, you have
programmatic control of that procedure. In this example, you use that HANDLE to
explicitly delete any surviving procedure contexts before exiting the main procedure.
Managing Interfaces
The strategies you employ for creating interfaces impacts the usability of your application. The
topics in this section present different interface designs, including:
1210
Single-frame interfaces
Multi-frame interfaces
Dialog boxes
Alert boxes
Multi-window interfaces
12.3.1
All of the interfaces in this tutorial have been either single-frame interfaces or single-frames
with dialog boxes as secondary interfaces.
If your main interface is a single frame in a window, it can still be dynamic. If you rely on one
frame, you can manipulate the widgets inside the frame to adapt the frame to the users current
task. For example, if your application is a database maintenance program, you could show a
selection list populated with the table names for the selected database. Using techniques you
learned in this tutorial, you could either repopulate the same selection list with valid data each
time the user selects a different database, or you could have a selection list for each database
and hide the others when appropriate.
Either of these techniques can work, but bear in mind that hidden widgets do use system
resourceshaving a large number of them might be a programming and resource burden.
12.3.2
Multi-frame can mean two different things. First, it could mean that you have more than one
active frame in a window. Second, it could mean that a window has several different frames,
each one appropriate for a different mode or task of the main interface.
Also, you can choose from two basic methods of organizing multiple active frames in a window:
Defining all the frames as independent siblings that are child widgets of the window.
Defining frame families (see Chapter 3, Programming the Progress Way), where at least
one frame is a parent that contains all the other frames as its child widgets.
In general, frame families solve a number of problems related to navigation and control in
multiple frame interfaces. Among these are tabbing and conditional display. However, some
code management is equally necessary for frame families and independent frames.
Tabbing in Multi-frame Windows
While there are several keyboard functions available to help a user navigate through an
interface, most users rely on the TAB function. From a users viewpoint, TAB moves input
focus to the next widget in the interface. From a technical viewpoint, TAB moves input focus
to the next widget in the frame. So, if you have two independent frames on screen, the user
cannot get to the second frame by using the TAB key. Input focus cycles within the first frame.
The user needs to invoke the NEXT-FRAME key function to move focus to another frame.
1211
However, a simpler method is to include all the frames in a single frame family. With this
approach, all tabbing behavior is built in. The user can tab among all the frames contained by
the parent frame. Focus automatically moves to the first or last field-level widget in the next or
previous frame, respectively.
Storing Many Frames
You can design several frames, one for each task that the user can accomplish from the main
interface. It might be helpful to store each of these frames in a separate file. They can be stored
as include files or as runnable modules (if you included the executable code that goes with the
frame). The Progress AppBuilder stores runnable interface code in procedure files with a .w
extension. You can adopt this convention to help keep your files organized.
Frame Scoping
Just like records, frames have a life span, and that life span is referred to as the frame scope. The
general rules for frame scope are:
Frame scope ends when the block that contained the first reference to the frame ends.
Frames are available to any nested blocks within the block that contained the first
reference.
If you violate these rules, Progress will notify you at compile time. In general, you wont need
to worry too much about frame scope because the code techniques used with the event-driven
programming model tend to scope all frames to a procedure block. Because the frames are
scoped to the procedure block, all references to the frame within the procedure block are legal.
1212
This is invalid code because of the attempt to reference Frame2, which is scoped to the FOR
EACH block, outside of that block. If you need to reference the frame in both blocks, you have
to make sure that the first reference is in the block that contains the FOR EACH block. The
DEFINE FRAME statement is not considered a reference.
For more information on frame scoping, see the Progress Programming Handbook.
Accessing Frame Attributes
Like other widgets, frames have attributes that you can access, but the syntax for accessing a
frame attribute is a little different. This is the normal widget attribute syntax.
SYNTAX
widget-name:attribute-name
1213
Frame Attributes
Attribute
Description
BOX
CENTERED
COLUMN
HIDDEN
ROW
For frames, the ROW attribute holds the row position of the
frame within the window.
SIDE-LABELS
VISIBLE
Hiding Frames
In Chapter 3, Programming the Progress Way, you learned about using the VIEW and HIDE
statements. These two statements operate on the VISIBLE attribute, which all widgets have.
The VISIBLE attribute is TRUE if the widget is currently visible in the display, and FALSE if
it is not. It is sometimes useful to access the VISIBLE attribute directly to make widgets appear
and disappear. VISIBLE does not give you complete control over a widget visibility, however,
because Progress has default behaviors that can make a widget visible, even if you made it
invisible. For example, displaying a frame makes all the widgets in that frame visible, including
any child frames.
Progress provides the HIDDEN attribute to allow you to suppress implicit viewing of a widget.
So to make a widget completely invisible, set VISIBLE to FALSE and HIDDEN to TRUE.
1214
In the first case, if the frames are stored separately as include files, then those frames need to be
scoped to the main procedure so they are available. As mentioned earlier, in large applications
this can make the main procedure overly large.
For runnable code modules, you can use external procedures that use the main interface (as
opposed to a dialog box).
Enabling Input in Frame Families
Typically, to enable all field-level widgets in a frame for input, you only have to execute a single
ENABLE statement as shown in the following code fragment:
ENABLE ALL WITH FRAME Frame1.
1215
While this might seem like unnecessarily redundant code, it does afford a measure of control
where you choose to group input fields within child frames by common function. You might
then enable and disable each child frame (group of fields) under the parent frame according to
input received by fields owned by the parent frame itself.
12.3.3
The dialog box is your main tool for implementing modal interface modules. Modal interfaces
require the user to complete or cancel the current operation before moving on. Modal interfaces
focus the users attention on the current task, helping to ensure valid data and minimizing the
time that Progress holds onto individual records. This behavior makes modal interfaces a natural
choice for working with records in a database application.
Typically, a dialog box is the interface to some functionality that the user launches by choosing
a button or menu command. This means that a dialog box is usually associated with an external
procedure. The Progress AppBuilder stores these secondary interface modules with a .w file
extension.
In the tutorial, you first saw the dialog box when you learned about the UPDATE statement. A
dialog box overlays the main interface and blocks interaction with the main interface until the
user dismisses the dialog box. In the case of the UPDATE statement, the main interface presents
data for the user to view and change. Without an UPDATE statement, the user can perform an
explicit action (choosing a button) to bring up the dialog box. The dialog box then gives the user
the ability to change the data.
1216
Figure 122:
A Modeless Interface
1217
Figure 123:
A Modal Interface
Syntactically, the difference between a frame and a dialog box is just the VIEW-AS
DIALOG-BOX option on the frame phrase. Also, while a dialog box can contain a frame
family, a frame family cannot contain a dialog box. The dialog box must be the top-level parent.
The idea of a dialog box is common to all event-driven programming, and there are some widely
implemented standards that go with dialog boxes. The first is the OK and Cancel buttons that
you see in Figure 123. These buttons implement the idea that a user must dismiss a dialog box
before the user can continue:
1218
A user who chooses the OK button is saying dismiss the dialog box and save any
changes made to data in the dialog box.
A user who chooses the Cancel button is saying dismiss the dialog box and discard any
changes made to the data.
12.3.4
An alert box is a dialog box for the message area of a window widget. An alert box is like a
dialog box in that an alert box blocks the rest of the interface until the user acknowledges the
alert box. When a message is important enough to interrupt the user, then the alert box is the
right interface component to use. Heres the alert box syntax, which is included in the
MESSAGE statement.
SYNTAX
TITLE title-string
1219
Component
alert-type
button-set
TITLE
1220
Description
Different environments define different types of alert boxes for use in
certain circumstances. This ensures that all applications running in the
environment use the same graphical cues for similar situations. This kind
of uniformity helps the user recognize the seriousness of the message. The
three most common types are:
While the alert-type syntax lets you specify the type of message to send,
the BUTTON-SET syntax lets you choose the method for user response to
the alert box. The most common button sets are:
YES-NO Use this button set with the QUESTION alert box type.
The alert box will return the logical value YES or NO depending on
the choice of the user to a LOGICAL field specified in the
MESSAGE statement. See below for a description of this technique.
Like a frame or dialog box, an alert box can have a title. Good style
dictates that you always include a descriptive title.
Figure 124:
This is the QUESTION alert box type and it uses the YES-NO button set.
The code fragment below shows the relevant part of procedure lt-08-06.p:
/*1*/
/*2*/
/*3*/
/*4*/
.
.
.
DEFINE VARIABLE Answer AS LOGICAL.
.
.
.
ON CHOOSE OF btn-Delete
DO:
MESSAGE "Do you really want to delete" Customer.Name "?"
VIEW-AS ALERT-BOX QUESTION BUTTONS YES-NO
UPDATE Answer.
IF Answer THEN DO:
DELETE Customer.
GET NEXT Cust-Query.
IF NOT AVAILABLE(Customer) THEN GET FIRST Cust-Query.
DISPLAY Customer.Cust-Num Customer.Name WITH FRAME Frame1.
END. /* IF Answer */
END. /* ON CHOOSE OF btn-Delete */
.
.
.
1221
You need to define a variable before you use the alert box to store the users response.
2.
The special VIEW-AS syntax on a MESSAGE statement re-routes a message from the
status area to an alert box.
3.
This UPDATE is an option of the MESSAGE statement (note that there is no period on
the line before). Use this option to specify the variable that will hold the users response.
4.
12.3.5
The scope of this tutorial is to provide a basic, but thorough, understanding of the interface
components and language statements needed to write single-window applications. Still,
Progress supports a wide range of advanced programming options to let you create
multi-window applications in graphical environments. For more information on these advanced
techniques, see the Progress Programming Handbook for more information.
What follows in the next few sections is a quick introduction to very basic window concepts.
The purpose is to contrast these concepts and techniques with those that apply to field-level
widgets and windows.
Window Attributes
The design of multi-window applications is outside the scope of this tutorial, but the tutorial
does show you how to create a second window. When working with windows, three attributes
are important to know about:
1222
MENU-BAR Use this WIDGET-HANDLE attribute to supply the widget handle of the
menu bar that belongs to the window. Chapter 11, Building Menus, discusses menus and
the menu-bar widget.
STATUS-AREA Use this LOGICAL attribute to specify whether you want a status
area in your window.
attribute = value
] ... ]
For the most part, you need to assign attributes to window widgets as you create them, as in the
following example:
DEFINE VARIABLE Mywindow AS WIDGET-HANDLE.
.
.
.
CREATE WINDOW Mywindow
ASSIGN MESSAGE-AREA = No STATUS-AREA = No.
Referencing Windows
Progress defines a window widget as the workspace of your application. Each time you start a
Progress session, it automatically creates a default window. In graphical environments, you start
with the default window, but you can create other, overlapping windows dynamically within
your application.
When you are working with the default window, you reference it by using the
DEFAULT-WINDOW system handle. This system handle holds the widget handle of the
default window.
When you are working with more than one window, the CURRENT-WINDOW system handle
holds the widget handle of the window that has input focus. For single-window applications,
DEFAULT-WINDOW and CURRENT-WINDOW are equal, but referring to
DEFAULT-WINDOW is a little clearer.
When you have two or more windows, only the current window has input focus.
1223
Window Events
When you are working with windows, there are four event functions that youll frequently use
to add functionality to the window.
1224
Viewing and hiding When you view any member of a window family, all family
members are viewed unless one or more of them have their HIDDEN attributes set to
TRUE. Progress also hides all descendant windows that are minimized when you hide a
parent.
Minimizing and restoring You can minimize and restore all members of a window
family individually. When you minimize (iconify) a window, Progress hides all of its
descendants. When you restore a parent window, Progress redisplays any hidden
descendants.
The relationships created by window families can be very useful because you can use them to
manage your interface more effectively, and with less code. If you define a window family, you
can control all the windows for an application as a single set, or as individual windows. For
example, you can ensure that Progress closes all windows in an application when the user closes
the root window. You can ensure that when a parent window is minimized, all the descendant
windows of that window are also closed. This is useful in applications that use persistent
procedures.
1225
1226
For a discussion of windows and window programming techniques, see the Progress
Programming Handbook.
12.4
12.4.1
Basic control is the ability to put up a functioning interface and allow your users to interact with
it. The WAITFOR statement is the statement that blocks the execution of an application and
specifies an end condition that signals Progress to end the current module and continue
processing or exit.
Only one WAIT-FOR statement should be active at once. Multiple WAIT-FOR statements can
interfere with each other, unless you take explicit control over enabling and disabling all
widgets to prevent conflicts.
1227
12.4.2
In Chapter 10, Creating Reports, the tutorial used a technique that violated the advice from
the last section. The programming examples in that chapter used a dialog box to display static
report output and blocked the interface with a nested WAIT-FOR statement.
In this case, the nested WAIT-FOR works, because:
The dialog box has no updatable widgets and therefore has no need for an UPDATE
statement.
The dialog box disables the main interface, avoiding conflict with the main WAIT-FOR.
The code took care of explicitly dismissing the dialog box. Without the HIDE statement
immediately following the WAIT-FOR, the code would yield an error message.
12.4.3
Although this tutorial does not cover multi-window applications, it is important to point out that
persistent procedures are a very important part of implementing this kind of application. If a
window needs a WAIT-FOR to allow user interaction, and you should only have one active
WAIT-FOR at a time, how do you implement multi-window applications short of having a huge
main procedure?
A window established by a persistent procedure will remain available to the user while the
context of the procedure that created it is still active. You need to control the creation and
deletion of the window and all communication between windows. For a complete discussion of
using persistent procedures for multi-window applications, see the Progress Programming
Handbook.
1228
12.5
Summary
Event-driven programs strive to make as much functionality available from the top-level of an
application as possible. This leads to a characteristic flat application structure consisting of one
large main procedure and several atomic modules that reside in separate procedure files. Having
a large main procedure may tax the execution limits of your system. To alleviate this problem,
you can use persistent procedures to create loadable and unloadable modules of resources.
SHARED resources, including variables, frames, buffers, queries, and streams, allow you to
create individual resources that can be available to many procedures.
Persistent procedures create resources that do not disappear when the creating procedure ends.
Persistent procedure contexts must be destroyed programmatically when the application no
longer needs them.
Progress supports a variety of interface designs, including:
Single-frame interfaces
Multi-frame interfaces
Dialog boxes
Multi-window applications
Like other widgets, frames and windows have attributes that you can manipulate to fine tune
your interface.
A successful application that mingles more than one interface needs to manage application
control by using WAIT-FOR statements, implied application blocking, and persistent
procedures in such a way as to give the user freedom to move through the application without
conflict.
1229
1230
13
Where to Go from Here
The tutorial introduced and developed several broad programming themes. The themes and
coverage were chosen to give you a solid foundation in the Progress 4GL. With what youve
learned, you could certainly begin to develop Progress applications. However, Progress
contains so many features and language options that theres a lot more to learn. This chapter
provides a conceptual map for learning more about the programming areas that are important to
you. The topics covered are:
Progress Tools
Multi-user programming
Data integrity
Record reading
Menus
Graphical features
13.1
Progress Tools
In the tutorial, you learned just enough about the Procedure Editor and Data Dictionary to help
you write procedures. These two basic tools have many more features that youll want to use.
These tools are covered in the Progress Basic Development Tools on-line help manual.
In addition to the two basic tools, there are two more that you should be aware of: the
AppBuilder and the the Debugger. Whether or not these tools are available to you depends on
the specific package you purchased and your development environment. Heres a quick
summary of these tools and their documentation.
AppBuilder
The AppBuilder is a tool for graphical environments that allows you to draw an interface and
the AppBuilder codes the interface for you. Of course, this is only the beginning of what the
AppBuilder can do. The tool takes full advantage of the graphical features of a GUI to make
creating Progress applications easier. The tool includes a section editor where you can write
code, including triggers.
The AppBuilder includes an implementation of encapsulated objects called SmartObjects.
These contain a variety of objects that you can combine to quickly build graphical applications.
When you use SmartObjects to build your application, you create an easily maintainable body
of code based on reusable objects. You can change a SmartObject and affect that change for
every instance of that SmartObject.
If you program in a graphical environment, the AppBuilder could easily become the hub of your
development environment. However, keep in mind that the AppBuilder can also be used to
design character environments, and that SmartObjects can be used in character environments.
For an introduction to the the AppBuilder and to SmartObjects, see the Progress Application
Development Environment Getting Started manual. For an in-depth treatment of the
AppBuilder, see the Progress AppBuilder Developers Guide. For information on porting
Progress applications, especially those containing SmartObjects, between Windows and
character interfaces, see the Progress Portability Guide.
Debugger
When your application grows and consists of many procedure files, debugging may take up
more of your time. The Progress Debugger can reduce that burden. The Debugger is
documented in the Progress Debugger Guide.
Other Tools
Progress has a number of other tools that serve very specific purposes. If you need to use one of
these tools, the Progress documentation set will point you towards it.
132
13.2
Designing Databases
As the tutorial pointed out early on, designing effective databases is an extensive topic in itself.
Chances are, if you have experience with other database systems, that you already know about
database design. In this case, you can probably gain the knowledge you need to implement your
database ideas by reading the Data Dictionary documentation found in the Progress Basic
Development Tools on-line help manual.
On the other hand, if you want to expand your knowledge of what makes a good database, then
youll want to read the Progress Database Design Guide.
13.3
13.4
Multi-user Programming
Perhaps the most significant topic that the tutorial does not cover is programming applications
that can be accessed by more than one user at a time. The whole topic of database access needs
to be revisited if you are programming for multi-user access. The central concept behind this
discussion is the idea of record locking. What should Progress do if more than one user wants
to access the same record? Basically, Progress can lock a record from being accessed by a user
while it is in use by another user. Progress has default locking behaviors designed to prevent the
kind of database corruption that can come from many users all trying to write data at the same
time. However, you can also take control of locking behavior to give your application the
amount of protection it needs.
For a discussion of locking and other multi-user programming issues, see the Progress
Programming Handbook.
133
13.5
Data Integrity
Protecting your data is a vital concern, and this topic encompasses different concepts. First, you
dont want users to enter illegal values. So, you want to check or validate new data before it gets
to the database. The tutorial touched on some of the ways you can validate data, like validation
expressions in the database or database triggers. On a lower level, you can use triggers in your
interface to check data as the user enters it. To learn more about validation, see both the
Progress Database Design Guide and the Progress Programming Handbook.
Next, if you begin to write a set of changes to a database, you need to make sure that either the
whole set is written to the database or the whole set is not written. Incomplete database writes
can cause database corruption, incomplete data, or conflicting data.
A set of data slated for writing to the database is known as a transaction. A transaction may be
interrupted by some user actions or system errors. Progress has many valuable default behaviors
that commit or roll back transactions in response to interruptions. Understanding when Progress
starts and ends transactions and how Progress decides to commit or roll back transactions is very
important for mission critical applications. See the Progress Programming Handbook for this
information.
13.6
Record Reading
Two chapters of the tutorial were devoted to data handling and record reading. In addition to
this material, multi-user programming and data integrity issues affect the techniques you use to
access records. Once you understand this material and the data-access material in the Progress
Programming Handbook, you can apply the Progress features that work best for your
programming needs.
Developing a sophisticated understanding of which statements and which options provide the
right amount of flexibility, the right amount of security, and the optimum efficiency is an effort
that can only pay off with better applications.
13.7
134
You can find information on these language statements in the Progress Language Reference.
13.8
Multiple-window Applications
Multiple-window applications are possible with Progress in the graphical environments that
support them. Using more than one window adds another complete set of programming
techniques and interface conventions that are covered in the Progress Programming Handbook.
13.9
Menus
You learned how to define the menu-bar type of menu in the tutorial. Another type of menu that
you might want to use is known as a pop-up menu. A popup menu is associated with a widget
and provides options that affect that widget. For example, you might want to have a pop-up
widget on a frame. See the Progress Programming Handbook section on menus for a complete
description of pop-up menus.
135
Graphical images
Colors
Fonts
Once youve created a functionally sound application that offers an intuitive interface, you can
begin to add images, colors, and fonts to create a unique and pleasant style.
The image widget allows you to place graphic files into your application. The image widget also
has syntax options that allow some interesting uses.
Most interface components support syntax options that give you some, or total, control over
color. Interface components that include text may also have options for specifying font choices
and font styles.
For pursuing any of these programming issues, your best bet is to look up the specific syntax in
the Progress Language Reference.
However, the Progress Programming Handbook is also a good resource for you to check
concerning graphical images, colors, and fonts.
136
Internationalization (I18N) is the process by which you design and program for a
non-specific linguistic and cultural user base.
A localized application is an application that you have customized for a specific region. The
region need not be another country; it can be a region characterized by a language, such as the
French-speaking part of Switzerland, or a region characterized by different business practices,
such as a province that has a different tax structure.
For more information about either of these types of applications, see the Progress
Internationalization Guide.
137
138
Glossary
Abbreviated Index
Uses just the first few characters of a field, if the field is a character data field. Indexes not
comprised of character data require an exact match.
Accelerator Keys
Function and special key combinations that you can press to choose a menu option.
Active Database
The database that is currently in use. If you have more than one database, the Data
Dictionary requires you to select an active, working database.
Aggregate Functions
A set of functions that allow you to evaluate groups of values.
Aggregate Phrase
A Progress language element that identifies one or more values to be calculated based on
a change in a break group.
Alert Box
A window that appears on the screen requesting user response. The user must dismiss the
alert box before the application can continue.
Application
A set of programming language instructions that accomplishes a specific task. An
application can be created from Progress procedures.
Argument
A piece of data that a calling procedure gives to a called procedure. Progress evaluates the
passed data at compilation time.
Glossary2
Glossary
Buffer
A small amount of memory used as a temporary storage area for data during input or
output operations. See also data buffer, record buffer, screen buffer. See also edit
buffer.
Button Widget
A field-level widget that the user can choose to direct an application to execute a trigger
or control the interface.
Character Client
A combination of hardware and software components that support a character-based
interface. The following platforms support Progress running in character mode: UNIX,
Windows NT, and Windows 95. Windows NT and Windows 95 only support the
character mode by enabling a character client to run in DOS only when DOS is running
under one of these 32-bit Windows operating systems.
Character Constant
A value made up of non-numeric or character data, or a combination of numeric and
non-numeric data that remains unchanged during a procedure. Character constants must
be enclosed in quotation marks when used in a procedure.
Character Data Type
A property of a field or variable that determines that the data stored there can be of the
character data type.
Character Field
A field having a character data type.
Child Frame
A frame parented to (contained by) another frame. See also parent frame.
Child Window
A window parented to (owned by) another window. See also parent window.
Child Window Family
A child window and all of its descendant windows.
Column
1.) A component of a record, a field. 2.) A vertically aligned set of character cells in the
character coordinate system.
Glossary3
Glossary
Database
A collection of data organized in logically related tables or fields that can be accessed or
retrieved.
Database Event
An action performed against a database, such as finding or writing to a record.
Database Object
A component of the database that is defined in the database schema such as a field or a
table.
Database Properties
The schema definitions that define the database, such as the database name, the database
type, and so on.
Database Trigger
A piece of code that an application associates with a component of a database and a
database action (such as writing a record). When the action occurs on the component,
Progress locates this piece of code and executes it on behalf of the application.
Data Dictionary
An interactive tool that enables you to create, modify, and delete Progress database
objects. You can also use it to generate database reports.
Data Type
A property of a field or variable that determines the nature of data that can be stored there
(integers as opposed to characters, for example). Progress supports five data types:
character, integer, decimal, date, and logical.
DATE Data Type
A property of a field or variable that determines that the data stored there can be a date. In
Progress, a date data type may contain a date and time from 1/1/32768 B.C. through
12/31/32767 A.D.
Date Field
A field having a date data type. You can specify dates in this century with either a two-digit
year, such as 8/9/90, or a four-digit year (8/9/1990). Dates in other centuries require a
four-digit year.
Decimal Data Type
A property of a field or variable that determines that the data stored there can be a decimal.
Glossary5
Glossary
External Procedure
A group of Progress 4GL statements that you store as an operating-system file.
Field
1.) The atomic particle of a database-that is, the smallest unit of useful information.
2.) A component of a record that holds a data value. Also called a column.
Field-level Widget
Any widget that can be placed in a frame.
Field Label
A label on the screen or printed reports that identifies the field. If you do not supply a label,
Progress uses the field name as the label.
Field Properties
The schema definitions that define the field, such as the field name, the field type, and so
on.
Fill-in Field Widget
A field-level widget that handles text entry and display. The fill-in field is the default
widget for displaying a variable or database field. Also known as a fill-in.
Footer
Text, such as a page number, placed at the bottom of each page of a report.
Format Phrase
A Progress language description of the display characteristics for a field, variable, or
expression.
Frame
A container widget composed of a display area within a window that Progress uses to
display field-level widgets.
Frame Family
A related collection of parent and child frames.
Frame Scope
The range or extent of a frames availability within a procedure.
Glossary7
Glossary8
Glossary
Inner Join
A join where records from the first (left-hand) table (or join) are only returned to the results
list that also return a corresponding record from the second (right-hand) table.
Input Focus
The ability for a widget to receive user-interface events.
Integer Data Type
A property of a field or variable that determines that the data stored there can be an integer.
Integer Field
A field having an integer data type.
Internal Procedure
Code blocks that you write and compile as part of a larger containing procedure.
Iteration
A repetition of a procedure block.
Join
A type of query operation that requests information from two tables or joins at a time. The
output is a results list where each row contains a record from each joined table. A join can
only occur when the two queried tables or joins have a common field.
Join Condition
The criteria used to relate the fields of one table in a join with those of another.
Key Functions
Tool functions that map to a keystroke.
Key Index
A primary, unique index field in a table.
Label
Text that appears with a field or variable when it is displayed.
Left Outer Join
A join that returns all the records of the first (left-hand) table, including the records from
the second (right-hand) table for an inner join and null field values for all records in the
right-hand table that have no corresponding records in the left-hand table.
Glossary9
Glossary10
Glossary
Menu Titles
The text strings in a menu bar.
Menu Owner
The widget a menu is associated with. For menu bars, the owner is always a window.
Message Area of Screen
Three lines at the bottom of a Progress screen. The first two lines are for
procedure-specific messages. The third line is for Progress system and help messages.
Method
A function associated with a widget or system handle that performs a specific action and
returns a value (like a function) representing the result of that action.
Mnemonic
A single letter that you can press to choose a menu option. The mnemonic for each option
is underlined when it is displayed.
Modal Application
An application or part of an application that forces you to perform a specific action before
you can go on to other tasks.
Modeless Application
An application that gives you control over which tasks you perform when. It allows you a
number of processing choices and then reacts depending on the event you trigger.
Mouse
A device for communicating with a user interface.
Nonterminating Sequence
A sequence that begins at an initial value and increments in one direction with no limit.
See also terminating sequence.
One-to-one Relationship
Occurs when one record can relate to only one instance of a record in another table.
One-to-many Relationship
Occurs when one record can relate to many records in another table.
Operating System
Software that controls and manages the execution of computer programs and services.
Glossary11
Glossary
Primary Index
Usually the most frequently used index. Progress allows you to set one index as primary
and uses it by default when searching for a record.
Procedure
The largest Progress unit of execution, consisting of one or more Progress source or r-code
statements in a single, outer block.
Procedure Area
The visible part of the current edit buffer. This is where you type and edit Progress
procedures. It is also called a text pane.
Procedure Block
A series of statements that Progress treats as a single unit.
Procedure Editor
An interactive utility that provides operations for editing code. You can use it to create,
compile, and run Progress procedure files.
Procedure File (.p file)
A source file containing Progress 4GL code which can be compiled into r-code. Procedure
files normally have a .p or .w (window procedure files) file extension.
Progress 4GL
An application development language which has a highly readable syntax employing a
default behavior while performing the work of multiple 3GL statements.
Pull-down Menu
A vertically displayed list of menu elements (menu items and submenus) appearing when
the user selects a menu title in a menu bar.
Query
1. ) A request for information from a database. 2.) A set of database records that you create
with your procedures. A query can involve one or more tables and can consist of all the
records in a particular table or just a subset. The browse widget is a ready-made interface
to a query.
Radio Button
One of the components of a radio set; it represents one of the possible values that the radio
set can take on.
Glossary13
Glossary
Root Window
A parent window that is parented only by the window system and is the top parent of a
window family. See also parent window, child window.
Row
1.) A collection of related items. Also called a record. 2.) A horizontally aligned set of
character cells in the character coordinate system.
Schema
A description of a databases structure-the tables it contains, the fields within the tables,
views, etc. In addition to database structure, Progress database schemas contain items such
as validation expression and validation message.
Screen Buffer
A display area for a field, variable, or the result of a calculation. When you prompt for
information or display information for the user, Progress places that information in the
screen buffer.
Selection Criteria
Conditional expressions used to select particular records from a database table or tables.
Selection-list Widget
A scrolling list of character strings. The strings are the possible values for an underlying
field or variable.
Self
In a trigger, SELF is a system-handle whose value is the widget handle of the widget that
received the event that fired the trigger. See also system handle and widget handle.
Sensitive Widget
A widget that reacts to user actions.
Sequence
A database object that provides incremental values to an application. Sequences can
generate sequential values within any integer range with a positive or negative value.
Sequence Properties
The schema definitions that define the sequence, such as the sequence name, the initial
value, and so on.
Setable Attribute
An attribute to which the application can assign a new value.
Glossary15
Glossary16
Glossary
Table
A collection of logically related records organized into rows and columns. A table can
contain a program, data, or text. A table is made up of records. It is also called a file.
Table Properties
The schema definitions that define the table, such as the table name, the table type, and so
on.
Terminating Sequence
A sequence which begins at an initial value and increments in one direction until it reaches
the designated limit. See also nonterminating sequence.
Text Widget
A field-level widget that displays any kind of data. It is read-only, and does not receive
normal user events. Text widgets cannot have input focus.
ToolTip
A brief text message that Progress automatically displays when the user pauses the mouse
pointer over a widget for which a ToolTip has been defined. These language elements
support the TOOLTIP option: DEFINE BROWSE statement, DEFINE BUTTON
statement, DEFINE IMAGE statement, DEFINED RECTANGLE statement, and
VIEW-AS phrase. These widgets support the TOOLTIP attribute: browse, button,
combo-box, editor, fill-in, image, radio-set, rectangle, selection-list, slider, text, and
toggle-box. ToolTips are only supported on Windows.
Toggle Box Widget
A field-level widget composed of a small box that represents a logical value. Only values
of type LOGICAL can be viewed as toggle boxes. The presence (TRUE) or absence
(FALSE) of filling in the toggle box indicates the current value. A toggle box can be a
field-level widget or a special type of menu item.
Top-down Programming
Traditional programming where you define larger structures first and then define smaller
and smaller components.
Trigger
A piece of code that Progress executes on behalf of an application when a certain database
action occurs or a certain user-interface event occurs. There are two types of triggers:
database triggers and user-interface triggers.
Glossary17
Glossary18
Glossary
Window Family
A related collection of parent and child windows.
Window Widget
The workspace of your application. Each time you start a Progress session, it automatically
creates a default window.
Word Index
Contains all the words from a character field or array of character fields. Searching with
this index makes it very easy to locate records that contain specific words.
Working Directory
The directory you are in when you issue a command.
Working Database
The connected database that is currently in use. Multiple databases can be connected at any
time, but only one is the current, working database.
Glossary19
Glossary20
Index
Numbers
Arguments
passing 617
using with include files 618
Arrays 55
4GL/RDBMS 15
A
Accelerator keys 115
defining 1116
Accessing help from the Procedure Editor
219
Action widgets 316
Aggregate functions
TOTAL BY 1016
B
Base fields 1029
BEGINS operator 94
Applications 15
Code 15
COL attribute 330
COLUMN attribute 336, 1214
Column events
browse widget 860
Combo box widget 314, 752
item selection 753
TOOLTIP option 754
Comparison operators 512
Compound indexes 19, 414
Concatenation operator 513
Conditional processing 632
CASE 633
IF 632
Constants 52, 510
Container widgets 316
CONTAINS operator 95
Context 123
Control blocks 624
C
CASE statement 633
CENTERED attribute 37, 1214
CHARACTER data type
combo boxes 753
Character operators 513
Data 14
CLOSE key 28
Index
Data Dictionary 110
exiting 44
using 47
Data locations 82
Data types 317, 329, 413, 53
character 413
constants 510
date 414
decimal 414
integer 413
logical 414
Database events
ASSIGN 419
CREATE 419
DELETE 419
FIND 419
WRITE 419
Databases 14
connecting 43, 45, 46
creating 44
defining objects 412
disconnecting 47
events 419
fields 58
help text 423
labels 423
logical names 46
normalizing 916
physical names 46
reports 424
schema 42
DATE data type
combo boxes 753
Date operators 513
DECIMAL data type
combo boxes 753
Default behavior 111, 38
applications 417
DEFINE BROWSE statement 855
E
EDGE-CHARS option 323
Edit buffers 25, 212, 215
multiple 215
Editing keys 213
Editor widget 314, 758
BUFFER-CHARS 759
BUFFER-LINES 759
LARGE option 759
MAX-CHARS 759
NO-WORD-WRAP 760
SCROLLBAR-HORIZONTAL 760
SCROLLBAR-VERTICAL 760
Index3
Field lists 88
Field-editing key functions 332
ENTER-MENUBAR key 28
FIELDS option 88
Error messages
displaying descriptions xxvi
Index
Frame backgrounds 1030
Frame families 327
enabling input 1215
rules 328
tabbing 1211
Frame headers 1030
Frame scope 1212
Frame widget 315
attributes 1213
default 323
defining 323, 336
frame phrase 326, 337, 344
IN 349
WITH FRAME 337
Frames
frame phrase 628
WITH FRAME 815
FREQUENCY option 740
FUNCTION statement 66
defining parameters 613
Functions 52, 514
arithmetic
SQRT 515
data conversion
ASC 628
CHR 628
event
ENDKEY 1219
GO 1219
VALUE-CHANGED 729, 741
WINDOW-CLOSED 1224
WINDOW-MAXIMIZED 1224
WINDOW-MINIMIZED 1224
WINDOW-RESTORED 1224
FUNCTION statement 515, 66
PAGE-NUMBER 1032
pre-defined 514
user-defined 515, 66
VALID-HANDLE 127
G
GO event 332, 1219
GO key 28
Graphic widgets 316
Graphical user interfaces 33
H
HANDLE attribute 329, 123
Help
accessing 4GL language information
224
basic concepts 221
Contents Tab 221
Find Tab 223
HELP key function (F1) 223
Index Tab 222
Progress messages xxvi
Windows Help Topics dialog box 221
HELP key 28, 219
HIDDEN attribute 329, 1214
HIDE MESSAGE statement 336
HIDE statement 344
High-level event functions 332
HOME event 860
HORIZONTAL option 733, 739
I
IF statement 624
IF THEN ELSE statement 632
Image widget 315
IN FRAME option 345, 349
Index5
CLOSE 28
END-ERROR 28
ENTER-MENUBAR 28
field-editing 332
GO 28
HELP 28, 219
navigation 332
PUT 28
universal 332
Keys 919
J
Joins
conditions 924
table 924
K
Key functions 27
Index6
L
LABEL option 317, 114
LARGE option 759
LARGE-TO-SMALL option 739
LAST-PROCEDURE attribute 124
LEAVE event 332, 860
LEAVE event function 724
LEAVE statement 626
Left outer joins 925
LIKE option 53, 54
LIST-ITEMS option 745
LIST-ITEMS( ) method 748
Literals
passing 617
LOGICAL data type
combo boxes 753
Logical database names 46
Logical operators 514
Index
M
Main logic 622
Main procedures 62
Manual
organization of xvii
syntax notation xxi
Monospaced typeface
as typographical convention xx
Mouse actions 27
Mouse functions 27
Multi-frame interfaces 1211
MULTIPLE option 745
MATCHES operator 94
MAX-CHARS option 759
NO-BOX option 37
Menu widget
attributes 1119
conventions 1120
toggle box 1115
Menus 27, 29
symbols 212
using 48
Normalization 916
Messages 336
displaying descriptions xxvi
Methods 349
OF option 919
ON statement 39, 336
Online Widget Tutorial 27
OPEN QUERY statement 819
inner joins 925
left outer joins 925
Index7
Phrases 218
Operands 52
Operations 52
Platform considerations
basic key functions 28
using the browse widget 854
Precedence 515
Pre-defined function 514
PREV-SIBLING attribute 127
Primary indexes 415
PRIVATE-DATA attribute 126
PROCEDURE statement 64
OR operator 311
Outer joins 927
P
PAGE-BOTTOM option 1032
PAGE-NUMBER function 1032
Parameters 611, 125
INPUT 612
INPUT-OUTPUT 612
OUTPUT 612
Procedures 14, 24
examples of xxiv
managing 122
parts 37
persistent 123, 125
procedure block 622
tutorial examples 22
Programmed responses 39
Programming models 32
PROPATH 25
Index8
Index
Property sheets 48
using 49
REPEAT statement
inner joins 925
Reports 102
aggregate values 1015
control blocks 104
editors 1012
multiple destinations 1028
multiple-table 1019
output statements 104
printing 1027, 1041
sending to other devices 1024
text widgets 103
viewing on screen 107
PUT key 28
PUT statement 1036
Q
Queries 811, 818, 853
R
Radio set widget 315, 732
HORIZONTAL 733
VERTICAL 733
RETURN statement
NO-APPLY option 312
ROW attribute 330, 336, 1214
Row events
browse widget 860
Record buffers 82
Records 17
creating 840
deleting 844
releasing 838
selecting 92
sorting 99
S
Sample procedures 22
Saving widget values 717
Schema 42
Schema triggers 419
Screen buffers 82
SCREEN-VALUE attribute 329
SCROLLBAR-HORIZONTAL option
Index9
SELF handle 58
Starting Progress
on Windows 22
Sequences 415
cycling 417
nonterminating 417
properties 416
terminating 417
Session triggers 419
SET statement 850
Setable attribute 329
SHARED option 610
Shared resources 124
Shared variables 610
Syntax 218
block 218
SIDE-LABELS option 37
System handles 58
CURRENT-WINDOW 118, 1223
DEFAULT-WINDOW 118, 1223
SELF 58
Index10
Index
THIS-PROCEDURE 127
T
Tabbing
between frames 1211
U
Universal key functions 332
UPDATE statement 832
Updateable browse widget 852, 856
Tables 16
keys 919
related 916
User input 35
V
ValExp option 417
Tool buttons 23
Validation 42
Data Dictionary 828
expressions 417
messages 417
Index11
W
WAIT-FOR statement 38, 331, 337,
1227
WHERE option 519, 922
selecting records 94
WHILE option 625
Widget attributes 329, 349
Widgets 26, 35, 314
action 316
attributes
readable 329
setable 329
browse 315, 98
button 315, 319
categories 316
checking values 717
combo box 314, 752
item selection 753
containers 316
data 316
default response 38
defining 37, 316
dialog box 315
disabled 341
editor 314, 758
enabled 35, 341
Index12