Professional Documents
Culture Documents
With the exception of this manual, the manuals are not designed to be
read in any one sequence, nor are the contents of each manual. In the
same way, DataFlex’s own features are not best learned in any
predefined sequence, again with the exception of those covered in this
manual. Two of the manuals contain only information about object-
oriented programming and the DataFlex User-Interface Management
System (UIMS). They are the UIMS Handbook and the UIMS Reference.
The other two manuals cover the basic concepts of DataFlex (the User’s
Guide) and a reference to the DataFlex commands (the Encyclopedia).
1 Introduction 1
DataFlex Application Framework methodology. By the time you
complete this section, you will be able to run DataFlex and create a
functional set of data-entry prototype programs in minutes, without
having to write one word of program code! The section concludes with
the creation of report programs for the same application using
DataFlex’s Query report generator.
There are also many sample applications supplied with the DataFlex
software. On disk or tape (UNIX only), the samples offer a ready
means of actually working with the source code, compiling it, running
it, and modifying it.
1.1.3 Encyclopedia
Since the UIMS offers over 500 messages and properties, the UIMS
Reference contains redundant, cascading lists of messages and
properties for which you will need explanations from time to time in
mastering the UIMS. These lists contain message and property names,
parameters, eligible values, default values, and source classes, so that
many times, just finding the desired keyword in a table will provide
the needed information.
1 Introduction 3
1.2 Introduction to DataFlex
This term has become a misnomer for DataFlex, however, since it now
can accommodate database drivers for a growing number of
proprietary data formats, including those that comply with the Open
Database Connectivity standard. DataFlex applications ("clients," or
"front ends") can be used with multiple database-file formats
concurrently, and in fact, need not use DataFlex (-format) data at all.
References in this and the other manuals to the "DataFlex database
manager" are in fact references to behaviors of the DataFlex database
driver. These behaviors may or may not be the same in other database
drivers supported by DataFlex.
First introduced in 1981, DataFlex has been used successfully for many
thousands of database-oriented applications. It has proven itself
countless times as an efficient environment for the development of
personal applications as well as applications for concurrent use by
hundreds of users, in both commercially packaged products and
systems developed for in-house use.
DataFlex’s DBMS has the capacity to manage very large data files
within a single application. It supports file relationships in multi-level
hierarchies (many records in a "child" file relate to one record in a
"parent" file). It supports the finding of records in data files through
B+ ISAM (Indexed Sequential Access Method) indexes, and can find
one among several million records in a fraction of a second under
typical data and hardware conditions.
1 Introduction 5
1.2.2 The Language
1 Introduction 7
The Query Utility (DFQUERY) provides an interactive means of
extracting data from DataFlex databases, either to a printer, a file, or
the screen. It is capable of addressing multiple related files for a single
report, and offers the means to select both fields to output and the
order in which records are output. It further provides the means to
specify selection criteria for the records output. Finally, it can store
queries (in either of two forms) to repeat later without re-entering
them. One form, for application users (Query format), can be run
directly by Query, while the other form is editable source code, which
can be run by the DataFlex runtime after compilation.
The Menu Utility includes both a system for displaying menus and
acting on user input to them and a means of modifying menus or
creating new ones. Its capabilities include presenting choices in a
scrollable list, prompting users with questions for choices made, and
acting on input to execute programs of all kinds, both DataFlex and
otherwise. DataFlex is supplied with a menu for its utilities, its sample
applications, and various operating-system functions.
Database
1 Introduction 9
Database Files. The database manager performs its basic work with
data on disk, retrieving data from disk, manipulating the data,
importing data, outputting data, and placing new or changed data
back onto disk. Like all data on disk, DataFlex data is in files. Database
files are known as "tables" in database theory and SQL.
Every database file has one, and only one .DAT data file. This file
contains the actual data in records of the database file. If you use file
compression, the data is kept in a .VLD (variable-length-data) file, and
the .DAT file then contains only pointers into that file. If the database
file is indexed, as most are, the fileset will include one index .K## file
for each index. Every database file is created with a .TAG file that
contains the names of the fields in the order in which they stand on
the disk. Similarly, every file is created with an .FD file definition file
to guide the compiler in references to the database file in programs.
Records. The values in the fields of database files are associated with
each other by records, sometimes referred to as rows in SQL and
database theory. A record is merely an instance of the complete set of
the file’s fields with values for some, but not necessarily all, of the
fields. If a file of persons contained names and phone numbers, each
record would contain a name and the phone number pertaining to that
particular name. DataFlex does not create blank records.
1 Introduction 11
An index can contain up to 16 fields, and DataFlex provides for up to
15 indexes on each database file. The programmer defines indexes at
the same time, and using the same utilities, as the rest of the database
file.
Aside from the fields making them up, there are four other basic
attributes of indexes. First, indexes may be unique or non-unique. If
they are unique, records with matching values in the fields making up
the unique index may not be created. If they are non-unique, records
may have matching values in the fields making up the index, but the
record number is appended to the index entry. Since every record
number is different, this allows DataFlex to differentiate between the
records in that index. Records having matching index-field values are
found in their record number order.
Second, indexes may be either batch or online. The batch index mode
is intended for indexes that are only used from certain programs for
certain purposes, such as the printing of a monthly report. A batch
index must be updated by an explicit process known as reindexing,
and then used before any changes are permitted to the database that
might render it obsolete. Online indexes are updated every time a
change is made to the value of an indexed field. While this process
keeps indexes up to date for ongoing use, it does impose a slight time
delay on saving and deleting records.
First, the telephone number for new entries, or existing persons who
changed their place of employment, could be changed merely by
selecting the record for the employer, pointing to it from the name
record, and saving that association (relationship) to the database.
Third, whenever the phone number (or address, or even the name) of
an employer changed, the number could be changed in the one
employer record, and the same correction would immediately take
effect for all persons whose records related to the employer record.
As you see, relations are not really between files, but rather between
fields in files, and they are defined that way (between fields) as part of
the process of defining database files. When there are records with
actual field values, relationships actually exist between records—
always from zero, one, or more records in the relating (child) file to
only one record in the related-to (parent) file.
1 Introduction 13
When one or more relationships to parent files are defined in a child
file, DataFlex commands automatically make use of the defined
relationship to create and maintain it, leaving the programmer to
concentrate on providing an interface that renders the relationship
clear and usable to users.
Data Entry
In most cases, the way data is entered into a database and maintained
is through a form—a type of data-entry object. A form usually contains
data windows (distinctively marked areas of the screen representing
the length of the file field that will hold the data) and static text (titles,
field names, and prompts, for example). The cursor progresses from
data window to data window in some logical fashion as operators type
in data, which is at some stage saved to the database.
The design of forms can make all the difference in easy, quick, and
efficient data entry. They are often made to resemble the (paper) form
from which operators may be typing data; they can cover the whole
screen or just part of it, and they can be as simple or as complex as
you like. A well-designed form also gives plenty of visual clues to
help operators move around it efficiently and keep track of what is
happening.
With AutoCreate you may create and edit one or more applications
(which consist of views and database files that address a particular
aspect of a business—all the payroll functions, for example).
AutoCreate maintains its own database of the information it needs
about the views and files in each of your applications.
If the data files connected with an application already exist, you may
open them through AutoCreate and insert fields from them into view
objects. You can also read ASCII text files containing images into
AutoCreate, and you can draw fields (using underscores) into new or
existing objects and have AutoCreate automatically convert them into
real fields in your files.
Within AutoCreate, you can also add, change and delete field, index,
and parameter definitions for files with no data in them. A DataFlex
Text field, or an ASCII field wider than the area of the object you are
working in, can be accommodated in an object called an editor. In
object-oriented DataFlex, you may also create an object called a table
for multi-record entry. You may also create objects called clients to
contain entry forms, tables, and editors so that they always appear
together on the screen. Two extremely powerful and useful pop-up
objects you may also create are prompts and zooms, both of which
display additional data temporarily over the current view. Prompt
objects temporarily display an expanded list of available choices, while
zoom objects temporarily display additional fields of the current
record.
1 Introduction 15
draw types and their colors, and you can specify the number of rows
in a table display, and the spacing between them.
Once fields are defined, you don’t have to worry about their length
and type, since you simply select them by name from a list, and they
are converted to a block of thick underscores, which you can move
around your screen and place in the desired position. You can
automatically center text and fields in an object if you wish, and draw
single or double lines with the arrow keys.
The use of the left mouse button for entry, menu, and list selection is
the same as in all other areas of DataFlex, but in AutoCreate you can
also use the right mouse button. The right button is used for moving
and resizing objects, and for converting a field to its block of
underscore characters, then dragging that block to wherever you want
it in one or more objects.
You can pick one or more entry options (referred to in the "Data
Entry" section above) to be added to the entry line in the program for
each field.
1 Introduction 17
Reporting
Once you have data in a database, you usually want lots of reports on
it. These reports are often highly formatted for presentation and
readability: you may have multiple breakpoints for grouping data;
totals and subtotals of numeric data; text such as dates, headers,
column titles, and page numbering; you may want to specify particular
page control, or that output goes to different devices for different
reasons; and most of all, you probably want some selection and sorting
process to take place, so that the records printed in the report are only
those relevant to the subject of the report.
The selection criteria may be fixed and always the same (all postal
codes in Bolivia, for example), or they may be calculated (all sales over
5% of the total), or they may be input by the operator (all contacts in
whatever city is keyed in).
To create a report, you can code the entire process manually if you
choose, but you can generate a report program completely
automatically, using the DataFlex Query Utility, then edit the resulting
program to "fine tune" it if necessary. DataFlex has an integrated set of
selectable predefined output procedures in the Report object classes.
You can use the selected procedures with messages and property
values relating to your requirements to "fill in" output "images" and
then send the images (with data in them) to the output device.
One of the best ways to learn how Report works is to "build" your
report in Query and then study the source-code file generated by your
session. Unless you need sophisticated formatting or subtotalling, it is
likely Query can satisfy all your reporting needs, and even if it can’t,
Query is an excellent way to begin a report program, by producing a
source file which you may then edit to contain all you need.
Once you have completed a particular query, you can go back and edit
it before or after you have produced its output. You can save your
query by assigning it a name. To repeat the query at any future time,
you can choose the name you assigned to it from a list of kept queries
which is presented automatically each time you open those same files.
Query also offers the option to generate report source-code files that
can be compiled and run as a DataFlex program. The main advantage
this has over keeping it in Query is that you can modify the generated
source code to produce literally any report action of which DataFlex is
capable. Of course, if you wish, you may easily do both.
1 Introduction 19
20 Developing Applications with DataFlex
2 PROGRAMMING IN DATAFLEX
This chapter introduces the DataFlex object-oriented programming
environment, an environment consisting of the DataFlex programming
language, the object-oriented engine, the User Interface Management
System (UIMS) and the high-level tool-kit (the high level classses). The
programming environment is built in layers. The UIMS is built upon
the object-oriented engine. The high-level classes are built upon the
UIMS by using the DataFlex language. Your applications will be
created by working with the high-level tools and the DataFlex
language.
2 Programming in DataFlex 21
with modal navigation where users are required to finish one task
before moving on to the next. Modal navigation is sometimes referred
to as being procedural. UIMS applications support both modal and
non-modal navigation. A real-world application will be primarily non-
modal (user-driven) mixed with occasional presentation of modal tasks
(sometimes the program must take control).
5. The developer can extend the UIMS toolkit to create their own
unique toolkit. Since OOP encourages reuse and not
rebuilding, you will not find yourself having to "re-invent the
wheel"; instead you will improve the wheel.
2 Programming in DataFlex 23
As you learn more about object-oriented programming, you might
want to make note of the following points:
In addition to using using supplied classes, you will also create your
own classes. In particular, you will create a set of classes called data-
set subclasses. You create a data-set subclass for each file in your
application and place the database rules for the file in the subclass.
These are the custom tools of an application.
Object packages are most often used to create global "utility" objects. A
global object is an object that all other objects may access. Common
examples of global objects are views, selection lists, the error handler,
the help system, a button bar, and the confirmation object. In some
cases, these objects could be small (a confirmation object, a selection-
list object). In other cases, an object package could be quite large (e.g.,
an order-entry view). While some object packages are supplied with
the product (the Confirm object package), most object packages will be
created by you, the developer.
3.2.2 Views
Views should be coded and tested in the exact same object package file
that will be used by the main program. Once such a view has been
tested, it may be added to a program by changing only a few lines of
code in a main program to include the package file. This, along with
views’ independence from one another, makes it quite easy to add and
remove views from a program.
A view package will usually use still other packages, these containing
objects and classes. For example, a view might contain a package of
data-set subclasses, several object packages for selection_lists,
and an object package for confirmations.
//======================================================================
// ordentry.src - Order Entry main program
//
//======================================================================
Use AllEntry
Use ExitApp // Smarter exit. Checks and warns of changes.
Set Application_name to "OrderEntry" // this is useful for the help system
//************************* create backdrop ***************************
Use BackGnd // Standard background and title...creates object
Send Paint_Desktop to (Background(Current_Object)) ;
"Software Order Entry System" // You set the title
The steps for creating a view are actually quite simple. Create a
container client object. Inside the container object, place all of your
data-set objects (DSOs). The data-set objects must be placed side by
side (as siblings of each other) and properly connected to each other
with updating clauses. Place your data-entry objects (DEOs) below
your data sets. These may be nested according to navigational needs.
Connect the DEOs to the DSOs with using clauses. That’s it.
A view must be fully encapsulated. This means that the entire view
must be contained inside a single object. The container object should
be based on the entry_view_client class. The
entry_view_client class is a subclass of the entry_client class.
It is ideally suited for containing a view. The surrounding program
will communicate with this view by sending messages to this container
object.
Before you create any data-set objects, you should first create one data-
set subclass for each database file in your program. This creation of
data-set subclasses should not be considered an advanced technique.
Instead, it should be considered a mandatory technique. Place all of
your special database rules in these data-set classes (not in the
objects—in the classes). Typical messages you will need in these
classes are update, backout, creating, validate_save and
validate_delete.
Your data-set objects will be based on the custom data-set classes that
you create and use in the top of your program. For example,
There are specific rules for placing data-set objects (DSOs) in a view
client. These are:
2. Data sets are placed as sibling objects inside the view client.
The parent-file data sets are created first; those for descendant
files are created in order by generation.
5. If you need your view to "see" only the records in a child file
that are related to the current parent-file record, you will need
to place a command constrain child_file relates to
parent_file inside a begin_constraints /
end_constraints command block. This constraint link is in
addition to the updating link. (They are separate links.) As a
general rule, do not create a relates to constraint unless it
is needed.
When you create and connect DSOs in a view, you are creating a data-
set structure. A connected group of data-set objects will all act in a
coordinated fashion—this is what you want. A data-set structure must
be encapsulated inside the view. You would never connect two data
sets (with updating) across two views.
Orders Inventory
Order_Detail
Container Client
Customer_DS
Terms_DS
Vendor_DS
Orders_DS
Inventory_DS
OrderDtl_DS
Your data-entry objects should be placed below your data sets in the
entry-view client. Do not nest data-entry objects inside data sets. The
DEOs are created with the following rules:
In some cases, a view’s DEOs will all connect to a single data set
(although this data set will often connect to other data sets). In other
cases, different DEOs within a view will use different data sets. An
order-entry view will have its header DEOs using a header data set
and the line-detail DEOs using a detail data set. In all cases, DEOs
only use the data sets that are internal to the view they are in
themselves.
Referencing Objects
(object_name(current_object))
Constructing a View
A View-Object Package
/*
Activate_View Activate_Customer FOR Cust_entry
Object Cust_Entry is an Entry_View_Client No_Image ;
Action_Bar (Main_Menu(current_object))
Object Customer_DS is a CUSTOMER_Data_Set NO_IMAGE
End_Object
Set Verify_Save_MSG to GET_Save_Confirmation
Set Verify_Delete_MSG to GET_Delete_Confirmation
Set Verify_Data_Loss_MSG to GET_Data_loss_Confirmation
Set Verify_Exit_MSG to GET_Exit_loss_Confirmation
Object Cust_Form is an Entry_Form Cust_Form ;
Using (Customer_ds(Current_Object))
Set Location To 3 33 Relative
Item_List
Entry_Item customer.number { AutoClear, AutoFind, NoPut, ;
iPrompt=(Cust_List_Prompt_List(Current_Object)) }
Entry_Item customer.customer ;
{ iPrompt=(Cust_List_Prompt_List(Current_Object)) }
Entry_Item customer.address
Entry_Item customer.city
Entry_Item customer.state { Capslock }
Entry_Item customer.zip
Entry_Item customer.discount
Entry_Item customer.pur_month { DisplayOnly }
Entry_Item customer.pur_year { DisplayOnly }
//---------------------------------------------------------------------------
// custlkup.sl - The customer lookup list object package
//
// Access: Send Popup to (Cust_lkup(current_object))
//---------------------------------------------------------------------------
Use Allentry
open customer
/Cust_Lkup_img
Customer List
Cust# Name
_____. ______________________________
_____. ______________________________
_____. ______________________________
_____. ______________________________
_____. ______________________________
_____. ______________________________
_____. ______________________________
/*
Object Cust_Lkup is a Selection_List Cust_Lkup_img PopUp ;
Main_File CUSTOMER
set auto_locate_state to TRUE
set allow_move_state to TRUE
Set auto_index_state to TRUE
Begin_Row
Entry_Item customer.number { AutoClear}
Entry_Item customer.customer { AutoClear}
End_Row
End_Object
When a program is run, these steps are executed in the order in which
they are listed. First, all of the classes are defined. These classes
typically consist of the standard high-level classes plus any custom
classes you have created. Next, objects are created and initialized.
These objects are based on the classes that were just defined. At this
point, some of the user-interface objects may be activated, which
means the objects are placed on the screen. Finally, the UI-event
processor is started by executing the start_ui command.
4.1 Overview
By the time you commence with this chapter, we assume that you
have read the first three chapters, or at least Chapters 2 and 3. If you
have not, you may find some of the information covered in this
chapter extraneous and confusing.
By the time you finish with this section, you will have created a fully-
functional object-oriented program; and, you won’t even know you did
it! Aside from building an application, you will also learn how to
generate a report using DFQUERY. The resulting program, called
CONTACTS, as well as the custom report can be put to immediate use
without further modifications.
DataFlex Tutorial 45
developers, such as business rules. You can then apply what you
learned in this section to build robust industrial strength database
applications for any business situation you encounter.
In effect, once you have read this chapter, you will know how to:
Before you begin working with the Tutorial, you should read the notes
in this section. Doing so will facilitate the process of working through
the Tutorial.
4.2.1 Notes
In all DataFlex utilities, you can access the action bar by clicking the
mouse on the name of a pull-down menu, or by pressing 0 l
then
r
or . To select a menu choice, click on it with the mouse, or move the
selection cursor (highlight bar) to it with arrow keys and press e .
A shortcut to display a particular pull-down menu is to press a and
its initial letter.
So, now that you have read about the numerous features and
capabilities that DataFlex provides, let's see how you can use DataFlex
to create sophisticated applications and generate custom reports. This
short section demonstrates how easy it is to design and generate a
complete, working application in short time without programming a
single line of code.
Once you have followed the steps in this section, you will know how
to
DataFlex Tutorial 47
• Create a data file
• Define an index
• Prototype a view
Note that when you are creating large-scale applications for clients,
you will have to use significantly more information gathering
techniques. The second example provides a more comprehensive (or
in-depth) discussion.
For the contacts application you are developing, you can state the
following:
The purpose of this application is to keep track of all the business and
personal contacts you have established throughout the years. Also,
the application should be able to produce a mailing list so that you
can send information to those contacts.
Figure 1- The form where you enter information for the contacts.
Title
Address
City
State
Country
Zip Code
Phone Number
Fax Number
Comments
As you can see from the list shown above, there are eleven data
elements that must be represented as fields in the database. Each field
DataFlex Tutorial 49
will store a particular piece of contact information. It is through these
fields that data entry will take place.
For each database field, a name, type and length must be specified.
There are several rules to consider when you are determining the
names of the fields for your database;
The field type defines what sort of data will be allowed in the field.
The data type you choose for your database should reflect the
information stored in the field.
For the Contacts application, create a database with fields that are the
same as the information contained on the manual form in Figure 1.
The field names, types and lengths are:
LAST_NAME ASC 15
FIRST_NAME ASC 15
COMPANY ASC 30
TITLE ASC 15
CITY ASC 14
STATE ASC 2
ZIP ASC 10
PHONE_NUMBER ASC 20
FAX_NUMBER ASC 20
There are certain files for which the default settings should be
changed; DFENV.CFG, SETPATH.BAT, FILELIST.CFG and
AUTOGEN.INI.
DataFlex Tutorial 51
The first three have been pre-configured so that the numerous Sample
Applications provided by DataFlex will operate in a proper fashion.
Before you start modifying the contents of these files, you should first
copy the files from the \FLEX\USR directory into the
\FLEX\PROJECT1 directory. You DON’T want to delete the contents
of the original files, since they are still required by other applications.
Since you will be developing and deploying (or distributing) your own
applications, it is unlikely that you will be including the DataFlex
Sample Applications in your software package. Therefore, you should
delete some of the information in these files so that you can customize
them to fit (or suit) your particular needs.
This first file is named DFENV.CFG. The DFENV.CFG file contains the
default value for the DFPATH environment variable. As you know
from the Installation Notes, DataFlex searches through the directories
specified in DFPATH when you are attempting to open (or reference) a
data file.
By default, the directory paths for all the Sample Applications are
included in the DFPATH environment variable. When you are
developing your own applications, you will not be using the database
files for the Sample Application. In other words, you will not have to
reference them in any way. Therefore, you should remove the Path
entry for the Sample Applications. Also, this will facilitate the process
of removing the Sample Application entries from the filelist. This is
because File Definition Utility (DFFILE) searches through the current
DFPATH setting and tags those data file entries which do not exist in
the DFPATH.
Now that you have created a new environment configuration file, you
need to modify the SETPATH.BAT file in such a way so that it points
to the DFENV.CFG file in the \FLEX\PROJECT1 directory.
DataFlex Tutorial 53
Figure 3-The DataFlex File Maintenance Utility, showing the current filelist.
The list of data files for the current Filelist will appear (see Figure 3).
Without further delay, let’s create the data file and indexes for the
Contacts database application. You will use the File Definition Utility
(DFFILE) to accomplish these tasks.
DataFlex Tutorial 55
Figure 5- The main screen for the DataFlex File Definition Utility.
The Main Screen for the File Definition Utility will appear (see
Figure 5).
Figure 6- The DataFlex File Definition Utility, showing the Parameters... panel
for the CONTACTS data file.
5. Press q.
6. Now you are going to create the fields for the CONTACTS
data file.
DataFlex Tutorial 57
In this panel, you will enter the names of the fields for the
CONTACTS data file as well as some field characteristics. Use
the table in section 4.3.2 to fill in all the field information.
Notice that when you enter the length for the COMMENTS
field, you will see a message stating that the record length has
extended to 1280 bytes from its default 512 bytes.
9. After you have finished entering the fields, the Fields panel
should look like Figure 8.
10. Press q.
58 Developing Applications with DataFlex
Now, you have to create the indexes for the Contacts database
application.
Adding/Creating Indexes
As you know from Chapter 1, there are several reasons why creating
an index for your database is an important task.
Figure 8- The DataFlex File Definition Utility, showing all the fields for the
CONTACTS data file.
For the contacts application, you need to create indexes for the
following reasons:
DataFlex Tutorial 59
field. This sorting sequence would provide two
benifits. First, it enables you to find a record in the
contacts application based on the value you entered in
the Last Name and First Name fields. Second, it allows
you to print out a report of all the records sorted by
Last Name and First Name.
4. Press the v to move the cursor to the U/C box and press
g to select it.
DataFlex Tutorial 61
5. Press the down arrow to move to the second Fields window.
Press 4 and select FIRST_NAME from the list of available
Figure 10- Creating an index, which allows you to find records in the
file in some specified order - in this case by Company, Last Name and
Record Number.
fields. Check the U/C field and leave the Desc field as is.
Move to the third field segment window and enter RECNUM
in the space provided.
The U/C (Upper Case) option tells DataFlex that the contents of the
LAST_NAME and FIRST_NAME fields should always be treated in
indexes as being upper case. This will have no effect on the data itself;
it will still appear in the same way it was entered.
If you also wanted the index to start at the end of the alphabet and
work backwards, you could check the Desc box (it stands for
descending). The Batch box is only checked when you don’t want an
6. Press PgDn to define the specifications for index #2. Use the
same steps shown above to define this index (see Figure 10):
COMPANY YES NO
LAST_NAME YES NO
RECNUM NO NO
After you have created the field and indexes for your data file, you are
ready to design and prototype the Views for your application.
Data Entry objects (e.g., Entry Forms, Tables and Editors) allow you to
examine, select or manipulate data in the database. In fact, all visual
interaction with the database occurs in data entry objects.
DataFlex Tutorial 63
Figure 11-An Application Style, showing the Code Style, names of the
Application, Main File and Title; dates of creation and Last Update; Author and
Comments.
To start up Autocreate,
1) An entry form
3) A text editor
DataFlex Tutorial 65
Designing the Contacts Entry Form, Editor, and Prompt
List
Figure 12-Creating an Object, which can be a Form, Table, Editor, Client, Data
Set, Prompt List or Zoom Form.
Entry Form Design. Let's start out by designing the Entry Form for the
Contacts Application.
Dialog and Pop-up are CUA terms describing what the form
will be used for - whether the user will be entering data into it
(conducting what CUA calls a Dialog), or will be a Pop-up,
containing prompts or messages. When you choose Dialog,
the form will have its title embedded in the top edge, and a
Pop-up has its title centered just beneath the top edge. If you
don’t choose either, or if you don’t enter text for a title, the
form will have no automatic title.
6. Press <OK> and the empty form will be drawn in the middle
of your screen, on top of the BACKGROUND.
Notice that the name of the object (Contacts) also appears in the status
line at the bottom of the screen. You can move the form by dragging
the top line with the right mouse button depressed (non-mouse users
select Move from the Objects pull-down to highlight the boundary,
then move the whole form with the arrow keys and press e when
done). You can also resize the form by dragging on the bottom or right
boundary - or the bottom right corner to change height and width
simultaneously (non-mouse users select Resize from the Objects pull-
down).
DataFlex Tutorial 67
There are several ways you can "paste" the fields onto a form. If the
fields already exist, you can pop up the Field Toolbox and get
them from there. If the fields do not yet exist, there are still several
ways to create them. Here’s a quick summary (For more information
on the methods shown below, please see the DataFlex User’s Guide):
• You can create the fields (in the same way as in the File
Definition Utility) through the Database pull-down, then
access them from the Field Toolbox.
• You can draw underscores between the static text, then tell
AutoCreate to scan for them, prompting you for names.
• You can pop up the New Field Toolbox and enter the
details of each field as you go.
Comments
___________________________________________
___________________________________________
___________________________________________
___________________________________________
___________________________________________
___________________________________________
1. Drag the top left corner of the form with the right mouse
button, (or select Move from the Objects pull-down, then use
the arrow keys) to place the top left corner under the "c" in
Application on the action bar.
4. Now, type in the static text descriptions for the rest of the
fields. The fields will be left justified.
When you place the fields in the form, make sure to position
the blinking underscore characters so that they are vertically
lined up.
As you can see in the figure in the previous page, you need to
create a horizontal line to separate the Comments section from
the rest of the form.
7. Position the cursor on the left edge of the form, two lines
down from the Fax# label. Press c1 + to enter Line
Drawing mode. Using the right arrow, draw a single line from
the left edge of the Form to the right edge of the Form.
Note: The Edit menu contains choices for various common text
editing functions, all of which are explained in the DataFlex
DataFlex Tutorial 69
Figure 13-The AutoCreate Utility, showing the form and editor for the
Contact’s Application. The editor is embedded in the form.
User’s Guide.
Editor Design. For the Comments area, you will be creating a new
editor object and placing it in a position inside the existing form. This
gives users full word-processing capabilities such as paging, scrolling,
word-wrap and block operations any time they are editing this field.
2. When the editor form appears, resize it and move it to the area
under Comments.
In the CONTACTS example, you need to create a prompt list for the
Contacts entry form. The Contacts prompt list will enable users to
easily browse through the list of existing contacts, select a contact, and
then retrieve information about the specified contact. To create a
prompt list,
DataFlex Tutorial 71
Figure 14-The AutoCreate Utility, showing the Contact prompt list as it will
appear when activated from the Contacts form.
You will design a prompt list that looks something like this:
Contact List
Last Name First Name Company
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
5. Press a+$ (or select Field Toolbox from the Fields pull-
down) to activate the Field Toolbox. Select the
LAST_NAME, FIRST_NAME and COMPANY fields of the
CONTACTS data file. Click and drag each field from the Field
Toolbox to a position underneath the appropriate heading in
the prompt list. You will notice that the fields repeat for each
row in the list (see Figure 14).
You can use various entry options to set ranges of allowable input
values, for cursor navigation, for formatting input, for database
integrity, and for retaining data in windows to avoid repetitive typing.
First, you will create a prompt for the Selection List pop-up on both
the LAST_NAME and FIRST_NAME fields. This will allow the user to
4
activate (or pop-up) the Selection List object by pressing when the
cursor is in the LAST_NAME or FIRST_NAME fields.
DataFlex Tutorial 73
4. Move the selection cursor to the STATE field (make sure the
status line says CONTACTS.STATE), and press 4
(or select
Entry Options from the Fields pull-down).
Since this is the first time you have used AutoCreate, you will
be asked if you want to create the application files. These are
files that AutoCreate uses to hold information about your
applications. Press on the OK button to create them.
Before you generate the code for the Contacts application, you must
use the Object Toolbox to reorganize the Object structure.
BACKGROUND <Client>
CONTACTS <Data Set> [ ]
Contacts <Form> [ ]
Comments <Editor> [ ]
Contact_lkup <Prompt List>
As you can see, there is an entry for each of the data entry objects you
have created; the Contacts Entry Form, the Comments Editor, and the
Contacts prompt list. A Data Set object was created for the Main File,
CONTACTS. Note that an entry consists of the Object Name followed
by the type of object.
The problem with this structure is that the Entry Form and Editor
would not appear on the screen at the same time. If you filled the
Entry Form with data from the Contacts data file (i.e, you retrieved a
record), the Editor would not appear; therefore, there would be no data
in the Comments section. In this case, the Editor object will appear
only if the user navigates to it.
To solve this problem, you must move the Editor entry so that it is one
level lower than the Form entry. This will nest the Comments Editor
object inside of the Contacts Entry Form object, thereby allowing both
objects to appear on the screen at the same time.
To move the Editor entry, you must first select it either by moving the
selection cursor to it and pressing e or by moving the mouse
cursor to it and holding down the right button; once selected, the entry
will begin to blink. Then, move the entry so that its first letter is in the
box to the right of the Form entry. You could have also used the right
mouse button to drag the entry to its new position. Now, the Object
Toolbox should look something like this:
BACKGROUND <Client>
CONTACTS <Data Set> [ ]
Contacts <Form> [ ]
Comments <Editor> [ ]
Contact_lkup <Prompt List>
DataFlex Tutorial 75
In the context of a family tree, the Editor is said to be a child of the
Form (parent).
After you have finished designing the visual components of your view,
you are ready to use AutoGen to produce the source code for the view
package, selection list object package and data set package.
You can invoke AutoGen from the AutoCreate Utility or from the
command line.
Figure 15- The main panel for the AutoCreate Source Code Generation Utility,
showing the View package as the current choice.
To generate the code,
Below is a brief description for each of the options listed on this panel.
View test program: This option will create all the re-usable
packages as well as a test program for the application you
selected. The test program has some built in debugging
facilities which will enable you to verify the integrity and
functionality of the views you have designed. It provides a
message tracer ( c9 + ), an object-tree browser ( c9 + ), a
a0
focus-tree browser ( + ), and an expression evaluator
(cE + ). For information about these debugging tools, see the
UIMS Handbook.
For this example, you will be using the Complete Application option.
Before you do, however, you will want to modify the default behavior
of this option.
DataFlex Tutorial 77
Figure 16-The AutoGen Utility, showing the settings for the source code
options.
3. Using the scroll bar or down arrow, move down to the section
labeled [DEFAULTS]. Do not change the Comments at the top,
which are preceded by ";" in the first column. The lines you
are looking for are found at about line 62. Change the settings
for CREATE_VIEW and CREATE_TEST to OFF.
A message will appear informing you of the fact that the code
generation has been successfully completed.
DataFlex Tutorial 79
CONTACTS.DS Contains Data Set class definition for the
Contacts data file.
The program AutoCreate just wrote for you has a great deal of
functionality, all of which is explained in the next section. (see
Figure 18).
own programs: the action bar with its pull-down menus; mouse
support; proper screen conventions; accelerator keys, and even built-in
Help. Absolutely no manual coding on your part is necessary to take
advantage of these features. See the UIMS Handbook for further details
on CUA.
Centered at the top of the screen is the title you gave the application.
Underneath that is an action bar which has the choices Record,
View, Text, Navigate and Help. At any time, you can move the
selection cursor up to the action bar by clicking the mouse on one of
its choices, or by pressing 0 .
Action Bar Choices. The Record pull-down shows all the "editing"
choices for records: clear, find, save, and so on (see Figure 19). As
always in DataFlex, you can invoke any of these choices by selecting
them from the menu, or by pressing the key or key combination noted
against each choice. The specific keys or key combinations to select a
DataFlex Tutorial 81
Figure 19-The Record pull-down, showing the choices for finding, saving,
deleting and editing records in a database.
The View pull-down contains the View you just created in AutoCreate
as well as a Close option (see ?).
Navigate has the keys you need for moving around the screen’s
panels and windows, and for popping up a zoom or prompt.
Help has the same choices as the Help pull-down in the DataFlex
utilities themselves. You can customize the text in the help files so it is
specific to your own applications.
Without a mouse, you can navigate the cursor around the entry
windows with e t s+t
, or . Notice that the cursor moves
around the windows from left to right, and from top to bottom of the
screen. If you want to change that order, you can simply change the
order the windows are listed in the source code.
Let’s enter some data. Enter the following records, pressing2 (or
selecting Save from the Record pull-down) after each record is
completed:
DataFlex Tutorial 83
Last First Company Title Address City St Zip
Name Name
Notice that, when you press 2 , a panel will appear asking you
whether the current record should be saved. If you want to save the
record, press2 . If you want to abort the save and exit out of this
panel, press q . Also notice that, whatever you type in the ST field,
it is converted into upper case.
As you can see, DataFlex has several function keys which allow you to
browse easily through the records in a data file. For more information
about these function keys and how DataFlex finds records in a data
file, see the DataFlex User’s Guide.
Now that you have entered some records into your database, you are
ready to generate a mailing list for the CONTACTS application.
Several basic formats of report are available, and when you have
designed a report, you can save it for later reuse within Query. As with
AutoCreate, you can also generate program code which you can edit or
not, as you please, then compile into a DataFlex program and run as
often as you like. If you have specified any selection criteria, any user
DataFlex Tutorial 85
Figure 22- Query’s DBMS File Selection screen, which enables you to point and
shoot the main file for your report- in this case there is only one file.
running the report has the opportunity to enter new criteria at runtime,
or you can "hard code" the selection criteria if you prefer.
Since you have just entered some names and addresses (or you may
have had an existing name and address database), mailing labels might
be appropriate. When you select the Mailing labels format, all
page breaks, numbering and headings are suppressed.
To create a report,
You will see a screen with the familiar title, action bar and status line
format (see Figure 22).
The file will be opened, and you will see the Print Field
Definition screen, consisting of a split panel on the left, with a main
definition area on the right (see Figure 23). The split panel on the left
contains the names of the open files in the upper portion, and the
names of the fields in the highlighted file in the lower portion. (In this
case, you have only one open file, but had it been related to other files,
Figure 23-The Print Field Definition screen, showing the fields you want in you
report, checkboxes for total and leading carriage return, starting position and
width of each field.
they would also be open.) The main definition area contains multiple
lines for the names of fields, each of which has check boxes for total
and carriage return, starting position and width.
DataFlex Tutorial 87
You can have a field output multiple times, by picking it as many
times as you like. You may have a numeric field totalled, by checking
the Total box, and you may change the width of a field’s display, by
changing the number in its Width column.
As you pick fields for output, Query keeps track of and displays the
starting position and width of each field, so you can decide whether to
break a line or not. You may break the lines where you like by picking
the first field for each output line and putting an X in the Cr check box
t
(by rotating to it with and pressing g ). You will notice
that the Start number starts over at 1 for the line after you do this.
This will start each of these fields on a new line, leaving STATE and
ZIP to follow on the same line as CITY (see Figure 23).
You should be aware that, as regards the "Printer" Run option, the
default output device is whatever device is specified in the
environment variable DFPRINTER. If none is specified, printer output
10. To keep the report, so that you can run it again from within
Query, press 2 , or select Save as from the File pull-down
(a+F ).
DataFlex Tutorial 89
Figure 25-The first screenful of your report, from which you can scroll
horizontally (if appropriate), see the next screenful, or quit.
Next time you load the file you were using (CONTACTS in this case),
you will be offered the opportunity to load (then edit) this query.
13. Finally, to generate the program code to run the report from
outside Query, press a+G , or select Generate from the
File pull-down.
14. Select Mailing labels and enter a file name for your
program (see ?). Let’s say you call it REPCONT. Don’t enter an
extension; it will be added for you.
You can compile the source code into an executable DataFlex program,
with or without editing it. There is, of course, much more about
programming reports in the DataFlex User’s Guide and the DataFlex
UIMS Handbook.
The screen will clear; the report will be compiled, and you will be
returned to the Development menu.
The DataFlex Main Menu system is the central access point to all the
DataFlex Utilities. From the DataFlex menu, you can access all of the
Development Utilities without ever contending with the operating
system.
DataFlex Tutorial 91
Figure 26-The File Maintenance Utility (DFFILE), showing a file list with three
entries.
1. The first thing you must do is copy the MENU.DAT file from
the USR directory to the PROJECT1 directory. Since you want
to create your own customized MENU for the Contacts
Application, you must delete all the information that is
currently being stored in the MENU data file.
2. You can use the DFMAINT Utility to erase the MENU data
file. At the command line, type DFMAINT. From the
MAINTENANCE menu, select Filelist. The list of data files will
appear. Select #49- @DataFlex Menu File (see ?). When
you select this entry, it should be highlighted. Press + aD
Key combination to activate the Database pull-down. From
this pull-down, select Erase.. . You will then asked if you
You now have a MENU file with no records. This means that
you can now use the MENUDEF utility to create your own
customized MENU.
Figure 27-The main screen for the DataFlex Menu Maintenance Utility
(MENUDEF).
DataFlex Tutorial 93
5. Now, in the space provided, enter Main Application Menu.
This is the name of the menu. When you activate the menu,
the name will appear in the top center portion of the screen.
Presse again until the selection cursor is at the bottom
area of the split panel.
Reports MENU 3
HELP HELP
11. In the Menu Number window, enter 2. The cursor will then
jump to the Returns to Menu Number window. Since you
want to return to Menu number 1 on exit from Menu number
2, enter 1 in this window.
In the top part of the split panel, you want to specify the name
of Menu number 2, so enter Applications in the space
provided. Press e again to move to the bottom part of the
split panel. Notice that you have entered Applications in this
The bottom part of the split screen will contain the options for
the Applications pull-down.
13. Repeat steps 11-12, but enter the following information instead:
Menu Number: 3
Return to Menu Number: 1
Top part of split panel: Report
Bottom part of split panel: Contacts Report
Action: CHAIN REPCONT
There are two ways to run your application. First, you can execute the
application from the command line. Second, you can execute the
application from the Main Menu. Both ways are valid.
DataFlex Tutorial 95
4.4 Real-world example, Order Entry System
In order to develop and implement this system, they have hired your
consulting team. After collecting the data and designing and
normalizing the database, the consulting team has developed the data
file structure for the Order Entry database (see Figure 28):
The actual steps performed by the consulting team to arrive at this file
structure are shown in Chapter 6. It is important to note that data
collection and database design are the first steps in any application
design process.
As you know from the first example, you must create a separate
working directory for each application you are developing. The
working directory for the Order Entry application will be located
under the FLEX directory and named PROJECT2. Change to the FLEX
directory and create the PROJECT2 directory. This directory will
contain all the application-related files for the Order Entry application.
The steps and techniques for creating the data files, fields and indexes
for the Order-Entry application are exactly the same as those shown in
the CONTACTS example. There are, however, a few differences you
should be aware of:
DataFlex Tutorial 97
In the Order-Entry database structure, there is one file at the
base (or lowest level) of the hierarchy. This file, named Order
Detail, has no children of its own; therefore it is considered the
childmost file in the hierarchy.
By contrast, you have four files which are at the top of the
hierarchy. These files (Customer, Salesperson, Courier and
Vendor), have no parents of their own (i.e., they do not relate
to any files); therefore, they are considered the parentmost files
in the hierarchy.
Note: As you can see from the Order-Entry example, parent files
can have parents of their own, and child files can have
children. While child and parent refer to the proximate
generation, the terms descendant and ancestor are used to
refer to files removed from the reference file by an
indeterminate number of generation.
NAME ASCII 30
ADDRESS ASCII 30
CITY ASCII 14
STATE ASCII 2
ZIP ASCII 10
PHONE_NUMBER ASCII 20
FAX_NUMBER ASCII 20
1 NUMBER NO NO
2 NAME NO YES
NUMBER NO NO
DataFlex Tutorial 99
Name Type Size
ID ASCII 4
Name ASCII 25
1 ID NO NO
2 NAME NO YES
ID NO NO
ID ASCII 12
NAME ASCII 30
ADDRESS ASCII 30
CITY ASCII 14
STATE ASCII 2
ZIP ASCII 10
PHONE_NUMBER ASCII 20
FAX_NUMBER ASCII 20
1 ID NO YES
2 NAME NO YES
ID NO YES
ID NUM 6.0
NAME ASCII 30
ADDRESS ASCII 30
CITY ASCII 14
STATE ASCII 2
ZIP ASCII 10
PHONE_NUMBER ASCII 20
FAX_NUMBER ASCII 20
2 NAME NO YES
ID NO NO
1 ORDER_NUMBER NO NO
2 CUSTOMER_NUMBER NO NO
ORDER_NUMBER NO NO
3 COURIER_ID NO YES
ORDER_NUMBER NO NO
4 SALESPERSON_ID NO YES
ORDER_NUMBER NO NO
1 ITEM_ID NO YES
2 VENDOR_ID NO NO
VENDOR_PART_ID NO YES
ITEM_ID NO YES
3 DESCRIPTION NO YES
ITEM_ID NO YES
Field Information
Index Information
1 ORDER_NUMBER NO NO
DETAIL_NUMBER NO NO
8. The Order Entry System file (or ORDSYS) stores the most
current order number, customer number and vendor number.
It differs from the previous files in that its maximum number
of records is one. This type of file is called a System File.
Field Information
Although business rules will often have common elements from one
application to the next (like the deletion constraint example), these
rules are more typically application specific and, as a result, may
encompass a tremendously diverse range of functionality. DataFlex is
outstanding in its ability to handle any data rule, no matter how
complex or unique; you’ll never find yourself unable to implement
what’s needed to deliver your application.
For the Order Entry application, you need the following business rules:
3. You cannot sell more parts than are already in the inventory
stock. If you do, an error message informing you of that fact
should be generated.
6. The order’s total field is the sum of all the extended prices.
10. To get the extended price for each item, you must multiply the
quantity ordered by the unit price.
You will place all the custom business (or database) rules for the
Order-Entry application in Data Set subclasses.
For this application, you will be creating seven Data Set classes, one
for each data file. The files that contain the Data Set classes will be
named CUSTOMER.DS, COURIER.DS, INVT.DS, ORDERDTL.DS,
ORDERHEA.DS, SALESP.DS and VENDORS.DS. The .DS extension
tells us that this file is a Data Set "package" that will be used by views
via the DataFlex USE command. The next section explains how to
create Data Set classes.
4. Since this is a new file, an empty edit screen will appear. Now
you can proceed to define the first Data Set class package.
Customer_Data_Set class
The first thing you’ll need in this package is to have DataFlex open the
data files you will be using in this class. This is achieved by entering
the following statements:
Open CUSTOMER
Open ORDERHEA
Open ORDSYS
As you can see, we’ve entered an Open” statement for each file, not
just those for which we’ll be creating a Data_Set Class. This is
because for us to be able to reference the file at all, it must first be
opened.
The next step is to create the class definition block for the
Customer_Data_Set. It is in the class definition block where the
class is defined and the business rules, if any, are implemented.
Note: In order for this optimization to work, ALL Data Sets participating
in a Save or Delete operation must have their Smart_FileMode_State
set to True. Smart Filemode is disabled if one or more Data Sets
participating in the operation have their Smart_Filemode_State set to
False.
By default, if a parent record has a related child record, and the parent
record is deleted, the child record will also be deleted. Frequently, as
suggested by our business rule, it is desirable to inhibit the deletion of
a record if there are any records that relate to the record being deleted.
To disallow this behavior, you must first set Cascade_Delete_State
to false. Then, you add the ORDERHEA file number to the list of files
in which related records might exist. That is the effect of the
Add_Client_File message.
Now, if you try to delete a Customer record which has a related child
record in the ORDERHEA file, the following error message will be
generated:
The class definition block can be considered the template for creating
sub-classes. The template syntax will be the same for all sub-classes,
except for the class name and the main file name. Of course, the
business rules will also vary from class to class. Note that the
CLASS.TEM file, which is located in the
\FLEX\USR\EXAMPLES\TUTORIAL directory, contains the skeleton
code for the class definition block.
Procedure Creating
Forward Send Creating // (1)
Add 1 to OrdSys.Cust_Number // (2)
Move OrdSys.Cust_Number to Customer.Number // (3)
SaveRecord OrdSys // (4)
End_Procedure
(3) Move the data from the ORDSYS.Cust_Number field into the
CUSTOMER.Number field
You will also add a procedure that ensures that the ORDSYS file will
be saved:
Procedure Reset_Filemodes_for_lock
Forward Send Reset_Filemodes_for_lock
File_Mode ORDSYS Default
End_Procedure
The final code for the Customer_Data_Set class looks like this:
//CUSTOMER.DS
Open CUSTOMER
Open ORDERHEA
Open ORDSYS
Class Customer_Data_Set is a Data_Set
Procedure Construct_Object Integer Img#
Forward Send Construct_Object Img#
Set Main_File to Customer.File_Number
Set Smart_FileMode_State to True
Set Cascade_Delete_State to False
Set Add_Client_File ORDERHEA.file_number
End_Procedure
Procedure Creating
Forward Send Creating
Add 1 to OrdSys.Cust_Number
Move OrdSys.Cust_Number to Customer.Number
SaveRecord OrdSys
End_Procedure
Procedure Reset_Filemodes_for_lock
Forward Send Reset_Filemodes_for_lock
File_Mode ORDSYS Default
End_Procedure
End_Class
Once you have finished writing the Customer_Data_Set class, you can
save the package by selecting the Save option from the File pull-
down.
Select New from the File pull-down. An empty edit screen will
appear.
Now you are ready to insert the Data Set class template.
Looking closer at the file, you notice that there are question marks in
the Class command syntax and the line that sets the Main File
property. You must replace both lines so that they read as follows:
Since the Data Set class will be controlling functions for the INVT data
file, you must change the Main_File to INVT. Also, you must set the
SmartFileMode_State to True.
Function Validate_Save
local integer rval // (1)
If Invt.ON_HAND lt 0 Begin // (2)
Error 300 "Insufficient Inventory Stock" // (3)
Function_return 1 // (4)
end // (5)
forward get Validate_Save to rval // (6)
Function_return rval // (7)
End_function // validate_save
(4) Return the value 1 (only a 0 returned will allow the save) and
exit the routine.
The next business rule, four, states that if an item appears on an order,
you cannot delete the item from the Inventory Report. Restated in
database terms: if a parent record has child records, do not delete the
parent record. More specifically, if an item appears in the ORDERDTL
data file, then it cannot be deleted from the INVT data file.
//INVT.DS
Open INVT
Open ORDERDTL
Class Invt_Data_Set is a Data_Set
Procedure Construct_Object Integer Img#
Forward Send Construct_Object Img#
Set Main_File to Invt.File_Number
Set Smart_FileMode_State to True
Set Cascade_Delete_State to False
Set Add_Client_File ORDERDTL.file_number
End_Procedure
Function Validate_Save
local integer rval // (1)
If Invt.ON_HAND lt 0 Begin // (2)
Error 300 "Insufficient Inventory Stock" // (3)
Function_return 1 // (4)
end // (5)
forward get Validate_Save to rval // (6)
Function_return rval // (7)
End_function
End_Class
OrderDtl_Data_Set class
Now you are ready to insert the Data Set class template. Follow the
same procedure shown in the previous page.
Procedure Creating
Forward_Send Creating
Add 1 to Orderhea.last_detail_num
Move OrderHea.last_detail_num to OrderDtl.Detail_number
End_Procedure
The purpose of this code is to assign a number for each line item
(business rule #13. Basically, it keeps track of the items being ordered.
Procedure Update
forward_Send Update
Move (Invt.Unit_Price*OrderDtl.Qty_Ordered) to OrderDtl.Extended_Price //(1)
Sub OrderDtl.Qty_Ordered from Invt.On_Hand //(2)
Add OrderDtl.Extended_Price to Orderhea.Order_Total //(3)
End_Procedure
Procedure Backout
Forward_Send Backout
Add OrderDtl.Qty_Ordered to from Invt.On_Hand
Sub OrderDtl.Extended_Price from Orderhea.Order_Total
End_Procedure
//ORDERDTL
Open ORDERDTL
Open INVT
Open ORDERHEA
Class OrderDtl_Data_Set is a Data_Set
Procedure Construct_Object Integer Img#
Forward Send Construct_Object Img#
Set Main_File to OrderDtl.File_Number
Set Smart_FileMode_State to True
End_Procedure // Construct_Object
Procedure Creating
Forward Send Creating
Add 1 to Orderhea.last_detail_num
Move OrderHea.last_detail_num to OrderDtl.Detail_number
End_Procedure
Procedure Update
Forward Send Update
Move (Invt.Unit_Price*OrderDtl.Qty_Ordered) to OrderDtl.Extended_Price
Sub OrderDtl.Qty_Ordered from Invt.On_Hand
Add OrderDtl.Extended_Price to Orderhea.Order_Total
End_Procedure
Procedure Backout
Forward Send Backout
Add OrderDtl.Qty_Ordered to from Invt.On_Hand
Sub OrderDtl.Extended_Price from Orderhea.Order_Total
End_Procedure
End_Class
OrderHea_Data_Set class
//ORDERHEA.DS
Open ORDERHEA
Open ORDSYS
Note that the Procedure Creating enforces business rule #9; it assigns
a system-generated order number to a new order record. Also, notice
that the Set_Cascade_Delete_State property has been set to
True. This is because we want to allow the deletion of existing
records. If this property was set to False, then users could not delete
existing orders.
//VENDORS.DS
Open VENDORS
Open INVT
Class VENDORS_Data_Set is a Data_Set
Procedure Construct_Object integer Img
Forward Send Construct_Object Img
Set MAIN_FILE to VENDORS.file_number
Set Cascade_Delete_State to False
Send Add_Client_File INVT.file_number
End_Procedure
Procedure Creating
Forward Send Creating
Add 1 to OrdSys.Vendor_Number
Move OrdSys.Vendor_Number to Vendors.ID
SaveRecord OrdSys
End_Procedure
Note that the Procedure Creating enforces business rule #9, and the
Set Cascade_Delete_State to false line enforces business rule
#2.
SALESP_Data_Set
//SALESP.DS
Open SALESP
Class SALESP_Data_Set is a Data_Set
Procedure Construct_Object integer Img
Forward Send Construct_Object Img
Set MAIN_FILE to SALESP.file_number
Set Smart_FileMode_State to True
Set Cascade_Delete_State to False
Send Add_Client_File ORDERHEA.file_number
End_Procedure
End_Class
COURIER_Data_Set
//COURIER.DS
Open COURIER
Class COURIER_Data_Set is a Data_Set
Procedure Construct_Object integer Img
Forward Send Construct_Object Img
Set MAIN_FILE to COURIER.file_number
Set Smart_FileMode_State to True
Set Cascade_Delete_State to False
Send Add_Client_File ORDERHEA.file_number
End_Procedure
End_Class
Now that you have created your data files and data sets, you are
ready to design and prototype the Data-Entry Views for your
application.
Data Entry objects (e.g., Entry Forms, Tables and Editors) allow you to
examine, select or manipulate data in the database. In fact, all visual
interaction with the database occurs in data entry objects.
Note: You have already created your Data Sets in this tutorial, in order to
give you a clearer understanding of this class. However, AutoGen
will create a prototype Data Set when one does not exist. You could
As you create the user interface for the Order-Entry application, there
are a number of points that you need to keep in mind. Topics such as
cursor navigation and source document emulation are critical to the
design of a successful application interface. Note that both of these
topics are explained in this section.
Cursor Navigation within an Object. The path that the cursor takes as
the user rotates from field to field in your application is known as the
cursor path”. In order for an interface to feel” right to the user, the
cursor should flow naturally from one input area to another, always
touching on these areas in a logical order.
The design of forms can make all the difference in quick, easy and
efficient data entry. They are often made to resemble the (paper) form
from which operators will be typing data; they can cover the whole
screen or just part of it, and they can be as simple or as complex as
DataFlex provides you with the power and flexibility to emulate most
paper forms you may come across. Careful analysis of the form usage
will almost certainly guarantee an application interface that's easy to
use and provides a high degree of user productivity.
The Order-Entry application will consist of six views and six selection-
list objects.
Order View. The order view is composed of four data entry objects:
4. Order List- this prompt list will allow us to browse through all
of the records from the ORDERHEA data file.
Although the first three elements are created separately, they must
appear on the screen as a single, coherent display.
5. Press <OK> and the empty form will be drawn in the middle
of your screen, on top of the BACKGROUND.
Notice that the name of the object (Hdr) also appears in the
status line at the bottom of the screen. You can move the form
by dragging the top line with the right mouse button
depressed. You can also resize the form by dragging on the
bottom or right boundary - or the bottom right corner to
change height and width simultaneously.
6. Drag the top left corner of the form with the right mouse
button, (or select Move from the Objects pull-down, then we
use the arrow keys) to place the top left corner under the "A"
in Application on the action bar (or position 1,2 in the
Background object).
7. Drag the bottom right corner of the form close to the right
edge of the screen (or position 9,79 in the Background object),
again with the right mouse button (or select Resize from the
Objects pull-down, then use the arrow keys).
8. As you can see from the drawing in the previous page, you
need to draw a horizontal line from the left edge of the form
to the right edge.
10. Select Open from the Database pull-down, and select Open
Related. This will open all ancestor files of ORDERDTL; in
other words, it will open all the files you have created.
11. Make sure the cursor is at the left of the first line in the Hdr
form, then type in the static text for the description of the first
field - Order Number:.
14. Repeat steps 11-13 (shown above), for the following fields:
At this point, you are finished with the Hdr Entry Form (see
Figure 29).
6. Tables must have a file name and index so, in the For File
window, press 4 to see the list of files available. Select
ORDERDTL.
8. Press <OK> and the empty Table will be drawn in the middle
of the screen, on top of the BACKGROUND and the Hdr Entry
Form.
As before, the size and position of the table are not suitable for our
purposes.
10. Drag the top left corner of the table with the right mouse
button to a position just underneath the Form (or position 10,2
in the BACKGROUND object). Make sure that the left edge of
the table is vertically aligned with the left edge of the form.
11. Drag the bottom right corner of the table so that the right edge
of the table is vertically aligned with the right edge of the
form. At this point, the table and form should have the same
height and width.
12. Now, you need to delete the top border of the Dtl Table. You
do this by placing the cursor on the top border (or position
1,2), pressingc\ + (block text on), pressing zthen
Backspace, and then pressing delete. The reason for doing this
is explained later in the chapter.
13. Type the column headings. Type the following headings above
their respective positions (see figure above) ; Item ID,
Description, Unit Price, Qty and Ext. Price.
15. Now you are ready to insert the fields. Press a+$ or select
Field Toolbox from the Fields pull-down.
AutoCreate will place as many rows in your table as will fit between
the top row and the bottom border. The top row is defined as the row
on which you place the first field. After once placing a field, you may
only place additional fields on the same top row, or on rows opened
up beneath that.
To add rows, press c+5 , or select Add Row from the Edit pull-
down. To delete rows, press c+6 , or select Delete Row from the
Edit pull-down. To insert a line (making the structure double-spaced),
press s0 + , and to close it up again, press s2 + .
Figure 30-The AutoCreate Utility, showing the Dtl Table with its grid, column
headings, and fields.
DESCRIPTION INVT
UNIT_PRICE INVT
QTY_ORDERED ORDERDTL
EXTENDED_PRICE ORDERDTL
The Table in its finished form should look like Figure Figure 30.
The last step is to connect the Dtl Table to the Hdr Form. As it stands
now, the two objects are separated from one another. The objective,
however, is to create one coherent display, with no separations.
Figure 31-The AutoCreate Utility, showing the Hdr Form and Dtl Table as one
coherent display.
19. Drag the top left corner of the Dtl Table with the mouse button
from its current position to a position directly underneath the
bottom border of the Hdr Form (see Figure 31).
Figure 32-The AutoCreate Utility, showing the size and location of the Ttl
Form.
5. Press <OK> and the empty form will be drawn in the middle
of the screen, on top of the BACKGROUND.
Total $ ________.__
The ttl Entry Form should be positioned directly underneath the Dtl
Table object. Use the techniques mentioned above to move and resize
the ttl Entry Form.
For now, position the TTl form near the center of the screen, so that
the Field Tool Box can be used to paste in the field.
The prompt list for the ORDERHEA file will look like this:
3. Press a+$ (or select Field Toolbox from the Fields pull-
down) and point and shoot each field to be placed on the
prompt list, as shown below:
ORDERHEA ORDER_NUMBER
ORDERHEA CUSTOMER_NUMBER
CUSTOMER NAME
ORDERHEA ORDER_DATE
ORDERHEA ORDER_TOTAL
4. Now, insert the grid lines and column heading as you did in
the Dtl Table.
5. Press tto rotate to the Hdr Form and move the cursor to
the ORDERHEA.ORDER_NUMBER field. Pop up the Entry
Options screen (make sure that Obj: Hdr and
ORDERHEA.ORDER_NUMBER appear on the status line) by
pressing . 4
6. Rotate to the bottom panel ( t e or ); press 4
again in
the Prompt: window and select your Ordr_lkup prompt list.
Press 2 to confirm the changes.
As you can see, the hierarchy consists of one Data Set object, two
forms, one Table object and three Prompt List objects. There is a
problem with this structure.
The Dtl Table displays information from the ORDERDTL data file. The
Hdr Entry Form and Ttl Entry Form both display information specific
to the Order.
You need to create a Data_Set object to use with the ORDERHEA data
file.
To create a Data Set object, select New from the Objects.. pull-
down menu, then Data Set. A panel will appear prompting us for the
name of the Data file for which a Data Set will be created. Select the
ORDERHEA data file. Now your object structure looks like this:
BACKGROUND <Client>
ORDERHEA <Data Set> [ ]
ORDERDTL <Data Set> [ ]
Hdr <Form> [ ]
Dtl <Table> [ ]
Ttl <Form> [ ]
Ordr_lkup <Prompt List>
Notice that both the Hdr Entry form and the Ttl Entry form are nested
within the ORDERDTL Data Set. These Entry Forms, however, display
information pertinent to the Header portion of the Order, which is
controlled by the ORDERHEA data file and data set. Therefore, you
must move both Entry Forms so that they are nested within the
ORDERHEA data set. The Dtl Table stays nested within the
ORDERDTL data set.
Once you are finished making the changes, the object structure looks
like this:
BACKGROUND <Client>
ORDERHEA <Data Set> [ ]
Hdr <Form> [ ]
You may be asking why the ORDERDTL data set is nested within the
ORDERHEA data set. By nesting the item Data Set within the header,
an automatic constraint is enforced: only related item records are
displayed for every parent record.
You will employ the same steps and techniques from section xx to
create the Customer View, since the Customer View has most of the
same elements of the Contacts Application.
2. The first object you will create is a Form. Enter the following
information in the New Form... panel:
Name: Cust
Window Color: 0
Text Color: 0
Border: Single
Title Style: Dialog
Title: Customer Entry Form
Name: Comments
Window Color: 0
Text Color: 0
Border: None
Title Style: None
Name: Cust_lkup
Window Color: 0
Text Color: 0
Border: Double
Title Style: Popup
Title: Customer List
For File: CUSTOMER
By Index: 1:NUMBER
9. Drag the Prompt List to a position left of the Cust form (see
figure x). Draw the lines for the grid and enter the static text
for both of the columns.
11. Finally, add the following Entry Options to the fields shown
below. pressing 2 after each is completed:
ST Capslock none
The remainder of the Views contain the same object structure: Form
and Prompt List. Since the creation of these objects has already been
discussed in previous sections, there will be no step-by-step
instructions for the visual design of the Views. Instead, for each View,
we will provide you with data which you must enter into the
Application Style panel, the Form Style panel and the Prompt List
Style panel. The Entry Options for all the fields will also be shown.
Remember to save the View after each one is completed.
Name: INVT
Main File: INVT
Title: Inventory Parts View
Name: Inventory_Parts
Window Color: 0
Text Color: 0
Name: Invt_lkup
Border: Double
Title Style: Popup
Title: Inventory List
For File: INVT
By Index: 1:ITEM_ID
INVT.VENDOR
_PART_ID Display Only none
Vendor View.
Name: VENDOR
Main File: VENDORS
Title: Vendors View
Name: Vendor_lkup
Border: Double
Title Style: Popup
Title: Vendor List
For File: VENDORS
By Index: 1:ID
Courier View.
Name: COURIER
Main File: COURIER
Title: Courier View
Name: Courier
Window Color: 0
Text Color: 0
Name: Courier_lkup
Border: Double
Title Style: Popup
Title: Courier List
For File: COURIER
By Index: 1:ID
Salesperson View.
Name: SALESP
Main File: SALESP
Title: Salesperson View
Name: SalesP
Window Color: 0
Text Color: 0
Border: Single
Title Style: Dialog
Title: Sales Person Entry
Name: Salesp_lkup
Border: Double
Title Style: Popup
After you have finished designing the visual components of your view,
you are ready to use AutoGen to produce the source code for the view
packages, selection list object packages and data set packages.
Figure 35-The AutoGen Utility, showing the Source Code Generation panel with
View package as the current choice.
You can invoke AutoGen from the AutoCreate Utility or from the
command line.
appear (see Figure x). Select the ORDER application. Note that
you can generate source code for only one application at a
time.
2. At this point, the main entry panel for the AutoGen utility will
appear:
Below are brief descriptions for each of the options listed on this
panel.
View test program: This option will create all the re-usable
packages as well as a test program for the application you
For this example, you will be using the View Package option.
The first thing you need to do is modify the default behavior of this
option.
You will leave all of the package names and options as is.
By default, the View Package option creates a test program so that you
can verify functionality of the view. Since you will not be creating a
test program, you must turn this setting off in the AUTOGEN.INI file.
3. Using the scroll bar or down arrow, move down to the section
labeled [DEFAULTS]. Change the settings for CREATE_TEST
to OFF.
Changes the Order Entry View. The following changes were made to
the ORDER.VW file.
Use Customer.sl
Use Invt.sl
Use Courier.sl
use Salesp.sl
:
Entry_Item CUSTOMER.NUMBER { AutoClear, AutoFind, NoPut, ;
iValidate=GET_FindReq_Auto_Prompt, ;
iPrompt=(Cust_lkup_sl(Current_Object)) }
:
Entry_Item COURIER.ID { AutoClear, AutoFind, NoPut, ;
iValidate=GET_FindReq_Auto_Prompt, ;
Note how the commands line are split with semi-colon (;). The
semicolon is the DataFlex line separator. It tells the Compiler to regard
this as one line. This make the code more readable.
The data-sets properly maintain the line total amount for each detail
record. The total is updated during a save and the screen is updated at
this point to reflect that change. Users will prefer to see this amount
change immediately upon exiting any window that effects that total.
An iExit parameter is added to the two items that can change the
line total (inventory id and quantity). When either item is exited the
message Total_Amount will be sent. This message will update the
total. The syntax of the iExit message is as follows:
iExit=MSG_Total_Amount
1 Introduction 149
The procedure total_amount will update the total. The concept is
simple: multiply the quantity times unit-price and move this value to
line item total. To do this we need to know the item number of the
column. While we could use the actual number, we will use a
symbolic replacement instead. The entry_name_item command
which is a variant of the entry_item command allows us to assign
the item number a symbolic value.
Note when working with lines in a table we must use the true item
number and not just the column number. A special property named
base_item give us the offset of column zero of the current-row. We
must add this offset to all of our calculations.
Finally, note that the value placed in the line item total does not get
updated to the database. We still let the data-sets do that for us. This
is only updated for presentation purposes.
Begin_Row
Entry_Item INVT.ITEM_ID { AutoClear, AutoFind, Capslock, NoPut, ;
iValidate=GET_FindReq_Auto_Prompt, ;
iPrompt=(Invt_lkup_sl(Current_Object)), ;
iExit=MSG_Total_Amount }
Entry_Item INVT.DESCRIPTION { DisplayOnly }
Entry_Name_Item Price## INVT.UNIT_PRICE { DisplayOnly, Thousands }
Entry_Name_Item Qty## ORDERDTL.QTY_ORDERED { AutoClear, ;
iExit=MSG_Total_Amount }
Entry_Name_Item Amount## ORDERDTL.EXTENDED_PRICE { DisplayOnly, Thousands }
End_Row
// Update line item total
//
Procedure Total_Amount
Local Integer Base
Local Number Price Quantity
// The item number Price##, qty## and Amount## are column
// values. We need to change the actual table cell value. We
// do this by using base_item as an offset value.
Get Base_Item to Base //offset of item 0 of current row
Get Value Item (Price## + Base) to Price
Get Value Item (Qty## + Base) to Quantity
Set Value Item (Amount## + Base) to (Price * Quantity)
End_Procedure //Total Amount
Old code:
New Code:
1 Introduction 151
Set Verify_Save_MSG to GET_Confirm_save_order
Set Verify_Delete_MSG to GET_Confirm_delete_order
Set Verify_Data_Loss_MSG to GET_Data_loss_Confirmation
Set Verify_Exit_MSG to GET_Exit_loss_Confirmation
We will add a pick_list for terms. Terms is not a related field and
there is no required value that must be entered in this field. However,
usually the text in this field is one of five standard responses. The
purpose of the pick-list is to make it easy to quickly fill in one of those
values. The user does not need to use this list. They can still type
anything they want in the field, or leave it blank. The pick-list prompt
should be thought of as "suggestions". The pick-list code is listed
below. The object is accessed with the prompt key in the exact same
method as a selection-list (iPrompt).
/Terms_Pick_List_Image
Terms
________________
________________
________________
/*
// Create a list of suggested values for terms. Pick-lists are
// used when we need to build a list of static, non-relational items.
// These can be thought of as "suggestions". The terms field will use
// this by adding the line:
//
// iPrompt=(Terms_pick_list(Current_Object))
//
Object Terms_Pick_List is a Pick_List Terms_Pick_List_Image Popup Radio
Set Auto_locate_state to True
Set Allow_move_State to true
Item_List
On_Item "Pre-Paid"
On_Item "COD"
On_Item "Net-30"
On_Item "Net-60"
On_Item "Net-90"
End_Item_List
End_Object
:
Entry_Item ORDERHEA.TERMS { AutoClear, ;
iPrompt=(Terms_Pick_list(Current_Object)) }
If you add this change, it will not be possible for the table to get out of
order. This means that there is no need for the table to regenerate itself
after a save or a delete; the record order will always be correct. When
this is the case, we can set the property auto_regenerate_state to
false. This will speed up our table navigations.
On_key kADD_MODE send append_a_row // assign insert row key to new message
Set Auto_Regenerate_state to false // table is always in order.
// Add new record to the end of the table.
procedure Append_a_Row // Q: how would a keyboard do this?
send End_Of_Data // A: Go to end of table and
Send Down // down 1 line to empty line
End_Procedure
This will be our most complex change. We want two new behaviors.
When exiting a table we want the table to save the current row just
like it does when you switch rows. This change is easy to make. By
setting the property, child_table_state to true, the table will save
the record (if required) when exiting the table.
1 Introduction 153
There is a tendency to want to try to handle this as part of the exiting
behavior of the header form and not the entry behavior of the table. In
an event driven system you don’t know to where you will exit the
header and you don’t know from where you are entering the table.
The only safe event driven rule is to say, "Certain conditions must be
met before a table can be entered."
Here is a summary:
1 Introduction 155
2. Replaced FindReq with Get_FindReq_Auto_Prompt in the
vendor field.
You’ve created your data-entry programs, and now you want a report
to round out your application. The easiest way to produce reports is to
use DataFlex’s Query Utility. Here, we’ll see how to produce a report
based on the data of our sample order-entry application.
Let’s say we want a list of items ordered, by order and line number,
and we want to display (in order) the line number, the part number,
the part description, the quantity ordered, the price, and the line
amount (the extension).
Start Query
If you have the DataFlex Main Menu system running, select Query
Database from the Database pull-down. If you’re not running the
menu, type DFQUERY from the command prompt.
With Query, you choose the "bottom" file of your report. In the
relationship "tree," this is usually the file whose fields contribute most,
if not all, of the data in the "body" section of the report. All files to
which this main file relates are also automatically made available to
your report, and we will use one of these. The main file to choose is
the one listed as Order Detail File in the list that automatically
appears when Query is started.
When you choose the main file, the descriptive file list will clear and
the screen shown in Figure 37 will appear. Note the files listed in the
The next field we need isn’t in the main file—it’s in a parent file,
Inventory. This appears in the DBMS Files box as INVT. Place the
cursor on that file name and select it. Note that the contents of the
1 Introduction 157
DBMS Fields box changes from the fields of ORDERDTL to those of
INVT when you move the cursor from one to the other. The cursor
will be in the DBMS Fields box, and you may have to scroll to
display the name of the next field desired, INVT.DESCRIPTION.
The next field needed is back in ORDERDTL; switch back to that file
and select its QTY_ORDERED field. The next field needed is
INVT.UNIT_PRICE, so change files again and choose that field. The
last field is ORDERDTL.EXTENDED_PRICE.
Figure 38-
Once you’ve selected the fields, the screen will look like Figure 38.
Figure 39-
Select View from the action bar, then Selections from the pull-
down menu. For this example, we’ll choose all the orders for 1993. The
order date in the ORDERHEA file, so choose that file, as shown in
Figure 39. From its field list, choose the ORDER_DATE field. Doing this
will cause the Selection Type panel to appear, in which the first
thing you choose is a mode (greater than, less than, etc.). Here, we can
start by specifying dates "greater than or equal to" 1/1/93. So choose
1 Introduction 159
>= Greater than or equal and the cursor will rotate to the value-
entry window. In this window, type 1/1/93. Press OK.
Figure 40-
You can run this query, as defined, from memory. To run it, press
a+R , then e , or you can click on Run from the action bar. You
can output to a file or printer, but for this test run, we’ll output to the
screen.
06/14/95 Page 1
Data Access Corporation
Orders for 1993
DETAIL LIST
NUMBER PART ID DESCRIPTION QTY PRICE AMOUNT
16 CASE Understanding Case Technology 2 39.00 78.00
17 DATES The 100 Important Dates in History 200 29.00 5800.00
1 DT The Database Programmer’s Tool 4 179.00 716.00
2 CITIES Cities I’ve Enjoyed - Photo Essays 1 49.00 49.00
3 TEXT-3 Computers Made Easy, Volume III 1 69.00 69.00
4 GOLD-DLX The Deluxe Gold Prospec Kit 2 1079.00 2158.00
5 TEXT-3 Computers Made Easy, Volume III 2 69.00 138.00
6 CASE Understanding Case Technology 1 39.00 39.00
1 TEXT-3 Computers Made Easy, Volume III 1 69.00 69.00
2 CASE Understanding Case Technology 2 39.00 78.00
3 DATES The 100 Important Dates in History 4 29.00 116.00
4 CUA The CUA Reference Guide 1 49.00 49.00
5 TEXT-3 Computers Made Easy, Volume III 1 69.00 69.00
1 DATES The 100 Important Dates in History 4 29.00 116.00
2 DT PK Database Toolbox and Software 1 229.00 229.00
1 CASE Understanding Case Technology 3 39.00 117.00
2 CASE Understanding Case Technology 1 39.00 39.00
3 CITIES Cities I’ve Enjoyed - Photo Essays 1 49.00 49.00
4 MENU Menu Planning for the Busy Family 1 129.00 129.00
5 DATES The 100 Important Dates in History 1 29.00 29.00
10 CASE Understanding Case Technology 2 39.00 78.00
Records printed = 21
When you run the query, you will notice that the output does not
appear as shown above. Instead, each line will wrap to the next line.
For readability purposes, we have provided you with data that is
formatted in the proper fashion.
You can save this query as DataFlex source code, after which you can
compile the code and run it anytime in the future. The code generated
will be based on the Report Object, which is introduced in Chapter 1.
1 Introduction 161
From the File menu, choose Generate. Choose Printable
report. Enter a filename: REPTUTOR (no extension). Click on <OK>.
// reptutor.rpt
// 06/13/95 15:54:42
// Orders for 1993
// Data Access Corporation
//
// Package generated by DFQuery 3.1
Use QryRpt
/REPTUTOR_Header
__/__/____ Page ___.
Data Access Corporation
Orders for 1993
DETAIL LIST
NUMBER PART ID DESCRIPTION QTY PRICE AMOUNT
/REPTUTOR_Body Resident
____. _______________ __________________________ ______. _____.__ _______.__
/REPTUTOR_Total
Records printed = _______.
/*
/REPTUTOR_Selection_Form
Select records by:
ORDER DATE greater than or equal to __/__/____
ORDER DATE less than __/__/____
/REPTUTOR_Selection_Client
Data Access Corporation
Orders for 1993
/*
1 Introduction 163
Query’s Good Programming Habits
This code differs in a few ways from the way you might code a report
entirely by hand, but the extra features are good to have, and we’ll
discuss these before getting into the "meat" of the program (or, strictly
speaking, the view).
// reptutor.src
// 06/08/95 17:28:21
//
// Data Access Corporation
//
// Program generated by DFQuery 3.1
Use REPTUTOR.rpt
Inherit_Screen
Send Activate_REPTUTOR_Report
1 Introduction 165
Query’s Report Object
Then come the three images used for output. The first is the header.
This material will appear at the top of every page. You see the
registration name (Data Access Corporation), the name of the
report (Orders for 1993) and then the names of the selected fields,
with any underscores in those names replaced by spaces. In the upper
corners are windows for the date the report is run and the pages
output by the report.
After the images, the data files involved, invt, orderhea, and
orderdtl, are opened. Index 1 of orderdtl is buffered in memory.
because this report finds repeatedly by that index. This index orders
the order-detail-line records first by order number, and then by line
number (detail_number).
The next procedure section, body, is, as its name suggests, the essence
of the report. Like the other procedure sections, it forward-sends its
own message, so that it augments the message definition in the
standard_report class. After that, this section just fills in the fields
of this one-line-per-record report.
1 Introduction 167
Procedure-section total forward-sends its own name, as usual, and
then, as the last such step in the report, fills the one window of its
image with the number of records in the report
(rec_count(current_object)). Then it outputs its image, ending
the report.
Section Breaks. Now, let’s say we would like this report broken up by
Order. Because the index in use is by Order Number, the list is already
grouped by order. All we need is the breaks. This, we can arrange as
easily as adding a single line to the report, right after the
report_index statement:
report_breaks orderdtl.order_number
Again, this break field is already in the index we’re using, so it isn’t
necessary to change the index selection or create a new index.
/reptutor_subheader1
Order Number _________ Date __/__/____
/*
procedure_section subheader1 as reptutor_subheader1
forward send subheader1
print orderdtl.order_number
print orderhea.order_date
output_pagecheck
end_procedure
Now, the order number and date will print out at the top of its detail
lines, with a blank line between it and the first line. The next order
number will appear two lines after the end of the order before it.
In this new section and image, by the way, we’ve continued Query’s
good programming habits of distinctively naming section images and
forward-sending each section’s name to the class.
Section Totals. This will produce a pretty intelligible list of the orders
and their details, but it’s still nowhere near as informative as it could
be. Adding a total to the bottom of each order would seem reasonable,
as would starting a new page for each new order. This is easily
arranged by insertion of (as usual) one procedure section and an
associated image:
/reptutor_subtotal1
------------
Order Total _________.__
============
/*
procedure_section subtotal1 as reptutor_subtotal1
forward send subtotal1
subtotal reptutor_body.6
output_pagecheck reptutor_subtotal1
set page_end_state to true
end_procedure
1 Introduction 169
The thing about this section’s image that isn’t obvious out of context is
that the window for the total is placed in the same columns as the
body window is in (reptutor_body.6) that it shows the total for.
Actually, the total window is two digits larger than the window it is
totalling (always good report practice), so the decimal point is what is
aligned, not the whole window. The hyphens above, and equals signs
below, the window make it much more obvious that the subtotal is,
indeed, the total of the line amounts of the order.
Now, every order will start on its own page, with the order number at
the top.
Done
// reptutor.rpt
// 06/13/95 15:54:42
// Orders for 1993
// Data Access Corporation
//
// Package generated by DFQuery 3.1
Use QryRpt
/*
Open INVT
Open ORDERHEA
Open ORDERDTL Index.1
Activate_View Activate_REPTUTOR_Report for REPTUTOR_Report
Object REPTUTOR_Report is a Query_View No_Image
Object Report is a Standard_Report
Report_Main_File ORDERDTL
Report_Index By Index.1
report_breaks orderdtl.order_number
Set Constraint_Value 0 to "1/1/93" // ORDERHEA.ORDER_DATE GE
Set Constraint_Value 1 to "1/1/94" // ORDERHEA.ORDER_DATE LT
Begin_Constraints
Constrain ORDERHEA.ORDER_DATE GE (Constraint_Value(Current_Object,0))
Constrain ORDERHEA.ORDER_DATE LT (Constraint_Value(Current_Object,1))
End_Constraints
Procedure_Section Page_Top as REPTUTOR_Header
Forward Send Page_Top
Send Update_Status_Page
Sysdate REPTUTOR_Header.1
Print (Page_Count(Current_Object)) to REPTUTOR_Header.2
Output_Pagecheck
End_Procedure
1 Introduction 171
/reptutor_subheader1
Order Number _________ Date __/__/____
/*
procedure_section subheader1 as reptutor_subheader1
forward send subheader1
print orderdtl.order_number
print orderhea.order_date
output_pagecheck
end_procedure
Procedure_Section Body as REPTUTOR_Body 2
Forward Send Body
Print ORDERDTL.DETAIL_NUMBER
Print ORDERDTL.PART_ID
Print INVT.DESCRIPTION
Print ORDERDTL.QTY
Print INVT.LIST_PRICE
Print ORDERDTL.AMOUNT
Output_Pagecheck REPTUTOR_Body
End_Procedure
/reptutor_subtotal1
------------
Order Total _________.__
============
/*
procedure_section subtotal1 as reptutor_subtotal1
forward send subtotal1
subtotal reptutor_body.6
output_pagecheck reptutor_subtotal1
set page_end_state to true
end_procedure
Procedure_Section Total as REPTUTOR_Total
Forward Send Total
Print (Rec_Count(Current_Object))
Output_Pagecheck
End_Procedure
End_Object
Object Selection_Client is a Query_Selection_Client REPTUTOR_Selection_Client
Set Output_Selection_State to True
Object Selection_Form is a Query_Selection_Form REPTUTOR_Selection_Form
Item_List
Repeat_Item 2 Times "" Send Next
End_Item_List
End_Object
End_Object
End_Object
If you looked carefully, you might be able to see the alignment of the
window in /reptutor_subtotal1 with that in /reptutor_body.
Making this kind of thing easier is one good reason why many
programmers do as Query did: put all the images at the top, in the
order in which the report would output them. But sometimes it helps
more to keep them with their procedure sections.
06/14/95 Page 1
Data Access Corporation
Orders for 1993
DETAIL LIST
NUMBER PART ID DESCRIPTION QTY PRICE AMOUNT
Obviously, this section shows only a small fraction of what you can do
with report objects. The subject is explored further in the DataFlex
UIMS Handbook. In fact, this section didn’t even fully explore all that
this example itself is doing for and with your report. Suffice it to say,
if it’s a report and you can think of it, report objects can probably do
it. Easily and swiftly, too.
Once you have finished modifiying the ORDER view, you are ready to
assemble all of your views into a single main program. Final program
assembly can easily be achieved in a matter of minutes. Assembling a
program is quite straightforward.
1 Introduction 173
To add the view to your program,
//======================================================================
// MainPrgB.Src - Alternate Template main program (has global button bar)
//
// This is a template for creating a main program. Enter the Views you
// need and USE the object package files as required. Look for ???
// where you need to fill in your own information
//
// 05/03/94 - Added for 1.1. This includes a global button bar
//======================================================================
//----------------------------------------------------------------------
// ??????.Src: ??????????????????????????????
//
//
//----------------------------------------------------------------------
Use AllEntry
Use ExitApp // Smarter exit. Checks and warns of changes.
Set Application_name to "???????" // this is usefull for the help system
//************************* create backdrop ***************************
Use BackGnd // Standard background and title...creates object
Send Paint_Desktop to (Background(Current_Object)) ;
"?????????????????????????????????????" // You set the title
//************************* create main menu ***************************
/Main_Menu
______ ____ ____ ________ ____
/View_Pull_Down
___________________________
___________________________
___________________________
___________________________
___________________________
___________________________
___________________________
/*
Create_Menu Main_Menu Location 1 0 Absolute
Set Action_Bar_Keys_Msg To Main_Menu_Keys
#INCLUDE RECDE_PD.INC
// ??????.Src: ??????????????????????????????
Send Paint_Desktop to (Background(Current_Object)) ;
"?????????????????????????????????????"
1 Introduction 175
Send Paint_Desktop to (Background(Current_Object)) ;
"Acme Computer Supplies-Order Entry System"
The second line identifies the name of the source code file
(ORDERENT.SRC).
The third line will insert the title "Acme Computer Supplies-Order
Entry System" into the program’s menu.
/Main_Menu
______ ____ ____ ________ ____
/View_Pull_Down
___________________________
___________________________
___________________________
___________________________
___________________________
___________________________
___________________________
/*
In the code for the Main Menu image, each set of underscore
characters represents a window that will contain the name of the
different pull-downs in your program’s action bar. Since you are going
to create a Report pull-down for your report view, you must add a
six character underscore window between window number two and
three. The result should look like this:
/Main_Menu
______ ____ ______ ____ ________ ____
The default size of the View Pull Down image has room for seven
pull-down items, which is exactly what we need; one for each of the
Data Entry views plus the "Close" option. The width, however, must
be increased to accommodate the static text labels for each of the
Views. Note that you will have to use the line drawing features of
your text editor to adjust the View Pull Down image.
The finished View Pull Down image and Report Pull Down image
looks like this:
/View_Pull_Down
________________________________
________________________________
________________________________
________________________________
________________________________
________________________________
________________________________
/Report_Pull_Down
__________________________
__________________________
This section defines the labels for the View pull-down menu items and
the message each item will perform when selected.
1 Introduction 177
On_Item "Courier Entry Screen...\aAlt+1" Send Activate_COURIER to desktop
Repeat the steps shown above for each of the remaining views:
6. Now you need to define the Report Pull Down. Copy the View
Pull Down section shown above and delete lines 3 through 6.
Change the first line with information that is appropriate for
the Report View Pull Down: the label should be "Re&port" and
the image name Report_Pull_Down. Next, modify the label in
the second line so that it reads "Order Entry Report...\aAlt+7",
and change Activate_COURIER to
Activate_REPTUTOR_Report. The finished section looks like
this:
7. Move down the template file until you find the following
section:
This first part of this section defines the accelerator keys for the
Record, View, Text, Navigate and Help pull-down menus.
These setting are fine as is.
The next section defines the accelerator keys for each of the View pull-
down menu options. The first line of this section should define the
accelerator key combination ( a1+ ) for the COURIER view. The line
will look like this:
Repeat the steps shown above for each of the remaining views:
CUSTOMERS Alt+2
INVT Alt+3
ORDER Alt+4
SALESP Alt+5
VENDOR Alt+6
1 Introduction 179
8. Move to the end of the file until you arrive at this section:
In this section, you specify the view packages to use in your program.
FIll in the ?????? with the name of the view packages (e.g.,
ORDER.VW). Fill in the ?????? with the name of the View objects (e.g.,
ORDER). The finished code for this section should look like this:
Now that you have created your application, you will want to walk
through it in order to examine the features, enter some data, and see
that you have properly implemented the Business Rules.
Type DFRUN ORDERENT from the command line. You will see the
familiar background, with the pull-down menu system you created.
The title at the top of the screen reads Acme Computer Supplies-
Order Entry System – the title that you programmed to be sent to the
Desktop background. The pull-down menu headers read Record
View Report Text Navigate l
Help. Press the , then
e , to pull down the View menu. You will see the view items you
created. Note that these views may be activated in several ways. If
you have a mouse interface, you may simply click on the item. Each
item listed contains its accelerator-key activation sequence, e.g.a! +
for the Courier Entry Screen. This key sequence may be used whether
the pull-down is currently active or not. Or you may, at any time,
press 0 to activate the Menu Bar, then press the activation letter for
any option in order to bring it up. For instance, if you are currently in
the View pull-down, pressing S will bring up the Sales Person Entry
view.
Your first task will be to enter some data into the master files: Sales
Person, Vendor, Customer and Courier.
Press a% + . The Sales Person Entry form will appear. Type your
initials into the Id field, and your name into the Name field. Press 2 .
You will see the Save Confirmation dialogue – the result of the
Set Verify_Save_MSG to GET_Save_Confirmation message
that AutoGen wrote for you in the Entry_View_Client of the
Salesperson View. Press 2 , and your record will be saved. While
you are at it, enter and save another Sales Person: Id: AR, Name:
Adolph Restani.
1 Introduction 181
file. This satisfies part of Business Rule #9. In fact, you might like to
try to make up and enter a Vendor ID and see what happens.
Press a@
+ to bring up the Customer Entry Form. Enter and save
some customers, using the following suggestions, if you wish, or make
up your own. Here too, Customer Number will be assigned by the
system, satisfying another part of Business Rule #9. You might also
enter some Comments in one of the records, to get a feel of the Text
Window's features.
Press a+! to enter some Couriers. Here are some suggested entries:
From any of the views, while in the first field, press F4. The Selection
List for that view will pop-up and display all the records that you
entered. Choose one of the records, and press Enter. The record will
display in your form. Try this with all the views that are currently
active.
Now it is time to enter some inventory items, so that you may create
an order. Press a# + to present the Inventory Parts form. Enter the
following item. Note that when you enter the Vendor Id, you may use
the 7 (Find Less Than), 8(Find Greater Than) and 9 (Find
Greater Than or Equal) keys to find the correct vendor. (In retrospect,
it might have been a good idea to have prompted the Vendor Selection
List from the Vendor Id entry item. We will leave it up to you to
implement that idea on your own.)
1 Introduction 183
SOLU-48-P Toner Solution #48 - 12 Pts .3 S48P 8.56 23
PAPER-123 EZ as 123 Paper - 10 Reams 3 123-10 48.48 2
After you select the Sales Person, the cursor will go to the first line of
the Order Detail table. What you, as the operator, cannot see is that
the Order record has been saved. This is due to the fact that you
programmed it to do so when you added the Save_Header function to
the AutoGenerated code.
Now, enter five more order items. Note that each time you save an
item, the order's total amount is updated (This fulfills Business Rule
Now enter your last item. Make it PAPER-123, which you entered as
having a quantity-on-hand of 2. Try to sell three of these. After you
OK the Save confirmation, you will get another dialogue box
informing you of “Insufficient Inventory Stock”. So Business Rule #3
has been confirmed.
Before you can enter another order, you must first clear the forms and
make them ready for the next order to be entered. Press c5 + , as
prompted on the bottom of the screen. You will see everything you
entered disappear. Remember, the Order Header was already saved,
as was each line item. Clearing the screen did not do away with the
order you entered. With the cursor in the Order Number window,
press4 . The Selection List will pop up with your order as the only
item. Thus you may restore the order as it was, so as to be able to
edit it, delete it, or just examine it.
Before you exit your application, check to confirm that the remaining
Business Rules have been correctly implemented. In turn, try to delete
the Customer that you sold your order to, the Sales Person who sold
it, one of the Vendors with a product in the Inventory file, one of the
Inventory Items that was sold, and the Courier which was assigned to
the Order. In each case you should, after confirming the delete, get
the “Cannot delete - related records exist” message.
1 Introduction 185
Now, take a look at the inventory quantities-on-hand in the Invt view.
You will see that the values have changed from what you entered,
because of Business Rule #5.
object
ui_object
menu
list
entry_list
wide_list
data_list
table
The two types of high-level tools provided with DataFlex are the data-
set class and data-entry classes. The data-set class allows you to create
a gateway (subclass) to each data file containing the custom business
rules for the file. The data-entry classes allow you to easily create
"data-aware" user-interface objects. The DataFlex Application
Framework will show you how to create, assemble, and connect these
components, and how to combine them into a single program. The
AutoCreate/Autogen Utility will get you started by allowing you to
visually design and generate Framework-style program components.
Properties are created and their values are assigned and queried
with the following syntax:
This is the file number of the data file. All data-set operations will be
centered around this file.
This determines if the data set will support "smart file locking", a
method that can significantly improve save and delete performance on
multi-user, multi-file systems. Sometimes this requires augmentation of
the reset_filemodes_for_lock message.
// Customer_Data_Set Class
//
// 1. Disallow deletes if orders exist for this customer.
// 2. Assign customer Number to new customers.
//
Class Customer_Data_Set is a Data_Set
Procedure Construct_Object Integer Img#
Forward Send Construct_Object Img#
Set Main_File to Customer.File_Number
Set Smart_FileMode_State to true
Set Cascade_delete_State to FALSE // do not delete if child records exist
// List all child (client) files
Send Add_Client_file Orderhea.File_Number
End_Procedure // Construct_Object
// A new Record: assign a new customer Id from a system file
Procedure Creating
Forward Send Creating
Add 1 to OrdSys.Cust_Number
Move OrdSys.Cust_Number to Customer.Number
SaveRecord OrdSys
End_Procedure
// required with smart-file locking. We must list the system file
Procedure Reset_Filemodes_for_lock
Forward Send Reset_Filemodes_for_lock
file_mode Ordsys Default
End_Procedure
End_Class
1. When one data set relates to another, you generally want the
data set to only show the records which relate to the current
record in the related-to data set. A relates-to constraint will do
this for you.
2. You may want a data set to look like a file, but that "logical
file" is actually a selection of records from some larger file. For
example, your customer data set may actually use the name-
and-address file, constrained to address_type eq
"customer". A constant-value constraint will do this for you.
Constraints are not part of your business rules. They are usually
determined by the needs and structures of your user-interface objects.
For this reason, constraints are coded into your data-set objects and
not into your data-set subclasses.
constrain file.field <op> value <op> = lt, le, eq, ge, gt, ne,
contains, matches.
Entry_view_client
Entry_client
Text_window
Table
Selection_list
The forms and list-based classes are item-based. Each object may
contain items. Each item connects to a field in a database file, or an
expression. In a form, items represent each blank in the form. In a list,
the items represent each item in a row. The entry_item command is
item_list
entry_item file.field {item_options}
:
end_item_list
begin_row
entry_item file.field {item_options}
:
end_row
entry_item (expression)
The iprompt= and izoom= options allow you to specify objects that
4
are to be popped up when users press the prompt ( ) or zoom
(a+9 ) keys while in that item. This will be used extensively to
popup selection-lists. The method for creating a selection-list is
discussed in the next section. Below is an example of how a selection
list would be accessed with the iprompt= option.
Example:
item_list
entry_item customer.id {autofind, findreq, ;
iprompt=(customer_list(current_Object)) }
:
entry_item salesper.id {autofind, findreq, ;
iprompt =(salesper_list(current_object)) }
:
end_item_list
A data-entry object should contain code that looks like the following:
Revision 3.1
DISCLAIMER
TRADEMARKS
1 INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 About the Manuals . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Developing Applications with DataFlex . . . . . 1
1.1.2 User’s Guide . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.3 Encyclopedia . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.4 UIMS Handbook . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.5 UIMS Reference . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Introduction to DataFlex . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.1 The DBMS . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.2 The Language . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.3 The Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.4 Basic Application-Development Concepts . . . . 9
2 PROGRAMMING IN DATAFLEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.1 The User-Interface Management System . . . . . . . . . . . . 21
2.2 Object-Oriented Programming . . . . . . . . . . . . . . . . . . . . 22
2.3 Learning to Use the UIMS Toolkit . . . . . . . . . . . . . . . . . 23
4 DATAFLEX TUTORIAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.2 Special Notes and Instructions . . . . . . . . . . . . . . . . . . . . 46
4.2.1 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4.2.2 Instruction Conventions . . . . . . . . . . . . . . . . . 47
4.3 Single-File Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.3.1 Program/Application Specifications . . . . . . . . 48
4.3.2 Defining the Field Name, Type, and
Length . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Table of Contents i
4.3.3 Creating a Working Directory for Your
Application (Starting from Scratch) . . . . . . . 51
4.3.4 Changing the Defaults . . . . . . . . . . . . . . . . . . 51
4.3.5 Creating the data file, fields and indexes . . . . 55
4.3.6 Designing the Views For Your
Application . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.3.7 Generating the code with the AutoCreate
Source Code Generation Utility
(AutoGen) . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.3.8 Compiling your program . . . . . . . . . . . . . . . . 80
4.3.9 Running your application . . . . . . . . . . . . . . . . 80
4.3.10 Generating a Report . . . . . . . . . . . . . . . . . . . 85
4.3.11 Adding your program and report to a
Main Menu program . . . . . . . . . . . . . . . . . 91
4.3.12 Running your application and report
from the menu . . . . . . . . . . . . . . . . . . . . . . 95
4.4 Real-world example, Order Entry System . . . . . . . . . . . 96
4.4.1 Creating a working directory for your
application . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.4.2 Changing the defaults . . . . . . . . . . . . . . . . . . . 96
4.4.3 Creating the data files, fields, and indexes . . . 97
4.4.4 Programming the Business Rules . . . . . . . . . 106
4.4.5 Interface Design . . . . . . . . . . . . . . . . . . . . . . 120
4.4.6 Generating a report with DFQUERY . . . . . . . 156
4.4.7 Endless Horizons . . . . . . . . . . . . . . . . . . . . . 173
4.4.8 Assembling your program . . . . . . . . . . . . . . 173
4.4.9 Compiling your program . . . . . . . . . . . . . . . 180
4.4.10 Running the Acme Order Entry System-
A Guided Tour . . . . . . . . . . . . . . . . . . . . . 181
6 INDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Table of Contents v
Prototyping with AutoCreate 31
Selection_list
example of 41
Selection_list object package 41
Structure of a view (diagram) 34
table0 class
hierarchy of 187
Test package 40
updating clause
and views 31
data sets and 33
using clause
and views 31
View
definition of 28
example of 29
rules for defining DEOs in 35
View object pacakge
example of 37
Views
access method for DSOs in 36
and AutoCreate 31
and data-entry objects 31
and data_sets 31
and DataFlex programs 28
assembling 26
constructing 37
creating 25, 31
creating classes for 31
data-set classes for 32
defining messages in 32
object package for 37
reusability of 29
rules for creating 31
rules for placing data sets in
33
selection_list for 41
structure of 34
testing 40
Zoom
using objects 204