Vous êtes sur la page 1sur 217

1 INTRODUCTION

1.1 About the Manuals

DataFlex is supplied with an Installation or Environment Guide and


five manuals, including this one.

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

Your approach to DataFlex and its documentation should, however,


begin with this manual. You are unlikely to be able to use DataFlex
efficiently and effectively until you have absorbed the contents of this
manual, plus occasional references to the other ones.

1.1.1 Developing Applications with DataFlex

This manual is an introduction to DataFlex. It is informative not only


for users new to DataFlex, but also to those updating from earlier
revisions of DataFlex.

It contains basic information about DataFlex, plus introductory


information concerning object-oriented programming and the DataFlex
User-Interface Management System (UIMS) and the DataFlex
Application Framework. It is intended to prepare you to branch off in
pursuit of your own particular requirements by the time you complete
it, regardless of what those requirements might be.

Developing Applications contains a section on how to create an actual,


working, multi-file, event-driven data-entry application, using the

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.2 User’s Guide

This volume describes the basic concepts of DataFlex. The traditional,


or procedural DataFlex that is covered in the User’s Guide is present in
every DataFlex program, whether that program makes any use of the
UIMS or not. The User’s Guide describes the DataFlex command
language in depth, and similarly documents the database manager that
is used by every DataFlex database program.

This volume also contains the in-depth documentation of all the


DataFlex utilities, including those for generating applications, for
developing programs, modifying database-file structures, and many
other processes. Various small but vital "core" subjects are treated in
the User’s Guide, including interpretation of error messages, a list of
specifications, and description of all environment variables used by
DataFlex.

1.1.3 Encyclopedia

This volume provides comprehensive support for every DataFlex


keyword available for use in DataFlex programs. This includes
commands, functions, and predefined variables of all types—more
than 200 words in all, arranged in articles in a single alphabetic
sequence just like a general-purpose encyclopedia.

Most articles contain short samples of code illustrating use of the


subject, and connection of the subject to other subjects treated in the
Encyclopedia is fully indicated in a "See Also" section of each article.

2 Developing Applications with DataFlex


Where the subject uses arguments, the nature and use of each
argument is fully delineated in a table.

1.1.4 UIMS Handbook

The UIMS Handbook presents the concepts of the object-oriented


DataFlex User-Interface Management System in depth. In its
perspective, it compares with the DataFlex User’s Guide described
above, but its scope is only object-oriented programming, the UIMS,
and the DataFlex Application Framework. It provides considerable
information about the UIMS, covering both basic and advanced topics.
It fully describes the high-level DataFlex classes and the Framework
method of program design, coding, testing, and implementation. If you
want to learn how to use object-oriented DataFlex, you will want to
read the UIMS Handbook.

1.1.5 UIMS Reference

This volume might be regarded as the "encyclopedia" of the UIMS. Its


contents faithfully reflect the "genetic" nature of objects and their
classes, making it indispensable for understanding the class hierarchy
scheme. The main articles on classes, being arranged alphabetically, are
not indexed. Messages (functions and procedures), however, are
indexed, and you can use the index to messages to quickly see which
classes a message is in. Properties, accelerator keys, child objects, and
commands defined in each class are also discussed.

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

DataFlex is software that helps manage data stored in computers. Its


orientation is to random-access data, such as the listings in a telephone
book, rather than to sequential-access data such as the words in a
novel. An important part of DataFlex is its database manager, so
DataFlex is sometimes called a "DBMS" (database-management
system).

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.

For this reason, DataFlex is more-accurately referred to as a "language"


or, in view of its style and capabilities, as a "4GL" (fourth-generation
language). While it was originally written to provide the means to
develop database applications, the language has developed to the point
where it is now possible to use it for pure processing without the use
of any data on disk.

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.

One of the conspicuous strengths of DataFlex is its transportability


from one computing environment to another. At present, DataFlex
runs in the DOS, OS/2, UNIX, and Windows operating systems, on
CPUs of Intel, Motorola, and some other manufacturers. Both its data

4 Developing Applications with DataFlex


and its programs can be moved from one environment to another with
no more than recompilation, and sometimes not even that.

Another attribute in which DataFlex has been an industry leader for


many years is transcultural versatility. DataFlex provides facilities for
configuration of date format, currency characters, numeric punctuation,
and other factors so that, again, programs may be moved from one
national environment to another and adapted for local uses in many
cases without even recompilation. As enterprises themselves more and
more frequently operate across multiple cultural environments, this
factor becomes more important. DataFlex today is supplied in over a
dozen language versions around the world.

1.2.1 The DBMS

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.

The DBMS is inherently multi-user, both for multi-user environments


such as UNIX, and for single-user environments such as DOS adapted
for multiple users through Local Area Network (LAN) software. Multi-
user locking facilities are provided that do not limit data access at all
for reading, and confine access restrictions to brief periods of only a
fraction of a second for writing.

Concurrent use of DataFlex applications by many users is further


supported by the (optional) DataFlex Server, which performs database
manipulations in the server rather than in workstations, potentially
reducing network traffic dramatically. Use of the Server in large
applications both enhances data integrity and improves (often greatly)
the performance even of modest workstation hardware.

1 Introduction 5
1.2.2 The Language

As an application-development system, DataFlex supplies the DBMS,


the utilities, and the DataFlex language, in which the source code for
all programs is written and/or generated. This language, containing
hundreds of keywords, provides all the power of a 4GL together with
the flexibility of a complete third-generation language (3GL). The
source code can be written and edited with any text editor and is, in
fact, contained in pure-ASCII files.

There are two "flavors" of the DataFlex language: procedural and


object-oriented. Both are provided with every DataFlex development
license, and both use the same database manager on the same
databases.

Procedural, or "traditional," DataFlex executes the way most


procedural languages execute—sequentially as the code stands in the
source code file, with non-sequential execution directed by various
commands to move or control execution such as conditionals, loops,
and subroutine calls. Like most command-based languages, its syntax
is verb-based.

Object-oriented DataFlex, on the other hand, retains major portions of


traditional DataFlex for data manipulation, but uses a more noun-
based syntax whose execution delivers applications described as
"event-driven." Revisions of DataFlex before 3.0 did not contain object-
oriented DataFlex, and just as before, programs can still be written
entirely in procedural DataFlex. In fact, programs containing modules
in both modes are entirely possible.

Object-oriented DataFlex, however, provides a much more-powerful,


flexible user interface than procedural DataFlex. This interface system
is known as the DataFlex User-Interface Management System (UIMS).
The UIMS further provides support for a mouse, and object-oriented
source code, being much more modular than procedural source code,
can be much easier to maintain, modify, and re-use in future
development projects.

The power and scope of DataFlex object-oriented technology is in fact


so great that a methodology for applying it to common business ("real
world") purposes has evolved and become the standard, recommended
way of deploying this technology. This methodology is called the

6 Developing Applications with DataFlex


DataFlex Application Framework, and it is described in depth in the
UIMS Handbook, which continues the subject where this manual leaves
off.

DataFlex includes two utilities that generate actual program source


code. The first, the DataFlex AutoCreate Utility, generates data-entry
"view" prototypes, which may be converted into Framework-compliant
source code by use of the AutoGen processor. The second, the
DataFlex Query Utility, not only permits user interaction with the
database, but also generates report programs so that queries can be
repeated. These utilities provide much more than runnable programs.
They provide source code that can be used as a learning vehicle, and
that can be edited to produce more-complex programs than can be
produced with the utilities alone. Especially for learners, virtually
every program should be begun with one of these utilities, and final
products derived from editing the programs they produce.

Files containing runnable programs are created from source-code files


with the DataFlex compiler. The compiler is actually a semi-compiler,
and produces runnable program files with the distinctive extension of
".FLX" and the same rootname as the source-code file. To run the
program, you must use the DataFlex runtime (included with every
license), DFRUN.

1.2.3 The Utilities

DataFlex includes many utilities for various purposes, of which three


have already been mentioned above. All of the utilities themselves use
the DataFlex UIMS, and their interfaces are written entirely in
DataFlex. Some have their own executable files, however, and do not
use the DataFlex runtime.

The AutoCreate Utility (DFAUTO) provides an interactive means of


generating data-entry "view" prototypes. The term "applications" here
includes not only the display of entry screens to accept and validate
user input and modify the database, but also the creation of actual
new database files, including groups of files related to each other.
AutoCreate is capable of modifying existing view prototypes as well as
creating new ones. View prototypes are converted into Framework-
compliant source-code modules by use of the AutoGen Utility.

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 File Definition Utility (DFFILE) provides an interface for


exercising more-extensive control over database files and their
relationships to each other than is provided in AutoCreate. Included is
the ability to change indexes, field lengths and types, adding and
deleting fields, and changing their order. These and other steps may be
carried out not only on newly created files, but also on files that have
data in them.

The File Administration Utility (DFADMIN) provides an interface for


reindexing database files, as well as creating, editing, and deleting file
lists. You can also create and print out file definitions with it.

The Import/Export Utility (DFIMPORT) provides the means to read


data from ASCII text files into DataFlex database files, and vice versa.
The utility can be used either from a command line, a response file, or
a complete user iinterface, and it provides extensive control over field
selection, placement, and data types.

The Compiler (DFCOMP) creates runnable program files from


DataFlex source code files. It includes options to aid in debugging, and
is capable of "precompiling" sections of programs that do not change
from one revision to the next, to speed the overall process of
recompiling a program under development.

The Runtime is the executable program required to run DataFlex


programs. It is supplied with all DataFlex development licenses, but
also forms the core of a different license, the runtime, intended to be
supplied with copies of applications to others who will use them on
separate computers or networks.

8 Developing Applications with DataFlex


The Configuration Utility (DFCONFIG) provides numerous system
options for DataFlex’s interface, including function keys, screen display
attributes, date format, currency characters, numeric punctuation, and
many other options. A whole set of options concerns the icon strings
used in the UIMS, and other aspects of its appearance and behavior.
The options set in Configuration can be used at a whole-network level,
at the single-workstation level, or at the application level.

The Setup Utility (DFSETUP) supports the configuration of DataFlex


for different hardware environments, including screen control codes
and function keys. Like Configuration, it can be used at a number of
different levels, including whole-system, individual-workstation, or
application. It is typically used only at installation, but can be changed
afterward as well.

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.

The Help Utilities provide context-sensitive help for programs


through the UIMS. Like Menu, Help contains a Help Maintenance
Utility in which help information may be entered and linked to
programs. Also like Menu, Help is supplied with data for the utilities
and sample applications. This data may be changed, deleted,
augmented, or even translated to other languages.

1.2.4 Basic Application-Development Concepts

Database

DataFlex is often referred to as a "database manager." While it also


includes a complete fourth-generation application-development
language, its database manager provides the functional core of
DataFlex, whether addressing disk data that is in DataFlex format or
any of a wide range of other formats.

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.

A DataFlex database file is not, however, a single disk file. Rather, it is


a family of disk files all sharing a common rootname and having
different extensions indicating their type. Thus, CUSTOMER.DAT,
CUSTOMER.K1, and CUSTOMER.TAG are all constituents of database
File CUSTOMER, and CUSTOMER.DAT, VENDOR.DAT, and
INVOICE.DAT are all data files in different database files because they
all have the distinctive .DAT extension.

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.

Sequenced lists of database files are maintained in special files with


the default name FILELIST.CFG. The file list in this file is used by
programs to locate the physical files making up each database file and
ensure that related files are accessed in a single, consistent sequence by
all users.

Fields. The data in a database file is classified into fields, sometimes


referred to as columns in database theory and SQL. A field represents
the equivalent item of data for all instances of whatever is recorded in
the file data. For example, every person has a name. In a file of
persons, the recording of each person might have a field for the
person’s name. If the list associated a phone number with the names of
persons who had telephones, every person would have a phone
number field, too, regardless of whether he actually had a phone.
Persons lacking telephones would have a blank telephone number
field.

10 Developing Applications with DataFlex


Each field is characterized by certain parameters applying to every
instance of it. For example, each field has a defined maximum length
and data type, which might be String, Numeric, Date, Text, or Binary.
The field lengths and types are assigned by the programmer in
creating database files.

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.

The DataFlex database driver distinguishes among records


automatically by the record’s number, and also finds records by their
numbers. The number is assigned when the record is first created, and
cannot thereafter be changed. The record number is simply the number
of records lying before the new record in the file, plus 1. There are, of
course, other ways of distinguishing among and finding records, but
internally, all methods ultimately use record number. Although record
numbers can be dealt with in some respects as though they were
actually a field, they are not a field. Any change to the value of a
record number is interpreted as a reference to a different record (often
a programming error).

Indexes. DataFlex indexes are used for finding records by values in


their fields. If you want to find the phone number of a person whose
name you knew, you would do so by using the name of the person
whose number you sought, and getting the number from the record
for the desired name. When a target (key) value such as a name is
input in a program for a field that is indexed, DataFlex can find the
record or records, with the matching field value, or a value that begins
with the key value.

An index can be made up of the values of one or more fields. A large


list of names might include duplicate names, but if the list included
the city in which each person lives and the name of the city were
entered as a key value, the record DataFlex found would much more
likely be the one desired. The city field would, of course, have to be
only a part of the index used in the search.

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.

Third, individual index segments may be designated as upper case.


This has no effect on the data in the files—just on how it is interpreted
for indexing purposes.

Finally, individual index segments may be designated as descending


(as opposed to the default of ascending). A descending index segment
gives you the ability to find and report on highest-to-lowest values for
that segment. An example frequently encountered is Date segments, in
situations where the most recent record is to be listed first, and then
the earlier ones.

Relationships. In real applications, it is very common for database


files to have relationships to other database files. File relationships are
a cornerstone of database management, and a particular strength of the
DataFlex database manager.

12 Developing Applications with DataFlex


File relationships come into play when many of the records of a file
have something (such as the value of a field) in common, especially
when what they have in common is subject to change, and/or
constitutes a large volume of data having some complexity in itself,
such as a name and address. If the list of names, for example,
contained phone numbers for the persons at their places of work, it
might be expected that a number of the people on the list work at the
same place, and thus have the same phone number. If the (work)
phone numbers were kept in a different (employer) database file
related to by the person file, this would result in a number of
advantages.

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.

Second, the telephone number itself would be provided by reference


into the employer file, reducing space consumed by the names file.
This space saving can be considerable if data such as the name and
address of the employer is desired for the listed persons.

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.

Finally, it would be easy to support data in addition to the shared


phone numbers. Obviously, placing the company name in each record
with the phone number would make sense for a number of reasons,
even if it was not desired to list the name of the employer with the
names of the persons. The phone number of a new or changing entry
could still be found and applied by finding the record for the
employer by name.

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.

In DataFlex, all sorts of different attributes may be given to individual


data windows, so the programmer may impose very precise
requirements or restrictions on each, and on how the database is
maintained. For example, the data itself can be checked to ensure it is
within a given range of values; or it can be converted to upper case, or
it can be made to stay in its data window after all the others have
cleared. Some data windows may be for display only and not allow
entry of new data; others may require entry of data. The handling of
records in the database can also be precisely controlled with window
entry options. For example, the finding of an existing record can be
required before data may be entered, and parent/child relationships
between records may be protected.

Sometimes you will impose restrictions on which data windows the


cursor will visit, but usually operators may navigate around all the
other data windows to make changes and to correct errors.

14 Developing Applications with DataFlex


AutoCreate. The DataFlex AutoCreate Utility allows you to design and
create data-entry views easily and, if you wish, the database files they
access. From AutoCreated view prototypes, the AutoGen processor can
generate source code for the views you design. The programs will
have everything needed for the efficient, easy entry, finding, and
editing of data. If you later decide you want to change or add features
beyond AutoCreate’s capability, the programs provide a good starting
point for producing truly custom applications, or you can make
changes through AutoCreate/AutoGen, generating fresh source code.

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.

AutoCreate can generate entry programs for maintaining a single file


or a group of related files, and you can create multiple objects in the
same session of AutoCreate, and switch between them—cutting,
copying, and pasting fields and static data as you wish. You can resize
objects and move them around your screen; you can set their line-

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.

The programs written by AutoCreate and AutoGen contain everything


needed to maintain a database. As explained elsewhere in the
documentation, the entry_form object class (with its associated
item_list and entry_item commands) is, in effect, a complete sub-
language you do not need to concern yourself with if you don’t want
to. It encompasses an entire group of processing routines that perform
the following functions:

1. Enter data via screen images, with validation, type checking,


range checking and error trapping.

2. Create records in the database file with data entered through


the screen image, and in the process, update related database records,
key indexes, etc., all without having to create routines and procedures
for such activities.

3. Find data in the database file by a key field and display it on


the formatted screen image. Single records or multiple related records
can be found with a single key stroke. Record data can then be
inspected, browsed, edited, or deleted.

16 Developing Applications with DataFlex


4. Edit existing records in the database file and in the process,
properly update related database records, key indexes, etc. without
custom routines and procedures.

5. Delete records from the database file while processing all


required updates on-line.

6. Clear displayed data from the screen image.

UIMS Toolkit. AutoCreate can be directed to produce data-entry


programs in procedural DataFlex. This is primarily to provide
backward compatibility for those users of previous revisions who
particularly desire it. In its default mode, AutoCreate generates object-
oriented programs through AutoGen.

UIMS programs, including those generated by AutoCreate, have many


features not provided or possible in procedural DataFlex. First and
foremost among these is mouse support. Some of the more discrete
features utilize or enhance mouse support, but all can be fully utilized
from the keyboard (without a mouse). These include action bars, pop-
up selection lists, buttons, check boxes, text areas, titles, messages, and
arrays. There is even a class of objects with which to add a debugging
mode to your programs. In this mode, you can not only troubleshoot
programs under development, but also observe the functioning of
programs, such as those generated by AutoCreate, that are working
properly.

Before making any attempt to modify source code produced by


AutoCreate/AutoGen, it is highly recommended that you run a few
generated programs long enough to become fully acquainted with the
many powerful features they contain.

While many UIMS features are automatically included in AutoCreate-


generated programs, they can all be added to or extended in such
programs through manual modification of the AutoGen-generated
source code. Such a generated program is not only the strongly
recommended place for new users to begin programming DataFlex, it
is also a potent prototyper for new projects of DataFlex programmers
who have years of experience. The part of this manual in which you
create a working order-entry application gives you a complete tour of
this utility.

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.

A Report program is divided into two major areas: images and


procedure sections. The images specify the page headings, section
headings, section totals, report totals, window captions, positions,
lengths, and types, etc. The procedure sections contain commands that
instruct the report object how to "fill in" data in the images for output.

In the DataFlex documentation, we refer to a "report" as a generalized


formatted output operation which may encompass formatted reports,
formatting for preprinted forms, labels, file output, etc.

18 Developing Applications with DataFlex


Query. The DataFlex Query Utility allows you to extract information
easily and quickly from a database. Query can automatically format
data from one database file or a group of related database files. Output
may be to the screen, printer or disk, and may be sequenced by any
index in existence for the database file being queried.

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.

Additional features of Query include optional totalling of numeric


fields, and a full range of logical selections (less than, less than or
equal to, etc.) can be used. In each query, as many selection criteria as
you wish are allowed. Selections may be based on criteria that you
enter, either while you are designing your query, or when you return
to it in the same or later sessions.

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.

Although Query can generate DataFlex programs for reports, it is not


intended to be a full report generator. The Report class (which
programs generated by Query use) is DataFlex’s central report-writing
facility, and in order to create sophisticated, formatted, multi-file
reports within DataFlex with operator prompting, you will need to
become familiar with its facilities, introduced in the UIMS Handbook. If
you don’t want to do any programming at all, you may decide to use
the separate report-writing program, FlexQL (for character-mode
environments) or WinQL (for Windows environments), to produce
some or all of your reports. Contact your dealer or Data Access
Corporation for more details about FlexQL and WinQL.

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.

DataFlex contains a rich programming environment. It is not possible


to cover all aspects of this environment in one short manual. The goal
of this manual is to provide enough background information so the
terms, syntax and method of the DataFlex application we create in the
tutorial section will make sense. Presenting introductory information is
always difficult. If too much information is presented, the product
appears too complicated; if too little information is presented, the
product appears too confusing. This manual has tried to maintain a
"happy medium". The programming language is straight-forward and
should make sense to anyone with programming experience. For this
reason, the language is not discussed at all (but is fully documented in
the DataFlex Encyclopedia). The UIMS concepts and terms that are
introduced comprise the information required to use the high-level
tools. The high-level tools, the data-entry and data-set classes, are
introduced in greater detail. Once again, this information is focused on
the knowledge you will actually need to create basic applications.

2.1 The User-Interface Management System

The User-Interface Management System (UIMS) is a DataFlex


programming environment in which programmers can create and
maintain attractive, intuitive, and powerful user interfaces for their
database applications. UIMS applications are event-driven, meaning
that users and not the program determine the order of events as the
application runs. In an event-driven system, if users can see something
on the screen, they should be able to move interaction to it. This is
referred to as modeless or non-modal navigation. This is contrasted

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

From the users’ point of view, event-driven navigation is both


powerful and intuitive (e.g., they simply "point and select" with their
mouse). From an implementation point of view, an event-driven
system can be quite complex. There are two primary reasons for this:
the mechanisms required to provide low-level support are
complicated, and the high-level tools required to create event-driven
applications must be quite sophisticated. In addition, these high-level
tools must allow the developer to seamlessly integrate event-driven
user interfaces with multi-file, multi-record, multi-user databases. The
goal of the UIMS is to provide both the low-level support and a high-
level toolkit, thus allowing the developer to bypass most of the
complexities of programming event-driven applications.

2.2 Object-Oriented Programming

To meet these low-level and high-level requirements, a relatively new


style of programming was implemented known as object-oriented
programming. The advantages of this style of programming are:

1. Objects contain (or encapsulate) all their data and the


methods to manipulate this data. The fact that objects are "self-
contained" is ideal for creating modeless and event driven
capabilities.

2. The extendibility and reusability of classes makes object-


oriented programming well suited for creating a high-level
database-development toolkit.

If object-oriented technology made it possible to provide an event


driven system with a high-level toolkit, it stands to reason that the
advantages of object technology should be made directly available to
the developer. That has been done. DataFlex provides the developer

22 Developing Applications with DataFlex


with complete object-oriented language support. The additional
advantages of this are:

3. The developer may easily customize their user interface


applications.

4. The developer can use object-oriented technology to create


"business rules" for each data-file.

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.

6. Object-oriented programming is also suited for non-user-


interface programming tasks. For example, objects can be and
are used to create sophisticated reports.

2.3 Learning to Use the UIMS Toolkit

If you are an experienced programmer but new to object-oriented


programming, you may have heard about the dreaded "OO learning
curve". With DataFlex, you may be pleasantly surprised to discover
that you will be able to immediately harness the power of object
orientation. The UIMS toolkit consists of high-level tools, a framework
showing you specifically how to use these tools, and a utility named
AutoCreate that allows you to visually design and generate data-entry-
program components. None of these requires extensive knowledge of
object-oriented programming.

As a tool-user, you do not need to first learn object-oriented


programming; instead, you need to learn how to use the high-level tools.
The advantage of this approach is that you can get started and become
productive almost immediately.

The object-oriented nature of DataFlex makes it extremely open-ended.


The more you know about object orientation, the UIMS, and the
supplied classes, the more you will be able to accomplish. DataFlex
provides the best of both worlds: fast start-up and open-ended
flexibility.

2 Programming in DataFlex 23
As you learn more about object-oriented programming, you might
want to make note of the following points:

1. Object-oriented programming is different from procedural-style


programming. It is a common error among programmers to try
to make object-oriented programming fit within existing
programming styles. Object orientation is not just giving new
names to old concepts. Accepting this difference will accelerate
the learning process.

2. Object-oriented programming uses all of the concepts of more-


traditional programming. You will not be throwing out your
existing knowledge and skills.

3. Event-driven interfaces are becoming a necessity for most


applications and this type of interface is more complicated to
make than older sequential-style interfaces. Do not blame
object-oriented programming for this complexity. Without
objects, it would be even harder (if not impossible) to create
complex event-driven applications.

4. The UIMS Handbook is a very important resource. This is the


document that provides the information to turn you into an
advanced DataFlex application programmer.

In upcoming sections, we will be referring to the terms object, class,


subclass, inheritance, message, message augmentation (forward-
sending messages), property, and delegation. It is beyond the scope of
this manual to discuss these basic object-oriented concepts. If these
concepts are completely foreign to you, review the Definitions of
Terms appendix in the DataFlex UIMS Handbook. Otherwise, this book
should be sufficiently self-explanatory for you to proceed without
external references.

24 Developing Applications with DataFlex


3 THE APPLICATION FRAMEWORK

3.1 Application Components

In DataFlex, an application is usually composed of several programs,


which in turn contain one or many views. Views are independent
object building blocks which are coded and tested stand-alone, and
then combined with other views to create a program. Views should act
independently of each other. Views will include other components
(packages) such as the data-entry classes, selection-list objects, and
data-set classes.

A program consists of global resources (an action-bar/pulldown-menu


system, a help system, an error system, and optional global button bar)
and most important, a collection of views. These views will usually
share the same global resources. The number of views added to the
program is based on function and, to a lesser extent, memory
resources. It is easy to add or remove views from a program. Two
major categories of views are data-entry views and report views. Data-
entry views are selected from a view pulldown menu. Report views
may also be contained in the view pulldown menu, but are more likely
to be placed in their own report pulldown menu. Interaction among
data-entry views is non-modal. You can switch back and forth between
views at will. Report views tend to be modal. You must finish a report
task before switching to another view. Different programs may contain
the same views. Each of the sample directories under
\FLEX\USR\EXAMPLES (ordentry, expense, and dar) contains
examples of source code for main programs (the .src filename
extension), views (the .vw extension), data-set classes (the .ds
extension) and selection lists (the .sl extension).

An application often consists of a main-menu program which contains


a title, an action bar, a help system, an about object, and is capable of
loading any number of programs (which contain the views). You can
only run one program at a time. Most programs will return to your
main menu program. Interaction between programs is modal. Users
must exit one before they enter the other. An example of a main-menu
application is MENU.FLX, provided with DataFlex.

3 The Application Framework 25


Sometimes an entire application will be contained in a single compiled
program (.flx filename extension). If this is the case, the views are
usually grouped into a single view pulldown. There is a definite
advantage in keeping all parts of an application in a single program.
The primary advantage is that users can switch back and forth
between different parts of their application without the need to exit
program modules. This happens only if you make the views all reside
in the same program. It is the nature of event-driven programming
and the mouse to be able to switch to any task that is visible on the
screen (just point and click).

In order to build applications in DataFlex, you need to know how to


create programs and views. Creating views is where most of your
development and debugging efforts will be placed. Taking views and
assembling them in a program is one of the last things you will do in
the development cycle. The DataFlex Application Framework enables
you to design and write object-oriented programs in DataFlex with
maximum efficiency. It provides a methodology (or framework) for
writing your programs, a set of tools (class and object packages), and,
perhaps most important, numerous sample programs showing how it
is all done.

3.2 The Method

The DataFlex Application Framework provides a proven, successful


method for working with the components listed above. It describes
when and how to use existing components, when and how to create
new components, and when and how to connect components.

You should be able to quickly design, prototype, and write simple


programs using this methodology. As your programs get more
complex, you will find that these methods become even more useful.
You will be presented a specific set of guidelines for writing object-
oriented DataFlex applications. You will also be provided a set of
guidelines about what not to do. You are being presented with an
application development road map. This map may not be the only way
to get where you want, but it will definitely get you there.

26 Developing Applications with DataFlex


3.2.1 Class and Object Packages

Any complex undertaking recommends a "divide and conquer"


approach, and this is definitely true of application development.
Programs must be broken down into small, manageable units. In
DataFlex, one of these units is the package file. Typically, a package
file contains a class definition. Classes are the reusable tools of object-
oriented programming. When a class package is used by a program
(through a use command naming the file), the class definition is
included in the program at compile time. That program’s source code
may thereafter create objects based on this class.

A full set of high-level, sophisticated class packages is provided with


DataFlex. These contain classes that comprise your development toolkit
and are called the data-entry classes. They are the building blocks that
allow you to create complex data-entry views. The classes allow you to
present your data in a variety of formats such as forms, tables, pop-up
lookup lists, text editors, checkboxes and radio lists.

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.

We need to introduce another type of package called an object


package. An object package is a predefined structure of objects that
may be used in programs. Unlike a class package, which just includes
class code, an object package includes the code to create one or more
objects. Because a package file is only included once in a program, this
means that an object package will be used to create its object(s) one
time in the program.

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 The Application Framework 27


The Framework development method consists of three steps:

1. You create class packages for your data-set subclasses. These


define the rules for the data.

2. You create object packages based on supplied classes and your


data-set subclasses. You are now creating application
components.

3. You combine your components (object packages) into a single


application.

An object package must be encapsulated—that is, everything must be


contained within a single object. To the rest of the program, your
object package must look like a single object with a fixed set of
interface messages (whether that object contains child objects is of no
concern to the rest of the program). The rest of your program must
only know the object’s name and the messages used to communicate
with it. The fewer the messages, the better. For example, a selection-list
object package might have a name (e.g., Vendor_List) and a single
interface message (e.g, Send Popup to
(Vendor_List(current_object))).

3.2.2 Views

A view is a specialized object package. It is a stand-alone data-entry


unit. An example of a view might be a customer-entry form or an
order-entry form.

In earlier revisions of DataFlex, we created views as chain wait


modules. Encapsulation was realized by placing separate views in
separate programs. While we can still use this technique, with object
technology, we now can place multiple views in a single program. The
non-modal, event-driven nature of CUA encourages us to place
multiple views in a single program.

As more views get added to a single program, the complexity of the


program will increase. If the views are allowed to interact with other
views, it will become increasingly difficult to manage and maintain a
large program. By making each view independent of other views, we

28 Developing Applications with DataFlex


will be able to control this complexity. A large program will merely be
a collection of small "programs" (views).

We must be able to create and test views by themselves. When we


eventually add them to the larger program, we can do so with the
knowledge that the new view will not affect or be affected by other
views in the program.

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.

The following sample shows a main program. This program consists of


a main menu and a series of use commands that includes the required
views. Notice that the entire program is quite small.

//======================================================================
// 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

3 The Application Framework 29


//************************* 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
On_Item "View" Begin_Pull_Down View_Pull_Down
On_Item "Order Entry...\aAlt+1" Send Activate_Order to desktop
On_Item "Customer Entry...\aAlt+2" Send Activate_Customer to desktop
On_Item "Sales Person Entry...\aAlt+3" Send Activate_SalesP to desktop
On_Item "C&lose\aF3" Send Exit_Function
End_Pull_Down
#INCLUDE txtw_pd.inc
#INCLUDE navi_pd.inc
#INCLUDE helpa_pd.inc // modified help pulldown. Includes about.
End_Menu
// Hot key support
Procedure Main_Menu_Keys For Desktop Integer Act_Obj
On_Key KEY_ALT+KEY_R Send Activate To (Record_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_V Send Activate To (View_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_T Send Activate To (Text_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_N Send Activate To (Navigate_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_H Send Activate To (Help_Pull_Down(Act_Obj)) Private
//
On_Key KEY_ALT+KEY_1 Send Activate_Order to Desktop Private
On_Key KEY_ALT+KEY_2 Send Activate_Customer to Desktop Private
On_Key KEY_ALT+KEY_3 Send Activate_SalesP to Desktop Private
//
End_Procedure
//************************* View Packages/Objects ***************************
Use OrdAbout.vw // about - Send about
Use OrderEnt.vw // order entry - Send Activate_Order to Desktop
Use CustEnt.vw // customer entry - Send Activate_Customer to Desktop
Use SaleEnt.vw // sales person entry - Send Activate_SalesP to Desktop
send activate to (main_menu(current_object))
Start_Ui // start the program

30 Developing Applications with DataFlex


3.2.3 Prototyping Views with AutoCreate

AutoCreate is a wonderful prototyping tool. The Framework


methodology supports and encourages the use of AutoCreate as a
"prototyping tool". Do not plan on using AutoCreate to create whole,
finished applications. Instead, use AutoCreate to create prototype
views and object packages. With AutoCreate, you can visually create
your data-entry panels and your selection-list panels.

With the AutoCreate Source Code Generation Utility (or AutoGen)


processor, you can take your AutoCreated prototype and, in a matter
of minutes, convert your work into a view. This view can then be
made into one or more object packages. The order-entry example in
this manual shows this process. In it, the customer-entry view is first
prototyped with AutoCreate. It is then converted into a view with
AutoGen. The other views are handled the same way.

Chapter 5 provides a full tutorial showing you how to use AutoCreate


and AutoGen.

3.2.4 Creating a View

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.

The Container Object

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.

3 The Application Framework 31


The message sent to every view (and in some cases the only message)
will be activate (e.g., send activate to
(vendor_view(current_object)) ). Views will most often reside
at the desktop (have no parent object). Therefore, we will often create
desktop messages to activate our views. For example, we might
create a message named activate_vendor that activates the vendor
view. This might be the only external access method to this object.

The Data-Set Objects

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.

These data-set classes should have their own package file. By


convention this file will be named with a .ds extension. Depending on
the size of your application, you may choose to place all data-set
classes in a single package file or each data-set subclass in its own
package file. Any program that needs to use a particular data file, and
the database rules in that data file’s data-set subclass, may simply use
the existing package file.

A given data file will probably be used in a single program by


multiple views. All the views accessing the file still will do so through
the same data-set subclass. Each view will have its own data-set object
based on this shared class. The data (objects) will be unique (objects);
the rules (classes) will be common and thus, consistent. The objects
will probably even have the same names, which is allowed as long as
they are encapsulated in different entry-view clients. No more than
one object of a given data-set subclass may reside in the same view,
regardless of naming.

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,

Object Vendor_DS is a Vendor_Data_Set

32 Developing Applications with DataFlex


where Vndr_Data_Set is the custom data-set subclass for a datafile,
presumably named something like vendor.

There are specific rules for placing data-set objects (DSOs) in a view
client. These are:

1. All data-set objects are based on specialized data-set subclasses


created for a particular data file.

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.

3. Parent/child relationships are established in data sets by using


the updating clause in their object-creation statements. The
link between a parent and child is established by the child data
set updating the parent data set. This link must be
established and it must match a relation recorded in the child
file’s definition. A child data set may be linked to multiple
parent data sets.

4. All objects referenced with the updating clause are referenced


using the (object_name(current_object)) access syntax, and no
other.

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.

Placing your DSOs in a view is easy. Take care to establish the


updating links properly. The following diagram provides an example

3 The Application Framework 33


of a database file structure, a visual representation of the data-set
structure (and linking), and how this structure is coded.

A typical database file structure:

Customer Terms Vendor

Orders Inventory

Order_Detail

The data-set structure with updating links:

Container Client

Customer_DS

Terms_DS

Vendor_DS

Orders_DS

Inventory_DS

OrderDtl_DS

34 Developing Applications with DataFlex


The code for the data-set structure:

Object View_Object is an Entry_View_Client no_image


Object Customer_DS is a Customer_Data_Set no_image
End_Object
Object Terms_DS is a Terms_Data_Set no_image
End_Object
Object Vendor_DS is a Vendor_Data_Set no_image
End_Object
Object Orders_DS is an Orders_Data_Set no_image ;
updating (Customer_DS(current_object)) ;
(Terms_DS(current_object))
End_Object
Object Inventory_DS is an Inventory_Data_Set no_image ;
updating (Vendor_DS(current_object))
End_Object
Object OrderDtl_DS is an OrderDtl_Data_Set no_image ;
updating (Orders_DS(current_object)) ;
(Inventory_DS(current_object))
Begin_Constraints
constrain OrderDtl relates to Orders
End_Constraints
End_Object
:

The Data-Entry Objects (DEOs)

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:

1. Data-entry objects may be nested inside each other (but never


inside data sets). Nesting DEOs has no effect on database
behaviors (saving, deleting, clearing, finding). You choose to
nest or not to nest DEOs based solely on desired navigational
behaviors.

2. Data-entry objects must be connected to data-set objects by


using the using clause. The specific DSO that you connect to
determines the DEO’s saving, clearing, finding and deleting
behaviors. The connection can be explicit (there is a using in
the object command line) or implicit (a DEO inherits the
data set of its parent).

3 The Application Framework 35


3. All data-set objects referenced with the using link are
referenced with the (object_name(current_object))
access syntax.

4. DEOs should use only data-set objects that are contained


inside the same view as the DEO.

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

Objects send messages to themselves and to other objects. To send a


message to an object, you must know the object’s identifier, or
object_id. When an object is sending a message to itself, it may
send the message to the current_object or not reference an object
at all (in which case current_object is assumed). If an object sends
a message to another object, the object_id receiving the message
must be identified with an access method.

The recommended syntax for accesing an object is:

(object_name(current_object))

Basically, this method says, "find an object named object_name that is a


child of the current_object". If this were all this could do, it would
be a limited method for accessing objects. The power of delegation,
however, makes this an extremely powerful object-access method.

If a child object of the current object named object_name is not found,


the access expression gets delegated to the current object’s parent. The
parent object then looks among its children for one named object_name.
At this point, you can access objects that are siblings of the current
object. If delegation occurs again, you are looking for an object that is
a sibling of the current object’s parent. Understanding the role played

36 Developing Applications with DataFlex


by delegation here is crucial. This object-access syntax is described
with the following rules:

1. All objects are accessed using the (object_name(Current_Object))


access syntax. This provides access to child objects, sibling
objects, and sibling-of-parent-objects on up the object tree.

2. If an object cannot be accessed using this access syntax, you


should not be accessing it from the object you are trying to
access it from. For example, no object should directly
communicate with any of its grandchild objects. This is a
violation of the principle of encapsulation, and the approved
access method discourages this. In this method, the objects that
can be addressed from any object are limited to its immediate
children, its ancestors, and the immediate children of its
ancestors, and these are all addressed automatically, every
time.

Constructing a View

This can all be summarized in the following way. A view object


consists of an entry_view_client, which encapsulates all data sets
and data-entry objects. All data sets are placed as sibling objects inside
the client. They are connected to each other with the updating and
the relates to syntax. Data-entry objects are placed after the data
sets and are nested (or not nested) according to navigational needs.
The DEOs are connected to the data-set structure with the using
syntax. Because views completely encapsulate their DSOs and their
DEOs, views are independent stand-alone units. They are brought to
life by sending an activate message to the entry_view_client. A
view can be added to any program without fear of this new view
creating side effects in other parts of the program.

A View-Object Package

Views should be created in their own package files. In addition to the


view object, this file will include commands to use other (non-view)
package files and an access method into the view from the desktop.
The following example shows what a simple view-object package looks
like.

3 The Application Framework 37


//---------------------------------------------------------------------------
// custent.pkg
//
//---------------------------------------------------------------------------
Use allentry
Use Confirm
Use OrdrDS.ds
Use Custlkup.sl
/Cust_Form
Customer Entry Form:
Customer Number: _____.
Name: ______________________________
Adrs: ______________________________
City: ______________
St: __
Zip: __________
Discount: _.%
--------------------------------------------
Purchases/month $______.__
Purchases/year $______.__
Profit/year $______.__
Comments

/*
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 }

38 Developing Applications with DataFlex


Entry_Item customer.profit { DisplayOnly }
End_Item_List
Object Comments_Editor is a Text_Window for customer.comments
Set Location To 14 2 Relative
Set Size To 5 42
End_Object // Comments_Editor
End_Object // Cust_Form
End_Object // Cust_Entry

This sample includes all of the elements required to create a view


package. These are:

1. Use ALLENTRY, which incorporates the DataFlex package


designed to support all data-entry views, including all of the
high-level classes. You should keep this package pre-compiled
to reduce the time consumed by including it in programs
when they are compiled.

2. Use the Confirm package, which creates a confirmation object


and the required desktop messages to access it. Your data-
entry object will use these messages by setting verify messages
(e.g., Set verify_save_msg to
GET_save_confirmation).

3. Use data-set class packages. You will have created a data-set


subclass for each data file. Those subclasses will either all be
contained in a single class package, or will be contained in a
series of packages. In the example above, all of the data-set
subclasses are in the ordrds.ds file. This package also opens
the data files.

4. Use selection-list-object support. Your selection-list objects will


be placed in their own object packages. These object packages
should be included in your program before you create the
view object.

5. Create a desktop access method for the view, to enable it to


be activated from any other view. This message will be used
by your main program in the view pulldown to activate the
view.

A special command, activate_view, allows you to easily


create such a view-access method. This command uses two
parameters: the name of the activation message and the name

3 The Application Framework 39


of the view to activate. In the above example, the command
activate_view activate_customer for cust_entry
creates the desktop message activate_customer, which
activates the view (cust_entry).

6. Create the entry_view_client container. It contains a


properly connected data-set object structure and data-entry
objects. Images required by these objects should also be
included.

Testing Your View

It is very important to test each view thoroughly before integrating it


into a larger program, particularly if the larger program is already
handling existing data. A package file named DFTEST.PKG enables
you to create very small "test-bed" programs for this purpose with as
few as four lines of code. Your program must use the test.pkg package
and the view package being tested, and contain commands to add the
view to a test pulldown menu and start the program.

DFTEST.PKG uses a special version of ALLENTRY with the test


program that provides debugging support. Built into this view-test
program is a powerful message tracer, an expression evaluator, an
object-tree browser, and a focus-tree browser. This will provide you
with much of the information you will need to test your view. Once
your view is tested, you can add it to a larger program without fear of
side effects.

The following sample shows the "test-bed" program required to test


our customer-entry view.

// vtest.src - view test program


Use dftest // include test-bed package
Add_test "Customer entry..." Send Activate_Customer to Desktop
use Custent.vw // include package being tested
Start_Ui (Main_Menu(current_object))

Add_test is a command defined in DFTEST.PKG. Its syntax is exactly


that of the on_item command.

40 Developing Applications with DataFlex


3.2.5 Selection Lists

Selection-list objects are often used by multiple views. A vendor-entry


view and a check-entry view might both use the same vendor selection
list. Therefore, it does not make sense to encapsulate such a selection
list inside a view—it should be visible to all views. Selection lists are
best placed at the desktop level. Selection lists should be placed in a
stand-alone object package. If a view package needs a selection list,
you should include the selection list with a use command at the top of
your view package. Below is a sample of a simple selection-list object
package. If you have more than one view including the same selection
list, this will do no harm. Use commands addressed to a package
already included are simply ignored.

//---------------------------------------------------------------------------
// 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

3 The Application Framework 41


3.3 Running a Program

Writing and running an object-oriented DataFlex program consists of


three steps, most of which are likely to require very little code actually
in the program you write.

1. Define all classes


2. Create objects
3. Start_ui - Start the User Input (UI) Event Processor

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.

The UI-event processor is an important part of the UIMS system in


that it allows users to interact with the UI objects. It makes modal
navigation possible. Once this UI-event processor is started, users have
command over the program. Users control the program by creating
events, typically with the keyboard or mouse. The UI-event processor
receives notification of the event and responds by sending a message
to some object notifying the object of the event. The object does
whatever is needed to handle the event and returns control to the UI-
event processor, which cycles while waiting for more events.
Normally, a program will run in this UI-event-dispatch mode until
users decide to terminate the application. This is the reason why the
start_ui command is usually the last command in a program.

When an application is written, a large number of classes and objects


will be created. If all of this code were placed in a single source file,
the source would be unmanageable. Instead, classes and objects are
placed in smaller source-code units called packages. These packages
are included in a program with the use command. Packages
themselves will often contain other packages. This modularization
makes it far easier to manage large applications.

42 Developing Applications with DataFlex


The following example shows how packages are used. This program
follows the three simple steps listed above (classes, objects,
start_ui). The package files can, and often do, hide tremendous
complexity. The modularity of classes, objects, and packages allows the
developer to write and maintain large applications.

// include the classes


Use AllEntry // define all standard class packages
Use Custom // define some custom classes
// Add some custom code
:
// include objects
Use SmpAbout // create an about object
Use View_1 // create some objects
Use View_2 // create some more objects
Use report_1 // create report objects
Start_Ui // start the UI-event processor

3 The Application Framework 43


44 Developing Applications with DataFlex
4 DATAFLEX TUTORIAL

4.1 Overview

The first chapter provided you with introductory material concerning


the DataFlex language and DataFlex Utilities. Chapters 2 and 3
introduced the DataFlex object-oriented programming environment
and the Application Framework Methodology, respectively.

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.

In this chapter, we present a tutorial that walks you through each of


the steps involved in creating a DataFlex database application and
report. It teaches you how to build an application by providing step-
by-step instructions and useful techniques for each phase of the
development process.

The tutorial itself is divided into two main sections.

The first section demonstrates how easy it is to design and generate a


complete, working application in a short time without
programming/writing a single line of DataFlex code. Explanations are
kept to a minimum so that you can finish these tasks quickly and in
the most efficient manner.

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.

The next section provides a comprehensive look at the entire


development process. You will develop a real-world Order-Entry
application for a fictional computer company. With DataFlex, you will
be able to overcome some of the real-world challenges faced by

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:

• Create the database for your application

• Design the User Interface elements for your application

• Implement Business Rules for your application

• Modify AutoCreated code in a matter of minutes

• Create a fully formatted report

• Compile your program

• Run your application

4.2 Special Notes and Instructions

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

1. We assume that you have properly installed a Full


Development License in the \FLEX directory.

2. The steps in this chapter were performed under the DOS


environment.

3. For simplicity’s sake, all application-related files for the two


examples shown in this chapter are located in the
\FLEX\USR\EXAMPLES\TUTORIAL directory.

46 Developing Applications with DataFlex


4.2.2 Instruction Conventions

Using a mouse is the easiest way to navigate around all DataFlex


utilities, but non-mouse users can always achieve the same results
from the keyboard. "Click on ..." means move the mouse cursor to an
object and press and release the left button. "Drag ..." means move the
mouse cursor to an object, press the right button, and keep it
depressed while moving the mouse until the object is in the desired
position, then release the button. Where it is not obvious, we will also
point out the keystrokes for non-mouse users. "Select" means either
click on the object, or rotate to it (move the selection cursor to it with
the arrow or t s+t or e
keys) and press . "Enter" means
type in the text given, then press e . "Press <BUTTON>" means
either click on the named button, or rotate the selection cursor to it
and press e . If there is a function key ("accelerator") or key
combination noted (e.g. <Alt+N=New Field>), you can also press the
named key(s) to achieve the given result. Material we are asking you
to type, screen prompts, and items you can choose from the screen are
shown in a different typeface like this.

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.

4.3 Single-File Example

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

• Set up a working directory

DataFlex Tutorial 47
• Create a data file

• Define an index

• Prototype a view

• Generate Framework compliant source code from


AutoGen

• Generate a report from DFQUERY

• Add the application and the report to a Main Menu.

4.3.1 Program/Application Specifications

The very first step in application design is to identify the purpose of


your application. Write down exactly what you want your application
to do with as much detail as possible. This can be a simple statement
for a small database application. For a large database that has more
than one data file and that might be used by many people, the
statement of purpose could be more elaborate. The main objective is to
come up with a purpose that you can refer to from time to time
during the design process. This will help you focus on your goals.

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.

Currently, the information is being entered manually in a form similar


to the one shown in Figure 1. If you make a list of the types of
information this form includes, it will look something like this:

48 Developing Applications with DataFlex


Last Name
First Name
Company

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.

4.3.2 Defining the Field Name, Type, and Length

For each database field, a name, type and length must be specified.

The field names you choose should be descriptive of the contents of


the field. Doing so will facilitate the program and database
maintenance activities you or another person will perform in the
future. Try to avoid using short nondescriptive names for your fields.

There are several rules to consider when you are determining the
names of the fields for your database;

• The name itself should not contain any spaces or the


slash character. If you decide to enter any slashes or
spaces into the field name, they will be automatically
replaced by underscores.

• A field name can be no longer than 15 characters.

• The field names will always appear in uppercase.

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:

Name Type Size

LAST_NAME ASC 15

FIRST_NAME ASC 15

COMPANY ASC 30

TITLE ASC 15

50 Developing Applications with DataFlex


ADDRESS ASC 30

CITY ASC 14

STATE ASC 2

ZIP ASC 10

PHONE_NUMBER ASC 20

FAX_NUMBER ASC 20

COMMENTS TEXT 1024

Notice a field size of 1024 for COMMENTS. This size should be


adequate for storing miscellaneous information about a contact. Also,
since the maximum number of characters allowed in this field exceeds
250, the field type must be defined as TEXT.

4.3.3 Creating a Working Directory for Your Application


(Starting from Scratch)

As a recommendation, when you are starting a new project, you


should store all of your application-related files in the same directory.

Basically, this will be the repository of all the application-related files,


which include database files, and application interface files. Creating
more than one application in a directory can create confusion, and you
might not be able to tell which components or building blocks go with
which application.

The working directory for the Contacts application will be located


under the FLEX directory and named PROJECT1. To create this
directory, change to the FLEX directory, and type mkdir PROJECT1 at
the command line.

4.3.4 Changing the Defaults

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.

AUTOGEN.INI is a configuration file that contains the default setting


for the AutoGen Utility. This utility will be discussed later in the
chapter.

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.

To create your own custom environment configuration file,

1. Change to the \FLEX\PROJECT1 directory.

2. Using your favorite editor, load the DFENV.CFG file and


delete all the characters after the \FLEX\USR\PKG path entry.

52 Developing Applications with DataFlex


Figure 2- The File Maintenance Utility menu, showing the Filelist option as the
current choice.

This action will prevent DataFlex from searching in this


directory for any files.

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.

Open the \FLEX\PROJECT1\SETBAT.BAT file with your favorite


editor. Move the cursor to the last line. Now change the path in the
dfenv entry from %DF31_DIR%\usr\dfenv.cfg to
%DF31_DIR%\project1\dfenv.cfg.

The last file which should be modified is named FILELIST.CFG. It


contains a listing of all the available data files. By default, DataFlex
comes with a single FILELIST.CFG for all the Sample Application data
files.

DataFlex Tutorial 53
Figure 3-The DataFlex File Maintenance Utility, showing the current filelist.

To clear all the information in the FILELIST.CFG file, follow these


steps:

1. From the \FLEX\PROJECT1 directory, type SETPATH to run


the batch file. Now type DFMAINT to execute the File
Maintenance Utility.

2. From the Maintenance pull-down, select the FileList


option (see Figure 2).

The list of data files for the current Filelist will appear (see Figure 3).

3. From the Database pull-down, select the Tag Bad Entries


option. At this point, DataFlex searches through the directories
specified in the DFPATH environment variable to see if data
files exist for each of the entries in the current file list. The
entries for data files not found in the search attempt are

54 Developing Applications with DataFlex


Figure 4-The DataFlex Main Menu System.

marked for removal in a distinctive color. Then, press


s2 + to remove all the entries from the filelist. Note that
the entries which remain in the file list will be discussed later.

You now have a file list with three entries.

4.3.5 Creating the data file, fields and indexes

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.

1. Make sure you are in the \FLEX\PROJECT1\ directory. From


the command line, type DFRUN.

The DataFlex Main Menu program will appear on your screen


(see Figure 4). You can use the Main Menu program to access

DataFlex Tutorial 55
Figure 5- The main screen for the DataFlex File Definition Utility.

any of the DataFlex Utilities.

2. All Database related utilities are grouped under the Database


pull-down menu. From the Database pull-down, select the
File Definition Utility.

Alternatively, you could have entered DFFILE from the


command line. Both of these methods execute the File
Definition Utility.

The Main Screen for the File Definition Utility will appear (see
Figure 5).

3. From the File pull-down, select New. A small panel will


appear, asking you to enter the file number and rootname of
the database file. Since you are creating the first database file
in the file list, the file number is one.

56 Developing Applications with DataFlex


4. In the Rootname field type CONTACTS, and then Press 2 to
continue.

Now, the Parameters.. panel will appear with the default


values (see Figure 6).

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.

7. Select Fields from the View menu (or press a+!).


8. The Fields panel will appear (see Figure 7).

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.

You can utilize the TAB and e keys to navigate forward


from field to field. To go back to a previous field, use the
st + key combination. To browse through the list of all
available field types, press4 when in the Type column.

Figure 7- The DataFlex File Definition Utility, showing an empty Fields...


panel.

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:

• You want the records sorted by Last Name and First


Name. In other words, records are first sorted by the
value in the Last Name field. Then, if there are any
records with matching values in the Last Name field,
the records are sorted by the value in the First Name

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.

What fields should the index be comprised of?


Obviously, you should include the LAST_NAME and
FIRST_NAME fields. If you were to create an index
which contained only those fields, then you have
created what is called a UNIQUE index— meaning
that every record must have a different value for the
field or combination of fields making up the index. A
user trying to enter a name which already exists will
get the error message, "DUPLICATE RECORDS NOT
ALLOWED".

Since there is a distinct possibility that the database


could contain two people with the same last name and
first name, you must define an index that allows for
the duplication of data in those particular fields.

To achieve this, you must include the RECNUM in the


index composition. RECNUM, which stands for record
number, is simply the record’s sequential number on
disk.

• You want the records sorted by Company. There are


times when you cannot remember the last name and
first name of a contact, but you do know the company
that the person belongs to. Also, it is very possible for
two Contacts to work for the same company. Defining
an index that contains the COMPANY field and the
RECNUM field has the following effect: (1) You are
able to find records by company (2) DataFlex will
allow you to create records with matching values in
the COMPANY field.

60 Developing Applications with DataFlex


Figure 9- Creating an index, which allows you to find records in the file in
some specified order - in this case by Last Name, First Name and Record
Number.

Creating the indexes:

1. From the View pull-down, select Indexes.. (or press a+@)


2. The Edit Specifications for Index #1 Panel will
appear.

3. Either begin typing LAST_NAME in the first Fields window


(you’ll notice an incremental search being applied, so you
won’t have to type much), or press 4 to scroll through the
list of available fields.

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 specification for index #1 should look like Figure 9.

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

62 Developing Applications with DataFlex


index to be updated online (as records are entered), but at some pre-
determined intervals (for month-end reports, for example).

6. Press PgDn to define the specifications for index #2. Use the
same steps shown above to define this index (see Figure 10):

Fields U/C DES

COMPANY YES NO
LAST_NAME YES NO
RECNUM NO NO

7. From the File pull-down, select Save to save the file


definition for the CONTACTS data file.

8. Press q to exit the File Definition Utility.

4.3.6 Designing the Views For Your Application

After you have created the field and indexes for your data file, you are
ready to design and prototype the Views for your application.

As you know from the previous chapter, a view is primarily composed


of two parts: data entry objects and database interface objects.

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.

By comparison, database interface objects (i.e. data sets) control what


records you see when you are accessing the database.

In DataFlex, there are two utilities which assist in the prototyping,


development and assembling of views.

The AutoCreate Utility (or DFAUTO) allows you to visually design


and prototype the data entry objects for your view.

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.

With the AutoCreate Source Code Generation Utility (AutoGen), you


can take your AutoCreated prototype and, in a matter of minutes,
generate views, object packages and data set subclass packages. Of
course, the view components that you build with DFAUTO and
AutoGen can all be part of one application or can be reused across
many applications, saving you development time and helping you to
maintain a consistent look for each of your programs.

To start up Autocreate,

1. From the Development pull-down, select the Auto Definition


Utility, or type DFAUTO from the command line.

2. From the Application pull-down, select New.

3. Accept OOP for Code Style.

64 Developing Applications with DataFlex


AutoCreate generates either object-oriented or procedural style
code, but you want object-oriented code, to take advantage of
features such as mouse support, tables, and text fields.

4. Enter CONTACTS as the Application Name.

The revision number will automatically increment as you save


edits to the application, so you can always revert to an earlier
revision if you want.

5. Accept CONTACTS as the Main File, and enter a description


such as Contacts Entry Autocreate Prototype as the title (see
Figure 11).
The Creation Date or Last Update will default to your
current system date, and you can enter the name of the
Author if you wish, together with any Comments to describe
the application. The Comments box is a full word-wrap
scrolling editor which can hold up to three lines of text.

6. Finally, press 2 or the <OK> button.


Your new application’s BACKGROUND object of shaded
characters will then be drawn. This is like a canvas, on which
you will be painting some entry screens. Notice that the name
of the application (CONTACTS) appears in the title line at the
top of your screen. Also appearing is the name of the utility
(AutoCreate), and the name of the main file (CONTACTS).
The main file is the lowest-level child file in the application’s
hierarchy. For right now, there is only going to be one file, but
we’ll discuss this concept in the second example.

The Contacts application will be composed of three data entry objects:

1) An entry form

2) A prompt list: This prompt list will allow us to browse


through all of the records from the CONTACTS data file.

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.

When designing objects in Autocreate, it is sometimes helpful if you


first draw the object on a piece of graph paper (preferably one that is
80 characters wide by 25 characters long). Once you have finished
designing the screen layout on paper, you can use the cursor position
coordinates in DFAUTO to align or arrange the interface elements on
the screen so that they match their paper counterparts.

Entry Form Design. Let's start out by designing the Entry Form for the
Contacts Application.

1. From the Objects pull-down ( a+O, 0 or mouse), select


New, then Form (see Figure 12).

2. Enter "Contacts" as the Name.

66 Developing Applications with DataFlex


3. Accept the system default colors (represented by 0 and 0).

Window Color is the background and foreground color


combination in which data from files will be displayed when
the application is running. Text Color is the background and
foreground color combination in which borders and static text
will be displayed.

4. Accept Single as the Border, or change it if you want, by


moving the radio button, with the arrow keys or mouse, and
pressing g .

5. Choose Dialog as the Title Style, by pressing g


or clicking the mouse, and accept or enter Contacts Entry
as the Title.

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.

You won’t be able to enter anything in the File and Index


windows - they are for tables only. The Prompt and Zoom
windows will be discussed later.

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.

You will be making an entry screen looking something like this:


Contacts Entry:
Last Name: _______________
First Name: _______________
Company: ______________________________
Title: _______________
Address: ______________________________
City: _______________
State: __
Zip: __________
Phone #: ____________________
Fax #: ____________________

Comments
___________________________________________
___________________________________________
___________________________________________
___________________________________________
___________________________________________
___________________________________________

Compared to the design shown above, the default form that


AutoCreate provided is a little small and is positioned improperly, so
first we'll move and resize it.

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.

68 Developing Applications with DataFlex


2. Drag the bottom right corner of the form so that the top right
edge of the form is under the “a” in Primary, again with the
right mouse button (or select Resize from the Objects pull-
down, then use the arrow keys).

3. Make sure the cursor is at the leftmost position of the second


line in the Contacts form. Type in the static text for the
description of the first field - Last Name:.

4. Now, type in the static text descriptions for the rest of the
fields. The fields will be left justified.

5. Next, press a+$ (or select Field Toolbox.. from the


Fields pull-down). The Field Toolbox, which contains the list
of available fields for the CONTACTS data file, will appear on
the bottom of the screen.

6. Move the mouse cursor to the field named "FIRST_NAME",


hold down the right mouse button, and drag the blinking
underscore characters to a position approximately two spaces
after the ":" in First Name. Now, drag the rest of the fields
(except for COMMENTS) to their respective positions, using
the First Name field as your guide.

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.

8. Press c1 + twice to exit Line Drawing Mode. The status


line at the bottom of the screen should read "Lines Off".

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.

1. Select New, then Editor from the Objects pull-down and


enter Comments as the name. The editor should not have a
border so that it can easily be embedded in the Entry Form.

2. When the editor form appears, resize it and move it to the area
under Comments.

3. From the Field toolbox, select the COMMENTS field.

70 Developing Applications with DataFlex


When you press the right mouse button there will be a
string of blinking underscores going off the edge of the screen.
You must make sure the status line says Obj: Comments and
that the left edge of the blinking underscores is somewhere
within the Comments object, but not on the title line. Press
e to place the field into the editor. Notice that the editor is
filled with underscores, and there is a scroll bar on the right
edge.

The finished screen will look like Figure 13:

Customer Prompt List. DataFlex provides for very powerful multi-


record lookups called prompt lists. A prompt list allows you to view
multiple records of a particular data file at the same time. Typically,
you would activate a prompt list from a field in an entry form. Once
activated, the prompt list will display a list of all the records for the
data file, from which you can scroll through and select a record for
retrieval. DataFlex will then fill in the fields in the entry form, which
originally activated the prompt list, with data from the chosen record.
Note that Prompt lists cannot be used for creating and editing records.

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,

1. Select Prompt List from the New choice on the Objects


pull-down, and enter Contact_lkup as the name, Double
border, Popup as the Title Style and Contacts List as the
title.

2. Each prompt list must refer to a particular file, so press 4in


the File window to pop up a list of files available, and select
CONTACTS. Press 4 in the Index window to pop up a list of
indexes available, and select 1:LAST_NAME,
FIRST_NAME,... Select the first index so that the records for
the CONCTACTS data file will be displayed in ascending order
by Last Name, First Name and Recnum.

3. Press the <F2=OK> button to create the prompt.

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
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________
_______________ _______________ ______________________________

72 Developing Applications with DataFlex


4. Insert headings for each of the columns in the prompt list and
stretch the Prompt List (see the figure above).

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

Adding Entry Options

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.

Second, you will put a capslock option on the STATE field.


Capslock converts everything the user types into upper case.

To set the aforementioned entry options:

1. Press t to rotate to the Contacts Entry form and move the


cursor to the CONTACTS.LAST_NAME field. From the
Fields.. pull-down, select Field Entry options. Pop up the
Entry Options screen (make sure that Obj: Contacts and
CONTACTS.LAST_NAME appear on the status line) by pressing
4 or by selecting Field Entry options from the Fields pull-
down.

2. Rotate to the bottom panel (t e or ); press 4


again in
the Prompt: window and select your Contacts_lkup
prompt list. Press2 to confirm the changes.

3. Repeat steps 1 and 2 for the CONTACTS.FIRST_NAME field.

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

5. Move the selection cursor to the Capslock option and press


g to toggle an X into its box.

6. Press the <OK> button to accept the options for STATE.

7. Now is a good time to save your application. Select the Save


option from the Application pull-down.

At any time, if you try to leave AutoCreate without saving the


changes, you will be asked whether you want to save first. The
new file structure will be saved, along with all the information
needed by AutoCreate to present us with everything you need
for editing the application later. You will only be able to
change file structures if no data has yet been saved to them,
however.

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.

Nesting the Objects

Before you generate the code for the Contacts application, you must
use the Object Toolbox to reorganize the Object structure.

The Object Toolbox contains a chart showing the hierarchy of the


objects and datasets in the application. It also reveals the relationships
between objects. The Background object, the area below the action bar,
contains shaded characters which can be thought of as a canvas, on
which you draw the forms for your application. It is always placed on
the highest level of the hierarchy tree. Data Entry objects are arranged
according to the order in which they were originally drawn. Data Set
objects are always placed right below the Background. A single Data
Set object is automatically created for the childmost data file specified
in the Main File field in the Application Style panel.

74 Developing Applications with DataFlex


Press a+@ to activate (or popup) the Object Toolbox.
In the CONTACTS application, you currently have the following object
toolbox 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).

4.3.7 Generating the code with the AutoCreate Source Code


Generation Utility (AutoGen)

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,

76 Developing Applications with DataFlex


1. Select the Generate option from the Application pull-
down. (Accept the option to save, if your work has not yet
been saved.)

Alternatively, you could invoke the AutoGen utility by typing


DFRUN AUTOGEN from the command line. If you choose to
do so, a list of all the applications you designed via
AutoCreate will appear. You can select only one application
for source code generation.

2. At this point, the Source Code Generation panel for the


AutoGen utility will appear (see Figure 15).

Below is a brief description for each of the options listed on this panel.

View Package: This option will create all the re-usable


packages associated with the application you selected.

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.

Complete Application: In addition to the re-usable packages,


this option will create the complete source code for the
application you have selected.

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.

1. Move the selection cursor to the Button labeled <Options...>.


The Source Code Options panel will appear (see Figure 16)

Leave all of the package names and options as is.

DataFlex Tutorial 77
Figure 16-The AutoGen Utility, showing the settings for the source code
options.

2. Move the selection cursor to the button labeled <Defaults...>.


The Configuration file for AutoGen will appear (see Figure 17):

This file, named AUTOGEN.INI, contains the default system settings


for the AutoGen Utility. This is an ASCII file, which is edited here in a
DataFlex Text Editor object.

By default, the Complete Application option creates several re-usable


packages. Since you will not be creating a View package or a test
program, you must turn these settings off in the AUTOGEN.INI file.

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.

78 Developing Applications with DataFlex


Figure 17-The configuration file (AUTOGEN.INI) for the AutoCreate Source
Code Generation Utility (AutoGen).

4. Press 2 to confirm the changes.


5. Press q to return to the Source Code Generation Panel.

6. Make sure that the selection cursor is on the Complete


Application panel. Press 2 to begin generating the code.

A message will appear informing you of the fact that the code
generation has been successfully completed.

7. Press q to leave AutoGen and return to AutoCreate. Press


q to exit AutoCreate.
You may use your text editor to examine the files that AutoGen
produces:

DataFlex Tutorial 79
CONTACTS.DS Contains Data Set class definition for the
Contacts data file.

CONTACTS.SL Contains the selection list package for the


view, which can be reused in any other
program.

CONTACTS.SRC Contains the complete source code for the


CONTACTS program.

4.3.8 Compiling your program

To compile your program, select the Compile Programs.. option


from the Development menu. Type CONTACTS.SRC in the space
provided, and then press 2 to accept.

Alternatively, you could haved type DFCOMP CONTACTS.SRC at the


command line.

4.3.9 Running your application

By now, you are probably very eager to run your program.

To run your program, select Run a DataFlex Program.. from the


File menu. Type CONTACTS in the space provided. You can also
accomplish the same thing by entering DFRUN CONTACTS from the
command line.

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

The CUA Look and Feel

All DataFlex utilities are designed to comply with CUA (Common


User Access) standards, and object-oriented code generated by
AutoCreate makes it easy for your applications to comply with these
standards also. All the essentials are automatically included in your

80 Developing Applications with DataFlex


Figure 18-The CUA-compliant action bar for the Contacts application, showing
the different pull-down menus.

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.

choice can be changed in your DataFlex configuration.

The View pull-down contains the View you just created in AutoCreate
as well as a Close option (see ?).

Because you created a Text window in this application, AutoCreate


automatically includes code for a Text pull-down in the action bar, to
give your users text-editing choices they can select when editing that
window. The items in this menu will activate only when you are in the
text window.

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.

82 Developing Applications with DataFlex


Figure 20-The View pull-down, showing the Contacts View as the current
choice.

Data Entry. To activate the View, press a!


+ . At this point, the
Contacts Entry Form will appear on your screen (see ?).

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

Smith John Original President 1123 S.W. Miami FL 33186


Creations 95th Ave.

Zorro Frank Swords, Inc. President 1211 S.W. Miami FL 33234


56th St.

Jones Fred All things Manager 43953 N.E. Miami FL 30323


Purple 112 St.

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.

After you finish entering the records, press 7 8


(find previous),
(find next) or 9 while the cursor is in the Last Name window.
DataFlex immediately finds a record based on index number 1, which
sorts records in alphabetical order by Last Name, First Name. If you
press 7 , the display area will fill with information about Zorro Frank
(see table above). If you press 8 , the display area will fill with
information about "Jones Fred". If you enter "Smith" in the Last Name
window, and then press 9 , the display area will fill with information
about
"Smith John".

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.

In the next section, we will be examining how to make a report, using


the data file you have just created and entered data into (or any other
DataFlex data file for that matter).

Activating the Prompt List. While in the Contacts form, press 4 on


the Last Name or First Name fields to activate the Contacts List.

84 Developing Applications with DataFlex


Figure 21-The Contacts Form and Editor, into which you will enter information
about a particular contact. Both of these objects together with the Contacts
prompt list make up the visual elements for the Contacts view.

4.3.10 Generating a Report

Now that you have entered some records into your database, you are
ready to generate a mailing list for the CONTACTS application.

DataFlex has another code-generating utility, named Query, which


enables you to design and run reports to the screen, printer or a file.
Your report can use any existing index, so you can output the records
in the order you want, and you can also specify one or more selection
criteria, so that only the records meeting those criteria will be reported.

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.

Don’t forget, further details on Query’s features can be found in the


Utilities section of the DataFlex User’s Guide, so the instructions here are
given without too much extra discussion.

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,

1. At the command line, type DFRUN. The DataFlex Main Menu


will appear. Alternatively, you can enter DFQUERY from the
command line.

86 Developing Applications with DataFlex


2. Select Query Database from the Database pull-down.

You will see a screen with the familiar title, action bar and status line
format (see Figure 22).

3. Choose CONTACTS from the list of files presented and press


the <OK> button.

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.

4. Choose CONTACTS; press t to rotate to the DBMS Fields


area, then select the fields FIRST_NAME, LAST_NAME,
TITLE, COMPANY, ADDRESS, CITY, STATE, and ZIP,
each time by simply pressing e .

5. Press t twice to rotate to the main definition area (skipping


the short-cut <Print All> button), then press the g
to place an X in the Cr column for COMPANY, TITLE,
ADDRESS, and CITY.

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

6. To specify the order in which the records will be presented,


press c+3 , or select Output order from the View pull-
down (a+V ). You will see a list of available indexes.

7. Move the selection cursor to LAST_NAME, FIRST_NAME,


RECNUM and press q or the <Esc=Close> button (see
Figure 24).

8. Select Screen from the Run pull-down ( a+R).


You will see the first screenful of data for your mailing labels "report"
(see Figure 25). You can view the next screenful of selected records if
you want, or press the <Quit> button to return to the previous screen.

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

88 Developing Applications with DataFlex


Figure 24-The Output Order Definition screen, showing the indexes available
for ordering the records output.

will go to your default printer.

9. To send the data to a printer or file, select Printer or File


from the Run pull-down, and choose Mailing labels as the
Query Output Type.

Your full report will then be output as directed.

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

11. Enter a description of the query (such as Contacts


information labels) for later identification, and a file
name - let’s say CONTACTS.

12. Press the <OK> button to save.

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.

Query will generate two files; REPCONT.RPT and


REPCONT.SRC. REPCONT.RPT is the report view package.
REPCONT.SRC contains a use statement for the report view
package and a line that activates the report view. To run the
report, you must first compile the REPCONT.SRC file.

90 Developing Applications with DataFlex


15. Exit Query by pressing a+4, or by choosing Exit from the
File pull-down.

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.

16. To compile the report, choose Development from the


DataFlex Main Menu System, then choose Compile
Program... Enter the name of the program (in this case your
report - REPCONT.SRC).

17. If you wish the listing of the program to go to the printer,


enter L (make sure you have a printer available), otherwise
presse and <OK>.

The screen will clear; the report will be compiled, and you will be
returned to the Development menu.

18. Choose Run a DataFlex Program... from the File pull-


down and enter REPCONT.

4.3.11 Adding your program and report to a Main Menu


program

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.

All of the data/information for the Main Menu System is contained in


an ordinary DataFlex data file called MENU.DAT. Each record in the
data file holds all the menu-related information for the DataFlex Main
Menu; the pull-down menu names, the options for each pull-down
menu and the action each option will perform when clicked on.

When you are deploying an application with a Runtime License, you


CANNOT include any of the Development utilities in your bundled
package. As a result, you should create your own custom menu so that
all of the application related programs and reports you have

DataFlex Tutorial 91
Figure 26-The File Maintenance Utility (DFFILE), showing a file list with three
entries.

developed can be accessed more easily.

To create your own custom menu,

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

92 Developing Applications with DataFlex


want to erase all the data in the MENU file. Press e twice,
or <OK> button twice.

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

3. At the command line, type DFRUN MENUDEF. The main


screen for the DataFlex Main Menu facility will appear (see
Figure 27).

4. In the Menu Number and Return to Menu Number windows


enter 1. The selection cursor will be positioned at the top of the
split panel. This is where you will enter some Menu Header
information.

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.

In this area, you will be defining the names of the pull-downs


for your Main Menu System.

7. On the first line, enter "Applications". Now, press TAB to


move the cursor to the Action column. The action column
displays the commands which are executed when a menu
choice is selected.

8. In the current window, enter MENU 2. This command will


display Menu number 2. You will define this menu later in the
discussion. You will not be entering a Password, so move to
the next line item by pressinge (or by using the mouse.)

9. Repeat steps 7 and 8, but enter the following information in


lines two and three instead:

Pull-down menu Name Action

Reports MENU 3
HELP HELP

10. When you are finished entering the information, press 2 to


save the record.

Now you are going to define the information for pull-down


Menu Number 2.

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

94 Developing Applications with DataFlex


window, even though you have developed only one
application. This is because in the second part of the chapter
you will be adding another pull-down option for the Order
Entry application.

The bottom part of the split screen will contain the options for
the Applications pull-down.

12. On the first line, enter Contact Application. Now you


want to specify the action DataFlex will take when this pull-
down option is selected. You want DataFlex to run the
Contacts application, so enter CHAIN CONTACTS in the space
provided. Press 2 to save this record.

Note: "CHAIN" is the command used in a DataFlex program to run


another DataFlex program. In this example, MENU is the DataFlex
program that runs the CONTACTS program.

Now you are going to define the information for pull-down


menu number 3.

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

Press 2 to save the record.


This will run the Contacts report (REPCONT) whenever the
Contacts Report option is selected.

14. Press q to exit out of the Menu Definition utility.

4.3.12 Running your application and report from the menu

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

The example in this section is based on a fictional computer software


and hardware Distributor called ACME Computer Supplies. ACME
Computer Supplies is a small company that sells a variety of hardware
and software products.

Currently, the company wishes to reduce the amount of manual paper


work by implementing an automated system for all activities relating
to order processing. This will enable the company to be more
productive.

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.

4.4.1 Creating a working directory for your application

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.

4.4.2 Changing the defaults

Copy AUTOGEN.INI, FILELIST.CFG, DFENV.CFG and SETPATH.BAT


from the \FLEX\USR directory to the \FLEX\PROJECT2 directory.

96 Developing Applications with DataFlex


Figure 28-The data file hierarchy for the Order Entry database.

4.4.3 Creating the data files, fields, and indexes

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:

1. Be certain that you are in the \FLEX\PROJECT2 directory and


not in the \FLEX\PROJECT1 directory.

2. The order in which files are created is significant, especially in


a database structure which has a relatively complex hierarchy.
It is helpful to create Parent files first, since there is no way to
set up a relationship from a child to a parent until the parent
is there.

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.

In the context of a family tree (with the child being at the


base), the child is Order Detail, while Order Header and
Inventory are the parents of the child, and Customer,
Salesperson, Courier and Vendor are the grandparents of the
child.

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.

Since Customer, SalesPerson, Courier, and Vendors do not


relate to any other files, you will create them first. Then, you
will create the ORDERHEA, INVT and ORDERDTL data files.
The order in which you create files that are at the same level
of the hierarchy is not important. For the Order-Entry example,
you will create the data files from left to right, as they appear
in Figure 28.

3. The obvious difference lies in the actual specifications for the


data files, fields, and indexes.

1. CUSTOMER data file


Number: 1
Root Name: CUSTOMER
User Display Name: Customers
DataFlex File Name: CUSTOMER

98 Developing Applications with DataFlex


Field Information (CUSTOMER)

Name Type Size

NUMBER NUMBER 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

COMMENTS TEXT 1024

Index Information (CUSTOMER)

INDEX # Fields DES U/C

1 NUMBER NO NO

2 NAME NO YES
NUMBER NO NO

2. SalesPerson Data File


Number: 2
Root Name: SALESP
User Display Name: Sales Person File
DataFlex File Name: SALESP

Field Information (SALESP)

DataFlex Tutorial 99
Name Type Size

ID ASCII 4

Name ASCII 25

Index Information (SALESP)

INDEX # Fields DES U/C

1 ID NO NO

2 NAME NO YES
ID NO NO

3. Courier Data File


Number: 3
Root Name: Courier
User Display Name: Courier Service
DataFlex File Name: COURIER

Field Information (COURIER)

Name Type Size

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

100 Developing Applications with DataFlex


Index Information (COURIER)

INDEX # Fields DES U/C

1 ID NO YES

2 NAME NO YES
ID NO YES

4. Vendors Data File


Number: 4
Root Name: VENDORS
User Display Name: Vendor Maintenance File
DataFlex File Name: VENDORS

Field Information (VENDORS)

Name Type Size

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

Index Information (VENDORS)

INDEX # Fields DES U/C

DataFlex Tutorial 101


1 ID NO NO

2 NAME NO YES
ID NO NO

5. The ORDERHEA data file is different in that it contains fields


that relate to fields in data files defined previously. This is
why you should create the parent data files before you create
the children.

Order Header Data File


Number: 5
Root Name: ORDERHEA
User Display Name: Order Header File
DataFlex File Name: ORDERHEA

Field Information (ORDERHEA)

Name Type Size Relates To File.Field

ORDER_NUMBER NUM 6.0 no relationship

ORDER_DATE Date 3 no relationship

CUSTOMER_NUMBER NUM 6.0 CUSTOMER.NUMBER

TERMS ASCII 30 no relationship

COURIER_ID ASCII 12 COURIER.ID

ORDERED_BY ASCII 12 no relationship

SALESPERSON_ID ASCII 4 SALESP.ID

ORDER_TOTAL NUM 8.2 no relationship

LAST_DETAIL_NUM NUM 4.0 no relationship

To create the relationships, follow these steps:

a. To define the relationship for the Customer_Number


field, you must first TAB over to the Relates to

102 Developing Applications with DataFlex


section. Then, press4 and select the Attach to
Field option. Using the arrows, highlight the
CUSTOMER file. Press e . Now you should have a
list of all the available Fields for the Customer data
file. Select Number. The Relates To section will fill
in with the name of the Data File and Field that the
Customer_Number relates to.

b. To define the relationships for the Courier_ID field and


SalesPerson_ID field, you should repeat the steps
above, selecting Courier and ID for the Courier_ID
field, as well as SALESP and ID for the SalesPerson_ID
field.

Index Information (ORDERHEA)

INDEX # Fields DES U/C

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

6. Inventory Parts Data File


Number: 6
Root Name: INVT
User Display Name: Inventory Parts
DataFlex File Name: INVT

Field Information (INVT)

Name Type Size Relates To File.Field

ITEM_ID ASCII 10 no relationship

DataFlex Tutorial 103


DESCRIPTION ASCII 35 no relationship

VENDOR_ID NUM 6.0 Vendors.ID

VENDOR_PART_ID ASCII 15 no relationship

UNIT_PRICE NUM 6.2 no relationship

ON_HAND NUM 6.0 no relationship

Index Information (INVT)

INDEX # Fields DES U/C

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

7. Order Detail Data File


Number: 7
Root Name: ORDERDTL
User Display Name: Order Detail File
DataFlex File Name: ORDERDTL

Field Information

Name Type Size Relates To File.Field

ORDER_NUMBER NUM 6.0 ORDERHEA.ORDER_NU


MBER

DETAIL_NUMBER NUM 4.0 no relationship

ITEM_ID ASCII 10 INVT.Item_ID

104 Developing Applications with DataFlex


QTY_ORDERED NUM 6.0 no relationship

EXTENDED_PRICE NUM 8.2 no relationship

Index Information

INDEX # Fields DES U/C

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.

To set the maximum number of records for this file to 1, you


must enter 1 in the Maximum Records window in the
Parameters... panel. This panel appears when you are creating
the data file for the first time.

Order Entry System File


Number: 8
Root Name: ORDSYS
User Display Name: Order Entry System File
DataFlex File Name: ORDSYS

Field Information

Name Type Size

ORDER_NUMBER NUM 6.0

CUST_NUMBER NUM 6.0

VENDOR_NUMBER NUM 6.0

DataFlex Tutorial 105


At this point, you have created all the database files for the Order-
Entry application. It is now time to program the business rules.

4.4.4 Programming the Business Rules

From the database application standpoint, Business Rules are the


underlying data processing "laws" of an application. Typical rules
would include data deletion constraints (such as not allowing the
deletion of a customer who has outstanding invoices) and data
validation (such as ensuring that a new order can't be created for a
customer who is already over their credit limit or making sure an
entered payment type is permitted).

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.

Our Application Business Rules

For the Order Entry application, you need the following business rules:

1. If a customer appears on several orders, you cannot remove


the customer from the Customer data file.

2. If a vendor supplies an item that appears in the Inventory data


file, you cannot delete the vendor from the Vendor data file.

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.

4. If an item appears on several orders (or is associated to several


orders), you cannot delete the item from the INVT data file.

106 Developing Applications with DataFlex


5. When an item is ordered, decrement the quantity ordered from
the quantity on hand. This will give you the current amount
on inventory for each item.

6. The order’s total field is the sum of all the extended prices.

7. Only one Customer can appear per order.

8. An inventory item can be purchased from only one vendor.

9. We need to automatically generate numbers for new orders,


customers and vendors.

10. To get the extended price for each item, you must multiply the
quantity ordered by the unit price.

11. If a salesperson is responsible for any existing orders, you


cannot remove that salesperson from the Salesperson data file.

12. If a courier delivers any existing orders, you cannot remove


that courier from the Courier data file.

13. Each line item in the table must be numbered.

As you’ll see in the following section, business rules may be


implemented at the database, the interface, or a combination of the
two. Where you decide to enforce the rules will depend on how you
need the application to interact with its users, and how strictly the rule
may need to be enforced across multiple programs or applications.

Implementing the Rules

You will place all the custom business (or database) rules for the
Order-Entry application in Data Set subclasses.

Data Set classes are high-level programming tools which coordinate


database activity among data-entry objects, and provide database
validation and update services to a program. It is in the Data Set class
where you program all the database-related rules. In essence, the Data
Set class is the repository of an application’s business rules. For more

DataFlex Tutorial 107


information about Data Set classes, see chapter 3 or Chapter 4 in this
manual.

For the Order-Entry application, we must be able to perform database


update functions (create, modify, and delete records) on seven of our
eighth files; these files will each require a Data_Set Class. The eighth
file, ORDSYS, is our system” file and needs only to be updated as a
result of actions on other files, and so will not require a Data Set of its
own. Data_Set Classes for an application are usually kept in
separate files from the main application source file. This is done so
that the same Data Set Classes, and the rules they describe, can be
used by more than one program. Should the rules change, all
programs can be updated by simply editing the file containing the
Data Set Classes and recompiling the programs that use it. This is just
one example of the power of Object Oriented program development -
the ability to change one Class definition and have all objects based on
that Class, in all programs, inherit” the new functionality.

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.

Programming our Business Rules into the Data Set classes.


DataFlex provides an integrated environment in which you can edit,
compile, and run programs. You will use this utility, called the
DataFlex Program Development System, to create the Data Set
packages for the Order-Entry Application. The utility has many more
features than we will be looking at, and full descriptions are contained
in the utilities section of The DataFlex User’s Guide. (When creating the
business rules for your application, you may use your favorite text
editor.)

1. Make sure you are in the \FLEX\PROJECT2 directory. At the


command line, type DFRUN.

2. From the DataFlex Main Menu System, select Development,


then Program Development System.

108 Developing Applications with DataFlex


3. You will be asked to enter the name of the file you want to
edit.You will begin by creating the class package for the
Customer Data Set class, so enter CUSTOMER.DS and click on
<OK>. This package will contain the class definition for the
Customer_Data_Set.

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 Customer_Data_Set class will be managing the database


activities for the CUSTOMER file.

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.

The Customer_Data_Set will contain three procedures. In the first


procedure, Construct_Object, you specify the class name and the
main file for the new data set class. You will also add code which will
enforce one of the business rules.

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
End_Procedure

DataFlex Tutorial 109


The Class command defines the new class, Customer_Data_Set, as a
subclass of the Data Set class. By doing this, you enable all objects
based on the Customer_Data_Set class to inherit all the
characteristics of the Data Set class as well as any additional methods
programmed in the Customer_Data_Set class, such as business
rules.

The Procedure Construct_Object will allow us to construct any


objects based on the Customer_Data_Set class. Setting the
Main_File property, which is inherited from the Data Set class,
designates CUSTOMER as the data file that will be used by the data
set for creating, finding, and deleting records.

The Smart_FileMode_State attempts to reduce the amount of


locking and rereading performed during the Save and Delete
operations in Data Sets. In large multi-user, multi-file systems, this
optimization can significantly improve save and delete performance.
This is especially true in programs that contain multiple views.

By default, Smart_FileMode_State is set to False, so you must set it


to True in order to take advantage of this optimization.

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.

Now you will be setting a property and adding a message which,


together, implement or enforce one of the business rules:

Rule# 1 states that if a Customer is associated with an Order,


you cannot delete the Customer. From this statement, you can
infer that two data files are involved in the business rule: the
CUSTOMER and ORDERHEA data files.

You can also restate the aforementioned business rule in


DataFlex database terms: if a parent record has child records,
do not delete the parent records.

The portion of the Construct_Object procedure that implements


this business rule is shown below:

110 Developing Applications with DataFlex


Set Cascade_Delete_State to False
Send Add_Client_File ORDERHEA.File_number

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:

"4140" (Cannot delete-related records exist).

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.

The next procedure is part of the Database Updating Messages.


Creating is sent when a new record is being saved. The following
code assigns a system-generated customer number to a new customer
record:

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

Here is an explanation for each line:

(1) When augmenting an existing message, good object-oriented


programming practice dictates that you forward send the
message. For information about the Forward_Send message,
see the UIMS Handbook.

DataFlex Tutorial 111


(2) Increment the value of the ORDSYS.Cust_Number field by one.

(3) Move the data from the ORDSYS.Cust_Number field into the
CUSTOMER.Number field

(4) Save the ORDSYS record.

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

See the UIMS Reference for further information on this 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.

112 Developing Applications with DataFlex


Invt_Data_Set

The INVT_Data_Set will be controlling all database activities for the


INVT data file.

Select New from the File pull-down. An empty edit screen will
appear.

In this class package, you will be referencing the INVT and


ORDERDTL data sets, so you must enter the following Open
statements:

Open Statements: Open INVT


Open ORDERDTL

Now you are ready to insert the Data Set class template.

Move the cursor so that it is positioned underneath the Open


statements. Select include from the File menu. In the File Name:
window, change *.src to *.tem. Then, click on the .. in the
directories box; use the scroll bar to find the usr directory and click
on that. Click on the examples directory, then tutorial. Now,
double-click on class.tem in the Files box. The file’s contents should
appear in the Edit screen (area).

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:

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
End_Procedure // Construct_Object

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.

Now, let’s implement two more of the business rules:

DataFlex Tutorial 113


Rule# 3 states that the amount sold for an item cannot exceed
the amount that exists in inventory stock.

We can express (or restate) the aforementioned business rule in


DataFlex database terms: You cannot order an item if the value
in ORDERDTL.QTY_ORDERED is greater than the value in
INVT.ON_HAND.

The portion of code that actually implements this business rule


is shown below:

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

Here is an explanation for each line of code:

(1) Declares the variable to use.

(2) If the value in the INVT.ON_HAND field is less than zero,


perform lines 2 and 3.

Otherwise, do not perform lines 2 and 3.

(3) Generate error: "Insufficient Inventory stock"

(4) Return the value 1 (only a 0 returned will allow the save) and
exit the routine.

(5) End the begin-end block.

(6)+(7) If Invt.ON_HAND is greater than or equal to 0, perform the


default function.

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.

114 Developing Applications with DataFlex


You already know, from the Customer_Data_Set, the code segment
that performs this function:

Set Cascade_Delete_State to True


Send Add_Client_File ORDERDTL.file_number

The final code for the INVT_Data_Set looks like this:

//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

You wil create a Procedure Construct_Object for each of the


remaining classes. Since the steps for creating the procedure
Construct_Object have already been documented in this section, no
further explanation on this subject will be given. However, to help you
in this endeavor, we have provided you with a class template
(CLASS.TEM), which contains the syntax for the procedure
Construct_Object. All you need to do is load the file in your text
editor and replace the ????? with the appropriate information. (Note
that the CLASS.TEM file is located in the
\FLEX\USR\EXAMPLES\TUTORIAL directory.)

DataFlex Tutorial 115


In this class package, you will be referencing the INVT and
ORDERDTL data sets, so you must enter the following open
statements:

Open Statements: Open ORDERDTL


Open INVT
Open ORDERHEA

Now you are ready to insert the Data Set class template. Follow the
same procedure shown in the previous page.

Now let’s implement a few more of our business rules:

When a new ORDERDTL record is saved, the following Creating


procedure increments the value in the Last_Detail_Num field by one:

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.

The Update and Backout procedures shown below will help us


implement business rules 5, 6 and 10 :

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

The code is explained below:

(1) Calculates the Extended_Price for each line item.

(2) Subtracts the quantity ordered from the Inventory on hand.

(3) Accumulates the total for each order.

Procedure Update is called when a record is being saved or edited.

116 Developing Applications with DataFlex


The Backout procedure is called when a record is being deleted or
saved. The calculations performed in this procedure are the exact
opposite to those shown for the Update 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

Here is the final code for the OrderDtl_Data_Set:

//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

Here is the final code for the OrderHea_Data_Set class:

//ORDERHEA.DS
Open ORDERHEA
Open ORDSYS

DataFlex Tutorial 117


Open ORDERDTL
Class OrderHea_Data_Set is a Data_Set
Procedure Construct_Object Integer Img#
Forward Send Construct_Object Img#
Set Main_File to Orderhea.File_Number
Set Smart_FileMode_State to True
Set Cascade_Delete_State to True
Send Add_Client_File OrderDtl.File_Number
End_Procedure // Construct_Object
Procedure Creating
Add 1 to OrdSys.Order_Number
Move OrdSys.Order_Number to OrderHea.Order_Number
SaveRecord OrdSys
End_Procedure
Procedure Reset_Filemodes_for_lock
Forward Send Reset_Filemode_for_lock
file_mode ORDSYS Default
End_Procedure
End_Class

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 Data Set (Vendors_Data_Set)

Here is the final code for the Vendors_Data_Set class:

//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

118 Developing Applications with DataFlex


Procedure Reset_Filemodes_for_lock
Forward Send Reset_Filemodes_for_lock
file_mode ORDSYS Default
End_Procedure
End_Class

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

Here is the final code for the SALESP_Data_Set class:

//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

Note that the Set Cascade_Delete_State to false line enforces


business rule #11.

COURIER_Data_Set

Here is the final code for the COURIER_Data_Set class:

//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

DataFlex Tutorial 119


Note that the Set Cascade_Delete_State to false line enforces
business rule #12.

4.4.5 Interface Design

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.

As you know from the previous chapter, a Data-Entry view is


primarily composed of two parts: data entry objects and database
interface objects.

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.

By comparison, database interface objects (i.e. data sets) control what


records you see when you are accessing the database.

In DataFlex, there are two utilities which assist in the prototyping,


development and assembling of views; DFAUTO and AutGen.

The AutoCreate Utility (or DFAUTO) allows you to visually design


and prototype the data entry objects for your view. AutoCreate
maintains its own database of the information it needs about the views
and database files in each of your applications.

With the AutoCreate Source Code Generation Utility (AutoGen), you


can take your AutoCreated prototype and, in a matter of minutes,
generate views, object packages and data set subclass packages. Of
course, the view components that you build with DFAUTO and
AutoGen can all be part of one application or can be reused across
many applications, saving you development time and helping you to
maintain a consistent look for each of your programs.

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

120 Developing Applications with DataFlex


have added your Business Rules, etc., to an AutoGen-created Data
Set just as well.

General Interface Considerations

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.

Source Document Emulation. When designing the layout for your


interface, always take the time to examine the paper documents that
may be the source of the information being entered into your
application. Care should always be taken to make the application
interface follow the flow of data on the source document. Doing so
enables the user to quickly relate their position on the form to the
input field(s) on the screen, speeding up data entry, and decreasing the
chance of erroneous or missing information.

The prior topic discussed the importance of cursor navigation to a


good interface designer and, here too, cursor navigation is critical. You
could spend hours designing a screen than was a nearly perfect copy
of a paper document, only to have it rejected by users because the
cursor didn't travel through input fields in the same sequence that was
used when filling out the paper form. This flow of information for
input fields may be obvious from just looking at the forms. In many
cases, however, you may need to interview the user to see exactly how
the form is currently being used. You may even find that sections of
the form have become obsolete!

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 Tutorial 121


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.

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.

Starting AutoCreate (DFAUTO)

The Order-Entry application will consist of six views and six selection-
list objects.

1. From the Development pull-down, select the Auto Definition


Utility.

2. From the Application pull-down, select New.

3. Accept OOP for Code Style.

4. Enter ORDER as the Application Name.

5. Press 4 to see a list of available data file. Enter ORDERDTL


as the Main File, and enter a description such as Order
Entry Autocreate Prototype.

The Creation Date or Last Update will default to your


current system date, and you can enter the name of the
Author if you wish, together with any Comments to describe
the application.

6. Finally, press 2 or the <OK> button.


Your new application’s BACKGROUND object of shaded
characters will then be drawn. Notice that the name of the
application (ORDER) appears in the title line at the top of your
screen. Also appearing is the name of the utility
(AutoCreate), and the name of the main file (ORDERDTL).
The main file is the lowest-level child file in the application’s
hierarchy. For right now, there is only going to be one file, but
we’ll discuss this in more detail later.

122 Developing Applications with DataFlex


Designing the Views with AutoCreate

Order View. The order view is composed of four data entry objects:

1. Header Entry Form-contains specific information about the


order.

2. Detail Table - contains information about the items being


purchased.

3. Total Entry Form- contains the total for the order.

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.

Header Entry Form (Hdr). You will begin by creating the


Header Entry Form (Hdr), which will look something like this:

Order Number: _____ Order Date: __/__/____ Customer Number: _____

Bill to: ______________________________ Terms


______________________________ _______________________________
______________ __ __________ Ship Via: _____________
Phone #: ____________________ Ordered By: _____________
Fax #: ____________________
Salesperson: ____

1. From the Objects pull-down ( a+O, 0 or mouse), select


New, then Form.

2. Enter Hdr as the Name.

3. Accept the system default colors (represented by 0 and 0).

DataFlex Tutorial 123


4. Accept Single as the Border, and no Title Style.

You won’t be able to enter anything in the File and Index


windows - they are for tables only.

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.

First, you will move and resize the Form.

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.

Line drawing is accomplished using the c1 + key. Pressing


c1 + once will allow you to draw a single line, while two
presses will create a double line. A third press will exit you
from line drawing mode altogether.

9. Move the cursor to the starting position (3,1 in the Background


c+1
object), turn on line mode, (watch the right end of the
status line change), then draw with the arrow keys. You can
also "speed draw" with oph , , and z . Turn

124 Developing Applications with DataFlex


off line mode by toggling c+1 until you see "OFF" in the
status line.

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

12. Next, press a$ + (or select Field Toolbox.. from the


Fields pull-down). The Field Toolbox, which contains the list
of fields for the ORDERDTL data file as well as all of its
parents and grandparents, will appear on the bottom of the
screen. Select the ORDERHEA data file.

13. Move the mouse cursor to the field named


"ORDER_NUMBER", hold down the right mouse button, and
drag the field icon to a position approximately one space after
the ":" in Order Number.

DataFlex Tutorial 125


Figure 29-The AutoCreate Utility, showing the Hdr Form with all the fields in
place.

14. Repeat steps 11-13 (shown above), for the following fields:

Label Field Name Data File

Order Date: ORDER_DATE ORDERHEA


Customer Number: NUMBER CUSTOMER
Bill to: NAME CUSTOMER
none ADDRESS CUSTOMER
none CITY CUSTOMER

none STATE CUSTOMER


none ZIP CUSTOMER
Phone #: PHONE_NUMBER CUSTOMER
Fax #: FAX_NUMBER CUSTOMER
Terms TERMS ORDERHEA
Ship Via: ID COURIER
Ordered By: ORDERED_BY ORDERHEA

126 Developing Applications with DataFlex


Salesperson: ID SALESP

After inserting all the fields, deactivate the Field Toolbox


by double-clicking on its system menu icon (the three-lined
character in its top left corner).

At this point, you are finished with the Hdr Entry Form (see
Figure 29).

Dtl Table. A table displays multiple records from the main


file, and allows the user to edit them one at a time. Tables can be used
when all the fields for a record can fit on one line. The purpose of this
table is to display all the items that are being purchased.

1. From the Objects pull-down ( a+O, 0 or mouse), select


New, then Table.

2. Enter Dtl as the Name.

3. Accept the system default colors (represented by 0 and 0).

4. Select a single border style.

5. Do not choose a title style.

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.

7. In the By Index window, pressing 4


will show you that
RECNUM and the index you created in section xx are available
- pick 1:ORDER_NUMBER, DETAIL_NUMBER and click on
<OK>.

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.

DataFlex Tutorial 127


9. Drag the bottom right corner of the table with the right mouse
button. Resize the table so that it is the same height as the
Form.

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.

The objective is to create a table that looks something like this:

Item Id Description Unit Price Qty Ext. Price


__________ ______________________________ ______.__ _____. ________.__
__________ ______________________________ ______.__ _____. ________.__
__________ ______________________________ ______.__ _____. ________.__
__________ ______________________________ ______.__ _____. ________.__
__________ ______________________________ ______.__ _____. ________.__
__________ ______________________________ ______.__ _____. ________.__
__________ ______________________________ ______.__ _____. ________.__
__________ ______________________________ ______.__ _____. ________.__

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.

14. Use the line drawing features of AutoCreate to draw the


table’s grid.

15. Now you are ready to insert the fields. Press a+$ or select
Field Toolbox from the Fields pull-down.

128 Developing Applications with DataFlex


16. Choose ORDERDTL. Move the selection cursor to ITEM_ID
and press e to select it, and e again when it is
positioned under its ITEM ID title (or position 3,2).

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.

Add 2 rows, so that the table has 6 rows as in Figure x.

17. Repeat step 16 for the following fields:

DataFlex Tutorial 129


Field Data File

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

130 Developing Applications with DataFlex


Ttl Entry Form. You need to create an Entry Form that will
house the ORDERHEA.ORDER_TOTAL field.

1. From the Objects pull-down ( a+O, 0 or mouse), select


New, then Form (see ).

2. Enter ttl as the Name.

3. Accept the system default colors (represented by 0 and 0).

4. Accept Single as the Border, or change it if you want, by


moving the radio button, with the arrow keys or mouse and
pressing g .

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.

DataFlex Tutorial 131


You will be making an entry screen looking something like this:

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.

6. Make sure the cursor is at the leftmost position of the second


line in the ttl Entry form. Type in the static text for the
description of this field - Total $.

7. Next, press a$ + (or select Field Toolbox.. from the


Fields pull-down). The Field Toolbox, which contains the list
of available fields for the ORDERHEA data file, will appear on
the bottom of the screen.

8. Move the mouse cursor to the field named "ORDER_TOTAL",


hold down the right mouse button, and drag the blinking
underscore characters to a position approximately one space
after the "$" in Total.

Order Prompt List. In the single file example, you created a


Prompt List for the Contacts Application. Now, you need to do the
same thing for the Order-Entry Application. This time, however, you
want the prompt list to perform the following function: when users are
in the Order Number field, you would like them to easily browse
through the list of existing orders, select an order, and then retrieve
information about the specified order.

To create the Order prompt list,

1. Select Prompt List from the New choice on the Objects


pull-down, and enter Ordr_lkup as the name, Double
border, Popup as the Title Style and Order List as the title.

132 Developing Applications with DataFlex


Figure 33-The AutoCreate Utility, showing the size, location, grid, column
headings and fields for the Ordr_lkup prompt list.

2. Each prompt list must refer to a particular file, so press4 in


the File window to pop up a list of files available, and select
ORDERHEA. Press 4 in the Index window to pop up a list of
indexes available, and select 1:ORDER_NUMBER. Press the
<F2=OK> button to create the prompt.

The prompt list for the ORDERHEA file will look like this:

DataFlex Tutorial 133


Order List
Order# Cust# Customer Name Date Amount
_____ _____ ______________________________ __/__/____ ________.__
_____ _____ ______________________________ __/__/____ ________.__
_____ _____ ______________________________ __/__/____ ________.__
_____ _____ ______________________________ __/__/____ ________.__
_____ _____ ______________________________ __/__/____ ________.__
_____ _____ ______________________________ __/__/____ ________.__
_____ _____ ______________________________ __/__/____ ________.__
_____ _____ ______________________________ __/__/____ ________.__

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:

Field Data File

ORDERHEA ORDER_NUMBER
ORDERHEA CUSTOMER_NUMBER
CUSTOMER NAME
ORDERHEA ORDER_DATE
ORDERHEA ORDER_TOTAL

It is a table, so you will only have to place the top row of


fields.

4. Now, insert the grid lines and column heading as you did in
the Dtl Table.

Now you need to specify where the prompts are to be available.

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.

134 Developing Applications with DataFlex


Now you need to specify the Entry Options for the following fields:

Field Entry Option

CUSTOMER.NUMBER Auto Find, Find Required,


No Put

CUSTOMER.NAME Display Only

CUSTOMER.ADDRESS Display Only

CUSTOMER.CITY Display Only

CUSTOMER.STATE Display Only

CUSTOMER.ZIP Display Only

CUSTOMER.PHONE_NUMBER Display Only

CUSTOMER.FAX_NUMBER Display Only

COURIER.ID Auto Find, Find Required,


No Put

SALESP.ID Auto Find, Find Required,


No Put, Capslock

INVT.ITEM_ID Auto Clear, Auto Find,


Capslock, Find Required,
No Put

INVT.DESCRIPTION Display Only

INVT.UNIT_PRICE Display Only

ORDERDTL.QTY_ORDERED Auto Clear

ORDERDTL.EXTENDED_PRICE Display Only

NESTING THE OBJECTS. Before you save the Order View,


you must create another object and reorganize the Object structure.

In the Order-Entry application, you currently have the following object


toolbox structure:

DataFlex Tutorial 135


BACKGROUND <Client>
ORDERDTL <Data Set> [ ]
Hdr <Form> [ ]
Dtl <Table> [ ]
Ttl <Form> [ ]
Ordr_lkup <Prompt List>

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> [ ]

136 Developing Applications with DataFlex


Ttl <Form> [ ]
ORDERDTL <Data Set> [ ]
Dtl <Table> [ ]

Ordr_lkup <Prompt List>

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.

Now, you should save the Order Application.

Customer View. The Customer View will contain information about


the customer that will be ordering the items. It will be composed of a
Form, and Editor and Prompt List.

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.

To create the data entry objects for the Customer View,

1. Repeat steps two through six on page xx, entering the


following information instead:

Application Name: Customers


Main File: CUSTOMER

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

4. Press <OK> when you are finished.

DataFlex Tutorial 137


5. Move the form to a suitable position. Resize the form so that
there is room for an editor (see Figure x). Type in the static
text for each of the fields. Activate the Field Toolbox and drag
the fields from the Field Toolbox to their respective positions
on the form.

6. Now, create the Editor object by selecting New from the


Objects pull-down and then Editor. Enter the following
information in the New Form... panel:

Name: Comments
Window Color: 0
Text Color: 0
Border: None
Title Style: None

7. Position the Editor inside of the Form. Drag the COMMENTS


text field from the Field Toolbox to the Comments area in
the form. Use the Object Toolbox to nest (or embed) the Editor
within the Form.

8. Next, create a Prompt List and enter the following information


in the New Form... panel:

Name: Cust_lkup
Window Color: 0
Text Color: 0
Border: Double
Title Style: Popup
Title: Customer List
For File: CUSTOMER
By Index: 1:NUMBER

The Customer Prompt List will allow users to perform the


following function: When users are in the Customer Number
field, you would like them to easily browse through the list of
existing customers, select a customer, and then retrieve
information about the specified customer.

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.

138 Developing Applications with DataFlex


10. Drag the NUMBER and NAME fields from the Field Toolbox
to the appropriate columns on the Prompt List.

11. Finally, add the following Entry Options to the fields shown
below. pressing 2 after each is completed:

Field Entry Option Popup Objects

NUMBER Auto Find, No Put Prompt:


Cust_lkup

NAME none Prompt:


Cust_lkup

ST Capslock none

12. Select Save from the Application pull-down.

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.

Inventory View. The Inventory View maintains information about the


items on inventory.

The Application Style is as follows:

Name: INVT
Main File: INVT
Title: Inventory Parts View

The Form Style is as follows:

Name: Inventory_Parts
Window Color: 0
Text Color: 0

DataFlex Tutorial 139


Border: Single
Title Style: Dialog
Title: Inventory Parts

The Prompt List Style is as follows:

Name: Invt_lkup
Border: Double
Title Style: Popup
Title: Inventory List
For File: INVT
By Index: 1:ITEM_ID

Here are the Entry Options for the following fields:

Field Entry Option Popup Objects

INVT.ITEM_ID Auto Find,


Capslock Prompt: Invt_lkup

INVT.DESCRIPTION none Prompt: Invt_lkup

VENDORS.ID Auto Find,


Find Required none

VENDOR.NAME Display Only none

INVT.VENDOR
_PART_ID Display Only none

Vendor View.

The Application Style is as follows:

Name: VENDOR
Main File: VENDORS
Title: Vendors View

The Form Style is as follows:

140 Developing Applications with DataFlex


Name: Vendors
Window Color: 0
Text Color: 0
Border: Single
Title Style: Dialog
Title: Vendors Information

The Prompt List Style is as follows:

Name: Vendor_lkup
Border: Double
Title Style: Popup
Title: Vendor List
For File: VENDORS
By Index: 1:ID

Here are the Entry Options for the following fields:

Field Entry Option Popup Objects

ID Auto Find, No Put Prompt:


Vendor_lkup

NAME none Prompt:


Vendor_lkup

STATE Capslock none

Courier View.

The Application Style is as follows:

Name: COURIER
Main File: COURIER
Title: Courier View

The Form Style is as follows:

Name: Courier
Window Color: 0
Text Color: 0

DataFlex Tutorial 141


Border: Single
Title Style: Dialog
Title: Courier Information

The Prompt List Style is as follows:

Name: Courier_lkup
Border: Double
Title Style: Popup
Title: Courier List
For File: COURIER
By Index: 1:ID

Here are the Entry Options for the following fields:

Field Entry Option Popup Objects

ID Auto Find Prompt: Courier_lkup

NAME none Prompt: Courier_lkup

STATE Capslock none

Salesperson View.

The Application Style is as follows:

Name: SALESP
Main File: SALESP
Title: Salesperson View

The Form Style is as follows:

Name: SalesP
Window Color: 0
Text Color: 0
Border: Single
Title Style: Dialog
Title: Sales Person Entry

The Prompt List Style is as follows:

142 Developing Applications with DataFlex


Figure 34-The AutoGen Utility, showing a list of applications, from which you
can select a single application to generate source code for.

Name: Salesp_lkup
Border: Double
Title Style: Popup

Title: Sales Person List


For File: SALESP
By Index: 1:ID

Here are the Entry Options for the following fields:

Field Entry Option Popup Objects

ID Auto Find, Capslock Prompt:


Salesp_lkup

NAME none Prompt:


Salesp_lkup

DataFlex Tutorial 143


Generating the Code with the AutoCreate Source Code
Generation Utility (AutoGen)

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.

To generate the code,

1. From the command line, type DFRUN AUTOGEN, and a list


of all the applications you designed via AutoCreate will

144 Developing Applications with DataFlex


Figure 36-The configuration file (AUTOGEN.INI) for the AutoGen Utility.

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 Package: This option will create all the re-usable


packages associated with the application you selected.

View test program: This option will create all the re-usable
packages as well as a test program for the application you

DataFlex Tutorial 145


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 (c0 + ), a
a0
focus-tree browser ( + ), and an expression evaluator
cE
( + ). For information about these debugging tools, see the
UIMS Handbook.

Complete Application: In addition to the re-usable packages,


this option will create the complete source code for the
application you have selected.

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.

1. Move the selection cursor to the Button labeled <Options...>.


The Source Code Options panel will appear:

You will leave all of the package names and options as is.

2. Move the selection cursor to the button labeled <Defaults...>.


The Configuration file for AutoGen will appear:

This file, named AUTOGEN.INI, contains the default system


settings for the AutoGen Utility.

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.

4. Press 2 to confirm the changes.


5. Press q to return to the Source Code Generation Panel.

6. Make sure that the selection cursor is on the Complete


Application panel. Press 2 to begin generating the code.

146 Developing Applications with DataFlex


A message will appear informing you of the fact that the code
generation has been successfully completed.

7. Press e to leave AutoGen and return to AutoCreate.


Let’s examine the files that AutoGen produced:

ORDER.VW This is the ORDER View object package.


Within it, you will find an entry_view_client
object, which contains data-set objects and
data-entry objects.

ORDER.SL Contains the selection list package for the


ORDER view, which can be reused in any
other program.

Modifying Auto Created code

The following changes demonstrate the types of changes you would


make in your auto-generated order entry program. They range in
difficultly from simple to intermediate. In order to make these kinds of
changes yourself you would need to have more knowledge about
DataFlex then is provided with AutoCreate or with this tutorial. The
knowledge is provided in the UIMS Handbook and the UIMS Reference

Normally, you would make these kinds of changes in iterations. You


would make a change, test it, correct it as needed, and re-test until it is
working. When complete, you would move on to the next change. As
you work through these modifications, study them one at a time.

The modifications are presented in order of difficulty. Each change is


fully documented below and source code is presented. If you do not
understand all of the features presented in this section, do not worry.
The main purpose of this section is to show how prototype code is
modified and to give you an idea of the range of changes that can be
made.

Changes the Order Entry View. The following changes were made to
the ORDER.VW file.

DataFlex Tutorial 147


1. Add the { Thousands } Delimiter.

DataFlex 3.1 supports an entry_item option which places the proper


thousands separator in numbers. You add this by adding the
parameter thousands inside your { } list. We are adding this to three
numbers, the line item unit price, the line item extension, and the
order total. In this example, all of these fields are displayonly. You
can use the thousands options with enterable fields as well.

Listed below are the three examples of using thousands:

Entry_Item ORDERHEA.ORDER_TOTAL { DisplayOnly, Thousands }


Entry_Name_Item Price## INVT.UNIT_PRICE { DisplayOnly, Thousands }
Entry_Name_Item Amount## ORDERDTL.EXTENDED_PRICE { DisplayOnly, Thousands }

The entry_name_item modification will be discussed shortly.

2. Add Missing Selection-Lists for Customer, Invt, Courier, and Salesp

When we designed the order entry screen we knew we would have


selection-lists for all of the support files. Since we only want to create
these lists once we did not create them during the order entry
autocreate session. Instead, we must add them to this program
manually. This requires two lines of code for each selection-list:

1. Use the selection-list package

2. Add an iPrompt line to each entry_item that needs


the prompt.

We’ve added four new selection-lists ("merged" might be a better term


since the lists were already created). Those lists and their associated
iPrompts are:

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, ;

148 Developing Applications with DataFlex


iPrompt=(Courier_lkup_sl(Current_Object)) }
:
Entry_Item SALESP.ID { AutoClear, AutoFind, Capslock, NoPut, ;
iValidate=GET_FindReq_Auto_Prompt, ;
iPrompt=(Salesp_lkup_sl(Current_Object)) }
:
Entry_Item INVT.ITEM_ID { AutoClear, AutoFind, Capslock, NoPut, ;
iValidate=GET_FindReq_Auto_Prompt, ;
iPrompt=(Invt_lkup_sl(Current_Object)), ;
iExit=MSG_Total_Amount }

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 Get_FindReq_auto_prompt will be discussed shortly.

3. Set Wrap_state in Tables to true

Tables have a property named wrap_state. This property determines


what happens when you reach the end of the line. When false (the
default) navigation will proceed to the next object. When true,
navigation stays within the table but moves to the next row. We want
this behavior so wrap_state in the table is set to true.

// Change 3: Wrap_state keeps navigation within table.


//
Set wrap_state to TRUE // keeps NEXT within table

4. Add Totaling Logic in Detail Entry

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

When messages are referenced inside of the entry_item parameter


block ( the { } block) you must preface the message with its message
type, msg_ for procedures and get_ for functions.

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

5. Change the FindReq to a Find Required Auto-Prompt.

Currently, an error message will be presented if the user attempts to


navigate past one of the fields requiring a parent file entry. Rather

150 Developing Applications with DataFlex


than presenting the error we will present the appropriate prompt-list.
This creates a more user friendly interface. To do this, we simply
replace all:

findreq with iValidate=GET_FindReq_Auto_Prompt

This feature is called auto-prompting. Two forms of auto-prompting


are supported. When entering an empty item auto-prompt can be
invoked (iEntry=msg_auto_prompt). When leaving a blank field, a
validation failure can trigger an auto-prompt. Most users find auto-
prompt to be more useful. Once a user is experienced, they find the
pre-entry auto-prompt can actually slow them down (they know what
code they want to type and they don’t need the list).

6. Create New Save and Delete Confirmations

We want the save and delete message in the order header to be


customized to Save this Order? and Delete this Order?. We
do this by creating two new confirmation functions and assigning the
save and delete verify messages to these functions. These new
functions use the generic confirm function which allows us to ask
any question we want. Below are the changes required to support
these changes.

Old code:

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

New Code:

Function Confirm_Delete_Order Returns Integer


local integer rval
Get confirm "Delete Entire Order?" to rval
Function_Return rval
End_Function
Function Confirm_Save_Order Returns Integer
local integer rval
Get Confirm "Save Entire Order?" to rval
Function_Return rval
End_Function
// Define Default Confirmation Messages

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

7. Add a pop-up Pick-List for Terms

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

8. Restrict Table Additions to the Bottom and Optimize Table Refresh.

152 Developing Applications with DataFlex


In the order detail table, new records will always get placed at the end
of the table (because the index contains a detail-id which is constantly
incremented). To make this more intuitive, we want to change the
behavior of the insert-row key ( s0 + ). Normally, this inserts a
new line. While this would work, it makes more sense to force this key
to add a new line to the end of the table (append instead of insert).

Since there is no table message to append a blank line we will create


one ourselves. We create a message append_a_row to perform this
task. We will use several existing behaviors to accomplish what we
need. In this case we need to go to the end of the list (send
end_of_data) and then go down one more line (send down). Very
often, when trying to create custom navigation events, it is best to send
the same messages the keyboard would send when you press the
required multi-key sequence to perform the task.

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

9. Force saves when entering and exiting tables.

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.

The entering behavior is more complicated. Here’s what we want:


Before entering a table we want to make sure that the header record is
saved. If for some reason the header does not save (it fails validation)
or if the header is blank, we want to disallow entry into 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."

When child_table_state is true we can use a function named


child_entering to check if all conditions are being met to enter the
table. If a non-zero value is returned the table will not be entered.
Rather than checking the conditions in the table, we will let the table
send a message to the header which says, "I am about to get the focus,
is everything proper in the header for this event?" It is up to you to
decide what the header’s definition of "proper" is. In this sample we
have decided we will try to save the header record. If the save
succeeds the header will tell the table that all is well. If the save fails
or there was no record to save we will return a failure. We want to
save the header record silently (no confirmation message and no
clearing after the save). We must custom code this.

Here is a summary:

1. Set child_table_state is true.

2. When the table is being entered, the function


child_entering if called. If it returns a non-zero the
table will not be entered.

3. Child_entering will call a function in the order


header which we’ve named save_header. This
function will return a non-zero value if the save fails.

4. Save_header will try to save the record. If after the


save there are still changes in the header (indicating
the save did not proceed) or there is no current record
in the header’s data-set (indicating that there was
nothing to save) we will return a non-zero value.

5. We must temporarily shut off the save confirmation


verification and we must make sure the header does
not clear after the save.

154 Developing Applications with DataFlex


Below is the code in the entry-form and the table required to support
these changes.

Object Hdr_EF is an Entry_Form Hdr_EF_Image Using (ORDERHEA_DS(Current_Object))


:
Function Save_header returns integer
Local integer NewRec Changed Srvr Oldmsg
// we must temporarily shut off the save verify message.
// We keep track of the old message so we can restore it.
get verify_save_msg to oldmsg // original message
set verify_save_msg to Get_No_Confirmation // no message
// request_save_no_clear does a save without clearing.
Send request_save_no_clear
set verify_save_msg to Oldmsg // restore original
// We now need to determine if the save was successful: (1) if there are
// no changes, and 2) we have a current record. Should_save tells us if
// we’ve got changes.
// We must check the data-sets current_record property to see if we have
// a record. If it is 0, we had no save.
Get Should_Save to Changed // is a save still needed
Get Server to Srvr // object id of data-set
Get Current_record of Srvr to NewRec // current record of data-set
// if no record or changes still exist, return an error code of 1
If (newrec=0 OR Changed) Function_return 1
end_function
End_Object // Hdr_EF
Object Dtl_TBL is a Table Dtl_TBL_Image ;
Using (ORDERDTL_DS(Current_Object)) by index.1
Set Location to 11 1 Relative
Set child_table_state to TRUE // Saves when exit object
// Called when entering the table. Check with the header if it
// has a valid saved record. If not, disallow entry.
//
Function Child_entering returns Integer
local integer rval
// Check with header to see if it is saved.
Get Save_Header of (hdr_EF(Current_Object)) to rval
function_return rval // if non-zero do not enter
End_Procedure
:
End_object // Dtl_tbl

Changes in the Inventory View. The Inventory entry view (INVT.VW


file) has been modified using the same customizations shown here.
Although they are not documented here they should be familiar to you
at this time.

The changes made were:

1. Added vendor selection-list for the vendor entry_item.

1 Introduction 155
2. Replaced FindReq with Get_FindReq_Auto_Prompt in the
vendor field.

3. Added the thousands option to the unit price and quantity-


on-hand fields.

4.4.6 Generating a report with DFQUERY

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.

Choose the Main File

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.

156 Developing Applications with DataFlex


Choose Fields for the Report

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

Figure 37 Choosing Files and Fields in Query


DBMS Files box. You see the chosen main file as ORDERDTL (its
logical, or programming, name), and its parent files. One field or
another of ORDERDTL relates to each of the other files listed.

The first field we want is the line-number field. This is


ORDERDTL.DETAIL_NUMBER, so place the cursor on ORDERDTL and
press e . The cursor will rotate to the DBMS Fields box, in which
you should select the DETAIL_NUMBER field. When you do this, the
name and length of the selected field appears to the right in the
Printed Fields (the largest) box of the screen. Move the cursor to
the ITEM_ID field and choose it. The name of that field will appear on
the right under the name of the first-selected field.

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.

158 Developing Applications with DataFlex


Choose the Order to Output the Records

Bring up the Output Order screen by choosing View from Query’s


Main Menu, then choosing Output Order from the View pull-down
menu (the shortcut key combination is c+3 ). In the Output
Order screen use the arrow keys to select an index. The one we want
is ORDER_NUMBER, DETAIL_NUMBER.

Set the Selection Criteria

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.

The Selection Definition screen will reappear with your first


selection listed in the Selection Panel. Select ORDERHEA again, and
ORDER_DATE again. This time in the Selection Type panel, choose
< Less than, and enter 1/1/94 in the value-entry window. The
screen should look like Figure 40. Press <OK>, then close this screen
with q .

Compose a Report Heading

From the View pull-down, choose Parameters. In the Query


Heading window, enter Orders for 1993. Press .q

Figure 40-

160 Developing Applications with DataFlex


Run the Report

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.

Generate Source Code for the Report

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

Code Output by Query

The source code generated by Query is in a file named


REPTUTOR.RPT. To run this program, you shouldn’t directly compile
this file; you should compile REPTUTOR.SRC, which uses
REPTUTOR.RPT. The reasons for this are discussed below. Here is
what the view source code looks like:

// 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

/*

162 Developing Applications with DataFlex


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
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
Procedure_Section Body as REPTUTOR_Body 2
Forward Send Body
Print ORDERDTL.DETAIL_NUMBER
Print ORDERDTL.ITEM_ID
Print INVT.DESCRIPTION
Print ORDERDTL.QTY_ORDERED
Print INVT.UNIT_PRICE
Print ORDERDTL.EXTENDED_PRICE
Output_Pagecheck REPTUTOR_Body
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

Note: We have altered the /REPTUTOR_Header and


/REPTUTOR_Body Resident sections so that the output will be
aligned properly. In most cases, you will have to make the same type
of modification.

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

Figure 41 Report Selection Client Display


The query_selection_client object and image use a report-
selection-client object to give users the choice of outputting to screen,
printer, or a file. This is a desirable feature in all reports launched by
users in real time (but not those run in batches). A reptutor_total
image is provided to show the number of records output by the report,
which you may or may not always want to know. It is filled by the
procedure section total, toward the bottom.

The places where Data Access Corporation appears in images


above are where Query inserts the name to which your DataFlex
license is registered—usually, your company name. You might not
always program this in manually, or want to. You can remove it from
source code easily, of course.

164 Developing Applications with DataFlex


Each of the procedure sections (e.g., procedure_section body)
leads off with a forward send procedure_sectionName
statement. In the report shown, these do nothing. But if you had
defined any of these as procedures in the class definition of the report
(standard_report in this case), these statements would be required
in order to use those definitions. If you were to hand-code one or
more child reports into this report object, this statement would be
needed in the body procedure section to start the child report(s) at the
proper time.

A similar consideration (nested reports) is why Query types in the


name you gave your report (reptutor in this case) as part of the
name of every one of the section images (e.g., reptutor_header).
This at least allows you to use the simple, reserved names (header)
for your images in your first child report. For the second and
succeeding child reports, you’ll have to adopt some sort of
differentiation again, because image names are global. But in that first
child report, you won’t have to name your images (as
reptutor_header) in your procedure-section statements, as Query
has helpfully done in all its statements, if you use the short-form
image names.

You might not automatically program your report as a view, as Query


has done, but you should. You will eventually acquire this important
good programming habit, but toward that end, Query does it for you,
and shows you how in this code. The view whose code is shown
above is started by a Send Activate_REPTUTOR_Report command
in a separate source-code file produced by Query, REPTUTOR.SRC.
The file containing the code above is REPTUTOR.RPT. Here is
REPTUTOR.SRC:

// 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

The report object created by query is simplicity itself. After outputting


some helpful documentation at the top, the code uses the qryrpt
package, which contains all the report packages Query needs for
reporting. These packages are supplied precompiled with DataFlex,
and if you produce your own versions of these packages (as you
should), you will find it helpful to keep those precompiled, as well.

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.

The next image, /REPTUTOR_body is set resident, since it gets


output every time a record is selected by the report. The last image,
total, has already been discussed.

The next two images are used for input. REPTUTOR_selection_form


is used to elicit input from users each time this report is run as to
what period of time is to be covered. REPTUTOR_selection_client
was discussed above.

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 activate_view command creates a procedure


(activate_reptutor_report) at the desktop to run this report.
That procedure is the one executed by the send
activate_reptutor_report statement in REPTUTOR.SRC. Finally,
the query_view object is created as a container for the report object
proper and the query selection client.

166 Developing Applications with DataFlex


Parts of the Report Object

Object report (of reptutor_report) is of the standard_report


class. The class name reflects our belief that most of your reports will
be based on objects of this class. Two of this report’s properties are
declared first in this rather simple object. The main file is identified as
orderdtl, the order-detail-line file, and the index of that file by
which this report’s output is to be ordered is Index 1
(report_index).

The first constraint_value is set to 1/1/93, and the second to


1/1/94, the values we entered when defining this query. These
values, as long as you don’t change them in the source code, appear as
defaults in the windows presented by Object
reptutor_selection_form whenever the report is executed. The
constraint section proper follows, constraining
orderhea.order_date to greater than or equal to the first value and
then the same field to less than the second value. These relationships
are repeated when the selection form is run, as you will see.

The first procedure section, page_top, identifies the header image


REPTUTOR_HEADER as its own, then forward-sends its own message to
the class. Then it puts today’s date (sysdate) to the first window of
the header, the the page number to the second windows. The page
counter (page_count) advances for each page, as does the clock,
which will advance one day if your first page is run before midnight,
and your last page, after. The image is output for each page by the
output_pagecheck command.

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.

Then, the one-line body image is output with output_pagecheck.


The Body procedure continued until the end of the page, at which
time page_top is invoked. And that cycle continues until the end of
the selected range, at which time procedure-section total comes into
play.

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.

The next object (reptutor_selection_client) is the one that


presents users with the choice of outputting to either printer, screen, or
file. It also has a child object (reptutor_selection_form) that
presents queries for the input criteria (1/1/93 and 1/1/94).

Extending the Report with Manual Additions

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.

What breaks do in a report is trigger the printing of some sort of break


delimiter, like a break heading, or a subtotal, or both. If we stopped
here, we’d get no change at all in our report output, even though the
breaks would be "there." Since we’re breaking the output by Order
(number), it would seem to make sense to print out the order number
at the top of each section, and since we’re selecting by date, printing
that out would also make sense. This is easily done with one
additional procedure section and associated image:

/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

168 Developing Applications with DataFlex


Here, the image is shown together with its associated procedure
section. Although Query generates all the images at the top, and then
the procedure sections, you can program them this way, too. This code
could be inserted almost anyplace in the report, but the most-logical
position for it would seem to be between the header and body
procedure sections. The image must go above the procedure section
that addresses its windows.

The reptutor_subheader1 image contains a blank line above and


below the captions for the order number and date; this provides
spacing in the output that will make it considerably easier to read.
Also, note that even though order_number is a numeric field, an
ASCII field has been provided after the order-number caption. This is
so that the output will left-justify one space after the caption. Much
better-looking than a right-justified number that might end up some
distance away from its caption.

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.

In the procedure section, the subtotal command fills the window in


with a running total of the line-item amounts, and then zeros that total
for the next order. Output_pagecheck outputs the image.

It is here that we should tell DataFlex to go to the next page if there


will be more output. This isn’t done in page_top, where you would
think it would be, nor in subheader1. It’s too late there. The new
page has to be in place before these sections are executed, so it is
triggered (conditionally on there being more output) when everything
for the previous page has been completed. All to do is set
page_end_state to true. When choosing output to the screen, by
the way, this same provision will halt output when the screen fills and
prompt users for a keypress to display the next "page" (screenful).

Now, every order will start on its own page, with the order number at
the top.

Done

The completed view source code looks as follows. Three sections of


code have been added, shown in boldface. Nothing has been deleted
from the code generated by Query.

// reptutor.rpt
// 06/13/95 15:54:42
// Orders for 1993
// Data Access Corporation
//
// Package generated by DFQuery 3.1
Use QryRpt

170 Developing Applications with DataFlex


/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

/*
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.

172 Developing Applications with DataFlex


Remember, when you compile your new report, don’t compile
REPTUTOR.RPT. Compile REPTUTOR.SRC, or whatever other
program you eventually have useing REPTUTOR.RPT. The first page
of the output should look something like this:

06/14/95 Page 1
Data Access Corporation
Orders for 1993
DETAIL LIST
NUMBER PART ID DESCRIPTION QTY PRICE AMOUNT

Order Number 125 Date 01/25/93


16 CASE Understanding Case Technology 2 39.00 78.00
17 DATES The 100 Important Dates in History 200 29.00 5800.00
------------
Order Total 5878.00
============

4.4.7 Endless Horizons

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.

4.4.8 Assembling your program

It is now time to bring your development efforts to a close for this


project.

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.

In fact, a template main program file named mainprog.tem is included


with the packages. It contains the skeleton code of a main menu
program. All you have to do is load the template, rename it, fill in the
?????? prompts and add your views.

1 Introduction 173
To add the view to your program,

1. First, copy MAINPRGB.TEM from the \FLEX\SRC\PKG


directory to the \FLEX\PROJECT2 directory.

2. Using your favorite text editor open the MAINPRGB.TEM file.

The template should look like this:

//======================================================================
// 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

174 Developing Applications with DataFlex


On_Item "View" Begin_Pull_Down View_Pull_Down
On_Item "???????????????? Alt+1" Send Activate_???????? to desktop
On_Item "???????????????? Alt+2" Send Activate_???????? to desktop
On_Item "Close F3" Send Exit_Function
End_Pull_Down
#INCLUDE TXTW_PD.INC
#INCLUDE NAVI_PD.INC
#INCLUDE HELPA_PD.INC // modified help pull-down. Includes about.
End_Menu
// Hot key support
Procedure Main_Menu_Keys For Desktop Integer Act_Obj
On_Key KEY_ALT+KEY_R Send Activate To (Record_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_V Send Activate To (View_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_T Send Activate To (Text_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_N Send Activate To (Navigate_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_H Send Activate To (Help_Pull_Down(Act_Obj)) Private
//
On_Key KEY_ALT+KEY_1 Send Activate_???????? to Desktop Private
On_Key KEY_ALT+KEY_2 Send Activate_???????? to Desktop Private
//
End_Procedure
//************************* Global Button Bar Object*************************
Use MainBtn // Btn_bar desktop object
//************************* View Packages/Objects ***************************
Use ???About // about - Send about
Use ??????? // View title 1 - Send Activate_???????? to Desktop
Use ??????? // View title 2 - Send Activate_??????? to Desktop
// always activate the btn bar before the action_bar
Send Add_Focus to (Btn_Bar(Current_Object)) Desktop
Send Activate to (Main_Menu(Current_Object))
Start_Ui (Main_Menu(Current_Object)) // start the program

3. Scroll down to the following three lines of code:

Set Application_name to "???????"

// ??????.Src: ??????????????????????????????
Send Paint_Desktop to (Background(Current_Object)) ;
"?????????????????????????????????????"

4. Fill in the question marks with the following :

Set Application_name to "Order-Entry"


ORDERENT.SRC: ACME Computer Supplies-Order Entry System

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.

5. Move down to the following section

/Main_Menu
______ ____ ____ ________ ____
/View_Pull_Down
___________________________
___________________________
___________________________
___________________________
___________________________
___________________________
___________________________
/*

This section defines the images for your program.

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.

176 Developing Applications with DataFlex


You must also create an image for the Report View pull-down. This
can easily be accomplished by copying the View Pull-Down image
and then deleting 5 of the six lines from the image.

The finished View Pull Down image and Report Pull Down image
looks like this:

/View_Pull_Down
________________________________
________________________________
________________________________
________________________________
________________________________
________________________________
________________________________

/Report_Pull_Down
__________________________
__________________________

5. Scroll down to the following section:

On_Item "View" Begin_Pull_Down View_Pull_Down


On_Item "???????????????? Alt+1" Send Activate_???????? to desktop
On_Item "???????????????? Alt+2" Send Activate_???????? to desktop
On_Item "Close F3" Send Exit_Function
End_Pull_Down

This section defines the labels for the View pull-down menu items and
the message each item will perform when selected.

Let’s fill in the question marks with information that is appropriate to


our View pull-down. The first pull-down menu item will be named
"Courier Entry Screen". The accelerator key for this item will be the
a! + key combination. We want the accelerator key label to be right
justified, so we include the string "\a" right before the label.

Next, we want to replace the Activate_??????? with


Activate_COURIER. This will activate the COURIER view whenever
the first View pull-down menu item is selected. The modified line
should look something like this:

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:

View Name Pull-down menu item label

CUSTOMERS Customer Entry Screen...\aAlt+2


INVT Inventory Entry Screen...\aAlt+3
ORDER Order Entry Screen...\aAlt+4
SALESP Salesperson Entry Screen...\aAlt+5
VENDOR Vendors Entry Screen...\aAlt+6

The new section looks like this:

On_Item "View" Begin_Pull_Down View_Pull_Down


On_Item "Courier Entry Screen...\aAlt+1" Send Activate_COURIER to desktop
On_Item "C&ustomer Entry Screen..\aAlt+2" Send Activate_CUSTOMERS to desktop
On_Item "Inventory Entry Screen...\aAlt+3" Send Activate_INVT to desktop
On_Item "Order Entry Screen...\aAlt+4" Send Activate_ORDER to desktop
On_Item "Salesperson Entry Screen...\aAlt+5" Send Activate_SALESP to desktop
On_Item "Vendors Entry Screen..\aAlt+6" Send Activate_VENDOR to desktop
On_Item "C&lose\aF3" Send Exit_Function
End_Pull_Down

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:

On_Item "Re&port" Begin_Pull_Down Report_Pull_Down


On_Item "Order Entry Report...\aAlt+7" Send Activate_REPTUTOR_Report to desktop
On_Item "C&lose\aF3" Send Exit_Function
End_Pull_Down

7. Move down the template file until you find the following
section:

Procedure Main_Menu_Keys For Desktop Integer Act_Obj


On_Key KEY_ALT+KEY_R Send Activate To (Record_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_V Send Activate To (View_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_T Send Activate To (Text_Pull_Down(Act_Obj)) Private

178 Developing Applications with DataFlex


On_Key KEY_ALT+KEY_N Send Activate To (Navigate_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_H Send Activate To (Help_Pull_Down(Act_Obj)) Private
//
On_Key KEY_ALT+KEY_1 Send Activate_???????? to Desktop Private
On_Key KEY_ALT+KEY_2 Send Activate_???????? to Desktop Private
//
End_Procedure

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:

On_Key KEY_ALT+KEY_1 Send Activate_COURIER to Desktop Private

Repeat the steps shown above for each of the remaining views:

View Name Accelerator Key

CUSTOMERS Alt+2
INVT Alt+3
ORDER Alt+4
SALESP Alt+5
VENDOR Alt+6

The section will look like this:

Procedure Main_Menu_Keys For Desktop Integer Act_Obj


On_Key KEY_ALT+KEY_R Send Activate To (Record_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_V Send Activate To (View_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_P Send Activate To (Report_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_T Send Activate To (Text_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_N Send Activate To (Navigate_Pull_Down(Act_Obj)) Private
On_Key KEY_ALT+KEY_H Send Activate To (Help_Pull_Down(Act_Obj)) Private
//
On_Key KEY_ALT+KEY_1 Send Activate_COURIER to Desktop Private
On_Key KEY_ALT+KEY_2 Send Activate_CUSTOMERS to Desktop Private
On_Key KEY_ALT+KEY_3 Send Activate_INVT to Desktop Private
On_Key KEY_ALT+KEY_4 Send Activate_ORDER to Desktop Private
On_Key KEY_ALT+KEY_5 Send Activate_SALESP to Desktop Private
On_Key KEY_ALT+KEY_6 Send Activate_VENDOR to Desktop Private
On_Key KEY_ALT+KEY_7 Send Activate_REPTUTOR_Report to Desktop Private
//
End_Procedure

1 Introduction 179
8. Move to the end of the file until you arrive at this section:

Use ???About // about - Send about


Use ??????? // View title 1 - Send Activate_???????? to Desktop
Use ??????? // View title 2 - Send Activate_??????? to Desktop

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:

Use ORDABOUT.VW // about - Send about //should have a .VW extension


Use ORDER.VW // View (childmost) - Send Activate_ORDER to Desktop
Use INVT.VW // View title 2 - Send Activate_INVT to Desktop
Use CUSTOMER.VW // View title 2 - Send Activate_CUSTOMERS to Desktop
Use COURIER.VW // View title 1 - Send Activate_COURIER to Desktop
Use VENDOR.VW // View title 2 - Send Activate_VENDOR to Desktop
Use SALESP.VW // View title - Send Activate_SALESP to Desktop
Use REPTUTOR.VW - Send Activate_REPTUTOR_Report to Desktop

Notice the reference to ORDABOUT.VW. This is a view package which


displays an about panel whenever the About.. item on the Help
pull-down is selected. The About panel contains background
information about a particular application. A sample about template
(DFABOUT.TEM) is provided to allow you to create your own custom
about panel.

To achieve this, copy the DFABOUT.TEM file from the


\FLEX\SRC\PKG to the \FLEX\PROJECT2 directory. Load the
template, replace the ???? with information that is pertinent to the
Order-Entry Application, and then save the file with the new name,
ORDABOUT.VW.

9. Now, save your program as ORDERENT.SRC.

4.4.9 Compiling your program

To compile your program, select the Compile programs.. option


from the Development menu. Type ORDERENT.SRC in the space
provided, and then press 2
to accept.

Alternatively, you could have typed DFCOMP ORDERENT.SRC at the


command line.

180 Developing Applications with DataFlex


4.4.10 Running the Acme Order Entry System-A Guided Tour

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.

Now press a^ + . The Vendors Information form will appear,


painting itself over Sales Person Entry. Enter and save a few vendors,
using the following suggestions, if you wish, or make up your own.
Note that you do not enter the Vendor ID. The IDs are assigned by
Procedure Creating in the Vendor Data Set, using the ORDSYS data

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.

Name Address City ST


ZIP Phone
Ace Manufacturing Corp. 1212 N. Beltway
East Park NJ 02199 (800)
345-9088

Sea Life Graphics, Inc. 909 E. Broadway New York NY


01010 (212) 888-4789

Photomatix Products 400 Beans Blvd. Murphy CO


80010 (891) 422-1259

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.

Name Address City ST


ZIP Phone
The Miami Dolphins P.O. Box #1 Miami FL
33199 (800) 111-1111

Data Access Corp. 14000 SW 119 Ave Miami FL


33186 (305) 238-0012

The Forensic Group 8 Willy Place Monmouth MA


00111 (617) 436-7543

Press a+! to enter some Couriers. Here are some suggested entries:

Name Address City ST


ZIP Phone
Pony Express 4545 Sagebrush St. Carson City NV
89765 (702) 887-1223

We-Deliver-FAST P.O. Box 333 Detroit MI


48284 (313) 988-2434

182 Developing Applications with DataFlex


Now that you have four view displayed, it is time to familiarize
yourself with some other navigation techniques. While in the Courier
Information view, press a6 + . You should now see the Sales
Person Entry form displayed on top of the others. Now press a6 +
again, and the Vendor screen will appear. Pressing a6 + again will
give Customers the current focus, and once more will again give it to
Courier. Now try c6 + ; and again. You will see that this will take
you through the same sequence, only in reverse. If you press 0 to
N
access the Menu Bar, then , you will see a list of this type of
navigation keys. Of course, if you have a mouse interface and a view
is displayed, you may click on it in order to be able to give it the
focus.

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

Item Id: MR. BONES


Item Description: Mr. Bones Human Skeleton Model
Vendor Id: 1 Ace Manufacturing Corp
Vendor Part Id: MRB144-98
Unit Price: 133.75
Quantity On Hand: 10

Here are some more inventory items to enter:


Item Id Item Description Vend Id Vend Part Id Unit Price QOH
WIDGET-S Small Widget 1 WID188-77 .455 04
WIDGET-L Large Widget 1 WID188-79 .85 189
SQCHART-L Large Squid Chart 2 5489.12 L 77.00 34
OCCHART-L Large Octopus Chart 2 5466.12 L 77.00 45
CLCHART-L Large Clam Chart 2 5478.12 L 77.00 39
SOLU-48-G Toner Solution #48 - 1 Gal. 3 S48G 1.44 3

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

Now you have enough inventory items to be able to create some


orders. Press a$ + to bring up the Order Entry screen. Return
through the Order Number (it will be auto-assigned, thus fulfilling the
remainder of Business Rule #9). Fill in the Order Date. Press 4 from
Customer Number, and select a customer, using the up/down arrow
keys to locate, and e to select. Observe all the fields which are
mapped to the Customer file fill with data. (Also, note that there is no
ability present to enter another Customer for this order, which fullfills
Business Rule #7.) Now press the Prompt key (Note from the buttons
on the bottom of the screen that this is 4 ) to pop up the Pick-List.
Select a Terms option, using the up/down arrow keys and e
(mouse users can just click on the desired option). Your cursor will
now be in the Ship Via window. Press e , without entering
anything. The Courier List will pop up. You will recall that you
added a GET_FindReq_Auto_Prompt iValidate option on this
entry_item. Now you see the effect of that message. Select a Courier.
You may fill in Ordered By, then prompt for the Sales Person, either
by pressing 4 , clicking on the <F4-Prompt> button, or just pressing
e .

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.

Press e to AutoPrompt the available Inventory Items, and select


one. Because you have entered more items than the selection list will
display at one time, you have the opportunity to use the variety of
keys which can navigate you through the list. Try op , , and
u v
the and (mouse users can click on the Scroll Bar arrows). Make a
selection for the line item. When you press e following the
display of the item information on the table line, you will be in the
Qty column. Enter a quantity to sell. This will produce a
Confirmation dialogue. When you press 2 to confirm, the line item
will save. Note that the Extended Price has been calculated, along
with the order's total amount. (This confirms Business Rule #10.)

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

184 Developing Applications with DataFlex


#6). Remember that you programmed this behavior with the iExit
message Total_Amount. After you save the sixth item (the table
has six rows), note that the table scrolls up one line, and you will be
entering the seventh item on the bottom row. (You programmed this
behavior when you added Append_a_Row to the code.) For the
seventh item, select from the Invt Selection List the same item that you
used in line 6. This mimics a common error that an entry operator
could make when entering an order from a hand-written form. Now
you need to remove that item. Note that the bottom of the screen
contains a set of buttons which includes <F5-Clear>. Press 5 , and
press2 to confirm that you want to abandon the changes; then the
line will clear. Now, say that you had gone ahead and saved that last
item. The <Shift+F2=Delete> button should suggest the next
course of action. Try it: Save a new record, then press the Up arrow
key to place the cursor back on that line; then presss2 + . When
you OK the confirmation dialogue, the line item will be deleted. You
might have noticed that, upon deletion, the Order Total was backed
out with a subtraction of the deleted amount, as one would expect.

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.

186 Developing Applications with DataFlex


5 THE HIGH-LEVEL CLASSES
The DataFlex runtime has a series of built-in low-level classes. These
are referred to as the base classes. Examples of the base classes are
menu, list, edit, array, form, button, client, and entry. While
these classes can be and often are used to create user-interface panels,
they are not particularly well suited for creating complex data-entry
panels, which is our goal.

To accomplish this, these base classes are built upon through a


hierarchy of subclasses eventually resulting in high-level classes.
Examples of the high-level classes are entry_form, table, and
data_set. For example, the high level-class table’s hierarchy is:

object
ui_object
menu
list
entry_list
wide_list
data_list
table

While this is an accurate representation of the class structure, it verges


on information overload. As application builders, we are going to look
at our classes from a different perspective. Since we will primarily be
using the high-level classes, we will concentrate on them. As
application builders, it makes little difference to us how these tools are
derived.

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.

5 The High-Level Classes 187


5.1 A Quick Review of Object-Oriented Syntax

The section provides a very brief summary of the object-oriented


language syntax used in DataFlex. The purpose here is to present just
enough information to make the syntax in the upcoming examples
familiar.

5.1.1 Class-Creation Syntax

class class_name is a superclass


procedure construct_object {integer image_name ...}
forward send construct_object image_name ...
declare new and initialize existing properties
define accelerator keys
end_procedure
define new and augment existing procedures and functions
end_class

5.1.2 Object-Creation Syntax

object object_name is a class {image_name} {object-parameters...}


declare new and initialize existing properties
define accelerator keys
define new and augment existing procedures and functions
create additional objects
end_object

5.1.3 Procedure- and Function-Definition Syntax

If a message handler is augmenting an existing message, the message


should be forwarded as shown in {braces}.

procedure procedure_name type1 arg1 ... ... typeN argN


{forward send procedure_name arg1 ... argN }
: // statements to perform when this procedure is executed
end_procedure

188 Developing Applications with DataFlex


function function_name type1 arg1 ... typeN argN returns return_type
local variable_type name ...
{forward get name arg1 ... argN to value}
: // statements to execute when this function is called
function_return value
end_function

5.1.4 Message-Sending Syntax

Messages are sent to objects as follows. If the object name is omitted,


the current_object (the object that is sending the message) receives
the message.

send procedure_name {to object_name(current_object))} arg1 ... argN

get function_name {of object_name(current_object))} arg1 ... argN to value

5.1.5 Property Syntax

Properties are created and their values are assigned and queried
with the following syntax:

property type property_name public value

set property_name {item item_number} to value {value2 ...}

get property_name {item item_number} to value

5.1.6 Accelerator-Key-Definition Syntax

on_key key_name send message {to (object(current_object))}

5.2 The Data-Set Class

Data-set objects coordinate activity between the database, other data-


set objects, and user-interface objects. The generic data-set class
provides these capabilities. Before using a data set, you will first want

5 The High-Level Classes 189


to take this generic class and create a custom data-set subclass for
every file in your database. Each custom subclass will contain all of
the business rules for the data file. The method for creating data-set
objects and the methods for connecting these objects to user-interface
objects is fully discussed in the next chapter.

The data-set class helps the developer to separate the functions of


database design and user-interface design. When you are creating
data-set subclasses, all of your attention is focused towards your data
files and their business rules. You code these rules into your data-set
subclasses by setting properties and augmenting special "hook"
procedures and functions. These hooks are designed to give you
control over database operations (find, save, delete and clear) at critical
points. Some of the properties, procedures and functions you are likely
to set and augment are:

5.2.1 The Main_file Property

This is the file number of the data file. All data-set operations will be
centered around this file.

5.2.2 The Cascade_delete_state Property

This determines if a data set will delete child records or disallow a


delete when child records exist. This also requires the use of the
add_client_file message.

5.2.3 The Smart_filemode_state Property

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.

190 Developing Applications with DataFlex


5.2.4 The Update, Backout, Creating, and Deleting Procedures

These messages allow you to assign and maintain balances during a


save or delete operation. These might be counters, record ids, or
relational balances.

5.2.5 The Validate_save and Validate_delete Functions

Before a save or delete transaction is processed, one of these functions


is called for their respective operations. If the function generates an
error or the function returns a non-zero value, the operation is
canceled. This provides an important hook allowing you to validate all
critical data before committing it to or removing it from disk.

Below are two sample data-set subclasses that contain typical


properties, procedures and functions:

// 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

5 The High-Level Classes 191


// OrderHea_Data_Set Class
//
// 1. Increment & assign system number, if it is a new order.
// 2. Adjust Customer Balances (Pur_Year, Due) on saves
// edits, and deletes.
// 3. Check that order id is assigned.
//
Class OrderHea_Data_Set is a Data_Set
Procedure Construct_Object Integer Img#
Forward Send Construct_Object Img#
Set Main_File to Orderhea.File_Number
Set Smart_FileMode_State to true
Set Cascade_delete_State to TRUE // we allow cascade deletes
// List all required child (client) files
Send Add_Client_file OrderDtl.File_Number
End_Procedure // Construct_Object
procedure Update
Forward Send Update
Add Orderhea.Total to customer.pur_year
Add Orderhea.Total to customer.due
End_procedure
Procedure Backout
Forward Send Backout
Subtract Orderhea.Total from customer.pur_year
Subtract Orderhea.Total from customer.due
End_procedure
function validate_save returns integer
local integer retval
// order ID can not be 0
if orderhea.id eq 0 ;
error 300 "You must assign an order number."
forward get validate_save to retval
function_return retval
end_function
End_Class

When a save or a delete is processed through a data set, it is processed


as a single transaction. A save will save a main-file record and one
record each in any number of ancestor files. A delete will delete a
main-file record, possibly delete all related descendant-file records and
update numerous ancestor-file records. These events occur as a single
transaction. The data set handles all multi-user requirements by
locking all files involved in the transaction. If an error occurs at any
time during a save or delete, the entire transaction is rolled back and
the data set and data files are restored to their pre-operation status.
This protects your data from expected and unexpected errors. Both the
database-locking and transaction-rollback processes are automatic.

192 Developing Applications with DataFlex


5.2.6 Constraints in Data Sets

A constraint is a restriction on what records in a file are visible to an


application. There are three reasons that you may want to constrain a
file in a data set:

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.

3. An application may only be concerned with a subset of records


at any one time. You could specify customers in a given region
and/or tax bracket. An arbitrary 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.

Constraints are placed inside a constraint block, which consists of the


begin_constraints command, followed by one or more constraints,
and ending with an end_constraints command. Each constraint is
defined with the constrain command. Multiple constraints are
additive. Below are examples of the different types of constraint
syntax.

constrain file relates to parent-file

constrain file.field <op> value <op> = lt, le, eq, ge, gt, ne,
contains, matches.

constrain file.field between low_value and hi_value

constrain file.field as (expression)

5 The High-Level Classes 193


The following shows a data-set object with a constraints block.

object detail_ds is a detail_data_set no_image ;


updating (header_ds(current_object))
begin_constraints
constrain detail relates to header
constrain detail.Status eq "A"
end_constraints
end_object

5.3 The Data-Entry Classes

The data-entry classes allow you to easily create "data-aware" user-


interface objects including forms, tables, look-up lists, check boxes,
radio boxes, and text editors. Some of the features of the data-entry
classes are:

• Provide for CUA-compliant user interface


• Record additions, deletions, editing, and viewing may be
performed all in one program
• Transparent access to multiple related files
• Finding of records by any key in any file
• Multiple display objects (images or pages) per file
• Separation of database and user interface requirements
• Text editing areas for note fields
• Form or list views of record data
• Pop-up areas for look-up lists, warnings, and record details
• Navigation via mouse or keyboard
• Easy integration of data entry with other UI components and
programs
• Multiple "views" of the database

5.3.1 Summary of the Major Data-entry Classes

entry_form This is used for form-based data-entry


needs. It supports the finding, saving
and deleting of data.

194 Developing Applications with DataFlex


table This is used for table-based data-entry
needs. Records are displayed in rows
in a scrolling table. It also supports
the finding, saving and deleting of
data.

text_window This is used for entering data into text


fields. Unlike tables and entry forms,
the text-window objects operate on a
single data field. These objects are
almost always placed inside an
entry_form or a table object.

selection_list Selection lists are displayonly tables.


They are often used to pop up data-
file lookup lists. Users search through
the list for the desired record and
select it. This returns the record to the
form or table that popped up (or
invoked) the list.

selection_list_row This is a subclass of


selection_list. It supports the
highlighting of entire rows.

pick_list Pick lists are used to display and


select items from a static list.

code_pick_list This is a subclass of pick_list. It


can provide DEO items that invoke it
additional services such as validation
and prompting.

code_selection_list This class combines the advantages of


code_pick_list (DEO services)
with those of selection_list (use
of a database file for its items).

radio_entry_form This class allows you to create a menu


or list of available choices for an entry
database item. You may create the

5 The High-Level Classes 195


value of the display description and
its corresponding database value.

code_radio_entry_form This class offers the same functionality


as radio_entry_form, but uses a
dedicated (separate) database file for
its code and display values.

entry_client The entry client is a grouping class. It


allows you to place DEOs inside a
container. You usually use these for
navigational purposes.

entry_view_client This is a specialized version of the


entry_client class. It is used to
create a view. All other DSOs and
DEOs should be encapsulated inside
the view object.

selection_list_client When you need to encapsulate a


selection list inside a client, you
should use this class.

5.3.2 Syntax of the Major Data-Entry Classes

The most-commonly used data-entry classes are


entry_view_client, entry_client, entry_form, text_window,
table and selection_list. The syntax for objects of these classes
is listed below:

Entry_view_client

Object obj_name is an entry_view_client [image |no_image] ;


{action_bar actionbar} ;
{popup}

//likely properties to set


Set Location to row column // if image exists
Set auto_locate_state to True // if image & a popup
Set allow_move_state to True

196 Developing Applications with DataFlex


// set verify messages which child DEOs will use
Set verify_data_loss_msg to vdlm_name
Set verify_delete_msg to vdm_name
Set verify_exit_msg to vem_name
Set verify_save_msg to vsm_name

// define properties needed by all child objects


property ......
:
// create DSOs as needed
object obj_name is a DSO_class
:
// create DEOs as needed
object obj_name is a DEO_class
:
end_object

Entry_client

Object obj_name is an entry_client [Image |no_image] ;


{popup} ;
{ring} ;
{using (data_set_obj(current_object)) }

//likely properties to set


Set Location to row column // if image exists

// set verify messages which child DEOs will use


Set verify_data_loss_msg to vdlm_name
Set verify_delete_msg to vdm_name
Set verify_exit_msg to vem_name
Set verify_save_msg to vsm_name

// define properties needed by all child objects


property ......
:
// create child DEOs as needed
object ....
:
end_object
end_object

5 The High-Level Classes 197


Entry_form

Object obj_name is an Entry_form image_name ;


{using (File_DS(current_Object))}

//likely properties to set


Set Location to row column relative
// set verify messages which child DEOs will use
Set verify_data_loss_msg to vdlm_name
Set verify_delete_msg to vdm_name
Set verify_exit_msg to vem_name
Set verify_save_msg to vsm_name

// create item list


item_list
:
end_item_list

// define all needed iEntry, iExit, iValidate handlers


:
// create child objects
object obj_name is a DEO_class
:
end_object

Text_window

Object tw_obj_name is a text_window for file.field


Set Location to row column relative
Set size to height width
end_object

Table

Object obj_name is a Table image_name ;


{using (data_set(current_object)) } ;
{by index.#}

198 Developing Applications with DataFlex


//likely properties to set
Set Location to row column relative
Set wrap_state to TRUE
Set child_table_state to TRUE
// set verify messages which child DEOs will use
Set verify_data_loss_msg to vdlm_name
Set verify_delete_msg to vdm_name
Set verify_exit_msg to vem_name
Set verify_save_msg to vsm_name

// create a row item_list


begin_row
:
end_row

// define all needed iEntry, iExit, iValidate handlers


:
// create child objects
object obj_name is a DEO_class
:
end_object

Selection_list

Object obj_name is a selection_list image_name popup ;


main_file filename by Index.#
set Auto_locate_state to True
set allow_move_state to True
set auto_index_state to True
begin_row
entry_item File.field { Autoclear }
:
end_row
end_object

5.3.3 Items in Data-Entry Objects

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

5 The High-Level Classes 199


used to connect an item with a database file and field. The
entry_item command also supports a number of options that
provide item formatting, validation, entering, exiting, and prompt
control. In entry_forms the entry_item commands are placed
inside an item block (item_list/end_item_list). In
selection_lists and tables, the entry_item commands are
placed inside of a row block (begin_row/end_row). The syntax for
these blocks is shown below.

item_list
entry_item file.field {item_options}
:
end_item_list

begin_row
entry_item file.field {item_options}
:
end_row

A calculated entry item may be created as follows:

entry_item (expression)

5.3.4 Entry-Item Options

In order to allow many of the commonly desired actions to occur


when users enter or leave a window, formatting and validation options
are available for entry items. The standard options that were used with
the procedural DataFlex entry command can be used with entry
items, as well as options that are used for entry items only. Many of
these options affect the settings of item properties.

Entry-Item Options Function


autoback Moves the selection cursor to previous item
when the l bor key is pressed
with the cursor on the first character of the
item window.

autoclear Automatically clears the remaining data from


the item when the first character typed is
printable.

200 Developing Applications with DataFlex


Entry-Item Options Function
autofind Causes a find eq operation to occur,
searching for a record that matches the data
in the items.

autofind_ge Causes a find ge operation to occur, in


the same manner as the autofind
option.

autoreturn Moves the selection cursor to the next item


when the last character in the entry window
is typed or when the r key is pressed with
the cursor on the last character of the item
window.

capslock Forces all keyboard entry into the window to


be capitalized.

check=check_string Restricts the data that can be entered into


the window to a matching sub-string of the
check_string.

displayonly Disallows entry into this item and prevents


changed item data being moved to the
record buffer.

findreq Disallows moving past the item if there is no


active record in the buffer of the file for the
field associated with the item.

forceput Forces data for the item to be moved to the


record buffer during the save operation.

ientry=message_id Specifies the message to send when the


item is becoming the current_item.

iexit=message_id Specifies the message to send when


another item is becoming the
current_item after this one.
ivalidate=message_id Specifies the message to send when the
item is validated. This occurs during forward
navigation of items and during the save
operation.

iprompt=object_id Specifies the object that should be popped


up when the prompt key is pressed while
the item is the current_item.

5 The High-Level Classes 201


Entry-Item Options Function
izoom=object_id Specifies the object that should be popped
up when the zoom key is pressed while the
item is the current_item.

noenter Prevents the item from becoming the


current_item via user navigation.
noput Prevents data from the window from being
moved into the record buffer during the save
operation.

points=precision Formats the entry window to use the


specified number of digits to the right of the
decimal point. This is normally specified by
using a period in the appropriate position in
the entry window.

range=low,high Restricts the entry of a numeric or date


window to a specified range of values
between low and high.

required Disallows forward navigation when the


item’s value is blank or zero.

retain Prevents the item from being cleared by the


normal clear operation.

skipfound Prevents the item from becoming the


current_item via user navigation if the
record buffer for the file that the item is
associated with is holding an active (found)
record.

retainall Prevents the item from being cleared when


the normal clear or the clear_all
operation.

thousands Adds thousands delimiter to numbers.

202 Developing Applications with DataFlex


Example:

object credit_types is a table credit_types_image ;


using (customer_ds(current_object))
begin_row
entry_item customer.company { autofind, capslock, findreq }
entry_item customer.title { skipfound }
entry_item customer.zip { displayonly }
end_row
end_object

This example shows how multiple entry_item options can be used


on entry items. While any number of options may be used together on
one entry_item, the purposes of some options conflict, while others
make no sense when used together. For example, noput and
forceput are, in effect, opposites, while capslock and
displayonly cannot really work together, as capslock depends on
user input being performed, while displayonly disallows operator
input altogether.

5.3.5 Using Item-Entry, -Exit, and -Validate Messages

Item-entry messages are normally used to set up defaults or to set


some property of the object indicating that the user has entered some
significant portion of the object. Item-exit messages are typically used
to set properties that indicate that data entry has progressed past a
certain point. This property could then be checked in item-entry
messages and in other parts of the program, as required.

If the standard entry-item options cannot perform the type of


validation you require, you will need an item-validation message for
the item. Normally when an item fails validation, your validation
function should generate an error and return a non-zero value. Note
that the item validate message is sent during forward navigation and
during a save.

The message specified in the ientry=, iexit=, or ivalidate=


option must contain the message prefix, which is msg_ for a procedure
and get_ for a function. The procedures or functions that are used for
item-entry, -exit, and -validate messages will be passed an integer
containing the item number being entered, exited, or validated.
Returning non-zero indicates that the item may be not be entered, or
exited, or it is invalid

5 The High-Level Classes 203


Example:
object cust_form is an entry_form
// if message is referenced before it is defined we must forward
// reference the message.
register_function check_area_code integer item_num returns integer
item_list
entry_item customer.id {autofind}
:
entry_item customer.area_code {capslock, ivalidate =get_check_area_code}
:
end_item_list
function check_area_code integer item_num returns integer
local integer ret_val
local string val
get value item item_num to val
if (length(val) <3) move 1 to ret_val
else if not (mid(val, 1, 2)) in "01" move 1 to ret_val
if ret_val ne 0 error 15 "Area Code"
function_return ret_val
end_function
end_object

5.3.6 Using Prompt and Zoom Objects

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

5.3.7 Confirming Data-Entry Operations

Often user confirmation is required before an important data-entry


operation should be carried out. The data-entry objects have special

204 Developing Applications with DataFlex


messages that can be set to determine what type of confirmation, if
any, should occur before a save, delete, clear, or an exit. The data-entry
verification properties that correspond to those events are
verify_save_msg, verify_delete_msg,
verify_data_loss_msg and verify_exit_msg. A number of
functions defined in a package named CONFIRM.PKG provide
common validation prompts. You must assign the appropriate function
message to the appropriate data-entry-verification property. A data-
entry object will inherit the verification messages of its parent. Usually
you will assign a single set of verification messages to a parent (view
object), causing all child data-entry objects to share the same messages.
The function messages available are listed below.

Get_Save_Confirmation Save this Record?


Get_Delete_Confirmation Delete this Record?
Get_Line_Save_Confirmation Save this Line?
Get_Line_Delete_Confirmation Delete this Line?
Get_Data_Loss_Confirmation Abandon Changes?
Get_Exit_Loss_Confirmation Changes Exist. Exit this
window?
Get_No_Confirmation no message

A data-entry object should contain code that looks like the following:

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

5.4 Some Sample Data-Entry Objects

We will conclude this chapter by showing some sample data-entry


objects. These samples are presented out of context. Little information
is presented about how these objects relate and connect to other
objects. Without this information, you cannot predict how these objects
will behave. This will be covered in the next chapter.

5 The High-Level Classes 205


object contact_info is an entry_form contact_info_image
set location to 2 0 absolute
item_list
entry_item customer.company {capslock, autofind, ;
iprompt=(cust_sl(current_object)) }
entry_item customer.title { iprompt=(cust_sl(current_object)) }
entry_item customer.zip { retain, iValidate=get_check_zip }
end_item_list
end_object // entry_form

object status_codes_maint is a table status_codes_img ;


main_file statcode by index.1 ;
using (statcode_ds(current_object))
set location to 5 5
set wrap_state to true
Set verify_save_msg to get_no_confirmation
set verify_delete_msg to get_line_delete_confirmation
begin_row
entry_item statcode.id { capslock, required }
entry_item statcode.description
end_row
end_object // table

Object comments_editor is an entry_client comments_editor


set location to 10 10 relative
object text is a text_window for dar.Memo
set location to 1 1 relative
set size to 5 30
end_object // text_window
end_object // entry_client

object Reported_by_lkup is a selection_list Repbylkup_prompt_list popup ;


main_file reportby
set allow_move_state to true
set auto_locate_state to true
set auto_index_state to true
begin_row
entry_item reportby.Reported_by { autoclear }
entry_item reportby.Name { autoclear }
entry_item reportby.Company { displayonly }
end_row
end_object // selection_list

206 Developing Applications with DataFlex


object pgmr_form is an entry_form pgmr_form ;
using (progrmr_ds(current_object))
set location to 3 10 relative
set allow_move_state to true
item_list
entry_item manager.Manager_id { autoclear, capslock, ;
autofind, findreq, ;
iprompt=(mnger_lkup(current_object)) }
entry_item manager.Name { displayonly }
entry_item progrmr.Programmer { autoclear, autofind, capslock, ;
ivalidate=get_validate_key_field, ;
iprompt=(pgmr_lkup(current_object)) }
entry_item progrmr.Name { iprompt=(pgmr_lkup(current_object)) }
entry_item progrmr.Office_phone
entry_item progrmr.Home_phone
entry_item progrmr.Nrml_office_hrs
entry_item progrmr.Nrml_sleep_hrs
end_item_list
object comments is a text_window for progrmr.Comments
set location to 10 3 relative
set size to 5 30
end_object // text_window
end_object // entry_form

object programmer_entry is an entry_view_client no_image ;


action_bar (main_menu(current_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
// create data-set objects
:
// create data-entry objects
:
end_object // entry_view_client

5 The High-Level Classes 207


DEVELOPING APPLICATIONS WITH DATAFLEX®

Revision 3.1

Copyright © 1995 Data Access Corporation

DATA ACCESS CORPORATION


Miami, Florida USA

Technical Support: (voice) 305.232.3142


(FAX) 305.238.0017
CompuServe Forum: GO DACCESS

Revision Date: October 18, 1995


COPYRIGHT NOTICE

Copyright 1995 Data Access Corporation.

No part of this manual, including (without limitation) the


accompanying software, which is an integral part of this product, may
be reproduced, transmitted, transcribed, stored in any manner in a
retrieval system, or translated into any human or computer language,
in any form or by any means, electronic, mechanical, magnetic, optical,
manual or otherwise, or disclosed to third parties without the express
written permission of the holder(s) of the copyright identified above.

DISCLAIMER

Data Access Corporation makes no representation or warranties,


express or implied, with respect to the software or manual which
constitute this product, including but not limited to warranties of
merchantability or fitness for a particular purpose.

The publisher(s) reserves the right to make changes, enhancements,


revisions and alterations of any kind to this manual and/or its
accompanying software without obligation to notify any person,
institution, or organization of such changes, enhancements, revisions,
and alterations.

TRADEMARKS

DataFlex and FlexQL are registered trademarks of Data Access


Corporation.

All other brand and product names are trademarks or registered


trademarks of their respective companies.
210 Developing Applications with DataFlex
CONTENTS

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

3 THE APPLICATION FRAMEWORK . . . . . . . . . . . . . . . . . . . . . . . . . . 25


3.1 Application Components . . . . . . . . . . . . . . . . . . . . . . . . 25
3.2 The Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2.1 Class and Object Packages . . . . . . . . . . . . . . . 27
3.2.2 Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.2.3 Prototyping Views with AutoCreate . . . . . . . . 30
3.2.4 Creating a View . . . . . . . . . . . . . . . . . . . . . . . 31
3.2.5 Selection Lists . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.3 Running a Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

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

5 THE HIGH-LEVEL CLASSES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187


5.1 A Quick Review of Object-Oriented Syntax . . . . . . . . . 188
5.1.1 Class-Creation Syntax . . . . . . . . . . . . . . . . . . 188
5.1.2 Object-Creation Syntax . . . . . . . . . . . . . . . . . 188
5.1.3 Procedure- and Function-Definition
Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
5.1.4 Message-Sending Syntax . . . . . . . . . . . . . . . . 189
5.1.5 Property Syntax . . . . . . . . . . . . . . . . . . . . . . 189
5.1.6 Accelerator-Key-Definition Syntax . . . . . . . . 189
5.2 The Data-Set Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
5.2.1 The Main_file Property . . . . . . . . . . . . . . . . . 190
5.2.2 The Cascade_delete_state Property . . . . . . . . 190

ii Developing Applications with DataFlex


5.2.3 The Smart_filemode_state Property . . . . . . . . 190
5.2.4 The Update, Backout, Creating, and
Deleting Procedures . . . . . . . . . . . . . . . . . 190
5.2.5 The Validate_save and Validate_delete
Functions . . . . . . . . . . . . . . . . . . . . . . . . . 191
5.2.6 Constraints in Data Sets . . . . . . . . . . . . . . . . 193
5.3 The Data-Entry Classes . . . . . . . . . . . . . . . . . . . . . . . . 194
5.3.1 Summary of the Major Data-entry Classes . . 194
5.3.2 Syntax of the Major Data-Entry Classes . . . . 196
5.3.3 Items in Data-Entry Objects . . . . . . . . . . . . . 199
5.3.4 Entry-Item Options . . . . . . . . . . . . . . . . . . . . 200
5.3.5 Using Item-Entry, -Exit, and -Validate
Messages . . . . . . . . . . . . . . . . . . . . . . . . . 203
5.3.6 Using Prompt and Zoom Objects . . . . . . . . . 204
5.3.7 Confirming Data-Entry Operations . . . . . . . . 204
5.4 Some Sample Data-Entry Objects . . . . . . . . . . . . . . . . . 205

6 INDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209

Table of Contents iii


iv Developing Applications with DataFlex
6 INDEX

Access methods Delegation


delegation and 36 and object access methods 36
desktop 39 Delete_confirmation function 205
for objects 33 DEOs
Allentry package 39 connecting to DSOs 36
Allrpt package 166 Desktop access method 39
Assembling views 26 DSOs
Base classes 42 access method for views 36
Business Rules 106 Encapsulation
Class package 27 and Views 31
Classes Entry item
base 42 options, function 200
high-level 42 High-level classes 42
Confirmation objects Item
package definition for 39 entry item options 200
Constraints Messages
Framework method for exit, using 203
defining 33 item entry, using 203
purpose 193 validate, using 203
Container objects 31 Method
Creating a view object 40 Framework 25, 26
Data entry objects Object package 27, 28
use of database fields 199 for Views 37
using 22, 23, 188 selection_list 41
Data sets Objects
and views 37 access method 33
Data-entry objects access methods for 36
and views 37 Package
placing in views 35 allentry 39
structuring in views 31 allrpt 166
Data-set structures test 40
coding for views 35 Packages
Data_sets class 27
defining in Views 33 object 27, 28
structuring in Views 31 Prompt
Database using objects 204
fields in data entry objects 199 Prototyping 31

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

vi Developing Applications with DataFlex

Vous aimerez peut-être aussi