Tutorials

Introduction

The Tutorials introduce several important areas of developing with Visual DataFlex Studio. Each section discusses the development of specific features using a series of steps. This provides a hands-on introduction to major features of Visual DataFlex Studio in a clear and ordered manner.

  • Start by reading the Overview of Visual DataFlex to learn about the major concepts behind Visual DataFlex. It also points you to additional sources of information about the tools and features available in Visual DataFlex.

  • Quick Start provides an introduction to Visual DataFlex Studio to get you started using the product right away.

  • Creating Basic Application Components demonstrates how to develop major application component types for Windows and Web applications.

  • Creating a Complete Order Entry System demonstrates, in detail, how to create a complete Order Entry system, like the Order Entry sample application.

Who Should Work Through The Tutorials?

Every Visual DataFlex developer should work through some parts of the tutorials, and through QuickStart at least once. Even if you are an experienced DataFlex developer, this short tutorial will familiarize you with the major Studio components and show you how we expect developers to use our tools.

Information Resources for Application Developers

You can find information on Visual DataFlex in the following ways:

  • Help System

  • Context Help (F1)

  • Sample Applications

  • Data Access Worldwide Support Services and Web Site

  • Visual DataFlex Community Newsgroups

For information about new features in this release, refer to What’s New in the online Help Contents and to the www.VisualDataFlex.com Web site.

Help System

The Online Help system is the most comprehensive information resource for users of Visual DataFlex. Online Help is updated with each release to include the latest features. It provides detailed information about user interface design, language implementation, programming tasks, and the components. It includes the Language Guide, reference material, and a host of topics covering all of the features available in Visual DataFlex.

To look up the components or any other topic, click the Index or Find tab and type your request.

Context Help (F1)

You can get context sensitive Help on any part of Studio, including the code editor, object properties window, dialog boxes, toolbars, and components by and pressing F1.

Sample Applications

Visual DataFlex includes sample applications for Windows, Web, Client-Side Web Services and Server-side Web Services. The purpose of the Sample Applications is to provide you with programs that you can run to see their operation, and then view the applications in Studio to see how they are constructed. The source code for the Sample Applications contains comprehensive comments to aid understanding and provides a rich source of code snippets that can be cut and pasted into your applications.

You run the examples from the "Visual DataFlex 12 | Examples" Start menu. See Learning from the Examples for information about the operations and techniques illustrated in each of the samples.

Data Access Worldwide Support Services and Web Site

www.dataaccess.com/support describes a variety of support offerings and facilities for Visual DataFlex developers, including support policy definitions, information about supported operating systems and product revisions, White Papers, on-line forms for submitting and tracking bugs and suggestions and access to our Developer Community Newsgroups. The Web site also contains the Data Access Worldwide “Knowledge Base” – a comprehensive, searchable library of information about the development, deployment and use of Visual DataFlex and Visual DataFlex applications. We suggest that you add the following link to your browser’s "Favorites" www.dataaccess.com/kbase.

Visual DataFlex Community Newsgroups

Public Newsgroups are available for all Data Access Worldwide products and related topics of interest. The Newsgroups offer a rich resource of information contributed by Data Access Worldwide and thousands of users around the world.

You can access the Visual DataFlex specific newsgroup at:

news://news.dataaccess.com/visual-dataflex

A search engine (WASP) for the Visual DataFlex newsgroups is located at:

http://www.sture.dk/wasp/login.asp


Overview of Visual DataFlex

What is Visual DataFlex?

Visual DataFlex is an advanced software tool designed for building dynamic, database independent applications for Windows and the World Wide Web.

Visual DataFlex is loaded with the advanced features that developers demand, including an advanced Studio for fast, easy visual development, easy integration of COM Automation and Active-X controls, Data Aware Controls without the need for custom programming, Data Dictionary Objects that encapsulate your business rules and validations for unmatched data integrity, reusable components, automatic multi-user applications, and increased ROI through a proven client/server database application architecture.

Professional developers use Visual DataFlex to create high-performance database applications for Windows and the Web. While developers can use Visual DataFlex for creating many types of programs, it is specifically geared for writing database applications.

One of the key differences between Visual DataFlex and other development environments is in the strength of the Visual DataFlex application interface presented to users entering data — the core of all database applications.

With Visual DataFlex Studio's application framework, class library and rich set of pre-programmed controls and components, the design and implementation of Windows and Web applications is a structured, well managed process. The Application Framework is designed to help you use Visual DataFlex to do what you want—quickly, reliably, and easily.

The visual design tools built into the Studio automatically generate fully customizable application components, such as data entry views, data entry web pages, Windows and Web-based reports. Visual DataFlex applications promote efficient data entry and processing for application users, while the Visual DataFlex tools provide capable design, implementation, and maintenance for application developers.

Visual DataFlex Studio allows you to develop Windows, Web and Web Services applications for Microsoft SQL Server, Pervasive.SQL, IBM DB2, any Open Database Connectivity (ODBC) data source and the embedded database. Visual DataFlex applications can use multiple databases or data sources concurrently within a single application. The "embedded database" is an efficient, high-performance multi-user database especially well suited for transaction processing. One of the strengths of Visual DataFlex is its ability to create applications that are database independent – they are transportable from one database environment to another without changing your application.

Visual DataFlex also provides facilities for configuring the date format, currency characters, numeric punctuation, and other local parameters, so that programs can be moved from one national environment to another and adapted for local use easily and without programming changes.

See Also

The Visual DataFlex Language

Data Dictionaries

The Tools

The Visual DataFlex Classes


The Visual DataFlex Language

At its core, Visual DataFlex is a language-based system. The Visual DataFlex language is the language used to create source code for Windows, Web and Web Services applications. Visual DataFlex Studio will generate much of your Visual DataFlex language source code for you. Then, using the Visual DataFlex language, you have the option to edit, modify and extend the generated source code.

The Visual DataFlex language is object-oriented, with a class library containing many predefined classes for Windows, Web and Web Services development. Developers work in Visual DataFlex Studio with objects created either from the integrated class library or from their own custom classes. Classes and objects support predefined and custom functions and properties.

Visual DataFlex source code is contained in simple text files that can be generated by tools supplied with Visual DataFlex, or written and edited with any text editor. Visual DataFlex Studio is designed to provide the full scope of capabilities that you will need to generate, write and edit all files associated with developing applications. Studio is the recommended tool for developing applications with the Visual DataFlex language.

Compiled program files (with the extension .EXE) are created with the Visual DataFlex compiler from source code files. The programs are then executed with the Visual DataFlex Client Engine.

We recommend that you learn more about the Visual DataFlex language in the Language Guide.


Data Dictionaries

Data Dictionaries are at the core of Visual DataFlex database applications. Your application database rules are expressed through and managed by Data Dictionaries. Data Dictionaries serve two main purposes:

  • Coordinate database activity among data-aware controls

  • Provide database validation and update services to a program

Data Dictionary classes are maintained in the Database Builder tool. Many business rules can be maintained here visually, but you also get unlimited flexibility by being able to customize and add to the Data Dictionary class code. You can further customize the code for each Data Dictionary Object (DDO) that is in a specific component, for example, a data entry view or web report.

You can create a set of Data Dictionaries for a particular project and define business rules in it that are shared across the entire project, whether they are used in Windows, Web or Web Services applications.

Read more about Data Dictionaries here.


The Tools

Visual DataFlex Studio

Studio is a single, integrated development environment specifically designed for developing Windows and Web database applications. Studio manages its projects inside workspaces, and coordinates all of the other tools that make up Visual DataFlex, so that they can be cohesively applied to a project. The finely tuned interaction among Studio's components enhances developer productivity; Data Dictionaries and Business Process Objects eliminate huge amounts of redundant, high maintenance code. Visual DataFlex Studio works efficiently for developers as they build, maintain, change and evolve applications.

In the Studio, you design applications and application components, such as data entry views, report views, web service objects, web reports, business process objects, etc. Studio also lets you configure and maintain Data Dictionary structures for your components.

Studio includes many wizards that allow you to quickly and easily create very complex, sophisticated database-oriented components, such as:

  • Header / detail data entry views for tables with that have child records that should be represented in a grid. This wizard allows you to preview the resulting view and customize its layout before completing the wizard.

  • Windows reports with breakpoint, subtotal and filtering features. This wizard allows you to preview the resulting report and customize its layout before completing the wizard.

  • Web report and web child report wizards to create polished web reports with advanced features like drilling down into report record details.

Each component is fully customizable in the Studio, whether created via a wizard or in the Studio's visual designer.

A full featured debugger is integrated into the Studio. It provides full source level debugging, flexible breakpoints, flexible program stepping options, message tracing, inspection of local variable values, tables and rows and expressions.

Database Builder

Database Builder is where you create and maintain the data dictionary classes for each table, which control the business rules for your projects across the range of Windows, Web and Web Services applications. Database Builder also provides an interface for extensive control over database tables and their relationships to each other.

Visual DataFlex Compiler

The compiler takes the DataFlex source code and creates executable files to be used with the Visual DataFlex virtual machine. The compiler 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.

Database Explorer

Database Explorer is a tool that lets you open any table (embedded or foreign via installed database connectivity kits) and view data in those tables. Besides the data, you can watch their column definitions, indexes and attributes. If you have the right permissions (network and tool), you can edit data. Viewing and editing of data is available in a grid-wise representation of the data and in a single record approach. A filter option is available to filter the data on certain criteria. This will make the number of records seen smaller and offer you a closer look at the data.

Finally, there is a wizard that guides you through exporting data to several formats (CSV, line delimited, fixed position and XML). The wizard can do a direct export or create a program (component) to repeat the export later.


The Visual DataFlex Classes

Visual DataFlex Classes

The Visual DataFlex class library contains many classes for Windows, Web and Web Services development. This page discussed some of the most commonly used classes.

A Visual DataFlex Windows application is normally made up of the following parts:

  • A main panel, which serves as the outermost container for most other components of a Windows application. This panel contains a number of supplied and easily configured components: a menu-bar system, a tool-bar system, a status-bar system, and a client area.

  • A client area is an MDI (Multiple-Document Interface) parent window. It contains views (main user-interaction areas, such as data entry views and views that launch reports) and modal popup panels (data lookup lists and dialogs).

  • A data entry view will consist of data-dictionary objects (DDOs) and data-entry objects (DEOs) that use the services of the data dictionaries.

A Visual DataFlex Web application is normally made up of the following parts:

  • A Web Application object serves as an outer "wrapper", which contains one or more web objects (WOs).

  • Web Objects can be either Web Browser Objects (WBO) for applications interacting with browsers and thin clients or Web Service Objects (WSOs) for serving Web Services.

A Visual DataFlex Web Services application is normally made up of the following parts:

  • A Web Application object serves as an outer "wrapper", which contains one or more web objects (WOs).

  • Web Objects are Web Service Objects (WSOs) for serving Web Services.

For many of the user-interaction classes, there are 2 class versions available, a data aware version and a non-data-aware version. The data-aware version is usually preceded by db (e.g. dbForm, dbGrid), while the non-data-aware version is not (e.g. Form, Grid). In most cases, the data-aware version of the class is better developed and can be used for non-data-aware purposes as well.

Below is a list is the most commonly used Visual DataFlex Classes. To view the complete Visual DataFlex class library, see the Class Reference.

Visual DataFlex Windows Application Classes

  • DataDictionary

  • dbCheckBox

  • dbComboForm

  • cDbTextEdit

  • cDbRichEdit

  • dbForm

  • dbGrid

  • dbGroup

  • dbList

  • dbModalPanel

  • dbSpinForm

  • dbView

  • Array

  • Button

  • cApplication

  • CheckBox

  • ComboForm

  • cTextEdit

  • cRichEdit

  • Form

  • Grid

  • Group

  • List

  • ModalPanel

  • Panel

  • Radio

  • SpinForm

Visual DataFlex Web Application Classes

  • DataDictionary

  • cWebApp

  • cWebBusinessProcess

  • cWebReport

  • cApplication

Visual DataFlex Web Services Application Classes

  • DataDictionary

  • cWebApp

  • cWebService

  • cApplication


Quick Start

Introduction

Quick Start provides an introduction to Visual DataFlex Studio to get you started using the product right away. This is a clearly defined starting point for you to get acquainted with the tools and framework that make Visual DataFlex so powerful.

Who Should Work Through QuickStart?

Every Visual DataFlex developer should work through some parts of the tutorials, and through QuickStart at least once. Even if you are an experienced DataFlex developer, this short tutorial will familiarize you with the major Studio components and show you how we expect developers to use our tools.

For step-by-step instructions on using Visual DataFlex to write Windows, Web and Web Service applications see:

Creating Your First Windows Application

Creating Your First Web Application

Creating Your First Web Service

Using Your First Web Service


Creating Your First Windows Application

This tutorial will guide you through the most basic steps of creating Windows projects using Visual DataFlex. Along the way, you will learn how to work with the main Visual DataFlex development tools. As you complete tasks, basic concepts will be explained to you.

This tutorial section will take you through the following steps:

  • Opening a Workspace

  • Creating a Windows Application

  • Compiling and Running a Windows Application

  • Creating Your First View

  • Handling Compiler Errors

  • Debugging Code in Windows Application


Opening a Workspace

Visual DataFlex applications are created and maintained in workspaces.

Workspace

A Visual DataFlex Workspace is a physical and logical container for your projects, with a well-defined structure. A Workspace can contain multiple projects, typically related in some logical manner, such as a Windows application and a Web application that access the same database. A workspace contains everything necessary to build and run a Visual DataFlex project.

Project

A Visual DataFlex Studio Project is a collection of components and other items of interest to the Studio that compiles into a target program.

For QuickStart, we have already provided you with a workspace. To save a lot of time and typing, the provided QuickStart workspace already has a set of tables and associated Data Dictionaries in it. To learn how to create a new workspace, see Creating a Workspace.

  1. Open the Visual DataFlex Studio. To do so, select Programs, then Visual DataFlex 12.0, then Visual DataFlex Studio from your Windows Start menu.

  2. Select Open Workspace... from the Studio’s File menu.

  3. Browse to C:\Program Files\Visual DataFlex 12.0\Examples\Quick Start in the Open Workspace dialog and select the file Quick Start.sws.

  4. Click the Open button or press the Enter key to open the workspace in the Studio.

Tip

  • You can also open a workspace in the Visual DataFlex Studio by finding the .sws file for the workspace in Windows Explorer and double-clicking on it.

  • To reopen a workspace you have previously opened in the Studio, select File, then Recent Workspaces from the Studio's menu.

Next Step

Creating a Windows Application


Creating a Windows Application

Let's create your first, very simple Windows application with Visual DataFlex.

Windows Application

A Windows application in Visual DataFlex is a Multiple-Document Interface (MDI) Application. The application is a container into which child components, such as data entry views and report views are placed.

There are numerous other features of Windows applications that Visual DataFlex creates for you, such as menus and toolbars. These features will be discussed in more detail in Standard Windows Application Features.

Creating a Windows Application

  1. Click on the Create New button on the Studio’s toolbar.

  2. Click on the Project tab of the Create New... dialog.

  3. Double click the Windows Project icon.

Tip:

You can use the Test Windows Project during development. This project has some special test features, such as auto-activation of views, automatic sizing of the main program panel and a Data Dictionary Inspector. You can also look at the source code of this type of project to see how to implement such features in your projects.

For this tutorial, please use the Windows Project instead, to be able to follow all of the steps in the tutorial as they are explained.

  4. The "Create a New Windows Project" dialog will open. Enter MyFirstWindowsApplication as the file name and click on the Save button. Accept the default location (the AppSrc folder in the QuickStart workspace) and the dialog will automatically add the .src extension to your filename (the extension for application components).

Naming a Project

A project, in this case a Windows application, might consist of one or more components, such as views, reports and various other components and objects. The name is usually something that identifies the whole project, such as the client company’s name, or maybe a description such as "Accounting System".

  5. You will now see the MyFirstWindowsApplication.src file open in the Studio's code editor.

  6. In the Code Explorer window, you will see an outline of the current source file in a tree. There are nodes that represent other source files that are used in this file, objects, and methods.

    If the Code Explorer window is not open, click on the Code Explorer toolbar button.

  7. Click on the Object Properties toolbar button to open the Object Properties window.

    As you click on different objects in the Code Explorer window, notice that the properties of the currently selected object are displayed in the Object Properties window.

  8. Select the oMain object, change the Label property to My First Application in the Object Properties window.

  9. Double-click on the oMain object in Code Explorer. The code editor window will place the edit cursor at beginning of the object declaration line for oMain (and bring that line of code into view in case it was scrolled off the page). You can see that the "set Label" statement reflects the change to the value of the Label property you just made in the Object Properties window.

  10. Change the set Label statement in the source code from My First Application to My First Windows Application. When you select the oMain object in Code Explorer again, you will see that the value of the Label property in the Object Properties window has been updated to reflect the source code change you just made.

You have now created your first Windows application. Of course, at this point, the application is only an empty container. Soon, you will learn how to add views and other components to it.

Compiling and Running a Windows Application


Compiling and Running a Windows Application

The next step is to compile, then run your application.

Compilation

Compilation is the process of creating an executable program from source code. The source code for any Visual DataFlex program needs to be compiled and linked into an executable (.exe) file before it can be executed (run).

  1. Click on the Compile Project button on the Studio's toolbar.

    You will see the embedded compiler display its progress in the Output window (if the Output window is not open, it will automatically open and move to the foreground when you compile).

The Compiler in Progress

You will see the Compiler including and compiling all the files specified in the source file being compiled. Visual DataFlex automatically includes any predefined library files your project needs when you create a new program in the Studio. These library files are typically called packages or "package files" in Visual DataFlex, since their extension is usually .pkg. See Package Filename Extensions for more information about packages.

  2. Once compiled without errors (you will see "----Compile Finished----" in the Output window), you can run your program.

    Click the Run toolbar button.

  3. Your application will run and appear like this:

Tip

You have another option for compiling and running your application in one step. If you simply click on the Run button on the Studio's toolbar, it will compile the program if changes were made to the source code that require recompilation, and then run the program, or simply run the program if recompilation is not needed.

You have just created and executed your first Windows application with Visual DataFlex. You can see that this application is an MDI container with menus and toolbars, but it is currently missing any child windows (the View menu has no items listed under it).

Close the program.

Creating Your First View


Creating Your First View

Now, let's create a view.

View

Views are one of the most commonly used components in Windows programs. They are used to create data entry screens and most other types of "screens" or "forms".

Creating a "Hello, World" view

We are going to illustrate some basic Visual DataFlex Windows application development techniques using a variation of the well-known "Hello, World" program, which is used as the first program to teach many programming languages.

The view you will create will be very simple, with 2 forms and a button. The first form will be labeled Name and the second form Result. The user will type his or her name into the Name form and click the button. The name will then be added to "Hello, ", resulting in "Hello, John" for example. This result will be placed in the second form.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the Data Entry View icon.

  2. The "Create a New Windows View Component" dialog will open. Enter oHelloWorld as the object name. Notice that the filename automatically changes to HelloWorld.vw as you type the object name. Accept the default directory path (the AppSrc folder in the QuickStart workspace). Click on the Ok button.

    You will now see the outline of a new view in the Studio's visual designer. It should look something like this:

  3. Take a look at the Workspace Explorer window. If Workspace Explorer is not open, click on the Workspace Explorer icon on the Studio's toolbar.

Workspace Explorer

The Workspace Explorer is a docking window that lists the current project and components included in the current project by type. Please read more about this in the Workspace Explorer topic in the Studio book.

  4. In Workspace Explorer, you should see MyFirstWindowsApplication.src as the Current Project. Click on the + in the tree view to expand MyFirstWindowsApplication.src, then click on the + to expand Views. You can see that HelloWorld.vw has been added to project MyFirstWindowsApplication.src.

  5. Click on the Class Palette button on the Studio's toolbar.

    This will bring up the Studio's Class Palette.

    Class Palette

    The Class Palette is a docking window that lists the controls available for use in the Studio for the current workspace. It is separated into different groups of controls based on the use and functionality of the controls in each group.

    The Class Palette is fully customizable. Please read more about this in the Class Palette topic in the Studio book.

  6. Drag and drop 2 Form controls from the Base Controls group on the Class Palette onto the blank view.

  7. Next, drag and drop a Button control from the Base Controls group on the Class Palette onto the view.

  8. Select the top first form control, then, while holding down the Ctrl key, select the other second form control. Right-click and select Align, then Left from the context menu. This will align the two forms so that their left edges are spaces the same distance from the left edge of the view.

  9. Select the button control, right-click and select Center, then Horizontally from the context menu. This will center the button horizontally on the view.

  10. Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, click on the View menu and then Hello World to open the view. Your running program will look like this:

    You can type text into the 2 form controls and you can click the button (although nothing happens when you do). Close the application.

  11. Select the first form control in the visual editor or Code Explorer and make sure the Object Properties window is open. Change the Name to oNameForm.

Object Names

It is very useful to give your objects meaningful names. The names oForm1 and oForm2 are not nearly as meaningful as oNameForm and oResultForm. In a more complex view, with dozens, or potentially hundreds of objects, having the ability to uniquely identify an object easily will save you time and effort.

We recommend using the prefix o for objects. You can read more about Visual DataFlex Naming Conventions in the Language Guide.

  12. Change the value of the Label property to Name and the value of the Label_Col_Offset property to 0.

    Click in the value column (the right column) for the Label_Justification_Mode property. Notice the combo form that allows you to select a value from a predefined enumeration list. The Studio will display different controls for each property based on the property type.

    Change the Label_Justification_Mode to JMode_Right.

    Changing the Label_Col_Offset property from 60 to 0 and the Label_Justification_Mode to JMode_Right aligns the label directly to the left of the form control, regardless of the length of the label (the label will extend as far to the left as needed).

Tip

You can see the documentation for any property by clicking on the property in the Object Properties window and pressing F1. This will take you directly to the Visual DataFlex help entry for the selected property.

Object Properties

The Object Properties window is used to view and edit property values for the selected object in the Studio's designers, such as the visual designer and Code Explorer.

Notice that all the property values that have been modified from their default values are shown in bold. These are also the only properties that are written out to the code of the current source file.

To reset a property value to its default value, right click on the property name column in the Object Properties window and select Reset Value.

  13. Click on the second form control. Change the Name to oResultForm, the Label to Result, the Label_Col_Offset to 0, and the Label_Justification_Mode to JMode_Right.

  14. Click on the view object (you can click on the view's background or the caption bar to select it). Change the view's Label to Hello, World!.

  15. Click on the button object, change its Name to oGoButton and its Label to Go.

    The view should now look like this in the Studio:

Now you are going to add some source code to the controls in this view to give them their functionality.

  16. Double click on the oGoButton control in the visual editor or Code Explorer. This will open the code editor and display the code for HelloWorld.vw with the button's object declaration line highlighted.

Navigating Between Views in the Studio

There are multiple ways of navigating between open views in the Studio. As you already saw, double-clicking on an object in the visual designer or Code Explorer opens the code editor to the code for that object. You could also have clicked on the Code Editor toolbar button to switch from the visual designer to the code editor, although that would not have brought you immediately to the code for a specific object.

To switch back to the visual designer, you can click on the Visual Designer toolbar button. You can also press F7 to toggle between the visual designer and the code editor for any given file.

Tip:

You can scroll through all open views by using the Ctrl + + or Ctrl + - keyboard shortcuts.

Once you are working in a larger project and have multiple files open, it may become useful to leave the File Navigator window open as a docked window. If the File Navigator is not already open, you can open it by clicking on the File Navigator toolbar button.

For more information about navigating around the Studio, see the Studio help book.

  17. You will now add code to the oGoButton control.

A button control typically only uses one event: OnClick. This event is fired when the button is clicked. When you drag and drop a button control onto a component in the Studio, it already has the outline of this procedure in it for your convenience. If this procedure is empty, as it is here by default, nothing will happen when the button is clicked, as you saw when you tried it in the running program.

Type the following lines of code inside the already declared Procedure OnClick:

  1. The first line of code is:

string sName sHello sResult

This line of code declares 3 local string variables with names sName, sHello and sResult.

Variable Scope

The scope of a local variable is limited to the method (procedure or function) in which it is declared. You can "use" these variables, meaning that you can assign values to them and access their existing values only while in the current method, in this case Procedure OnClick. Attempting to reference variables outside of the scope in which they are declared will result in a compiler error.

Variable Names

Just as with object names, it is useful to give your variables meaningful names. The names x and y are not nearly as meaningful as sName and sResult. In a more complex method, with dozens of variables, having the ability to easily identify the meaning of a variable name will make you a more efficient programmer.

We recommend using the prefix s for all string variables. Prefixes like this also help in identifying the meaning of variable names. If you stick with this naming convention, you will never confuse a variable that holds a string with one that holds a number. You can read more about Visual DataFlex Naming Conventions in the Language Guide.

  2. The next line of code is:

get Value of oNameForm to sName

This line of code reads the value of the oNameForm Form object to the String variable sName. The current content of a Form control can be retrieved using a String property named Value.

The syntax for fetching a property's contents is:

get {PropertyName} of {ObjectName} to {VariableName}

CodeSense

CodeSense is a set of Studio features that intelligently assist you in writing code, providing lists of context sensitive options and related information. Using CodeSense dramatically increases productivity, giving you context sensitive information directly when you need it as you are typing code in the editor, so you don't have to leave the editor to look up references in the documentation. It can even be used to complete your typing for you, minimizing typos.

Here are some examples of CodeSense in action that you can see right in the current line of code you are typing:

  • If you type "get Value " (make sure you type the trailing space), you will notice a tooltip pop up displaying parameter information about the Value property. It will show you that it is a property of type String.

  • If you type "get Value of " (make sure you type the space after of), you will notice a list pop up displaying possible words to insert at the current place in the syntax of the current line of code. In this case this includes object names -- you can select oNameForm from the list.

  • If you type "get " (make sure you type the space after get), then press Ctrl + Space, you will notice a list pop up displaying possible words to insert at the current place in the syntax of the current line of code. This list includes Browse Objects at the top. If you press the right-arrow key with Browse Objects selected, you will see a second list, listing objects. Select object oNameForm and press the right-arrow key again to see a third list, this one showing properties and functions available for oNameForm. If you select Value from this list, notice that the property name and the object name are both filled into the proper syntax for the selection made.

Tip:

If you attempt to invoke CodeSense, but no information appears, there is a good chance that there is some kind of syntactical error on the current line of code prior to the location where you are trying to invoke CodeSense.

You can learn more about using CodeSense here.

  3. The next line of code is

move "Hello, " to sHello

This line of code initializes the String variable sHello to "Hello, ".

The syntax for setting the value of a variable is:

move {Value} to {VariableName}

Initializing Variables

Uninitialized local variables are automatically initialized to "" for strings or 0 (zero) for numeric variables (integer, real, etc.). However, it is a good habit to always initialize all variables you intend to use, even if you initialize them to "" or 0.

  4. The next line of code is

move (sHello + sName) to sResult

This line of code concatenates the contents of the String variables sHello and sName and moves that value to the String variable sResult. So, if for example, sName contains "John", this would move "Hello, John" to sResult.

  5. The next line of code is

set Value of oResultForm to sResult

This line of code places the contents of the String variable sResult into the Value property of the oResultForm Form object.

The syntax for setting the contents of an object's property is:

set {PropertyName} of {ObjectName} to {VariableName}

  18. The completed code should look like this:

    You may want to consider adding some blank lines to your code, to separate the code into meaningful blocks, as demonstrated above. This can make code easier to read, particularly when code you write becomes more complex than this small sample.

Commenting Code

Another good habit to get into is commenting your code. Comments are lines of code that are not compiled into the program, and are in the source code purely to inform the reader of the code about the code's intentions. Comments are typically added for anything that may not be easily apparent to anyone reading the code, including you, the code's author. It's uncanny how sometimes your own code can seem hard to follow after a few years of not working on a particular project. In particular, a good habit to form is to place a comment about the intention of a method above that method.

To add a comment to Visual DataFlex source code, simply place 2 forward slashes (//) anywhere in a line of code, and the remainder of that line will be treated as a comment, instead of source code, as seen below:

Tip:

You can comment or uncomment one or more lines of code by pressing the Ctrl + K keyboard shortcut.

  19. So, let's test the completed view.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project.

    When the application runs, click on the View menu and then Hello World to open the view. Type your name into the form labeled Name, then click the Go button. You will see "Hello, {Your Name}" in the form labeled Result.

    The result will look like this:

    Close the program.

Handling Compiler Errors


Handling Compiler Errors

Handling Compiler Errors in Windows Applications

The next thing you will need to know is what to do when something doesn't go as smoothly as anticipated. You will learn how to deal with compiler errors. These are the most common type of error that programmers encounter and are normally easy to fix.

Compiler Error

Compiler errors are mistakes in an application's source code, typically syntactical in nature, such as a mistyped object, function or variable name.

You are going to make a couple of simple changes in the code of your "Hello World" view to cause compiler errors. Then, you will learn how to resolve these compiler errors in the Studio.

  1. Double click on the button control in the visual editor or Code Explorer to display the code for the button object.

  2. Change the line

get Value of oNameForm to sName

to

get Value of oNameForm to Name

  3. Change the line

Set Value of oResultForm to sResult

to

Set Value of ResultForm to sResult

  4. Click on the Compile Project button on the Studio's toolbar.

    The program will start to compile. As the compiler runs, it will display it's progress in the Output window. When the compiler stops, the Studio will display all compiler errors in the Output window, below ---Compiler Error Summary---, as shown below:

    Notice the red icon with an exclamation mark in it next to each compiler error. If you scroll up, you will see each error flagged with this symbol during the compilation process, but each error found during the compilation process is listed again in the     Compiler Error Summary section at the bottom of the listing.

Tip

If the complete error cannot be read because it is wider than the Output window, you can place your cursor over the error line and a tooltip will display the full error text. You could also widen the window as needed. You can also rearrange the docking windows in the Studio. See Docking Windows for more information about this.

  5. The full text of the first error is:

    C:\Program Files\Visual DataFlex\Examples\Quick Start\AppSrc\HelloWorld.vw (ln 49) Undefined symbol in argument NAME

    In this case, this is because there is no variable called Name declared. The variable that is declared is called sName and the error was caused by a simple typing error.

  6. To fix the error, double-click on the error listing in the Output window. This will place the cursor at the beginning of the line of code that triggered the error. Correct the typo, changing Name back to sName.

  7. Now double-click on the second error listed in the Output window. This will place the cursor at the beginning of the line of code that triggered the second error.

    The full error text is:

    C:\Program Files\Visual DataFlex 12.0\Examples\Quick Start\AppSrc\HelloWorld.vw (ln 53) Undefined symbol in argument RESULTFORM

    In this case, this is because no object called ResultForm exists. The object that does exist is called oResultForm and the error was caused by a typo.

  8. Correct the typo, as seen here:

  9. Now that both errors are fixed, click on the Compile Project button on the Studio's toolbar.

    The changes you have made in the source code to fix the compiler errors are automatically saved by the Studio, and the program should compile without errors.

Debugging Code in Windows Applications


Debugging Code in Windows Applications

A type of problem that programmers encounter is a program that compiles, but then behaves differently than expected. You will discover how to solve such problems using the Debugger.

Debugging

Debugging is the act of observing the run-time behavior of a program and determining the location of semantic errors. With the debugger, you can break (suspend) execution of your program to examine your code, evaluate and edit variables in your program, view data in database tables and control the execution of the instructions in your source code.

Once again, you are going to make a change in the code of your "Hello World" view, this time to cause it to behave slightly differently than you want it to behave. Then, you will learn how to use the debugger to track down and solve the problem.

  1. Double click on the button control in the visual editor or Code Explorer to display the code for the button object.

  2. Change the line

move "Hello, " to sHello

to

move "Hello," to sHello

  4. Click on the Run button on the Studio's toolbar. When the application runs, click on the View menu and then Hello World to open the view.

  5. Type your name into the Name form and click on the Go button.

    You will see that the text that appears in the Result form now is, for example, "Hello,John", with the space between the comma and the name missing. You will now use the debugger to track down why the space is missing.

  6. Leave the program running and switch back to the Studio. Click in the left hand margin of the code editor next to the code line

get Value of oNameForm to sName

  7. This will place a red dot in the left margin, indicating that you have just placed a breakpoint on this line of code.

Breakpoints

Debuggers work by causing executing programs to stop and examining the program at this "frozen" time. Breakpoints on lines of code cause the debugger to halt the program when reaching that line of code, just prior to executing it.

  8. Now you will execute the program up to this line of code to have the debugger stop at this point. Since the breakpoint is in the OnClick event of the button, you need to run your program and click on the button to get the debugger to execute the program's code up to this breakpoint.

    Return to the running program and click on the Go button again.

    This time, the program is stopped by the debugger at the breakpoint.

  9. If you place your mouse cursor over any local variable in Procedure OnClick, you will see the current value of the variable pop up as a tool tip. Of course, at this point in the code, all variables should show up to be blank.

    Notice also the green arrow in the left margin, which currently overlaps the red dot for the breakpoint you placed. The green arrow indicates the line on which the program is currently "frozen". This is the next line that will execute in the program.

  10. Take a look at the Locals window. If the Locals window is not open, click on the Local Variables Watch Window icon on the Studio's toolbar.

    This will open the Locals window, which lists all local variables and their current values. This is a useful window to keep open when debugging, since it reflects the values of all local variables as you step through the code.

  11. Click on the Step Over button on the Studio's toolbar (or press F10).

Stepping through code

Stepping through code is an important debugging concept. A step causes the debugger to tell the program being debugged to execute lines of code as you tell it to.

The most common step type is Step Over, which remains in the current method and executes the currently selected line of code (the line indicated by the green arrow).

  12. The debugger has executed the line

get Value of oNameForm to sName

Notice that the variable sName now contains the name you typed into the Name form of the program. You can see this in the Locals window and also by holding the mouse cursor over the variable sName anywhere inside Procedure OnClick.

  13. Click on the Step Over toolbar button.

    Notice that the variable sHello now contains "Hello," and sName still contains the name you typed into the Name form.

  14. Click on the Step Over toolbar button.

    The variable sHello now contains "Hello," sName contains the name you typed into the Name form, and sResult contains the concatenated result of sHello + sName ("Hello,Dennis" in our example images).

    It is now readily apparent that the reason for the missing space is that there was no space placed either at the end of sHello or the beginning of sName.

Red values in Locals window

You will notice that the value of sResult is displayed in red in the Locals window. This is a visual cue to indicate that the value of sResult has just changed.

  15. Take a look at the Watches window. If the Watches window is not open, click on the Watches Window icon on the Studio's toolbar.

    This will open the Watches window, another useful window to keep open when debugging. The Watches window can display any expression you wish to evaluate while debugging. Try it like this:

  • Double-click on sResult in the code editor (this selects the entire word). Drag and drop it into the Name column of the Watches window.

    You will see that the Value column displays the current value of sResult, which is "Hello,Dennis" in our current sample.

  • Highlight the expression (sHello + sName) in the code editor (this selects the entire word). Drag and drop it into the Name column of the Watches window.

    You will see that the Value column displays the current value of (sHello + sName), which is "Hello,Dennis" in our current sample (just like sResult).

  • Click in the Name column of the Watches window of the row which currently contains (sHello + sName). This will highlight the entire current row. If you click in the Name column once more, you will see that it is now editable.

    Change the expression to (sHello + " " + sName) and press Enter.

    You will see that the Value column now displays the current value of (sHello + " " + sName), which is "Hello, Dennis" in our current sample.

We encourage you to spend some time debugging, it is a very powerful tool and the features we have shown you here barely scratch the surface of what you can do. Mastering debugging will help you understand how Visual DataFlex works and make you a better programmer!

See the Debugging topic of the Studio help book for more information regarding debugging.

Next Step

You have just learned how to create a Windows application and a view in the Visual DataFlex Studio, and how to compile and debug them.

To learn how to add help to a Windows application, go on to Adding Help to Your Windows Applications.
To learn how to create web applications, go on to Creating Your First Web Application.


Adding Help to Your Windows Applications

This topic will show you how to add Compiled HTML Help to your Visual DataFlex Windows projects, and link to specific pages (topics) and bookmarks in a Compiled HTML project. This allows you to create help for the users of your projects, including context-sensitive links from individual views or objects in your project.

Compiled HTML Help

Compiled HTML Help has replaced WinHelp as the standard help format for Windows-based software projects. Compiled HTML Help files are created by compiling standard HTML pages into .CHM files, which creates the type of help like the Visual DataFlex help that you are reading now, including (usually) a pane on the left hand side with a Table of Contents, Index and text search capabilities).

Important!

This section requires that the "My First Windows Application" Windows project and the "Hello World" view were created in the QuickStart workspace.

If this is not the case, switch to the Creating Your First Windows Application step now and return here when you have completed it.

Creating Compiled HTML Help

There are many products available, including some free ones, that allow you to edit and compile Compiled HTML Help projects. You can find detailed documentation about Compiled HTML Help in the Microsoft Developer documentation (MSDN) under "HTML Help". The Visual DataFlex help you are currently reading is created using RoboHelp, with the exception of the Class Reference, which is created dynamically from source code comments in the Visual DataFlex packages and compiled using the Microsoft HTML Help Workshop compiler.

The basic concept is that you have numerous individual HTML pages that are added to "books" and then compiled. A single HTML page (such as this one), is referred to as a topic. You can link to any topic directly from a Visual DataFlex Windows project, so that the user can access it by pressing the help button on the keyboard (F1).

Just as in HTML pages that are viewed in web browsers, you can have bookmarks in Compiled HTML Help files that refer to specific places on a page. This is useful if you have very long HTML pages and want users to be able to get to a specific spot on the page. You can also link to any bookmark on a page (topic) directly from a Visual DataFlex Windows project, so that the user can access it by pressing the help button on the keyboard (F1).

Adding HTML Help to an Application

Once you have a compiled CHM project, it is very simple to integrate links to it into a Windows project.

  1. If not already open, open the Visual DataFlex Studio and open the QuickStart workspace.

  2. Make sure that MyFirstWindowsApplication.src is the Current Project selected in Workspace Explorer.

  3. Open the MyFirstWindowsApplication.src file. You can do so by double-clicking on the file in Workspace Explorer or right-clicking on it and selecting Open <MyFirstWindowsApplication.src>.

  4. Select the oApplication object in Code Explorer. In the Object Properties window, change the value of peHelpType to htHtmlHelp. This sets the help type for the entire application to Compiled HTML help.

    Set the psHelpFile property to MyFirstWindowsApplication.chm. MyFirstWindowsApplication.chm is a Compiled HTML help file that was created for use with this application in the QuickStart workspace. It will allow you to see how to connect to a Compiled HTML help file.

  5. Click on the "Compile and debug-run program" button on the Studio's toolbar.

    Your application will run. Once the application is on the screen, press F1. You will see the "My First Windows Application" help file appear.

    As you can see, your Windows application is now connected to a Compiled HTML help file. Since we have not specified any context-sensitive connections yet, the application opened with the default page (in this case, the "My First Windows Application" page).

    Close the help file and the "My First Windows Application" program.

Adding Context Sensitive Help Links

  1. Open the "Hello World" view in the Studio. Click on the + in the tree view to expand MyFirstWindowsApplication.src, then click on the + to expand Views. Double-click on HelloWorld.vw in Workspace Explorer or right-click on it and select Open <HelloWorld.vw>.

  2. Select the oHelloWorld view object in Code Explorer. In the Object Properties window, change the value of psHtmlHelpTopic to Hello_World.htm.

psHtmlHelpTopic Property

The psHtmlHelpTopic property should be set to the name of an actual HTML page that is part of your Compiled HTML Help project. This allows you to use sensible names for your help pages, such as the names of views and dialogs in your application. This makes maintenance of your help projects alongside your applications much simpler.

In this sample, the psHtmlHelpTopic property is set only at the view level, and all objects in the view find the same page via delegation. You can, however, set this property in any object and thus make your application help as granular or general as is needed for your application.

  3. Click on the Compile Project, then the Run toolbar button. When the application runs, click on the View menu and then Hello World to open the view. Once the view is open, press F1.

    You will see the "My First Windows Application" help file appear, but this time, the "Hello World" page is displayed instead of the default page.

    Close the help file and the "My First Windows Application" program.

  4. Change the psHtmlHelpTopic property of the oHelloWorld view object to Hello_World.htm#TestBookmark.

  5. Click on the Compile Project, then the Run toolbar button. When the application runs, click on the View menu and then Hello World to open the view. Once the view is open, press F1.

    Once again, you will see the "My First Windows Application" help file appear. This time, the "Hello World" page is displayed, but it is scrolled all the way to the bottom of the page, where the Hello_World.htm page contains a bookmark named TestBookmark.

Adding Help Buttons to an Application

You may want to add "help buttons" to various objects in your project, so that users can click a button to get help instead of, or in addition to, pressing F1.

  1. Drag and drop a Button control from the Base Controls group on the Class Palette onto the oHelloWorld view.

  2. Click on the Object Properties toolbar button to open the Object Properties window.

  3. Change the Label property of the button control to Help in the Object Properties window.

  4. Double click on the button control in Code Explorer to display the code for the button object.

  5. Add the following line of code to Procedure OnClick:

send Help of oHelloWorld

The completed code should look like this:

The code fires the Help method, which is the standard help message, of the oHelloWorld view object. This way, the program will see what context sensitive help page is defined for the view object and open it. Depending on what you want to display help for, you can send the Help message to the desired object.

  4. Click on the Compile Project, then the Run toolbar button. When the application runs, click on the View menu and then Hello World to open the view. Once the view is open, click on the Help button.

    You will see the "My First Windows Application" help file appear and the text for the TestBookmark on the "Hello World" page displayed. This result is identical to pressing F1 anywhere in the "Hello World" view.


Creating Your First Web Application

This tutorial will guide you through the most basic steps of creating Web Applications using Visual DataFlex. Along the way, you will learn how to work with the main Visual DataFlex development tools. As you complete tasks, basic concepts will be explained to you.

Caution

In order to run Visual DataFlex Web Application Server, you must be running on an operating system that has Microsoft Internet Information Server (IIS) installed. If you do not have IIS installed, you should have received a warning when you installed Visual DataFlex that the Web components of Visual DataFlex will not be installed. If you do not have IIS installed, and you want to run Visual DataFlex Web Application Server, you must install IIS, then reinstall Visual DataFlex.

This book assumes that you have already completed the Creating Your First Windows Application section of the Quick Start tutorial, which introduces development of Windows applications in Visual DataFlex and introduces Visual DataFlex Studio.

However, in case you want to jump directly into Web application development, sections in this book that assume that you have completed steps in Creating Your First Windows Application will point this out to you.

This tutorial section will take you through the following steps:

  • Creating a Web Application

  • Compiling and Running a Web Application

  • Creating Your First Web Application Page

  • Debugging Code in Web Applications


Creating a Web Application

Let's create your first, very simple Web application with Visual DataFlex.

Web Application

A Web Application is a Visual DataFlex program that hosts WBOs (Web Browser Objects) or WSOs (Web Service Objects) that serve data to client ASP (Active Server Pages) pages or Web Service client applications.

Important!

For QuickStart, we have already provided you with a workspace. This section assumes that you have been going through the Quick Start tutorial step by step, in which case, you will have already opened the required workspace.

If this is not the case, switch to the Opening a Workspace step now and return here when you have completed it.

This application will at first be very simple.

Creating a Web Application

  1. Click on the Create New button on the Studio’s toolbar.

  2. Click on the Project tab of the Create New... dialog.

  3. Double click the Web Project icon.

  4. The "Assign Web Application Information" dialog will open. Accept the defaults for Web Application Name (Quick Start) and Virtual Directory Name (QuickStart) and click the Ok button.

Virtual Directory

The Virtual Directory maps the AppHtml folder (which contains ASP and HTML files for the Web application) of your workspace with a Uniform Resource Locator (URL) to allow users to access these files over the Web. Keep in mind that you are setting the name of the virtual directory, not the name of your Web application.

  5. You will now see the source code of a new Web application in the Studio.

You have now created your first Web application. Of course, at this point, the application is only an empty container. Soon, you will learn how to add web browser objects (WBOs) and other components to it.

Compiling and Running a Web Application


Compiling and Running a Web Application

The next step is to compile, then run your application.

Compilation

Compilation is the process of creating an executable program from source code. The source code for any Visual DataFlex program needs to be compiled and linked into an executable (.exe) file before it can be executed (run).

  1. Click on the Compile Project button on the Studio's toolbar.

    You will see the embedded compiler display its progress in the Output window (if the Output window is not open, it will automatically open and move to the foreground when you compile).

The Compiler in Progress

You will see the Compiler including and compiling all the files specified in the source file being compiled. Visual DataFlex automatically includes any predefined library files your project needs when you create a new program in the Studio. These library files are typically called packages or "package files" in Visual DataFlex, since their extension is usually .pkg. See Package Filename Extensions for more information about packages.

  2. Once compiled without errors (you will see "----Compile Finished----" in the Output window), you can run your program.

    Click the Run toolbar button.

    When the application runs, your browser should display the testcontent.htm page.

Tip

You have another option for compiling and running your application in one step. If you simply click on the Run button on the Studio's toolbar, it will compile the program if changes were made to the source code that require recompilation, and then run the program, or simply run the program if recompilation is not needed.

You have just created and executed your first Visual DataFlex Web application. You can see that this application is merely a container that can be compiled and executed. Any specific functionality for this application will be provided by web browser objects (WBOs).

Close the browser to close the application.

Creating Your First Web Application Page


Creating Your First Web Application Page

Now, let's create a Web page that interacts with Visual DataFlex Web Application Server.

This section assumes that you are familiar with Hypertext Markup Language (HTML) and Active Server Pages (ASP) coding. We will only explain coding and methodology that is specific to Visual DataFlex.

If you are unfamiliar with ASP, enter http://localhost into your browser's address bar to load the IIS start page. Click on the IIS Online Documentation link, which includes the documentation for ASP.

Web Browser Object (WBO)

Web Browser Objects are the main building blocks of Web applications in Visual DataFlex. These objects are components you can build in the Studio. They contain functions coded in the Visual DataFlex language. These functions can be "published" so that they can be called from ASP pages.

Creating a "Hello World" Web page

We are going to illustrate some basic Visual DataFlex Web application development techniques using a variation of the well-known "Hello, World" program, which is used as the first program to teach many programming languages.

The Web page you will create will be very simple, with 2 forms and a button. The first form will be labeled Name and the second form Result. The user will type his or her name into the Name form and click the button. The name will then be added to "Hello, ", resulting in "Hello, John" for example. This result will be placed in the second form.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double click the Web Browser Object icon.

  2. The "Create a New Web Object" dialog will open. Enter oHelloWorld as the object name. Notice that the filename automatically changes to HelloWorld.wo as you type the object name. Accept the default directory path (the AppSrc folder in the QuickStart workspace). Click on the Ok button.

    You will now see the source code of a new WBO in the Studio.

  3. Take a look at the Workspace Explorer window. If Workspace Explorer is not open, click on the Workspace Explorer icon on the Studio's toolbar.

Workspace Explorer

The Workspace Explorer is a docking window that lists the current project and components included in the current project by type. Please read more about this in the Workspace Explorer topic in the Studio book.

  4. In Workspace Explorer, you should see WebApp.src as the Current Project. Click on the + in the tree view to expand WebApp.src, then click on the + to expand Web Browser Objects. You can see that HelloWorld.wo has been added to project WebApp.src.

  5. If the Code Explorer window is not open, click on the Code Explorer toolbar button.

  6. In the Code Explorer window, you will see an outline of the current source file in a tree. There are nodes that represent other source files that are used in this file, objects, and methods.

  7. Double-click on the oHelloWorld control in Code Explorer to display the code for this object. This will place the edit cursor at beginning of the object declaration line for oHelloWorld.

  8. You are going write a function in this WBO which accepts a name as parameter and returns as result a string of "Hello, " and the name. Type the following lines of code inside the already declared Object oHelloWorld:

  1. The first line of code is:

Function HelloWorld string sName returns String

This line of code declares a function named HelloWorld. It specifies that the function accepts one string variable named sName and that the function will return one string variable when the function completes.

This line also creates a local variable named sName, since it is declared as a function parameter.

  2. The next line of code is:

string sResult sHello

This line of code declares 2 local string variables with names sResult and sHello.

Variable Scope

The scope of a local variable is limited to the method (procedure or function) in which it is declared. You can "use" these variables, meaning that you can assign values to them and access their existing values only while in the current method, in this case Function HelloWorld. Attempting to reference variables outside of the scope in which they are declared will result in a compiler error.

Variable Names

Just as with object names, it is useful to give your variables meaningful names. The names x and y are not nearly as meaningful as sName and sResult. In a more complex method, with dozens of variables, having the ability to easily identify the meaning of a variable name will make you a more efficient programmer.

We recommend using the prefix s for string variables. Prefixes like this also help in identifying the meaning of variable names. If you stick with this naming convention, you will never confuse a variable that holds a string with one that holds a number. You can read more about Visual DataFlex Naming Conventions in the Language Guide.

  3. The next line of code is:

move "Hello, " to sHello

This line of code initializes the string variable sHello to "Hello, ".

The syntax for setting the value of a variable is:

move {Value} to {VariableName}

Initializing Variables

Local variables that are not initialized are automatically initialized to "" for strings or 0 (zero) for numeric variables (integer, real, etc.). However, it is a good habit to always initialize all variables you intend to use, even if you initialize them to "" or 0.

  4. The next line of code is:

move (sHello + sName) to sResult

This line of code concatenates the contents of the string variables sHello and sName and moves that value to the string variable sResult. So, if for example, sName contains "John", this would move "Hello, John" to sResult.

CodeSense

CodeSense is a set of Studio features that intelligently assist you in writing code, providing lists of context sensitive options and information. Using CodeSense dramatically increases productivity, it gives you context sensitive information directly when you need it as you're typing code in the editor, so you don't have to leave the editor to look up references in the documentation. And it can even be used to complete your typing for you, minimizing typos etc.

Here is an example of CodeSense in action that you can see right in the current line of code you are typing:

  • If you type "move (sHello + sName) to " (make sure you type the trailing space), then press Ctrl + Space, you will notice a list pop up displaying possible words to insert at the current place in the syntax of the current line of code.

You can learn more about using CodeSense here.

  5. The next line of code is:

function_return sResult

This line of code returns the contents of the variable sResult to the calling routine.

  6. The next line of code is:

End_Function // HelloWorld

This line of code declares the end of the HelloWorld function.

  9. The completed code should look like this:

    You may want to consider adding some blank lines to your code, to separate the code into meaningful blocks, as demonstrated above. This can make code easier to read, particularly when code you write becomes more complex than this small sample.

  10. Next, the function needs to be published so that it can be invoked from a Web page.

    In Code Explorer, click on the + in the tree view to expand the oHelloWorld object. This will expand the oHelloWorld WBO object to show its child objects and methods.

  11. Right-click on the HelloWorld function in Code Explorer and select Published from the context menu.

    The HelloWorld function is now published. Notice that its icon has changed. Notice also that the Studio has inserted the following meta-data tags above the function declaration line in your source code:

{ Published = True }

{ Description = "" }

Publishing Web Application Functions

Publishing web application functions is a security measure of Visual DataFlex web applications. Only published functions can be invoked externally, so you are in complete control over how the calling web interface can interact with your application.

  12. Edit the Description meta-data tag to describe the purpose of the function, as below.

    { Description = "This function accepts a name and returns it in form 'Hello, Name'" }

  13. Next, you will create the ASP page that will serve as the "front end" of your application and call the HelloWorld function.

    Click on the Create New button on the Studio’s toolbar. Click on the Web Markup tab of the Create New... dialog. Double click the ASP icon.

  14. The "Create a New Web Markup file" dialog will open. Enter HelloWorld.asp as the file name and click on the Save button. Accept the default location (the AppHtml folder in the QuickStart workspace).

    You will now see the source code of your new ASP file in the Studio.

  15. Let's change the title of the page. This is the title that will show up on the caption bar of your browser when you load this page.

Change the line

<title>New Page 1</title>

to

<title>Hello, World</title>

  17. Next, you are going to add some code into the <body> section of the page. Type the following lines of code inside the <body> and </body> tags.

  1. The first block of code is:

<%
if Request("Request_Method")="POST" then

if Request("Go")<>"" then

sName = Request("Name")

  2. The next line of code is:

sResult = oHelloWorld.Call("get_HelloWorld", sName)

This is the only line of code that is not standard ASP code.

This code makes a call to your Visual DataFlex HelloWorld function via the call interface. It passes sName to HelloWorld and returns the result into sResult. The call interface is the interface that allows access from ASP script code to any published methods in a Visual DataFlex application.

  6. The remaining code is:

end if

end if

%>

<form method="POST" name="Form1" action="HelloWorld.asp">

Name: <input type="text" name="Name" value="<%=sName %>" size="20"><br>

Result: <input type="text" name="Result" value="<%=sResult %>" size="20"><br>

<input type="submit" value="Go" name="go"><br>

</form>

  18. The completed code should look like this:

  19. So, let's test our completed Web application page.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project.

    When the application runs, your browser should display the testcontent.htm page.

  20. Click on the link to Hello World.wo to open the "Hello, World" page:

  21. Type your name into the form labeled Name, then click the Go button. You will see "Hello, {Your Name}" in the form labeled Result.

    The result will look like this:

    Close the browser to close the application.

Debugging Code in Web Applications


Debugging Code in Web Applications

A type of problem that programmers encounter is a program that compiles, but then behaves differently than expected. You will discover how to solve such problems using the Debugger.

Debugging

Debugging is the act of observing the run-time behavior of a program and determining the location of semantic errors. With the debugger, you can break (suspend) execution of your program to examine your code, evaluate and edit variables in your program, view data in database tables and control the execution of the instructions in your source code.

Important!

This section assumes that you have been going through the Quick Start tutorial step by step.

If you skipped the Windows application part of Quick Start, you should read the Handling Compiler Errors section now and return to this page when you have completed it.

You are going to make a change in the code of your "Hello World" WBO, to cause it to behave differently than you want it to behave. Then, you will learn how to use the debugger to track down and solve the problem.

  1. Switch back to the HelloWorld.wo file in the Studio.

Tip:

You can scroll through all open views by using the Ctrl + + or Ctrl + - keyboard shortcuts.

Once you are working in a larger project and have multiple files open, it may become useful to leave the File Navigator window open as a docked window. If the File Navigator is not already open, you can open it by clicking on the File Navigator toolbar button.

For more information about navigating around the Studio, see the Studio help book.

  2. Double-click on the HelloWorld function in Code Explorer to display the code for this function.

  3. Change the line

move "Hello, " to sHello

to

move "Hello," to sHello

  4. Click on the Run button on the Studio's toolbar.

    When the application runs, your browser should display the testcontent.htm page.

  5. In testcontent.htm in your browser, click on the Hello World.wo link. Type your name into the Name form and click on the Go button.

    You will see that the result that appears in the Result form now is, for example, "Hello,John", with the space between the comma and the name missing. You will now use the debugger to track down why the space is missing.

  6. Leave the program running and switch back to the Studio. Click in the left hand margin of the code editor next to the code line

move "Hello," to sHello

  7. This will place a red dot in the left margin, indicating that you have just placed a breakpoint on this line of code.

Breakpoints

Debuggers work by causing executing programs to stop and examining the program at this "frozen" time. Breakpoints on lines of code cause the debugger to halt the program when reaching that line of code, just prior to executing it.

  8. Now you will execute the program up to this line of code to have the debugger stop at this point. Since the breakpoint is in the HelloWorld function of the oHelloWorld WBO, you need to run your program and click on the Go button to get the debugger to execute the program's code up to this breakpoint.

    Return to the running program and click on the Go button again.

    This time, the program is stopped by the debugger at the breakpoint.

  9. If you place your mouse cursor over any local variable in Function HelloWorld, you will see the current value of the variable pop up as a tool tip. Of course, at this point in the code, all variables should show up to be blank.

    Notice also the green arrow in the left margin, which currently overlaps the red dot for the breakpoint you placed. The green arrow indicates the line on which the program is currently "frozen". This is the next line that will execute in the program.

  10. Take a look at the Locals window. If the Locals window is not open, click on the Locals icon on the Studio's toolbar.

    This will open the Locals window, which lists all local variables and their current values. This is a useful window to keep open when debugging, since it reflects the values of all local variables as you step through the code.

  11. Click on the Step Over button on the Studio's toolbar (or press F10).

Stepping through code

Stepping through code is an important debugging concept. A step causes the debugger to tell the program being debugged to execute lines of code as you tell it to.

The most common step type is Step Over, which remains in the current method and executes the currently selected line of code (the line indicated by the green arrow).

  12. The debugger has executed the line

move "Hello," to sHello

Notice that the variable sHello now contains "Hello,". You can see this in the Locals window and also by holding the mouse cursor over the variable sName anywhere inside Function HelloWorld.

  13. Click on the Step Over toolbar button. The green arrow should now be next to the line

Function_Return sResult

The variable sHello now contains "Hello," sName contains the name you typed into the Name form, and sResult contains the concatenated result of sHello + sName ("Hello,Dennis" in our example images).

It is now readily apparent that the reason for the missing space is that there was no space placed either at the end of sHello or the beginning of sName.

Red values in Locals window

You will notice that the value of sResult is displayed in red in the Locals window. This is a visual cue to indicate that the value of sResult has just changed.

  14. Take a look at the Watches window. If the Watches window is not open, click on the Watches icon on the Studio's toolbar.

    This will open the Watches window, another useful window to keep open when debugging. The Watches window can display any expression you wish to evaluate while debugging. Try it like this:

  • Double-click on sResult in the code editor (this selects the entire word). Drag and drop it into the Name column of the Watches window.

    You will see that the Value column displays the current value of sResult, which is "Hello,Dennis" in our current sample.

  • Highlight the expression (sHello + sName) in the code editor. Drag and drop it into the Name column of the Watches window.

    You will see that the Value column displays the current value of (sHello + sName), which is "Hello,Dennis" in our current sample (just like sResult).

  • Click in the Name column of the Watches window of the row which currently contains (sHello + sName). This will highlight the entire current row. If you click in the Name column once more, you will see that it is now editable.

    Change the expression to (sHello + " " + sName) and press Enter.

    You will see that the Value column now displays the current value of (sHello + " " + sName), which is "Hello, Dennis" in our current sample.

We encourage you to spend some time debugging, it is a very powerful tool and the features we have shown you here barely scratch the surface of what you can do. Mastering debugging will help you understand how Visual DataFlex works and make you a better programmer!

See the Debugging topic of the Studio help book for more information regarding debugging.

Next Step

You have just learned how to create a web application and a web application page in the Visual DataFlex Studio, and how to compile and debug them. Next, you will learn how to create web services: Creating Your First Web Service


Creating Your First Web Service

This tutorial will guide you through the most basic steps of creating Web Services using Visual DataFlex. Along the way, you will learn how to work with the main Visual DataFlex development tools. As you complete tasks, basic concepts will be explained to you.

Caution

In order to run Visual DataFlex Web Application Server, you must be running on an operating system that has Microsoft Internet Information Server (IIS) installed. If you do not have IIS installed, you should have received warning when you installed Visual DataFlex that the Web components of Visual DataFlex will not be installed. If you do not have IIS installed, and you want to run Visual DataFlex Web Application Server, you must install IIS, then reinstall Visual DataFlex.

This book assumes that you have already completed the Creating Your First Windows Application section of the Quick Start tutorial, which, besides introducing Windows application development in Visual DataFlex, introduces Visual DataFlex Studio and discusses handling of compiler errors.

However, in case you want to jump directly into Web Services application development, sections in this book that assume that you have completed steps in Creating Your First Windows Application will point this out to you.

In this tutorial, you will create a Greeting Web Service, which will have one public function that accepts a Name as an argument and returns a string containing "Hello, {Name}, how are you today?".

This tutorial will take you through the following steps:

  • Creating a Workspace

  • Creating a Web Service Application

  • Compiling and Running a Web Service

  • Creating Your First Web Service Function

  • Debugging Code in Web Services


Creating a Workspace for the Greeting Web Service

Creating a Workspace

Let's create a new workspace for the Greeting Web Service.

Workspace

A Visual DataFlex Workspace is a physical and logical container for your projects, with a well-defined structure. A Workspace can contain multiple projects, typically related in some logical manner, such as a Windows application and a Web application that access the same database. A workspace contains everything necessary to build and run a Visual DataFlex project.

Project

A Visual DataFlex Studio Project is a collection of components and other items of interest to the Studio that compiles into a target program.

Typical Workspace Structure

Each of a Workspace’s sub-folders contain files indicated by the folder name (e.g. bitmap files used in the application are in ..\Contact\Bitmaps, data is in ..\Contact\Data, application source is in ..\Contact\AppSrc, etc.)

For this tutorial, we will limit the scope of a workspace to a single set of Windows folders and subfolders that contain the various files that make up a project. In practice, the workspace structure can refer to a local set as in this example or it can refer to a set of folders that are located across a network and that are not necessarily physically co-located as they are in this example.

  1. Open the Visual DataFlex Studio.

  2. Select New Workspace... from the Studio’s File menu.

  3. Click Next on the wizard's Welcome page. Enter GreetingWebService as the name, Greeting Web Service as the description and accept the default location. This will be the drive letter to which Visual DataFlex was installed, followed by \Visual DataFlex Projects\GreetingWebService. If you have previously create a workspace in another location, the "Workspace Root Directory" will default to that location. Click Next.

  4. On the 'Workspace Directory Folder" wizard page, accept the default, "Standard workspace structure (recommended)".

Standard Workspace Structure

A workspace with a standard workspace structure has a main folder with sub-folders that contain files indicated by the folder name. The standard workspace structure includes sub-folders AppHtml for web pages, AppSrc for application source code, Bitmaps for image files, Data for database files, DDSrc for Data Dictionary files, Help for application-related help files and Programs for compiled programs.

  5. Click Next on the Workspace Paths (page 1) and Workspace Paths (page 2) pages.

  6. On the Database Type wizard page, you can select the type of database you will use in this workspace. For this tutorial, keep the default choice, Embedded.

Database Type

Visual DataFlex workspaces can support multiple database types. For example, you can use Microsoft SQL, Pervasive.SQL and embedded database tables in the same workspace and even sharing the same views and reports. Typically, however, developers keep all or most tables in a workspace in the same database or perform most work in one database type at one time, thus each workspace has a default database type. This selection does not preclude you from using databases that are not the default type, but it makes working with the default database type more efficient.

  7. On the Setting Up Your Database wizard page, you can specify whether to create a new database immediately after the wizard concludes. For this tutorial, you will not use a database, so select the option I do not wish to describe a database at this time.

  8. On the last wizard page, click Finish.

    You have now created a Visual DataFlex workspace. You should now be back in the Studio, and the Studio has the new workspace loaded. You can verify this by looking for (GreetingWebService) on the Studio's caption bar.

Creating a Web Service Application


Creating a Web Service Project

Creating a Web Service Application

Let's create your first, very simple Web Service application with Visual DataFlex.

Web Application

A Web Application is a Visual DataFlex program that hosts WBOs (Web Browser Objects) or WSOs (Web Service Objects) that serve data to client ASP (Active Server Pages) pages or Web Service client applications.

Important!

This section requires that a GreetingWebService workspace was created and assumes that you will follow the Creating Your First Web Service tutorial step by step, in which case, you will have already created the GreetingWebService workspace.

If this is not the case, switch to the Creating a Workspace step now and return here when you have completed it.

Creating a Web Service Application

  1. Click on the Create New button on the Studio’s toolbar.

  2. Click on the Project tab of the Create New... dialog.

  3. Double click the Web Project icon.

  4. The "Assign Web Application Information" dialog will open. Accept the defaults for Web Application Name (GreetingWebService) and Virtual Directory Name (GreetingWebService) and click the Ok button.

Virtual Directory

The Virtual Directory maps the AppHtml folder (which contains ASP and HTML files for the Web application) of your workspace with a Uniform Resource Locator (URL) to allow users to access these files over the Web. Keep in mind that you are setting the name of the virtual directory, not the name of your Web application.

  5. You will now see the source code of a new Web application in the Studio.

You have now created your first Web application. Of course, at this point, the application is only an empty container. Soon, you will learn how to add web browser objects (WBOs) and other components to it.

Compiling and Running a Web Service


Compiling and Running a Web Service Project

Compiling and Running a Web Service Application

The next step is to compile, then run your application.

Compilation

Compilation is the process of creating an executable program from source code. The source code for any Visual DataFlex program needs to be compiled and linked into an executable (.exe) file before it can be executed (run).

  1. Click on the Compile Project button on the Studio's toolbar.

    You will see the embedded compiler display its progress in the Output window (if the Output window is not open, it will automatically open and move to the foreground when you compile).

The Compiler in Progress

You will see the Compiler including and compiling all the files specified in the source file being compiled. Visual DataFlex automatically includes any predefined library files your project needs when you create a new program in the Studio. These library files are typically called packages or "package files" in Visual DataFlex, since their extension is usually .pkg. See Package Filename Extensions for more information about packages.

  2. Once compiled without errors (you will see "----Compile Finished----" in the Output window), you can run your program.

    Click the Run toolbar button.

    When the application runs, your browser should display the testcontent.htm page.

You have just created and executed your first Visual DataFlex Web Service application. You can see that this application is merely a container that can be compiled and executed. Any specific functionality for this application will be provided by web service objects (WSOs).

Close the browser to close the application.

Creating Your First Web Service Function


Creating Your First Web Service Function

Now, let's create the Greeting Web Service function.

This section assumes that you are familiar with Web Services and Web Service Definition Language (WSDL). We will only explain coding and methodology that is specific to Visual DataFlex.

If you are unfamiliar with WSDL, enter http://www.w3.org/TR/wsdl into your browser's address bar to read the World Wide Web Consortium's (W3C) definition of it. There are also many places on the Web where you can learn more about Web Services and WSDL.

Web Service Object (WSO)

Web Service Objects are the main building block of Web Service applications in Visual DataFlex. These objects are components you can build in the Studio. They contain functions coded in the Visual DataFlex language. These functions can be "published" so that their interface can be called as a web service using the SOAP protocol.

Creating a Greeting Web Service

We are going to illustrate some basic Visual DataFlex Web Service development techniques using a variation of the well-known "Hello, World" program, which is used as the first program to teach many programming languages.

The Greeting Web Service you will create will be very simple, with 1 public function, named Greeting. The Greeting function will accept a Name as an argument and returns a string containing "Hello, {Name}, how are you today?".

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double click the Web Service Object icon.

  2. The "Create a New Web Object" dialog will open. Enter oGreeting as the object name. Notice that the filename automatically changes to Greeting.wo as you type the object name. Accept the default directory path (the AppSrc folder in the GreetingWebSerivce workspace). Click on the Ok button.

Object Names

It is very useful to give your objects meaningful names. The name oNewWebService is not nearly as meaningful as oGreeting. In a more complex project, with dozens, or potentially hundreds of objects, having the ability to uniquely identify an object easily will save you time and effort.

We recommend using the prefix o for objects. You can read more about Visual DataFlex Naming Conventions in the Language Guide.

  3. You will now see the source code of a new WSO in the Studio. Take a look at the Workspace Explorer window. If Workspace Explorer is not open, click on the Workspace Explorer icon on the Studio's toolbar.

Workspace Explorer

The Workspace Explorer is a docking window that lists the current project and components included in the current project by type. Please read more about this in the Workspace Explorer topic in the Studio book.

  4. In Workspace Explorer, you should see WebApp.src as the Current Project. Click on the + in the tree view to expand WebApp.src, then click on the + to expand Web Service Objects. You can see that Greeting.wo has been added to project WebApp.src.

  5. If the Code Explorer window is not open, click on the Code Explorer toolbar button.

  6. In the Code Explorer window, you will see an outline of the current source file in a tree. There are nodes that represent other source files that are used in this file, objects, and methods.

  7. Double-click on the oGreeting control in Code Explorer to display the code for this object. This will place the edit cursor at beginning of the object declaration line for oHelloWorld.

Navigating Between Views in the Studio

There are multiple ways of navigating between open views in the Studio. As you already saw, double-clicking on an object in Code Explorer opens the code editor to the code for that object. You could also have clicked on the Code Editor toolbar button to switch to the code editor, although that would not have brought you immediately to the code for a specific object.

Tip:

You can scroll through all open views by using the Ctrl + + or Ctrl + - keyboard shortcuts.

Once you are working in a larger project and have multiple files open, it may become useful to leave the File Navigator window open as a docked window. If the File Navigator is not already open, you can open it by clicking on the File Navigator toolbar button.

For more information about navigating around the Studio, see the Studio help book.

  8. You are going to write the Greeting function which accepts a name as parameter and returns as result a string of "Hello, " and the name. Type the following lines of code inside the already declared Object oGreeting, just above the "End_Object" line.

  1. The first line of code is:

Function Greeting string sName returns String

This line of code declares a function named Greeting. It specifies that the function accepts one string variable named sName and that the function will return a string variable when the function completes.

This line also creates a local variable named sName, since it is declared as a function parameter.

  2. The next line of code is:

string sReply sHello sHowAreYou

This line of code declares 3 local string variables with name sReply sHello and sHowAreYou.

Variable Scope

The scope of a local variable is limited to the method (procedure or function) in which it is declared. You can "use" these variables, meaning that you can assign values to them and access their existing values only while in the current method, in this case Function Greeting. Attempting to reference variables outside of the scope in which they are declared will result in a compiler error.

Variable Names

Just as with object names, it is useful to give your variables meaningful names. The names x and y are not nearly as meaningful as sReply, sHello and sHowAreYou. In a more complex method, with dozens of variables, having the ability to easily identify the meaning of a variable name will make you a more efficient programmer.

We recommend using the prefix s for string variables. Prefixes like this also help in identifying the meaning of variable names. If you stick with this naming convention, you will never confuse a variable that holds a string with one that holds a number. You can read more about Visual DataFlex Naming Conventions in the Language Guide.

  3. The next line of code is:

move "Hello, " to sHello

This line of code initializes the string variable sHello to "Hello, ".

The syntax for setting the value of a variable is:

move {Value} to {VariableName}

Initializing Variables

Local variables that are not initialized are automatically initialized to "" for strings or 0 (zero) for numeric variables (integer, real, etc.). However, it is a good habit to always initialize all variables you intend to use, even if you initialize them to "" or 0.

  4. The next line of code is:

move ", how are you today?" to sHowAreYou

This line of code initializes the string variable sHowAreYou to ", how are you today?".

  5. The next line of code is:

move (sHello + sName + sHowAreYou) to sReply

This line of code concatenates the contents of the string variables sHello, sName and sHowAreYou, and moves that value to the string variable sReply. So, if for example, sName contains "John", this would move "Hello, John, how are you today?" to sReply.

CodeSense

CodeSense is a set of Studio features that intelligently assist you in writing code, providing lists of context sensitive options and information. Using CodeSense dramatically increases productivity, it gives you context sensitive information directly when you need it as you're typing code in the editor, so you don't have to leave the editor to look up references in the documentation. And it can even be used to complete your typing for you, minimizing typos etc.

Here is an example of CodeSense in action that you can see right in the current line of code you are typing:

  • If you type "move (sHello + sName + sHowAreYou) to " (make sure you type the trailing space), then press Ctrl + Space, you will notice a list pop up displaying possible words to insert at the current place in the syntax of the current line of code.

You can learn more about using CodeSense here.

  6. The next line of code is:

function_return sReply

This line of code returns the contents of the variable sReply to the calling routine.

  7. The next line of code is:

End_Function // Greeting

This line of code declares the end of the Greeting function.

  9. The completed code should look like this:

    You may want to consider adding some blank lines to your code, to separate the code into meaningful blocks, as demonstrated above. This can make code easier to read, particularly when code you write becomes more complex than this small sample.

  10. Next, the function needs to be published so that it can be invoked from a Web page.

    In Code Explorer, click on the + in the tree view to expand the oGreeting object. This will expand the oHelloWorld WBO object to show its child objects and methods.

  11. Right-click on the Greeting function in Code Explorer and select Published from the context menu.

    The Greeting function is now published. Notice that its icon has changed. Notice also that the Studio has inserted the following meta-data tags above the function declaration line in your source code:

{ Published = True }

{ Description = "" }

Publishing Web Application Functions

Publishing web application functions is a security measure of Visual DataFlex web applications. Only published functions can be invoked externally, so you are in complete control over how the calling web interface can interact with your application.

  12. Edit the Description meta-data tag to describe what the purpose of the function is. Type

This function accepts a name and returns it in the form 'Hello, Name, how are you today?'

inside the quotes of the Description meta-data tag, as seen below.

  13. If the Object Properties window is not open, click on the Object Properties toolbar button to open it.

Object Properties

The Object Properties window is used to view and edit property values for the selected object in the Studio's designers, such as Code Explorer.

  14. Select the oGreeting object in Code Explorer. In the Object Properties window, change the psServiceName from tempService to GreetingService.

Service Name

The Service Name uniquely identifies the service within your application and is used by clients to access the service. In this case, the name of the service is GreetingService and the virtual directory in which the service will run is http://localhost/greetingwebservice. The service will be accessed with the URL http://localhost/greetingwebservice/greetingservice.wso. The name of this .wso file is important. Each WSO within a single web application should have a unique psServiceName.

  15. Change the value of the psServiceTitle property from Visual DataFlex Web Service to Greeting Web Service.

    The resulting object properties should look like this:

Tip

Notice that all the property values that have been modified from their default values are shown in bold. These are also the only properties that are written out to the code of the current source file.

To reset a property value to its default value, right click on the property name column in the Object Properties window and select Reset Value.

Tip

You can see the documentation for any property by clicking on the property in the Object Properties window and pressing F1. This will take you directly to the Visual DataFlex help entry for the selected property.

Tip

The Studio will display different controls for each property based on the property type. For example, click in the value column (the right column) for the pbDocumentStyle property. Notice the combo form that allows you to select a value from a predefined enumeration list (in this case, True or False for this Boolean property).

psServiceURI

A web service must define a TargetNamespace URI. This is supposed to be a unique identifier that keeps all parts of your web-service unique. The psServiceURI does not have to point to an actual web-address, it is just supposed to be a unqiue name. The default setting for this is http://tempuri.org/. This name will work fine for testing but it is strongly suggested that you change this before you actually publish a web-service.

  16. Create a description for the entire web service to be published as part of the service’s description. Double-click on the oGreeting object in Code Explorer to display the code for this object. Find the following source code:

//------------------------------------------------------------------------------------

// psDocumentation provides high level documentation of your web service. Clients using

// this service will see and use this documentation.

//------------------------------------------------------------------------------------

Set psDocumentation to ;

("Visual DataFlex Web Service .... " + ;

" ... " + ;

"documentation")

Replace the psDocumentation string with meaningful information. Notice that this source is broken up into multiple lines to demonstrate how to create long, yet readable description within the edit area.

Set psDocumentation to ;

("Greeting Web Service is used by the Visual DataFlex Tutorials " + ;

"to demonstrate a simple Web Service.")

  17. When you select the oGreeting object in Code Explorer again, you will see that the value of the psDocumentation property in the Object Properties window has been updated to reflect the source code change you just made.

Compiling and Running Your First Web Service


Compiling and Testing Your First Web Service

Now, let's test the Greeting Web Service function you have just created.

  1. Click on the Run button on the Studio's toolbar.

  2. The application should automatically load in your default browser and display the testcontent.htm page, with a link to the Greeting Web Service. Click the Greeting Web Service link. Your browser will now show the GreetingService.wso page:

    There are a number of things to note on this page:

  • The page that is used to access this Web Service (http://localhost/GreetingWebService/GreetingWervice.wso) is determined by the psServiceName property of the WSO that you set in the Studio's object properties dialog.

  • The title "Greeting Web Service" is the value of the WSO's psServiceTitle property.

  • The description of the service, right beneath the title is the value of the WSO's psDocumentation property.

  • The list of operations is created by an enumeration of all published functions in your WSO. In the case of our Greeting WSO, Greeting is the only published function.

  • The description below the Greeting function is the description you typed into the "Method Properties" dialog in the Studio.

  3. Click on the Service Description link to see the WSDL document for this service. When you are done viewing the WSDL, click on the Back button of your browser to return to the WSO page for your Web Service.

Testing your Web Service

  4. Click the Greeting link to load the test page for the Greeting function. You should see the following page:

    On this page, you can actually test your web service's functionality. The Studio has created the page for you to test calling the Greeting web service function.

Web Service Test Page

The test page that Visual DataFlex Studio creates for your Web Service is just that, a test page. Normally, a Web Service function is called from a Web Service client without any visual interface. The test page provides a quick and simple way of testing your Web Service's functionality without having to create a client for it.

  5. Type your name into the sName window and click the Invoke button. Another web page should open, displaying the result of the Greeting function:

The Web Service you have just created could now be placed on a Web server and access by Web Service client's designed in any tool that supports web services anywhere in the world.

Debugging Code in Web Services


Debugging Code in Web Services

A type of problem that programmers encounter is a program that compiles, but then behaves differently than expected.

Debugging

Debugging is the act of observing the run-time behavior of a program and determining the location of semantic errors. With the debugger, you can break (suspend) execution of your program to examine your code, evaluate and edit variables in your program, view data in database tables and control the execution of the instructions in your source code.

You can debug your Web Service function code in several different ways:

  • Debug the code using the Debugger.

  • Use the Web Service function's test page to call the Web Service function and examine the result.

  • Build a Web Service client and debug the Web Service from the client side. If you build a Windows client, you can use the Web Service Helper view to see the XML code sent to and returned from the Web Service.

    You will learn about building Web Service clients in Using Your First Web Service.

Important!

This section assumes that you have been going through the Quick Start tutorial step by step.

If you skipped the Windows application part of Quick Start, you should read the Handling Compiler Errors section now and return to this page when you have completed it.

You are going to make a change in the code of your Greeting Web Service function, to cause it to behave differently than you want it to behave. Then, you will learn how to use the debugger to track down and solve the problem.

  1. Bring up the code for the Greeting function in the Greeting.wo file in Code Explorer.

  2. Change the line

move "Hello, " to sHello

to

move "Hello," to sHello

  4. Click on the Run button on the Studio's toolbar. The program will compile and run.

  5. When the application runs, your browser should display the testcontent.htm page. Click the Greeting Web Service link to load the GreetingService.wso page. On this page, click on the Greeting link. Type your name into the sName form and click the Invoke button.

    You will see that the result that appears in the Result form now is, for example, "Hello,John, how are you today?", with the space between the comma and the name missing. You will now use the debugger to track down why the space is missing.

  6. Leave the program running and switch back to the Studio. Click in the left hand margin of the code editor next to the code line

move "Hello," to sHello

  7. This will place a red dot in the left margin, indicating that you have just placed a breakpoint on this line of code.

Breakpoints

Debuggers work by causing executing programs to stop and examining the program at this "frozen" time. Breakpoints on lines of code cause the debugger to halt the program when reaching that line of code, just prior to executing it.

  8. Now you will execute the program up to this line of code to have the debugger stop at this point. Since the breakpoint is in the Greeting function of the oGreeting WSO, you need to run your program and click on the Invoke button to get the debugger to execute the program's code up to this breakpoint.

    Return to the running program and click on the Invoke button again.

    This time, the program is stopped by the debugger at the breakpoint.

  9. If you place your mouse cursor over any local variable in Function Greeting, you will see the current value of the variable pop up as a tool tip. Of course, at this point in the code, all variables should show up to be blank.

    Notice also the green arrow in the left margin, which currently overlaps the red dot for the breakpoint you placed. The green arrow indicates the line on which the program is currently "frozen". This is the next line that will execute in the program.

  10. Take a look at the Locals window. If the Locals window is not open, click on the Locals icon on the Studio's toolbar.

    This will open the Locals window, which lists all local variables and their current values. This is a useful window to keep open when debugging, since it reflects the values of all local variables as you step through the code.

  11. Click on the Step Over button on the Studio's toolbar (or press F10).

Stepping through code

Stepping through code is an important debugging concept. A step causes the debugger to tell the program being debugged to execute lines of code as you tell it to.

  12. The debugger has executed the line

move "Hello," to sHello

Notice that the variable sHello now contains "Hello,". You can see this in the Locals window and also by holding the mouse cursor over the variable sName anywhere inside Function HelloWorld.

  13. Click on the Step Over toolbar button twice. The green arrow should now be next to the line

Function_Return sReply

The variable sHello now contains "Hello," sName contains the name you typed into the Name form, sHowAreYou contains ", how are you today?" and sReply contains the concatenated result of sHello + sName + sHowAreYou ("Hello,John, how are you today" in our example images).

It is now readily apparent that the reason for the missing space is that there was no space placed either at the end of sHello or the beginning of sName.

Red values in Locals window

You will notice that the value of sReply is displayed in red in the Locals window. This is a visual cue to indicate that the value of sReply has just changed.

  14. Take a look at the Watches window. If the Watches window is not open, click on the Watches icon on the Studio's toolbar.

    This will open the Watches window, another useful window to keep open when debugging. The Watches window can display any expression you wish to evaluate while debugging. Try it like this:

  • Double-click on sReply in the code editor (this selects the entire word). Drag and drop it into the Name column of the Watches window.

    You will see that the Value column displays the current value of sReply, which is "Hello,John, how are you today" in our current sample.

  • Highlight the expression (sHello + sName + sHowAreYou) in the code editor. Drag and drop it into the Name column of the Watches window.

    You will see that the Value column displays the current value of (sHello + sName + sHowAreYouToday), which is "Hello,John, how are you today" in our current sample (just like sReply).

  • Click in the Name column of the Watches window of the row which currently contains (sHello + sName + sHowAreYou). This will highlight the entire current row. If you click in the Name column once more, you will see that it is now editable.

    Change the expression to (sHello + " " + sName + sHowAreYou) and press Enter.

    You will see that the Value column now displays the current value of (sHello + " " + sName + sHowAreYou), which is "Hello, John, how are you today?" in our current sample.

    It is now readily apparent that the reason for the missing space is that there was no space placed either at the end of sHello or the beginning of sName.

  15. Be sure to change "Hello," back to "Hello, ". You will call the Greeting web service function in the Using Your First Web Service tutorial.

We encourage you to spend some time using the Visual DataFlex Debugger, it is a very powerful tool and the features we have shown you here barely scratch the surface of what you can do with it.

Mastering the Debugger will help you understand how Visual DataFlex works and make you a better programmer.

Next Step

You have just learned how to create a web service application and a web service function in the Visual DataFlex Studio, and how to compile and debug them. Next, you will learn how to use web services in Visual DataFlex applications: Using Your First Web Service


Using Your First Web Service

This tutorial will guide you through the most basic steps of using Web Services in Visual DataFlex Applications. As you complete tasks, concepts will be explained to you.

This tutorial consists of two sections, one for each application type you may want to use Web Services in:

  • Using Web Services in Windows Applications

  • Using Web Services in Web Applications

This tutorial will call the Greeting Web Service that you have created in Creating Your First Web Service, but you can just as easily build clients to access any Web Service in the world that was built in any tool that supports creation of Web Services.


Creating a Web Service Client Class

If your Studio is not currently open to the QuickStart workspace, please switch to it now. To learn how to switch workspaces in the Studio, switch to Selecting a Workspace now and return here when you have completed it.

Important!

This section assumes that you have completed the Creating Your First Web Service tutorial. Since the code you will create here will call the Greeting Web Service created in Creating Your First Web Service, you must complete that tutorial before continuing with this section.

To simplify development of Web Service client applications, Visual DataFlex Studio creates Web Service client classes for you. A Web Service client class is a Studio-generated class that locally represents the exposed functionality of a Web Service. The class defines methods that represent the actual methods exposed by a Web Service. When the client application creates an instance of the class, it is capable of calling the Web Service methods as if the Web Service was a locally available component.

So, the first step in calling an existing Web Service from a Visual DataFlex application is to create a Web Service client class, regardless of whether your application is a Windows, Web or Web Service application.

Before you can create a Web Service client class, you need to locate the service’s WSDL file. You can do this by loading your Internet Browser and pointing to a WSDL file. Any service available on the web should have a mechanism for locating its WSDL.

  1. Open the Studio to the QuickStart workspace.

  2. Click on the Create New button on the Studio’s toolbar.

  3. Click on the Class tab of the Create New... dialog.

  4. Double click the Client Web Service Class icon.

  5. Type or paste the URL for the WSDL file into the WSDL URL form and click the Parse button.

    The address to the Greeting Web Service you created in the Creating Your First Web Service tutorial should be http://localhost/greetingwebservice/greetingservice.wso?WSDL.

    You can now see the class that the Web Service Client Class Generator will generate for you on the Class tab page.

    You can view the WSDL file on the WSDL tab page.

  6. Click the Generate Class button to generate the class. The "Create Web Service Client Class" dialog will pop up:

    You can see in this dialog that it will generate a class named cWSGreetingService, which is local to the current workspace (in our case QuickStart), and it will place an icon for this class in the "Web Services" group of the Studio's Class Palette.

  7. Leave everything in this dialog as it is and click Ok to create the class. When the Web Service Client Class Generator returns you to the Studio, you will see the package file in which the Web Service client class was created open so you can view the code of the class that was created.

Using a Web Service in a Windows Application


Using a Web Service in a Windows Application

This section will show you how to call a Web Service function from a Windows Application using the following steps:

  • Calling a Web Service from a Windows Application

  • Debugging a Windows Application Web Service Call

Important!

This section assumes that you have completed the Creating a Web Service Client Class section. You cannot complete this section without first generating a Web Service client class, so, if you have not done so, switch to Creating a Web Service Client Class now and return here when you have completed that step.

This section also assumes that you have completed the Creating Your First Windows Application book.


Calling a Web Service from a Windows Project

Calling a Web Service from a Windows Application

In this section, you are going to create a view that calls the Greeting function in the Greeting Web Service that you created in the Creating Your First Web Service tutorial.

The view we will create will be very simple, with 2 forms and a button. The first form will be labeled Name and the second form Result. The user will type his or her name into the Name form and click the button. The name will then be passed to the Greeting Web Service function and the returned string displayed in the second form.

Important!

This section assumes that you have completed the Creating a Web Service Client Class section. You cannot complete this section without first generating a Web Service client class, so, if you have not done so, switch to Creating a Web Service Client Class now and return here when you have completed that step.

This section also assumes that you have completed the Creating Your First Windows Application book.

Tip

If you have worked through the entire Quick Start book up to this point, your QuickStart workspace will contain at least one Windows application and a web application. Ensure that the Current Project in Workspace Explorer is MyFirstWindowsApplication.src, not WebApp.src. If you try to create a Windows project component, such as a view, and the current project is a web application, the Studio will display an error message and not allow you to create the component.

  1. Click on the Create New button on the Studio’s toolbar.

  2. Click on the View / Report tab of the Create New... dialog.

  3. Double click the Data Entry View icon. The "Create a New Windows View Component" dialog will open. Enter oCallGreetingWebService as the object name. The filename automatically changes to CallGreetingWebService.vw as you type the object name. Accept the default directory path (the AppSrc folder in the QuickStart workspace). Click on the Ok button.

  4. Drag and drop 2 Form controls from the Base Controls group on the Class Palette onto the blank view. Make both forms about twice as wide as their default width.

    Next, drag and drop a Button control from the Base Controls group on the Class Palette onto the view.

  5. In the Object Properties window, change the Label of the oCallGreetingWebService view object to Call Greeting Web Service

    Change the Name of the first form to oNameForm, its Label to Name and its Label_Col_Offset to 30.

    Change the Name of the second form to oResultForm, its Label to Result and its Label_Col_Offset to 30.

    Change the Label of the Button control to Go.

    Your view should now look similar to this:

  6. Drag and drop a cWSGreetingService control from the Web Services group on the Class Palette onto the view.

    You will notice that you do not see a visual object displayed for the cWSGreetingService control in the visual designer. You will, however, notice an object named oWSGreetingService1 in the Code Explorer tree for this view.

  7. Double-click on the oWSGreetingService1 object in Code Explorer to display its source code. The source code for this object is made up entirely of comments, which contain information about the class.

    The first thing in the comments for this object is the class's interface; you can see that the only function in the class's interface is Function wsGreeting. You also see in its declaration that is accepts a string argument and returns a string, which will aid you in calling this function.

    Below the interface listing is a comment about debugging this web service. Ignore this for now; it is discussed in detail in Debugging a Windows Application Web Service Call.

  8. Now you will add code to the Button control. The code here will get the name the user has entered from form oNameForm, call the Web Service function wsGreeting and display the result of wsGreeting in form oResultForm.

    Type the following lines of code inside the already declared Procedure OnClick.

  1. The first line of code is:

string sName sResult

  2. The next line of code is:

get Value of oNameForm to sName

  3. The next line of code is:

get wsGreeting of oWSGreetingService1 sName to sResult

This code line makes the call to the wsGreeting function of the oWSGreetingService Web Service client object. It passes the name in sName to wsGreeting and receives the return argument in sResult.

  4. The last line of code is:

set Value of oResultForm to sResult

  9. The completed code should look like this:

  10. So, let's test the completed view.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project.

    When the application runs, select oCallGreetingWebService from the View menu. Type your name into the form labeled Name, then click the Go button. You will see "Hello, {Your Name}, how are you today?" in the form labeled Result.

    The result will look like this:

As you can see, calling a Web Service from a Visual DataFlex Windows application is simple and completely transparent, any complexities have been handled by Studio.

Debugging a Windows Application Web Service Call


Debugging a Windows Application Web Service Call

There are several tools available to you when debugging calls to Web Services:

  • Using the Web Client Helper View

    Visual DataFlex client-side web services have a built-in helper view (WebClientHelper.vw) to help you debug calls to web services.

  • Using the Debugger to Debug Web Service Calls

    You can debug the web service call using the Debugger.

Using the Web Client Helper View

  1. Double-click on the cWSGreetingService1 object in the CallGreetingWebService view to bring up its source code. At the bottom of the code you will see the following commented code:

// phoSoapClientHelper

// Setting this property will pop up a view that provides information

// about the Soap (xml) data transfer. This can be useful in debugging.

// If you use this you must make sure you USE the test view at the top

// of your program/view by adding: Use WebClientHelper.vw // oClientWSHelper

//Set phoSoapClientHelper to oClientWSHelper

  2. Uncomment the last line of code, so that the result is this:

Set phoSoapClientHelper to oClientWSHelper

  3. At the top of the view's source code, right beneath the Use statements are already in place, add the following Use statement:

Use WebClientHelper.vw

  4. After you do this, every web service request to this client will cause a helper view to be activated showing you the web service call and the web service's response in XML.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project.

    When the application runs, select oCallGreetingWebService from the View menu. Type your name into the form labeled Name, then click the Go button. You will see "Hello, {Your Name}, how are you today?" in the form labeled Result.

    You will also see the web service helper view pop up:

    In this helper view, you can see a lot of information about the Web Service call that was made, the information passed to the Web Service, the information returned, the status (e.g. "wssOk = Success") and the raw XML data being sent to and returned from the Web Service.

Using the Debugger to Debug Web Service Calls

You can also use the Debugger to debug the code making the call to a Web Service. You can place breakpoints and step through your code while analyzing local variables and other information about your program. You could also open the client Web Service class package (cWSGreetingService.pkg in our example) and place breakpoints within the appropriate functions in the class.

Please see Debugging Code in Windows Applications to learn more about debugging Windows application code.

Next Step

You have just learned how to call and debug web service from a Visual DataFlex Windows application. Next, you will learn how to call web services in Visual DataFlex web applications: Using a Web Service in a Web Application


Using a Web Service in a Web Application

This section will show you how to call a Web Service function from a Web Application using the following steps:

  • Calling a Web Service from a Web Application

  • Debugging a Web Application Web Service Call

Important!

This section assumes that you have completed the Creating a Web Service Client Class section. You cannot complete this section without first generating a Web Service client class, so, if you have not done so, switch to Creating a Web Service Client Class now and return here when you have completed that step.

This section also assumes that you have completed the Creating Your First Windows Application book.


Calling a Web Service from a Web Project

Calling a Web Service from a Web Application

In this section, you are going to create a web page that calls the Greeting function in the Greeting Web Service that you created in the Creating Your First Web Service tutorial.

The Web page you will create will be very simple, with 2 forms and a button. The first form will be labeled Name and the second form Result. The user will type his or her name into the Name form and click the button. The name will then be passed to the Greeting Web Service function and the returned string displayed in the second form.

Important!

This section assumes that you have completed the Creating a Web Service Client Class section. You cannot complete this section without first generating a Web Service client class, so, if you have not done so, switch to Creating a Web Service Client Class now and return here when you have completed that step.

This section also assumes that you have completed the Creating Your First Web Application book.

Tip

If you have worked through the entire Quick Start book up to this point, your QuickStart workspace will contain at least one Windows application and a web application. Ensure that the Current Project in Workspace Explorer is WebApp.src, not a Windows application. If you try to create a Web object, such as a WBO, and the current project is a Windows application, the Studio will display an error message and not allow you to create the component.

  1. Click on the Create New button on the Studio’s toolbar.

  2. Click on the Web Object tab of the Create New... dialog.

  3. Double click the Web Browser Object icon. The "Create a New Web Object" dialog will open. Enter oCallGreetingWebService as the object name. The filename automatically changes to CallGreetingWebService.wo as you type the object name. Accept the default directory path (the AppSrc folder in the QuickStart workspace). Click on the Ok button.

  4. At the top of the view's source code, right beneath the Use statements are already in place, add the following Use statement:

Use cWSGreetingService.pkg

  5. Below the code for object oCallGreetingWebService, add the following code:

Object oWSGreetingService1 is a cWSGreetingService

End_Object

  6. The completed code should look like this:

  7. Now you will add a function inside the WBO (cWebBusinessProcess) object. The code here will accept a name, call the wsGreeting web service function and return the result of wsGreeting.

    Inside the code for object oCallGreetingWebService, add the following code:

  1. The first line of code is:

Function CallGreeting string sName returns String

  2. The next line of code is:

string sResult

  3. The next block of code is:

if (sName = "") begin

move "stranger" to sName

end

This block of code moves stranger to sName if no name was passed to the function.

  4. The next line of code is:

get wsGreeting of oWSGreetingService sName to sResult

This code line makes the call to the wsGreeting function of the oWSGreetingService Web Service oWSGreetingService object. It passes the name in sName to wsGreeting and receives the return argument in sResult.

  5. The next line of code is:

function_return sResult

  6. The last line of code is:

End_Function // CallGreeting

  8. The completed code should look like this:

  9. Next, the function needs to be published so that it can be invoked from a Web page.

    Right-click on the CallGreeting function in Code Explorer and select Published from the context menu.

The CallGreeting function is now published. Notice that its icon has changed. Notice also that the Studio has inserted the following meta-data tags above the function declaration line in your source code:

{ Published = True }

{ Description = "" }

Publishing Web Application Functions

Publishing web application functions is a security measure of Visual DataFlex web applications. Only published functions can be invoked externally, so you are in complete control over how the calling web interface can interact with your application.

  10. Next, you will create the ASP page that will serve as the "front end" of your application and call the CallGreeting function.

  11. Let's change the title of the page. This is the title that will show up on the caption bar of your browser when you load this page.

Change the line

<title>New Page 1</title>

to

<title>Call Greeting Web Service</title>

  12. Next, you are going to add some code into the <body> section of the page. Type the following lines of code inside the <body> and </body> tags.

  1. The first block of code is:

<%
if Request("Request_Method")="POST" then

if Request("Go")<>"" then

sName = Request("Name")

  2. The next line of code is:

sResult = oCallGreetingWebService.Call("get_CallGreeting", sName)

This is the only line of code that is not standard ASP code.

This code makes a call to your Visual DataFlex CallGreeting function via the call interface. It passes sName to CallGreeting and returns the result into sResult. The call interface is the interface that allows access from ASP script code to any published methods in a Visual DataFlex application.

  6. The remaining code is:

end if

end if

%>

<form method="POST" name="Form1" action="CallGreetingWebService.asp">

Name: <input type="text" name="Name" value="<%=sName %>" size="40"><br>

Result: <input type="text" name="Result" value="<%=sResult %>" size="40"><br>

<input type="submit" value="Go" name="go"><br>

</form>

  13. The completed code should look like this:

  14. So, let's test our completed Web application page.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should come up with the testcontent.htm page (http://localhost/quickstart/testcontent.htm).

  15. Click on the Call Greeting Web Service link to bring up the web page you have created:

  16. Do not type a name into the form labeled Name and click the Go button.

    You will see "Hello, stranger, how are you today?" in the form labeled Result:

  17. Type your name into the form labeled Name, then click the Go button.

    You will see "Hello, {Your Name}, how are you today?" in the form labeled Result:

    Close the browser to close the application.

As you can see, calling a Web Service from a Visual DataFlex Web application is simple and completely transparent, any complexities have been handled by Studio.

Debugging a Windows Application Web Service Call


Debugging a Web Application Web Service Call

Using the Debugger to Debug Web Service Calls

You can use the Visual DataFlex Debugger to debug the code making the call to a Web Service. You can place breakpoints and step through your code while analyzing local variables and other information about your program. You could also open the client Web Service class package (e.g. cWSGreetingService.pkg) and place breakpoints within the appropriate functions in the class.

Please see Debugging Code in Web Applications to learn more about debugging Web application code.

Next Step

You have just learned how to call and debug web service from a Visual DataFlex web application. Next, you will learn how to create database application components: Creating Database Application Components


Creating Database Project Components

Creating Database Application Components

Introduction

This Tutorial demonstrates how to develop major application component types for Windows and Web applications.

This Tutorial consists of the following sections:

Creating Tables and Data Dictionaries

Creating Windows Components

Creating Web Components


Creating Tables and Data Dictionaries

This section will introduce readers to some very important topics: workspaces, tables and DDs. It will discuss the concepts using the provided QuickStart workspace and, for the tables and DDs, the Customer table and DD.

  • Creating Workspaces

  • Creating Tables

  • Creating Data Dictionaries


Creating Workspaces

Workspace

A Visual DataFlex Workspace is a physical and logical container for your projects, with a well-defined structure. A Workspace can contain multiple projects, typically related in some logical manner, such as a Windows application and a Web application that access the same database. A workspace contains everything necessary to build and run a Visual DataFlex project.

Project

A Visual DataFlex Studio Project is a collection of components and other items of interest to the Studio that compiles into a target program.

In this section, you will not create a new workspace. Instead, you will keep using the QuickStart workspace that was used for the Quick Start tutorial. To learn how to select the QuickStart workspace, see Opening a Workspace.

To learn how to create a new workspace, see Creating a Workspace.

Typical Workspace Structure

Each of a Workspace’s sub-folders contain files indicated by the folder name (e.g. application source files are in ..\Contact\AppSrc, data dictionary source files are in ..\Contact\AppSrc, etc.)

Creating Tables


Creating Tables

Database tables are designed, created and maintained in Database Builder. Let's take a closer look at Database Builder to see how this is done.

This section will show you how to create an embedded database table. You will create a simple Contacts table for maintaining personal contacts.

  1. Open the QuickStart workspace in Visual DataFlex Studio.

  2. Click on the Database Builder toolbar button.

  3. Click the Create New Table button in Database Builder.

    In the New Table dialog, change the Table Name to Contacts:

    The new table will open and the Columns tab page will be the active tab page.

Defining Tables vs. Data Dictionaries

The Database Builder tool is used for defining database tables as well as Data Dictionaries for those tables. The first 4 tab pages in Database Builder (those highlighted in yellow in the image above) are used for defining and maintaining database tables and the remaining tab pages are used for defining and maintaining Data Dictionaries.

  5. Click on the Add a column toolbar button to add a new column.

  6. Type Id as the Name of the first column to add and press the Tab key to move to the next grid column. Choose Numeric as the column type from the combobox and press Tab; make the length 4.0 and press Tab twice. This will complete the definition of the Id column and move you to the next row in the Columns grid.

    The Id column will be an auto-increment column, so its value will always be unique. How to define this column as an auto-increment column will be explained in the next section.

  7. Type First Name as the Name of the second column; choose ASCII as the column type and make the length 20.0.

  8. Continue to add columns to the table until your Columns grid looks like the one in the image below.

    Note: For this tutorial, we are using a very simple table, so we are not normalizing data. In a real-world application, Continent would be an attribute of a Country table and Country would be a parent of the Contact table.

  9. Click the Index tab.

    You are skipping over the Relationships tab since this table will not have any relationships. Relationships are discussed in more detail in other places in the Visual DataFlex help.

  10. Click on the Add an index toolbar button to add a new index.

  11. Enter the Segments grid and select Id as the column to add as the first index segment from the combo box. The first index will consist of only the Id column. This is the primary key index for this table.

  12. Click on the Add an index toolbar button to add another index. The segments of this index will be First_Name, Last_Name and Id.

    Check the Ignore Case checkboxes for the First_Name and Last_Name index segments. This will ensure that the names of your contacts are sorted correctly regardless of the casing when you add them to the database.

    Adding the Id column to this index allows you to add multiple contacts with the same first and last name.

  13. Click on the Add an index toolbar button to add another index. The segments of this index will be Last_Name, First_Name and Id. Again, check the Ignore Case checkboxes for the Last_Name and First_Name index segments.

    The finished index page should look like this:

  14. Click on the Parameters tab.

    The parameters for the embedded database are defaulted to what you are most likely to use.

    The main parameter that you may want to change here is "Max Records". Depending on what you will use this table for, you may want to increase or decrease this number from the default.

  15. Click the Save table toolbar button, or select Save Table from the File menu. It is useful to have a text file (*.DEF) showing you all the details of the table, so check Create .DEF and accept the suggested restructure options.

    Note that a Data-Dictionary file is automatically created when you save the table. In the next step, you will learn how to define Data Dictionary rules for this table.

    Leave Database Builder as it is now and continue to the next step.

Creating Data Dictionaries


Creating Data Dictionaries

Data Dictionaries are designed, created and maintained in Database Builder.

This section will show you how to define a Data Dictionary for the Contacts table created in the previous step. We will only scratch the surface of the power of Data Dictionaries here, but you will learn about the main concepts of Data Dictionaries and how to add simple business rules to Data Dictionaries.

Data Dictionary Classes

Visual DataFlex is an object oriented language. When you define a Data Dictionary in Database Builder, it creates a class from that definition. When you create a component (e.g. a view or report) in the Studio that uses a table, the Studio instantiates an object based on this class.

For example, Database Builder will create a class called Contacts_DataDictionary for the Contacts table. The Studio will instantiate an object named Contacts_DD when you create a component that uses the Contacts table. Thus, the class definition from Database Builder is inherited in your Studio components.

  1. Click on the Column Settings tab of the Contacts table you created in the Creating Tables section.

    As discussed in Creating Tables, the first 4 tab pages in Database Builder are used for defining and maintaining database tables and the remaining tab pages (those highlighted in yellow in the image above) are used for defining and maintaining Data Dictionaries.

Exclusive Table Mode

You have probably noticed the green lock icon in the Contacts table dialog by now.

The green lock icon means that the table is open exclusively in Database Builder so that the table's structure can be edited. If you click on it, you will toggle the table from exclusive to non-exclusive table editing mode.

Non-Exclusive Table Mode

Non-exclusive table editing mode allows you to view the table's structure (without modifying it) and it allows you to define and modify Data Dictionaries. This mode is very useful, because it allows you to work on a Data Dictionary definition in Database Builder while working on components that use that Data Dictionary in the Studio.

Once a table has been created, you will work in non-exclusive table mode most of the time, unless you need to change the structure of the table.

  2. Select the State column and check the Capslock checkbox.

    This is one of the simplest rules you can define in a Data Dictionary. This will force data entered into the Contacts.State column to always be capitalized.

  3. Select the Zip column and click on the Mask tab. Type #####-#### into the Custom Mask window.

    This custom mask will force data to be entered into the Contacts.Zip column to be of the specified format, #####-####. # signifies that only a numeric character (0-9) can be entered. So, the mask allows 5 numeric characters, followed by a dash (or minus sign) and then 4 numeric characters, which is the U.S. zip code format.

  4. Select the Continent column and click on the Validation Table tab.

    Select Static as the Type. Click in the Value column of the grid and type Africa. Press Tab twice to go to the next row in the grid. Continue to add continents to the list until it looks like the image below.

    Defining a validation table to the Continent column will cause the column to be associated with this validation table wherever it is used. In a Windows application, Contacts.Continent will appear as a combobox with the list of continents in the drop down list.

    Checking the Validate checkbox will cause an error message to appear if the user navigates past the control or saves a record without selecting a valid choice from the list.

    Leaving the Blanks checkbox unchecked will force users to enter or select a value for this column before navigating past the control or saving a record.

  5. With the Continent column still selected, click on the Other tab.

    Type North America into the Default Value window.

    This will default the value of the Continent column to "North America" when a view or web form is cleared to start a new record.

Auto Number Columns in the Embedded Database

Auto numbering is supported in the embedded database via a counter column in a system table. To enable auto numbering, we need to create a column in a system table of the same size and type (always numeric) as the column in the table that is to be auto numbered.

System Table

A system table is a table that contains only one record and also has its Max Records parameter set to one. Visual DataFlex will automatically find and load this record upon opening the table.

  6. Open the Order Entry System Table (OrdSys) in Database Builder.

    Answer No to the question whether to create a .DD file for this table. System tables normally do not require Data Dictionaries.

  7. Toggle the lock on the OrdSys table to exclusive table mode (green).

  8. Add a column named Contact_Number, type Numeric and length 4.0, to match the length of Contacts.Id.

  9. Save the OrdSys table and close it.

    You should now be back in the Contacts table, on the "Column Settings" > Other tab page, with the Continent column selected.

  10. Select the Id column. Click on the prompt button (...) in the Auto Increment window.

    Select the OrdSys table and the Contact_Number column and click Ok.

    Once the "Auto Increment" window is filled in with the system table and column to increment from, the Data Dictionary does the auto numbering automatically.

  11. Save the Contacts table.

Next Step

This concludes your introduction to Data Dictionaries. You now understand the most common types of business rules and where to go to define them. Next, you will learn how to create Windows components: Creating Windows Components


Creating Windows Components

This tutorial will guide you through the steps of creating Windows application components using Visual DataFlex. As you complete tasks, concepts will be explained to you.

Important!

In order to complete the pages in this tutorial section, you must have at least one Windows application in the QuickStart workspace. If you have worked through the Creating Your First Windows Application section of the Quick Start tutorial, your QuickStart workspace will contain at least one Windows application.

If not, complete the Creating a Windows Application and Compiling and Running a Windows Application pages now, and then return to this section and continue where you left off.

This tutorial section will take you through the following steps:

  • Creating a Data Entry View

  • Creating a Lookup List

  • Creating a WinPrint Report

  • Standard Windows Application Features


Creating a Data Entry View

Let's create a Customer data entry view in the Studio, using the "Data Entry View Wizard".

Data Entry View

A data entry view is a component that contains data entry objects (DEOs), such as dbForm and dbGrid objects designed for creating new records and editing existing records.

Tip

Ensure that the Current Project in Workspace Explorer is a Windows Application, not a web application. If you try to create a Windows project component, such as a view, and the current project is a web application, the Studio will display an error message and not allow you to create the component.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the Data Entry View Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, enter oCustomerEntry as the object name, CustomerEntry as the filename and Customer Entry as the description and click Next.

Naming Views

Views are containers for the forms and other controls which go to make up data-entry screens. Most programs are made up of one or more views, each containing several controls. For example, the dialogs in the wizard you are using to create your application have title bars with appropriate names, bitmaps for illustration, text-boxes for instructions, forms for the entry of specific information and buttons for navigation.

  4. On the "Entry View Style" wizard page, select Create a Simple Form Entry View, then click Next.

  5. On the "Main Data Dictionary" wizard page, click on CUSTOMER - Customer_DataDictionary to select it as the data dictionary to be used, then click Next.

  6. On the "Entry Fields" wizard page, add Customer_Number and Name fields using the Add button, then click on the Tab Page button (this will place the fields following the --Tab Page-- divider on another tab page in the view). Add Address, City, State, Zip, Phone_Number, Fax_Number and Email_Address, then click on the Tab Page button again. Add Credit_Limit, Purchases and Balance. Click on the Tab Page button once more and add Comments. Click Next.

  7. On the "Labels, Alignment and Preview" wizard page, check the checkboxes in the Same Line column for Customer.State and Customer.Zip. This will keep fields City, State and Zip on the same line (vertical location) in the view. Replace the 3 blue Tab Page Label labels with Address, Balances and Comments, in order from top to bottom.

    The field labels are defaulted from the data dictionary, but you can customize them here for your view.

  8. You can now click the Preview button to preview what your view is going to look like. This is a great feature, because it allows you to tweak your view layout very easily right here in the wizard before finalizing it.

    Notice that many properties defined in the data dictionary are already displayed in this preview:

  • The "Customer Number " and "Customer Name" forms have prompt buttons in the form (the buttons with the 3 dots), which indicates that they have a lookup list associated with the database field.

  • The State field is represented by a combo form.

  • All form sizes are approximated depending on their field lengths and types.

Click the X button in the upper right hand corner of the preview to close it.

  9. Try previewing the view with both left and right label justifications to see which you prefer.

    Once you are satisfied with the layout of your view, click the Next wizard button.

  10. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly created view in the Studio's visual designer.

  11. In Workspace Explorer, you should see a Windows application (most likely MyFirstWindowsApplication.src) as the Current Project. Click on the + in the tree view to expand MyFirstWindowsApplication.src, then click on the + to expand Views. You can see that CustomerEntry.vw has been added to project MyFirstWindowsApplication.src.

At this stage, you have created a fully functioning data entry view. The Studio has saved your view as CustomerEntry.vw and it has registered it as a component in the current workspace so that you can open it anytime to work on it.

  12. So, let's test the completed view.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, click on the View menu and then Customer Entry to open the view.

Creating a Lookup List


Creating a Lookup List

You are going to add a Customer lookup list so that users can easily find existing Customer records.

Lookup Lists

Lookup lists are separate components that are typically popped up from other components, such as views, to allow listing and searching for records.

Tip

Ensure that the Current Project in Workspace Explorer is a Windows Application, not a web application. If you try to create a Windows project component, such as a view, and the current project is a web application, the Studio will display an error message and not allow you to create the component.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Dialog / Lookup tab of the Create New... dialog. Double-click the Lookup Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the "Main Data Dictionary" wizard page, click on CUSTOMER - Customer_DataDictionary to select it as the data dictionary to be used, then click Next.

  4. On the Names wizard page, enter Customer_sl as the object name, Customer as the filename and Customer Lookup List as the description and click Next.

  5. On the "Column Fields" wizard page, click the Auto button. This will automatically add all indexed fields to the lookup list, in this case, Customer_Number, Name and Balance. Click Next.

  6. On the "Column Labels and Preview" wizard page, leave the default column names as they are.

  7. You can now click the Preview button to preview what your lookup list is going to look like. This is a great feature, because it allows you to tweak your lookup list layout very easily right here in the wizard before finalizing it.

    Notice that all column sizes displayed in this preview are approximated depending on their field lengths. Click the X button in the upper right hand corner of the preview to close it.

  8. On the "Assign Lookup List to Fields in the Data Dictionary" wizard page, leave the selected columns as they are.

    Try the different buttons on this wizard page to see the different results. Most of the time, "Auto Select" is what you want, since it chooses all indexed fields that you have added to the lookup list. Click Next when you are done.

  9. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly created lookup list in the Studio's visual designer.

At this stage, you have created a fully functioning lookup list.

In addition, each field that was checked on the "Assign Lookup List to Fields in the Data Dictionary" wizard page is now associated with this lookup list in the Customer DataDictionary. So, whenever you add those fields to a data entry view or other component, this lookup list is automatically attached to it.

Creating a WinPrint Report


Creating a WinPrint Report

Next, you will create a Customer report in the Studio, using the "WinPrint2 Report Wizard".

WinPrint

WinPrint is a reporting tool that is integrated into Visual DataFlex. You can also choose to use other reporting tools with Visual DataFlex, such as Crystal Reports.

Tip

Ensure that the Current Project in Workspace Explorer is a Windows Application, not a web application. If you try to create a Windows project component, such as a view, and the current project is a web application, the Studio will display an error message and not allow you to create the component.

The report you will create will be a simple Customer listing.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the WinPrint2 Report Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, enter oCustomerList as the object name, CustomerList as the filename and Customer List as the description and click Next.

  4. On the "Main Data Dictionary" wizard page, click on CUSTOMER - Customer_DataDictionary to select it as the data dictionary to be used, then click Next.

  5. On the "Reporting Order and Breakpoints" wizard page, select index 1:Customer_Number as the index to be used, then click Next.

  6. On the "Body Section Fields" wizard page, add the Customer_Number, Name, Address, City, State, and Zip fields by clicking on the Add button. Click Next.

  7. On the "Report Styles and Totals" wizard page, change the name of the Customer Name field to Name.

  8. You can now click the Run a Test Report button to preview what your report is going to look like. This is a great feature, because it allows you to tweak your report layout very easily right here in the wizard before finalizing it.

    When you preview this report as it is now, you can see that Customer records with zip codes that have more than 5 digits wrap to the next line in the report.

    Click the X button in the upper right hand corner of the preview to close the WinPrint report viewer.

  9. Back on the "Report Styles and Totals" wizard page, adjust the Font Size from 10 to 8 and test run the report again.

    The report now fits much more nicely onto the page.

    Click the X button in the upper right hand corner of the preview to close the WinPrint report viewer.

  10. Back on the "Report Styles and Totals" wizard page, click Next.

  11. On the "Filter Fields" wizard page, add the Customer_Number and Name fields by clicking on the Add button. Click Next.

  12. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly created report view in the Studio's visual designer.

Report View

A Report View is a view from which a report is launched. Report Views often contains additional controls besides the Print button that prints the report.

For example, your Report View that was created with the "WinPrint 2 Report Wizard" has radios that allow the user to choose whether to run the report to the WinPrint Report Viewer or directly to the printer, a Printer Setup button from which printer options can be viewed and changed, and a cancel button to close the Report View. Last, but not least, there are forms for your "Filter Fields".

Note: You can place reports in Report Views or you can use the Report View wizard to develop reports and then integrate the reports into data entry views. The Adding Print Support to the Order View topic shows you how to do this.

Filter Fields

Filter Fields are also known as "selection criteria" or constraints. These fields allow the report's user to filter the results of the report. For example, the user can enter From 1 To 5 into the filter fields forms in the "Select Customer Number" group to only see those Customer records where Customer.Customer_Number falls into that range.

  13. In Workspace Explorer, you should see a Windows application (most likely MyFirstWindowsApplication.src) as the Current Project. Click on the + in the tree view to expand MyFirstWindowsApplication.src, then click on the + to expand Reports. You can see that CustomerList.rv has been added to project MyFirstWindowsApplication.src.

At this stage, you have created a fully functioning WinPrint report. The Studio has saved a report view as CustomerList.rv and it has registered it as a component in the current workspace so that you can open it anytime to work on it.

  14. So, let's test the completed report view.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, click on the Report menu and then Customer List to open the report view. Launch the report by clicking on the Print button.

Standard Windows Application Features


Standard Windows Applications Features

Windows Applications built with Visual DataFlex have a lot of features built into the standard application framework. Some of these features are specific to database applications, typically those defined by data dictionaries and many are typical of any Windows application, such as toolbars, menus and floating popup menus. You will see some of these features here and you will discover many more as you continue to learn Visual DataFlex.

Data Entry and Data Dictionary Features

  1. With "My First Windows Application" open in the Studio, click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the program is running, select Customer Entry from the View menu.

  2. Take some time to appreciate the features of the data entry view in this application.

    The view starts out cleared, so the user is ready to enter a new record.

  • Notice that the State field's value is defaulted to "FL", as it is set up by the DataDictionary. If you click on the Balances tab page, you will see the other defaulted field value, 1000.00 for the "Credit Limit" form.

  • The "Customer Number" and "Customer Name" forms have "prompt buttons" in them. These buttons are automatically added to data aware forms via the DataDictionary when the field has a lookup list defined for it.

  3. Click the Find Next button on the application's toolbar to find the first record.

  4. Click on the prompt button in the Customer Name window or press <F4> while in that window. The lookup list you created earlier pops up.

    Observe that the lookup list popped up with the current record selected. It is sorted in "Customer Name" order, because that is the field from which you popped up the list. You can resort it by "Customer Number" order by clicking in the Number column.

    If you click in the Customer Name column again, the sort order changes back to sort by this field. You can also start typing the first few letters of the customer name you want to find and the lookup list will jump into the list at that point.

    Once you have found the desired record, you can press <Enter> to return to the view, and the selected record will populate the connected windows in the view.

Standard Application Features

  5. While in either the "Customer Number" or "Customer Name" forms, try clicking on some of the toolbar buttons, such as Find Next.

Standard Toolbar

By default, a predefined toolbar is included in your application, which includes a lot of predefined features. You have already used the "Find Next" toolbar button to find the next record. There are several other buttons on the toolbar for record finding.

If you place the cursor over any toolbar button, it pops up a tooltip with a short description of the button, followed by the shortcut key for the button. While your cursor is over the button, you will also see a longer, more descriptive explanation of what the button does on the status bar at the bottom of the program.

The Clear and "Clear All" buttons are for clearing the current record, which returns you to the blank record stage that you saw when you first opened the "Customer Entry" view. This gets the view ready for the user to enter a new record.

The prompt button on the toolbar does the same thing as the prompt button in a specific form.

Most of the above buttons are context sensitive. For example, if you click on the prompt button in a form for a database field that does not have a "prompt object" or lookup list defined, nothing will pop up.

The Save and Delete buttons are for saving and deleting the current database record.

The remainder of the buttons on the toolbar are for the standard Windows features Cut, Copy and Paste.

Try the buttons on the toolbar in your sample program to become familiar with them.

  6. While still in a form in the "Customer Entry" view, click on the File menu.

    Note that, depending on the form that is currently selected (the cursor is in), some of the items on this menu may be disabled. For example, if, as shown in the image above, the selected form is for the "Street Address" field, the Find, Next, Previous, and other finding operations are disabled. This is because this database field is not indexed, so the user cannot find records using this field.

Standard Menus

Many of the features represented on the toolbar are also on the standard menus. All the menus you see in your application are standard for all Visual DataFlex Windows applications.

For each View and Report View that you add to your program, the Studio automatically adds a menu entry under the View and Report menu items.

  7. Right-click in any form in the "Customer Entry" view.

    You will see a "floating popup menu". This menu includes many of the features that you have already seen in the application's toolbar and menus. This menu is also context-sensitive. The items listed and the items that area available (enabled) will vary depending on the type of object you pop this menu up in and it's database and data dictionary options.

  8. Close the application and return to the Studio.

    Right-click on MyFirstWindowsApplication.src in Workspace Explorer, then select Project Properties from the context menu.

  9. This will bring up the "Project Properties" dialog.

    Here you can tell the Studio whether to automatically generate menus for your application when adding (creating) components in the Studio.

Creating Web Components


Creating Web Components

This tutorial will guide you through the steps of creating Windows application components using Visual DataFlex. As you complete tasks, concepts will be explained to you.

Important!

In order to complete the pages in this tutorial section, you must have at least one web application in the QuickStart workspace. If you have worked through the Creating Your First Web Application section of the Quick Start tutorial, your QuickStart workspace will contain at least one web application.

If not, complete the Creating a Web Application and Compiling and Running a Web Application pages now, and then return to this section and continue where you left off.

Important!

In order to complete the pages in this tutorial section, you must have at least one Windows application in the QuickStart workspace. If you have worked through the Creating Your First Windows Application section of the Quick Start tutorial, your QuickStart workspace will contain at least one Windows application. If not, complete the Creating a Windows Application and Compiling and Running a Windows Application pages now, and then return to this section and continue where you left off.

This tutorial section will take you through the following steps:

  • Creating a Web Report

  • Creating a Data Entry Web Page

  • Standard Web Application Features


Creating a Web Report

You will now learn how to create a Web report in the Studio, using the "WBO Report Wizard". This page is going to show you how to create a Customer Listing web report like the one in the Visual DataFlex Order sample.

Tip

Ensure that the Current Project in Workspace Explorer is a web application, not a Windows Application. If you try to create a Web object, such as a WBO, and the current project is a Windows application, the Studio will display an error message and not allow you to create the component.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Report Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, Enter oCustomerReport as the object name, CustomerReport as the filename and Customer Report as the description and click Next.

  4. On the "Main Data Dictionary" wizard page, click on CUSTOMER - Customer_DataDictionary to select it as the data dictionary to be used, then click Next.

  5. On the "Entry Fields" wizard page, add columns Customer_Number, Name, Phone_Number, Balance and Status, then click Next. The completed list of columns should look like this:

  6. On the Index wizard page, leave the default selection of Create index combo - design time control selected and click Next.

  7. On the "Selection Fields" wizard page, add the Customer_Number column. The completed wizard page should look like this:

    Click Next.

  8. On the "Records per Page / Drill Down Report" wizard page, enter 10 as the number of records per page and click Next.

  9. On the "Drill Down" wizard page, select Customer.Name from the combo form. Click on the Use existing ASP file for the zoom, entry or report and type CustomerEntry.asp into the file name form. Click Next. The completed wizard page should look like this:

Drill Down

The "Drill down" column indicates which column (column) in the report will display as a hyperlink. When the user clicks that hyperlink, the link will "drill down" to a different web page that displays more information about the current record.

In our case, the page we entered here, CustomerEntry.asp does not exist yet. You will create this page in the next step of this tutorial, Creating a Data Entry Web Page.

  12. On the "Style sheet options" wizard page, simply accept the default Cascading Style Sheet (CSS) and click Next.

  13. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly CustomerReport.wo and CustomerReport.asp pages open in the Code Editor.

  14. In Workspace Explorer, you should see WebApp.src as the Current Project. Click on the + in the tree view to expand WebApp.src, then click on the + to expand Web Browser Objects. You can see that CustomerReport.wo has been added to project WebApp.src.

At this stage, you have created a fully functioning Web report. The Studio has saved your WBO as CustomerReport.wo and it has registered it as a component in the current workspace so that you can open it anytime to work on it.

  15. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page.

  16. Click on the Customer Report link. The next page should look like this:

  17. Click on the Run Report button.

    You can click the Next Page link to see the next 10 records in the report. You can click the New Report link to reset the report.

    If you click on any of the hyperlinks in the Customer Name column, you will get a 404 "Page not found" error in your browser, because that page does not exist yet. We are going to create this page next.

  18. Close your browser to return to the Studio.

Creating a Data Entry Web Page


Creating a Data Entry Web Page

Next, you will create a data entry Web page in the Studio, using the "WBO Entry Wizard".

Data Entry Web page

A Data Entry Web page in Visual DataFlex is an HTML form-based page that calls functions in a Web Browser Object for retrieving and saving data to a database.

Tip

Ensure that the Current Project in Workspace Explorer is a web application, not a Windows Application. If you try to create a Web object, such as a WBO, and the current project is a Windows application, the Studio will display an error message and not allow you to create the component.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Entry Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. Accept the default selection on the "Component Types" page. This will allow you to create a both a WBO and an ASP page that accesses the WBO. Click Next.

  4. On the Names wizard page, Enter oCustomerEntry as the object name, CustomerEntry as the filename and Customer Entry as the description and click Next.

  5. On the "Main Data Dictionary" wizard page, click on Customer - Customer_DataDictionary to select it as the data dictionary to be used, then click Next.

    You have now completed the part of the wizard that creates the WBO. Next, you will go through the wizard steps that define the ASP page.

  6. On the "Description ASP/HTML Page", leave the default of Customer Entry as the description and click Next.

  7. On the "Entry Fields" wizard page, click on the All button to add all fields from the Customer table to the data entry Web page. Select the Customer.Status field in the list on the right and click on the Remove button to remove just this field from the list. The completed list of fields should look like this:

    Click Next.

  8. On the Buttons wizard page, leave all of the default checkboxes as they are. Enter CustomerReport.asp in the ASP selection list form (this is the report you created in the previous section, Creating a Web Report). Click Next.

  9. On the "Index Finds in your ASP/HTML page" wizard page, leave the default selection of Create index combo - design time control selected and click Next.

    On the "Labels in your ASP/HTML page" wizard page, use the default selections and click Next.

    On the "Input Controls in your ASP/HTML page" wizard page, use the default selections and click Next.

    On the "Style sheet options" wizard page, leave the default style sheet that is filled in and click Next.

  10. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly CustomerEntry.wo and CustomerEntry.asp pages open in the Code Editor.

  11. In Workspace Explorer, you should see WebApp.src as the Current Project. Click on the + in the tree view to expand WebApp.src, then click on the + to expand Web Browser Objects. You can see that CustomerEntry.wo has been added to project WebApp.src.

At this stage, you have created a fully functioning data entry Web page. The Studio has saved your WBO as CustomerEntry.wo and it has registered it as a component in the current workspace so that you can open it anytime to work on it.

  12. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page.

  13. After compiling, your program should once again load in your default browser and now look like this:

    Note that the page looks just like it did before, but now there is a hyperlink to "Customer Entry".

    Click on the Customer Entry link.

  14. Now the browser loads the "Customer Entry" data entry web page you built.

    You can click on the < and > buttons to find the previous and next Customer records, respectively.

  15. Click on the List button. You will see that the Customer report you built in the previous section displays.

  16. Click on the Wilson Bolt & Nut Company link.

    As you can see, the customer data entry web page you built also serves as the "drill down" page for your customer report. It displays the details of the customer record you clicked on in the in the customer report. The fact that you can immediately edit the customer record is an additional bonus.

    You could also quite easily change the customer report to link to a different page, or even link to different pages conditionally. For example, if some employees accessing a web application have rights to edit records and other do not, this could be very easily implemented.

Index ComboForm

If you select a different index from the "By" comboform, "Customer Name", for example, everything on this page will be determined by that index. If you click the > or < find buttons to find the next or previous customers, they will use the order specified in the comboform. If you click the list button, the customer report will also use the index specified in the comboform. lay around with this feature, it is very powerful and done with no custom coding at all.

Standard Web Application Features


Standard Web Application Features

Web Applications built with Visual DataFlex have a lot of features built into the standard application framework. Some of these features are specific to database applications, typically those defined by data dictionaries. You will see some of these features here and you will discover many more as you continue to learn Visual DataFlex.

Data Dictionary Business Rules

One of the most powerful features of Visual DataFlex are DataDictionaries. These allow you to define very simple (e.g. CapsLock on a table field set via a checkbox) as well as very complex (code-based) business rules. These business rules can be shared across multiple applications, or, more typically, across Windows and web-based applications that use the same database.

For example, in the image below you can see a Customer data entry web page with a cleared customer record, ready to add a new customer. The state field is a comboform that allows selection of any U.S. state and has defaulted to Florida. The credit limit field has defaulted to a value of 1000. All of this is done via simple business rules.

High Level of Integration Among Wizard-Created Pages

The Web-based wizards in the Studio do a lot of work for you and are designed to integrate easily. For example, a report that lists customers can "drill down" into either another report, such as a report listing all of the orders for a given customer, or into a customer entry page, where the customer information can be edited. All of this can be done with no custom coding at all, just by using wizards.

For example, in the image below you can see a wizard-generated customer report with links on the customer name. Clicking on the link for any customer will bring up another page, which could be another report or a data entry page, also wizard-generated, which would know which customer was selected and would automatically bring up that customer's information.

High Level of Flexibility

With minimal amounts of additional coding, additional features can be integrated into wizard-generated code. For example, giving users rights to certain fields on a data entry web page. It is very easy to make a for field read-only or even not to appear as a form, but just plain text, based on users' rights or other conditions.

Next Step

This concludes your introduction to creating database application components in the Visual DataFlex Studio. Next, you will put this newfound knowledge to practical use and create a complete order entry system: Creating a Complete Order Entry System


Creating a Complete Order Entry System

Creating a Complete Order Entry System demonstrates, in detail, how to create a complete Order Entry system. This tutorial essentially shows you how to reproduce the Order Entry sample application.

This Tutorial consists of the following sections:

Creating a Workspace

Creating a Set of Tables and Data Dictionaries

Creating Windows Data Entry Components

Creating Web Data Entry Components

Adding ActiveX Controls to the Order Entry System


Creating a Workspace

Let's create a new workspace for this part of the tutorial.

Workspace

A Visual DataFlex Workspace is a physical and logical container for your projects, with a well-defined structure. A Workspace can contain multiple projects, typically related in some logical manner, such as a Windows application and a Web application that access the same database. A workspace contains everything necessary to build and run a Visual DataFlex project.

Project

A Visual DataFlex Studio Project is a collection of components and other items of interest to the Studio that compiles into a target program.

Typical Workspace Structure

Each of a Workspace’s sub-folders contain files indicated by the folder name (e.g. bitmap files used in the application are in ..\Contact\Bitmaps, data is in ..\Contact\Data, application source is in ..\Contact\AppSrc, etc.)

For this tutorial, we will limit the scope of a workspace to a single set of Windows folders and subfolders that contain the various files that make up a project. In practice, the workspace structure can refer to a local set as in this example or it can refer to a set of folders that are located across a network and that are not necessarily physically co-located as they are in this example.

  1. Open the Visual DataFlex Studio.

  2. Select New Workspace... from the Studio’s File menu.

  3. Click Next on the wizard's Welcome page. Enter OrderTutorial as the name, Order Tutorial as the description and accept the default location. This will be the drive letter to which Visual DataFlex was installed, followed by \Visual DataFlex Projects\OrderTutorial. If you have previously create a workspace in another location, the "Workspace Root Directory" will default to that location. Click Next.

  4. On the 'Workspace Directory Folder" wizard page, accept the default, "Standard workspace structure (recommended)".

Standard Workspace Structure

A workspace with a standard workspace structure has a main folder with sub-folders that contain files indicated by the folder name. The standard workspace structure includes sub-folders AppHtml for web pages, AppSrc for application source code, Bitmaps for image files, Data for database files, DDSrc for Data Dictionary files, Help for application-related help files and Programs for compiled programs.

  5. Click Next on the Workspace Paths (page 1) and Workspace Paths (page 2) pages.

  6. On the Database Type wizard page, you can select the type of database you will use in this workspace. For this tutorial, keep the default choice, Embedded.

Database Type

Visual DataFlex workspaces can support multiple database types. For example, you can use Microsoft SQL, Pervasive.SQL and embedded database tables in the same workspace and even sharing the same views and reports. Typically, however, developers keep all or most tables in a workspace in the same database or perform most work in one database type at one time, thus each workspace has a default database type. This selection does not preclude you from using databases that are not the default type, but it makes working with the default database type more efficient.

  7. On the Setting Up Your Database wizard page, you can specify whether to create a new database immediately after the wizard concludes. For this tutorial, you will not use a database, so select the option I do not wish to describe a database at this time.

  8. On the last wizard page, click Finish.

    You have now created a Visual DataFlex workspace. You should now be back in the Studio, and the Studio has the new workspace loaded. You can verify this by looking for (OrderTutorial) on the Studio's caption bar.

Creating a Set of Tables and Data Dictionaries


Creating a Set of Tables and Data Dictionaries

In this section, you are going to recreate all of the tables and Data Dictionaries for the Order Entry sample application.

In the process, you will learn how to:

  • Create complete relational structure of tables for the Order Entry application

  • Create complete relational structure of Data Dictionaries for the Order Entry application

  • Define Business Rules in Data Dictionaries, both simple and complex

Important!

If you wish to skip this section of the tutorial, the manual creation of tables and DataDictionaries, you may instead copy the contents of the data folder from the Order Entry sample application to the data folder of the tutorial workspace.

Taking this action will provide you with a complete set of tables which already contain sample data.

Overview

The following is a schematic of the tables we shall be using, and their relationships to each other. The arrows below signify that the data in a column in the lower table (the child) is the same as the data in a unique column in the higher table (the parent). This allows the relationship of many child records to one parent record, increasing table integrity and consistency, and reducing the amount of data entry necessary. Once you have defined a relationship, Visual DataFlex handles the maintenance of it automatically.

Before Creating the Tables, Columns, and Indexes

There is information you should know before you start building the tables:

The order in which tables are created is important, because you cannot add relationships from one table to another table that does not exist. This is especially true in a database structure that has a relatively complex hierarchy. It is helpful to create system tables first, then parent tables and finally child tables.

In the Order Entry database structure, there is one table at the base of the hierarchy. This table, the Order Detail table, has no children of its own; therefore, it is considered the "childmost" table in the hierarchy. By contrast, you have three tables that are at the top of the hierarchy. These tables (Customer, Salesperson and Vendors) have no parents of their own (i.e., they do not relate to any tables); therefore they are considered the "parentmost" tables in the hierarchy. There is one other table, a "system" table, which is a special type of table that has only one record and no indexes. It is used to hold the next-available order, customer, and vendor numbers.

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. The Customer, Salesperson and Vendors are the grandparents of the child.

Note: As you can see, parent tables can have parents of their own, and child tables can have children of their own. While child and parent refer to the proximate generations, the terms "descendant" and "ancestor" are used to refer to tables removed from the reference table by any number of generations.

First, you will create the Order Entry System table. Since Customer, Sales Person, and Vendors do not relate to any other tables, you will create them next. Finally, you will create the Order Header, Inventory, and Order Detail tables. The order in which you create tables that are at the same level of the hierarchy is not important. For this example, we will create the tables from left to right, as they appear in the chart at the beginning of this section.

The specifications for the tables, columns, and indexes are shown in the next several pages. For consistency of screen shots and to allow for copying of completed tables, we have used the same table numbers as those in the finished samples area. You could in fact use any table numbers you like (1-4096 with 48-50 and 250-300 reserved), but we suggest you use the ones shown for the purposes of this tutorial.

Note: There is a completed sample program (called Order Entry example) located in the Order11 workspace. This completed program can be used to compare and debug your code. Run the Order Entry example program; adding a few orders and examining this sample will give you a better understanding of the manual code added during the tutorial.

Data-Dictionaries

A Data-Dictionary contains all the database rules for a table. It has the same rootname as the table and the extension .DD.

The best (and easiest) way to create the Data-Dictionaries for your application is to let Database Builder do it. The database Builder creates the Data-Dictionaries based on a few options that you enter - mostly by clicking checkboxes in various tab pages that appear when you are building the tables.

After creating Data-Dictionaries, you can edit them with a text editor, and as long as you are careful about where you place your code, you will be able to maintain them from within the Studio.

This tutorial section will take you through the following steps:

  • Creating Business Rules

  • Creating the Order Entry System Table

  • Creating the Customer Table

  • Creating the Sales Person Table

  • Creating the Vendor Table

  • Creating the Order Header Table

  • Creating the Inventory Parts Table

  • Creating the Order Detail Table

  • Checking Your Table Relationships

  • Changing Tables and Data Dictionaries


Creating Business Rules

You will now learn about business rules and how to define them for the Order Entry sample application.

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

  • Data validation (such as ensuring that a new order can’t be created for customers who are already over their credit limits 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, therefore, may encompass a tremendously diverse range of functionality. Visual DataFlex is outstanding in its ability to handle any data rule, no matter how complex or unique; you will be able to implement what is needed to deliver your application.

Business Rules for the Order Entry Application

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

  1. If a customer appears on any order, users cannot remove that customer from the Customer table.

  2. If a vendor supplies an item that appears in the Inventory table, you cannot delete the vendor from the Vendors table.

  3. Users cannot sell more parts than are already in the inventory stock. If they do, an error message informing them of that fact should be generated.

  4. If an item appears on an order (or is associated with several orders), you cannot delete the item from the Inventory table.

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

  6. The order's Total column is the sum of all the extensions.

  7. Only one customer per order is allowed.

  8. Automatically incrementing numbers must be created for new orders, customers and vendors.

  9. The extension for each item is the quantity ordered multiplied by the unit price.

  10. If a salesperson is responsible for any existing orders, you cannot remove that salesperson from the Salesperson table.

  11. Each line item in the invoice’s table (or grid) must be numbered.

Business rules may be implemented at the database level (in the Data-Dictionaries), at the interface level, 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. It is better to implement as many of the rules as possible in the Data-Dictionaries. They will be enforced whenever the referenced tables are used, and maintenance is centralized in one area.

Creating the Order Entry System Table


Creating the Order Entry System Table

You will now create the Order Entry System Table for the Order Entry sample application.

System Table

A system table is a table that contains only one record and also has its Max Records parameter set to one. Visual DataFlex will automatically find and load this record upon opening the table.

The first table, the Order Entry System table (OrdSys), stores the most-current order number, customer number and vendor number.

To create a new table, click on the Database Builder toolbar button in the Studio.

Click the Create New Table button in Database Builder.

Change the Table Name to OrdSys:

Use the following definition to create the OrdSys table:

The above is a printout of the OrdSys.DEF file. .DEF files are plain text table definitions that can be printed from Database Builder's File menu. .DEF files contain information about the tables structure, including its columns, indexes and other structural parameters.

Click on the Add a column toolbar button to add a new column, then enter the name, type, and length of each column as shown in the table’s definition above.

Here are some tips for this process:

  • You can type spaces instead of underscores (e.g. Order Number); they will be replaced with underscores for you. Any invalid character will be converted to a correct one via the appropriate Database Connectivity Kit.

  • You can type the first letter of the column type to change it from the default ASCII. Type n, for example, to change the type to Numeric.

Change the User Name to something more descriptive, such as Order Entry System Table. To set this table as a system table, go to the Parameters tab page and check the System File checkbox, which will also change "Max Records" to 1:

Finally, click the Save table toolbar button. It is useful to have a text file (*.DEF) showing you all the details of the table, so check Create .DEF and accept the suggested restructure options. If you try to exit Database Builder without saving any new or changed tables, you will be prompted as to whether you want to save your changes.

Note that a Data-Dictionary file is automatically created when you save the table. However, since this table will be maintained exclusively by the system, we will not maintain a Data Dictionary with business rules for it.

Creating the Customer Table


Creating the Customer Table

You will now create the Customer Table for the Order Entry sample application.

This is the structure of the next table, Customer:

As before, to build the table, click the Create New Table button, enter the Rootname Customer, and click Ok.

Here is how the columns should look when you are done (note that we've also changed the Description to Customers):

Next, click the Index tab and enter the information for each of the indexes.

Click on the Add an index toolbar button to add a new index.

Next, enter the Segments grid and select the column to add as an index segment from the combo box. Select Customer_Number for index 1.

This is the only segment for the first index, meaning that we will never be allowed to have two customers with the same number. This is what we want.

Click on the Add an index toolbar button to add index 2. Select Name as the first segment and Customer_Number as the second segment. Check the Ignore Case checkbox for Name. Checking this checkbox means that searching on that column will be case insensitive. The column value in the index is stored in its uppercased value. Checking Descending for an index segment means that searching starts at the end of the index and works backwards.

Do not check "Index is a batch index", since that means the index is only updated when you specifically call a reindex routine to do that (You can do so using Database Builder or via the sort command in your own applications). The data in a batch index is always out of sync in a true multi user system. In all these tables, we want all the indexes to be on-line, meaning they are updated automatically every time data is entered, edited, or deleted.

For index 3, select Balance as the first segment and Customer_Number as the second segment. Here is how the indexes should look when you are done:

Next, click the Parameters tab to see an overview of the table. See the Database Builder help book if you want to know more about any of the parameters listed here. You are now finished with the table definition of the Customer table.

Data-Dictionary Settings

Now you will add some business rules and other settings to the Data-Dictionary.

The Column Settings, Methods, Options and Structures tab pages is where you define these settings. Some of them have their own sub-tab pages, so pretty much anything you could want to put into a Data-Dictionary can be done from here. The recommended method of entering information is to think about one feature at a time. Make its settings for all the columns, then move on to the next feature.

For Column Settings, the current column is always highlighted in the list on the left, and the settings for that column are shown in the various tab pages to its right. We will be setting just a few options. For explanations of these and all other available options, press F1 or refer to the on-line documentation for the Database Builder.

Column Settings - Options

In the Options tab page of the Column Settings tab page, check Auto Find, Key Field and No Put for the Customer_Number column:

AutoFind performs a find and, if a record is found whose value in the main index exactly matches, it is displayed to the screen. You may define a single primary key for any table. Although there can be only one primary key it can consist of multiple columns. Such a key is defined by setting the key_field_states of all of its columns to true. In this case, the primary key consists of just the Customer.Customer_Number column. No Put means that users can enter data into the connected window for finding purposes, but that data will not be put back to the record buffer or saved. The No Put is used because we want the value of this column to be assigned by the system.

Select the State column in the Columns list, and check Capslock, which means that any data entered into that column is converted to uppercase for display and input purposes.

In the Purchases and Balance columns, check Display Only. This is because the Order Header Data-Dictionary will be maintaining these columns.

Column Settings - Validation/Lookup

The Validation / Lookup tab page allows you to set up some simple rules for validating data entered into each column. The Lookup section allows you to connect columns to a lookup list object that you can use to search the table. Don't forget your F1 key for full explanations.

The Lookup Object and Lookup Package forms are normally maintained by the Lookup Wizard in the Studio. When you create a lookup list using the wizard, the wizard fills this information in when it completes. You can create lookup lists manually if you want to and then select the appropriate lookup list object from the prompt in the Lookup Object form.

Column Settings - Validation Tables

The Validation Table tab page allows you to set up tables of valid column entries. The validation tables are attached to one or more columns in the table and can be used to validate the entered data or merely to provide a list of suggested values.

Validation tables are lists of values that may be used by a column for lookup, display, and validation. There are three types of tables, each with its own class; two are usually used if you have a small amount of static data and one for when you have larger amounts of dynamic data brought in from tables. The classes for static data are ValidationTable and DescriptionValidationTable, and the class for dynamic data is CodeValidationTable.

By default, all these tables are used for column validation. If a value in the column is not a member of the validation table's list, the column will be considered invalid. If validation is not required, this may be disabled by setting the tables validate_state property to false (or unchecking the "Validate" box.).

This particular Data-Dictionary uses a CodeValidationTable and points to records in the Codemast.Dat table. To build this type of validation, click on the "Dynamic" radio button, located in the Type Section. All records of Type STATES are valid records. Each record contains a code and description value. Setting the property allow_blank_state to true (or by checking the "Blanks" box) specifies that an empty entry is valid. As you can see, CodeValidation tables consist of a code (the value that is read and written to the table) and an optional description (the value that is displayed).

Now select State and select the Dynamic radio button. We are entering a new type value, so click on the New Type Value button.

Type States into the Type form and Names of States into the Description form click on Ok.

Back on the Validation Table tab page, select STATES from the Type Value combo box drop down list. Enter the following values for Value into the list:

Value | Description
AK | Alaska
AL | Alabama
AR | Arkansas
AZ | Arizona
CA | California
CO | Colorado
CT | Connecticut
DE | Delaware
FL | Florida
GA | Georgia
HI | Hawaii
IA | Iowa
ID | Idaho
IL | Illinois
IN | Indiana
KS | Kansas
KY | Kentucky
LA | Louisiana
MA | Massachusetts
MD | Maryland
ME | Maine
MI | Michigan
MN | Minnesota
MO | Missouri
MS | Mississippi
MT | Montana
NC | North Carolina
ND | North Dakota
NE | Nebraska
NH | New Hampshire
NJ | New Jersey
NM | New Mexico
NV | Nevada
NY | New York
OH | Ohio
OK | Oklahoma
OR | Oregon
PA | Pennsylvania
RI | Rhode Island
SC | South Carolina
SD | South Dakota
TN | Tennessee
TX | Texas
UT | Utah
VA | Virginia
WA | Washington
WI | Wisconsin
WV | West Virginia
WY | Wyoming

Tip

This is a lot of typing, but once you have done this, you can use this for validation tables for any workspace simply by copying the CodeMast and CodeType tables from this workspace.

When you are done, the Validation Table tab page should look like this:

Column Settings - Masks

The Mask tab page enables you to set up a data-entry mask for each column. Masks can be used to restrict data entry to a column to a defined pattern of numbers, letters, and punctuation marks or to provide displays of column values complying with pre-defined patterns and formatting. We will set a mask for the Zip column:

Choose Text from the Mask Type combobox, then enter #####-####. This means that users will only be able to type in numeric digits, and that a dash will be placed for them when they get past the fifth number. Any other data entered will be ignored. This mask is only used for display and input and you should not use masks for validation. The data will be saved without any masking characters.

For the Credit_Limit, Purchases and Balance columns, we will use a currency mask. The Purchases and Balance values are maintained by the OrderHea Data-Dictionary. Changes in order totals should automatically adjust these balances. Because of this, you do not want users to be able to enter data, but you still want to display these values with a proper currency format. A currency sign will precede the data entered, and the data will be formatted with a thousands delimiter and rounded to two places after the decimal. The currency sign, delimiter, and decimal point are all customizable in your Windows setup.

For ease of data entry, the mask characters disappear while the column is being edited. While it is possible to define an explicit currency mask for this column, it is usually best not to do so. The mask will be assembled at runtime by using the length of the column and a global currency mask defined in the global string DEFAULT_CURRENCY_MASK. By changing this string at the top of your program, you can easily change the appearance of all currency masks.

When you want to add or change a setting for several columns, you can press Ctrl-Down Arrow to get you from one column to the next without having to leave the window you are in (Mask Type for example):

Column Settings - Appearance

On the Appearance tab page, you may set what type of visual control the Studio will use when you drag the column onto a form. You may also set long and short labels that will be applied to the column. If a visual control type is entered for a column, the Studio will create that type of control whenever the column is dragged onto a component. This setting does not stop you from explicitly choosing a different control class for the column in the Studio, or from changing the class of control on an individual basis.

If a long label is entered for a particular column, the Studio will use it whenever a form-based control is created for that column. The label is only used as a default and can be adjusted on an object-by-object basis in the Studio. If you leave this blank, the Studio will use an intelligently converted column name as a label (where Zip_Code would be displayed as "Zip Code").

If a short label is entered for a particular column, the Studio will apply it as the column label whenever a list-type control that includes that column is created. The label is only used as a default and can be changed. If you leave it blank, the Studio will use the long label in list-type controls. If the long label is also blank, then the column name is used. Here are the suggested entries for you to make. Ctrl-Down Arrow is very useful here for entering the labels in sequence:

Column Name | Visual Control | Long Label | Short Label
Customer_Number |  | Customer Number | Number
Name |  | Customer Name | Customer Name
Address |  | Street Address | Address
City |  |  |
State | dbComboForm | State | St.
Zip |  | Zip/Postal Code | Zip
Phone_Number |  | Phone Number | Phone
Fax_Number |  | Fax Number | Fax
Email_Address |  | E-Mail Address | E-Mail
Credit_Limit | DbSpinForm |  |
Purchases |  | Total Purchases | Purchases
Balance |  | Balance Due | Balance

Column Settings - Other

The Other tab page contains various miscellaneous settings. Checking the Checkbox option sets a column up for use in a checkbox control. A checkbox column can only store a true value or a false value. Status Help is any helpful text you want displayed on the status bar when the user moves the cursor to a data-entry object for the column. A Default Value is the value that will appear by default when a user enters data into a form containing the column. It can be accepted by the user or overwritten.

An Entry Method allows you to specify the name of a method that is executed whenever the cursor moves into a data-entry form connected to the column. Exit Method allows you to specify the name of a method that is executed whenever the cursor moves out of a data-entry form connected to the column. Auto-increment columns are automatically assigned a sequentially incrementing number each time a new record is created.

For the Customer_Number column, we will enter an auto-increment column and some status help. These are the short help messages that will be displayed on the status line when users enter the named columns. Sometimes these seem too self-explanatory to be needed for every column, but Windows conventions expect them, and it is a good idea to get into the habit of providing status-help text:

As a short-cut you can enter, for example, the status help for the current column, press Ctrl-Down Arrow to enter the status help for the next column and so on.

Here are some suggested Status Help settings:

Column Name | Status Help
Customer_Number | Customer ID Number (system assigned)
Name | Customer/Company Name
Address | Street Address
City | City Name
State | Two letter state Id
Zip | Zip or Postal Code
Phome_Number | Telephone Number
Fax_Number | Fax Phone Number
Email_Address | E-mail Address
Status | Active Inactive Status of Customer

Here are some suggested Short Description (technical documentation note) settings:

Column Name | Short Description
Purchases | Total Orders. Maintained by Orderhea DD
Balance | Maintained by Orderhea DD

Next, for the Customer_Number column, also add the Auto Increment column, OrdSys.Cust_Number, from the system table. You can pick this from the offered combo-box or you can just type it in. This tells the system to give each new customer entered the next available customer number (which is why we made this column No Put in the system table itself, because we don't want users entering their own customer numbers somehow). Each time we add a new customer, the next available customer number is allocated and the system table is updated for the next time a new customer number is needed. This enforces part of another of our business rules:

Business Rule #8 states that unique numbers must be created automatically for new orders, customers and vendors. The same technique will be used for orders and vendors.

Auto increment will cause the following behaviors when a new record is saved: The value of table.column OrdSys.Cust_Number is incremented, saved, and then moved to Customer.Customer_Number. This system-assigned customer number will be saved along with the Customer record. Since the OrdSys table is not related to the customer table, later in the tutorial we will ensure that the OrdSys table is locked.

For the Default Value of the State column, you can enter your own state if you want. This is the value that will default into the State column for any new (cleared) customer record. If you like, you can also enter other default values for other columns - we used 1000 in the Credit_Limit column in our sample application, and Y in the Status column.

For the Status column, check the Checkbox checkbox. Enter Y in the True window and N in the False window. This sets the Status column to use a checkbox control and tells the Data Dictionary what values to store in the database as True or False.

Methods

You should add nothing to the Methods tab page for the moment. This tab page allows you to directly edit the Data-Dictionary (.DD) table. You may enter any valid Visual DataFlex code or comments.

Options

The Options tab page mostly contains settings for foreign columns. This term may need some explanation. The database controls that make up a data entry view in your application are connected to Data-Dictionary objects that serve them data. These are the Server Data-Dictionary objects for each control. The database column that is shown in the control must belong to either the server Data-Dictionary or a parent table of the server Data-Dictionary. When a column from a parent table is used, the foreign column entry options are used.

When you are designing your application, the data entry rules for columns of a parent table are usually different from the rules for a server table. For example, when entering a new record for the servers table, the parent table records are not modified. Their role is to provide column values (customer number, etc.) on which relations are based from the main table to the ancestor. When the parent table must be changed (add, delete, modify) this is done in a different view, where that table is the main (server) table.

Because of this, foreign columns often require additional option settings. Three special type designators are used to assign foreign-field options to all columns of a specified column type. Those types are key columns (the primary indexed column of a table), indexed columns (other indexed columns), and default columns (non-indexed). Foreign-field properties are added to any column properties that may have been already applied directly to the column.

For Key Foreign Field Options, verify that Find Required (and nothing else) is checked. For Indexed Foreign Field Options, just No Put should be checked, and for Default Foreign Field Options just Display Only should be checked. In Other Settings, you should check Protect Key Fields.

Find Required on foreign key column means that a record in the ancestor table must be found before entry can continue. No Put on foreign index columns means that users can enter data into the connected window for finding purposes, but that data will not be saved directly into any ancestor tables.

The Data-Dictionary structure will properly update ancestor tables when necessary. Display Only prevents data being entered into connected windows and ancestor tables. Foreign column options are added to column options already set. Therefore there is no need to check AutoFind or NoPut - they are already set. The complete option set for Customer.Customer_Number column key column is AutoFind, NoPut and FindRequired.

Structures

The Structures tab page is used to define the database structure for the table you are editing. In this tab page, you must identify all related parent tables, all related child tables, and all non-related external tables (like system tables). It is crucial that you identify all of these tables properly. The information is used by the Studio to build and connect proper data-dictionary object structures in your view components. At runtime this information is used to perform validity checks (i.e., it makes sure that all required tables are present for a save or delete operation) and to intelligently lock tables during save and delete operations.

There are several ways to create the list of required parent and child tables. If the parent and child tables exist and their relationships already established in the Relates To column (on the Relationships tab), you can click the magic wand button. The proper tables will automatically be added to the list. Since this only works if all tables have been created, a developer may first choose to create all other tables and data-dictionaries. Then, for each table, return to the Structures tab page and set all child and parent requirements by clicking the magic wand button.

An alternate approach, which we will use in this tutorial, is to type the name of required child tables into the list. When entered, the child table will not yet exist. This is allowed as long as we create the properly named child tables before we attempt to use the Data-Dictionary.

Since we are creating our tables in a top down fashion (we create the parent tables first) we can always use the magic wand button to create our list of required parents. The magic wand button enumerates through all the columns of the current table; if a column has a relationship to a parent table, this table will be added to the list (if it is not in the list already). We must enter the child tables manually. If you want, you may defer the entry of all required child tables until those tables are created. Child tables will try to add themselves automatically to the parent tables' DataDictionaries in the required child tables list.

Upon completion of all table and Data-Dictionary creation you will want to close all your tables and run the Check Relationships Report by selecting Check Relationships from the Reports menu. This report will allow you to verify that all required tables are properly accounted for.

On this tab page, you need to ensure that OrderHea is entered as a required child table, in compliance with the table chart at the beginning of the tutorial, and that OrdSys is entered as an External Structure. Again the options for entering these details include the magic wand button, a combo-box offering currently found choices and a blank page for you to enter names manually. Click the Add 'unknown' table button then type in OrderHea for the Required Child tables entry. You need to add OrderHea as an "unknown" table, since you will not create this table until later in the tutorial. Uncheck Cascade Deletes.

Business Rule #1 states that if a customer is associated with an order, you cannot delete the customer. Two tables are involved: the customer and order header tables. Restated in DataFlex database terms, this says: if one or more child-table (OrderHea) records relate to (contain matching data in the column(s) the relationship is based on) a parent-table (Customer) record, do not allow deletion of the parent record.

If you had not unchecked Cascade Deletes, deleting a Customer record would also delete descendant records (all orders belonging to that customer, and all order lines belonging to each order). Our business rule states that a record deletion should be disallowed if any child records exist. Now however, if users try to delete a customer record that has a related child record in the OrderHea table, they will see an appropriate error message.

For Externally Updated Tables, pick OrdSys from the offered choices (click the Select from 'known' tables button). Also, click the Change the lock mode for the selected table button and select the Lock On New Save radio:

Lock on New Save in this case adds the OrdSys table to the Data-Dictionaries lock list and determines under what conditions this table should be locked. This option means that the table OrdSys will only be locked when a new record is saved. This increases efficiency in a multi-user situation. Visual DataFlex locks all open lockable tables (DF_FILE_MODE attribute set to DF_FILEMODE_DEFAULT) but DataDictionaries use a technique to only lock those tables that are involved in the current update, delete or create operation.

This concludes all the Data-Dictionary entries we will make for the Customer table, so click the save button, or select Save from the table menu. Check Create .DEF and accept the suggested restructure options.

At this stage, it may be helpful for you to look at the Customer.DD table with your editor, to see the results of what you just accomplished. Without entering a single line of code, you have a fully functional Data-Dictionary for the customer table. It contains details of all the column options and defaults, status-help, prompt-lists, check values, masks and so on that will be applied every time the table is accessed by any program. You do not have to worry that data entered will be inconsistent.

The data-dictionary also knows about required child and system tables, and it will enforce two of our business rules. An incrementing number will be created for each new customer, and a customer cannot be deleted if it has any order history. Finally, it contains defaults that the Studio will use when you create data-aware objects from this table in your applications.

We will be seeing the value of each of these later in the tutorial. You may also want to compare this new Data-Dictionary table with the one distributed with Visual DataFlex. Its name is also Customer.DD and its in the examples area. If you have followed all the instructions here, the two tables should be identical.

Data-Dictionary Report

After creating a table and its Data-Dictionary, the best way to ensure everything is as you want it is to print out a Data-Dictionary report. In Database Builder, select Data Dictionary from the Report menu.

Check the file for which you want the report, in this case Customer table, then click Print.

Verify that it matches the following screen:

Creating the Sales Person Table


Creating the Sales Person Table

You will now create the Sales Person Table for the Order Entry sample application.

Here is the definition for the Sales Persons table:

The columns and indexes are easy enough for this simple table, and there are not very many options to be entered. As before, to build the table, click the Create new table button, enter the Rootname SalesP and click OK.

After entering the column and index information, you are again ready to change some Data-Dictionary settings. On the Column Settings - Options tab page, for the Id column, check Auto Find, Capslock, Required and Key Field. This sets the column options to require and automatically find a salesperson Id record and to convert all data entered into the associated form into uppercase.

The Salesperson Id is not system-assigned - users must enter a valid Id. AutoFind will ensure that the Id is unique. If the Id already exists, the existing record will be automatically found.

On the Column Settings - Validation Table and Column Settings - Mask tab pages, no entries are made.

On the Column Settings - Appearance tab page, enter these values:

Column Name | Visual Control | Long Label | Short Label
Id |  | Sales Person Id | Id
Name |  | Sales Person Name | Sales Person Name

In the Column Settings - Other tab page, enter these values:

Column Name | Status Help
Id | Sales person Id code - Upper-case alpha
Name | Sales person name - first and last

Column Name | Short Description
Id | Unique U/C ASCII ID. Assigned by user.

On the Options tab page, verify that only the Find Required and No Put options are checked for Key Foreign Field Options. In addition, verify that only No Put is checked for Indexed Foreign Field Options. Finally, verify that only Display Only is checked for Default Foreign Field Options.

In the Structures tab page, enter OrderHea as a Required Child Table and uncheck Cascade Deletes.

Business Rule #10 says that if a salesperson is responsible for any existing orders, you cannot remove that salesperson’s record from the SalesP table. Disallowing Cascade Deletes enforces that rule.

Click the Save Table button. Check Create .DEF and accept the suggested restructure options.

Now print your Data-Dictionary Report and verify that it matches the following:

Creating the Vendor Table


Creating the Vendor Table

You will now create the Vendors Table for the Order Entry sample application.

Here is the definition for the Vendors table:

The columns and indexes for this table are also fairly simple. Enter the column and index information then, on the Column Settings - Options tab page, for the Id column, check Auto Find, Key Field and No Put; for the State column, check Capslock.

On the Column Settings - Validation Table page, for the State column, we want to use the same Validation Table as for the State column in the Customer table, so select Dynamic as the Type, then select STATES from the Types Value comboform. Make sure Validate is checked and Blanks is unchecked.

On the Column Settings - Mask tab page, for the Zip column, choose Text from the Mask Type combobox, then enter #####-#### as the mask.

On the Column Settings - Appearance tab page, enter these values:

Column Name | Visual Control | Long Label | Short Label
Id |  | Vendor Id | Vndr Id
Name |  | Vendor Name | Name
Address |  | Street Address | Address
City |  |  |
State | dbComboForm | State | St.
Zip |  | Zip/Postal Code | Zip
Phone_Number |  | Phone Number | Phone
Fax_Number |  | Fax Number | Fax

On the Column Settings - Other tab page, enter these values:

Column Name | Status Help
Id | Vendor ID Number (system assigned)
Name | Vendor Name
Address | Street Address
City | City Name
State | Two letter State Id
Zip | Zip or Postal Code
Phone_Number | Phone Number
Fax_Number | Fax Phone Number

On the Column Settings - Other tab page, for the Id column, also add the Auto Increment column, OrdSys.Vendor_Number, from the system table.

In the Options tab page, verify that only Find Required is checked for Key Foreign Field Options. In addition, make sure that only No Put is checked for Indexed Foreign Field Options. Finally, verify that only Display Only is checked for Default Foreign Field Options.

In the Structures tab page, enter Invt as a Required Child table and verify that Cascade Deletes is not checked. For Externally Updated Tables, pick OrdSys from the offered choices (click the Select from 'known' tables button). Also, click the Change the lock mode for the selected table button and select the Lock On New Save radio.

Click the Save Table button. Check Create .DEF and accept the suggested restructure options. The procedure for the last few tables is a little different because they relate to other tables and they contain a small amount of custom code.

Now print your Data-Dictionary Report and verify that it matches the following:

Creating the Order Header Table


Creating the Order Header Table

You will now create the Order Header Table for the Order Entry sample application.

The structure of OrderHea follows (we will describe how to incorporate the relationships):

Add the columns and indexes using the information above.

You then need to create the relationships. Click on the Relationships tab page. Click on the Run the create relationship wizard toolbar button to add a new relationship.

Click Next on the first wizard page.

On the "Parent Table" page, select Customer as the parent table to relate to. Click Next.

On the "Parent's Primary Key" page, select 1. Customer_Number to identify the primary key index of the Customer table.

Leave the "Foreign Key Matching Options" set to the default, Select column(s) that match parent's primary key (size & type).

Click Next.

On the "Child's Foreign Key" page, select Customer_Number in the "Relate From Table" column to identify the OrderHea table's foreign key to relate to Customer.Customer_Number. Click Next.

The final wizard page will display the selections you have made for your inspection. Click Finish.

After the wizard completes, it will return you to Database Builder's Relationships tab page, where you will see the new relationship for the OrderHea table.

Now click on the Run the create relationship wizard toolbar button to run the "Create Relationship wizard" again. This time, you will relate from OrderHea.Salesperson_Id to SalesP.Id.

After the wizard completes the second time, it will return you to Database Builder's Relationships tab page, where you will see both relationships for the OrderHea table.

Next, you will continue to the other Data-Dictionary settings. On the Column Settings - Options tab page, for the Order_Number column, check Auto Find and Key Field. For Order_Total check Display Only.

For the Terms and Ship Via columns, we are going to use 2 different types of validation tables. The first one is a DescriptionValidationTable and specifies the actual values and text to be used. To build this type of table, click on the Static radio button, located in the Type group. The first column of values in the table (NONE, COD, NET30, etc.) are your valid data-column values. The second-column values (None established, COD, Net 30, etc.) are the values that will be displayed.

The second is a CodeValidationTable like the one we used for the Customer.State column.

The two different classes of table were created for sample purposes. They could both have been the same class. Item changes in a DescriptionValidationTable require recompiling your programs. Item changes in a CodeValidationTable are made to a database table and do not require recompiling. There are advantages and disadvantages in both methods. For further details on all of these classes, see the online documentation.

Verify that Terms is highlighted in the column list and that you are in the Validation Table tab page. Select the Static radio button. Enter the following values for Value and Description.

Value | Description
NONE | None established
COD | COD
NET30 | Net 30
NET60 | Net 60
NET90 | Net 90
PREPAY | Pre-payment required

Verify that Validate is checked and Blanks is unchecked. For Object Name enter Terms_Table.

Now highlight Ship_Via and select the Dynamic radio button. We are entering a new type value, so click on the New Type Value button. Type Shipping and click on OK. From the Type Value combo box, select Shipping.

Enter the following values for Value and Description.

Value | Description
FEDEX | Federal Express
FEDEXCOD | Federal Express COD
UPS | United Parcel Service
USINTL | USPS International Mail
USMAIL | US Postal Service
WILLCALL | Will Call

Verify that Validate and Blanks are both checked and enter Ship_Table as the Object Name.

On the Column Settings - Mask tab page, for the Order_Date column, choose Date from the Mask Type combobox. For the Order_Total column, choose Currency from the Mask Type combobox.

On the Column Settings - Appearance tab page, enter these values:

Column Name | Visual Control | Long Label | Short Label
Order_Number |  |  |
Customer_Number |  |  |
Order_Date | dbSpinForm |  |
Terms | dbComboForm |  |
Ship_Via | dbComboForm |  |
Ordered_By |  |  |
Salesperson_Id |  | Sales Person ID | Sales ID
Last_Detail_Num |  |  |

On the Column Settings - Other tab page, enter these values:

Column Name | Status Help
Order_Number | Order Number. An order number is generated automatically
Order_Date | Date on which the order was placed
Terms | Payment terms
Ship_Via | Shipping method
Ordered_By | Order placed by
Salesperson_Id | Sales Person who initiated the order

Column Name | Short Description
Ordered_By | This is just a suggested list. No parent tables support this
Order_Total | Maintained by the OrderDtl DD

On the Column Settings - Other tab page, for the Order_Number column, also add the Auto Increment column, OrdSys.Order_Number, from the system table. This satisfies the part of Business Rule # 8 that says that automatically incrementing numbers must be created for new orders.

On the Options tab page, verify that only Find Required is checked for Key Foreign Field Options. In addition, verify that only No Put is checked for Indexed Foreign Field Options. Finally, verify that only Display Only is checked for Default Foreign Field Options and that Protect Key Fields is checked.

On the Structures tab page, enter OrderDtl as a Required Child table and verify that Cascade Deletes is checked. We need this enabled in the order header table because we want to be able to delete an order and, when that happens, for all its associated item records to be deleted.

For Required Parent tables, ensure that Customer and SalesP are listed (they should have been added to this list by the relationship wizard). For Externally Updated tables, pick OrdSys. Also, click the key button and check Lock On New Save and Delete. Below in Procedure Deleting, you will create code to decrement conditionally the system-assigned order ID counter. This requires locking the system table for deletes as well as new saves. This is advanced usage of the message already seen to add a system table, and it optimizes table locking so that only new or deleted records cause a lock.

For the first time, you are now going to enter some code for processing which can’t be selected from checkboxes, radio buttons and so on. Select the Methods tab page. Expand the Unaugmented Methods tree. Double-click on Backout, Deleting, and Update. When you have completed this process, the corresponding procedures will be listed in the code editor on the right. The Unaugmented and Implemented sections of the tree will update themselves, moving these procedures to the correct tree section.

Right-click in the left side of the tree view and select New Method. Verify that Procedure is checked and enter Adjust_Balances as the Method Name.

Click Add, then click on Method Name again. Enter Entry_Order_Date, click on OK. We will discuss these in logical groups as they relate to each other, but it does not matter in what order they appear in the Data-Dictionary.

Within the code editor, you will see your new procedures outlined for you. You can cut and paste from the tables in the samples area if you wish. However, we recommend that you enter the following code manually to get the feel for the editor and to follow along with the logic. Do not forget the parameters on the procedure declaration:

Procedure Entry_Order_Date Integer iField Date dDate

Integer iChanged

Get Field_Changed_State iField To iChanged

If (iChanged=0 And dDate=0) Begin

SysDate dDate

Set Field_Default_Value iField To dDate

End

End_Procedure

We want to assign today’s date as the default for the order date. We want to assign this date when:

  • A user moves into a form or item representing this column, and

  • If the current date is unassigned.

We do this by creating a procedure (or function) to perform this action and then assigning this procedure to a column’s entry message. In this case, the procedure entry_order_date will get called anytime a DEO for the column OrderHea.Order_Date is entered. The procedure entry_order_date demonstrates several important techniques:

Column-entry, -exit, and -validate messages are always passed two parameters: the column number and the current column value.

We will update the column if the current date value is 0 (blank) and the column is not changed (we want to allow users to change a date to blank). The property field_changed_state is queried to determine if the column is changed. The passed date value is used to determine if the current date is 0. We are passed the column’s date value as a parameter. We could also have acquired this value by getting the field_current_value.

We set the date by setting the field_default_value property. This sets the column value without setting the DDO’s changed state. This allows you to set defaults without causing data-loss-warning messages to be generated when a view is cleared or closed.

Setting field_default_value (or field_current_value) will update DEOs assigned to this table and column. This is, of course, the whole purpose of creating this procedure.

The field_changed_state and field_default_value properties are accessed using the column number passed to the procedure. You do not need to use the column table.column syntax to access these values. In this sample, the following two lines would perform the same action. The first method, however, is faster, more flexible, and simpler.

Set Field_Default_Value iField to dDate

Set Field_Default_Value Field OrderHea.Order_Date to dDate

The Update and Backout procedures are used to maintain automatic balances in a table. This can be used to adjust balances for the table or one of its parents. In this case, we need to maintain two customer totals. Each time an order amount changes, the customer’s balance due and total purchases balance must be adjusted.

Procedure Update

Forward Send Update

Send Adjust_Balances OrderHea.Order_Total

End_Procedure

Procedure Backout

Forward Send Backout

Send Adjust_Balances (-OrderHea.Order_Total)

End_Procedure

Procedure Adjust_Balances Number Amt

Add Amt To Customer.purchases

Add Amt To Customer.Balance

End_Procedure

The Update procedure is called when a record is being saved or edited and the Backout procedure is called when a record is being deleted or edited. The calculations performed in these procedures are opposites. They both call the procedure adjust_balances with the appropriate parameter to adjust the data as required.

Procedure Deleting

Forward Send Deleting

// see if we can decrement the order number in sys file...can only do

// this if this is the newest order.

If (OrderHea.Order_Number=OrdSys.Order_Number) Begin // if this is

Decrement OrdSys.Order_Number // the last number,

Saverecord Ordsys // decrement and save.

End

End_Procedure

Order numbers are assigned when the order-header record is created. Often a user will delete an entire order during the entry of the order’s detail items. For example, the user may discover that an item is out of stock and want to stop processing the entire order. Normally the order would be deleted, but the system-assigned order number would not be rolled back. In a multi-user environment, it would not be safe to unconditionally roll back the system order number. It may not be the last order created. However, we can create a conditional rollback. If the order’s number is the same as the last order assigned, we will roll it back (decrement it).

The deleting procedure is called when the table is locked and reread. If the order number of the order is the same as the system table’s order number, we know we can safely decrement the system number. This is an advanced and somewhat unorthodox use of a Data-Dictionary, but it demonstrates the power and flexibility of the code-based Data-Dictionary.

On the Column Settings - Other tab page, highlight the Order_Date column and click on the prompt button on the Entry Method line. Select Entry_Order_Date as the Entry Method. Now that you have created the Entry_Order_Date procedure, you can choose it from the popup list.

Click the Save Table button. Check Create .DEF and accept the suggested restructure options.

Now print your Data-Dictionary Report and verify that it matches the following:

Creating the Inventory Parts Table


Creating the Inventory Parts Table

You will now create the Inventory Parts Table for the Order Entry sample application.

Next, create the Invt table, with the columns, indexes and relationship shown:

7

On the Column Settings - Options tab page, for the Item_Id column, check Auto Find, Capslock and Key Field. For Vendor_Id check Capslock.

On the Column Settings - Validation/Lookup tab page, you will now enter some ranges for entries into columns that require users to stay within certain limits. For Unit_Price, enter 0 and 999999.99 in Range From and To respectively. This disallows any negative entries or entries over $1 million. Enter 0 for Validation Error. This is the value returned to the program at runtime if a user enters a value outside the range allowed. For On_Hand, enter -999999 and 999999 in Range From and To respectively.

On the Column Settings - Mask tab page, for the Unit_Price column, choose Currency from the Mask Type combobox.

On the Column Settings - Appearance tab page, enter these values:

Column Name | Visual Control | Long Label | Short Label
Item_Id |  | Invt.Item ID | Item ID
Description |  | Invt.Description | Description

On the Column Settings - Other tab page, enter these values:

Column Name | Status Help
Item_Id | Inventory Item ID - user defined identification
Description | Inventory Part Description
Vendor_Id | Vendor Number
Vendor_Part_Id | Vendor ID name for this item
Unit_Price | Retail unit price
On_Hand | Units currently available

Column Name | Short Description
On_Hand | This is adjusted by the OrderDtl DD

On the Options tab page, verify that only Find Required is checked for Key Foreign Field Options. In addition, verify that only No Put is checked for Indexed Foreign Field Options. Finally, verify that only Display Only is checked for Default Foreign Field Options and that Protect Key Fields is checked.

On the Structures tab page, enter OrderDtl as a Required Child table and verify that Cascade Deletes is not checked. For Required Parent tables, ensure that Vendor is listed (it should have been added to this list by the relationship wizard).

Business Rule #4 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 table, then it cannot be deleted from the Invt table.

You'll now be entering a small amount of code to add a function that will enforce another of our business rules:

Business Rule #3 states that the quantity sold of an item cannot exceed the number that exists in inventory stock. We can restate this business rule in DataFlex database terms as "you cannot order an item if the value in Invt.On_Hand would be less than zero afterwards."

Select the Methods tab page and from the Unaugmented methods list, double-click on Validate_Save. Enter the rest of this code:

Function Validate_Save Returns Integer

Integer iRetVal

Forward Get Validate_Save To iRetVal

If iRetVal Function_Return iRetVal

If (Invt.On_Hand < 0) Begin

Error 300 "Insufficient Inventory Stock"

Function_Return 1

End

End_Function // Validate_Save

The code above for the function that implements this business rule simply augments the validate_save message to return an error if the user tries to enter more of an item than is available. A save is only performed on a function return value of 0, so returning 1 (or a non-zero value) means no save takes place.

Notice that we did not try to accomplish this validation by using set field_value_range. The inventory quantity check can only be performed while the record is being saved and the record is locked. Validate_save is called right before the actual save. All required records are locked and all columns have been updated. The value in the column is the value that will be saved (i.e., any quantity adjustments have already taken place).

All other validations occur during data entry or at the start of a save process before any locking has taken place. Validate_save is special in that it occurs in a locked and fully updated state. These validations should be as quick as possible. Also note, that the error command in this function will not be executed in a locked state. Before the error is reported, the transaction is canceled and rolled back as required.

DataFlex does this for you automatically. As usual, save the table and accept the suggested restructure options.

Now print your Data-Dictionary Report and verify that it matches the following:

Creating the Order Detail Table


Creating the Order Detail Table

You will now create the Order Detail Table for the Order Entry sample application.

Finally, create the OrderDtl table with the columns, indexes and relationships shown:

On the Column Settings - Options tab page, for the Order_Number and Detail_Number columns, check No Put.

These options are set because the order and detail numbers are set automatically, so we don’t want users able to change them manually. OrderDtl.Order_Number relates to OrderHea.Order_number, and will be assigned as part of the save. OrderDtl.Detail_number is assigned by the Auto Increment included in this Data-Dictionary.

For Extended_Price, check Display Only. This option is set because the extended price is calculated automatically, so we do not want users to be able to change it manually. This value is calculated when the detail line is saved.

On the Column Settings - Mask tab page, for the Qty_Ordered column, choose Numeric from the Mask Type combobox. For the Price and Extended_Price columns, choose Currency from the Mask Type combobox.

On the Column Settings - Appearance tab page, enter these values:

Column Name | Visual Control | Long Label | Short Label
Qty_Ordered |  | Quantity Ordered | Quantity
Price |  | Price per Unit | Price
Extended_Price |  | Extended Price | Total

On the Column Settings - Other tab page, enter these values:

Column Name | Status Help
Qty_Ordered | Number of items ordered
Price | Price per Unit
Extended_Price | Total extended price

Column Name | Short Description
Order_Number | Relates to OrderHea DD
Detail_Number | This is maintained internally and is normally not displayed
Item_Id | Relates to Invt DD
Price | Default is set from Invt. Can be adjusted for each order
Extended_Price | System maintained: Ext Price = Qty * Price

For the Detail_Number column, add the Auto Increment column, OrderHea.Last_Detail_Num from the parent table.

This satisfies Business Rule # 11, which states that each line item in the invoice’s table (or grid) must be numbered automatically.

Notice that the source auto-increment table and column is not a system table; it is the parent order-header record. In this sample, each order-detail item number is assigned a consecutive value from the parent order record.

On the Structures tab page, for Required Parent tables, ensure that OrderHea and Invt are listed (they should have been added to this list by the relationship wizard).

On the Methods tab page, add the following procedures: Update, Backout, Adjust_Balances, Entering_Price, Adjust_Display_Total. This is the code:

Procedure Update

Forward Send Update

Move (OrderDtl.Price * OrderDtl.Qty_Ordered) To OrderDtl.Extended_Price

Send Adjust_Balances OrderDtl.Qty_Ordered OrderDtl.Extended_Price

End_Procedure

Procedure Backout

Forward Send Backout

Send Adjust_Balances (-OrderDtl.Qty_Ordered) (-OrderDtl.Extended_Price)

End_Procedure

Procedure Adjust_Balances Number Qty Number Amt

Subtract Qty From Invt.On_Hand

Add Amt To Orderhea.Order_Total

End_Procedure

Whenever a detail line is saved, edited or deleted, a number of other balances must also be adjusted.

  • Business Rule # 5 states that when an item is ordered, you must decrement the quantity ordered from the quantity on hand. This will maintain the amount on hand for each item.

  • Business Rule # 6 states that the order's Total column is the sum of all the extended prices.

  • Business Rule # 9 states that to get the extended price for each item, you must multiply the quantity ordered by the unit price.

The Update and Backout procedures shown above will help us implement these business rules. The update procedure is called when a record is being saved or edited and the backout procedure is called when a record is being deleted or edited. The calculations performed in these procedures are opposites. They both call the procedure adjust_balances with the appropriate parameters to adjust the data as required.

The value of OrderDtl.Extended_Price is calculated when the detail record is saved. Other methods are used (and described below) which will keep this column current during data entry (before the save). These other methods (Adjust_Display_Total and Entering_Price) are used only to supply the user with useful information during data entry. The calculation that occurs during the save is the calculation (in procedure update) that ensures that the extended price is correct.

Procedure Adjust_Display_Total

Integer iQty

Number nAmnt

Get Field_Current_Value Field Orderdtl.Qty_Ordered To iQty

Get Field_Current_Value Field Orderdtl.Price To nAmnt

Set Field_Current_Value Field Orderdtl.Extended_Price To (nAmnt * iQty)

// note we set value, but not changed state!

End_Procedure

During data entry, we always want extended price to be up-to-date. Anytime the item price (OrderDtl.Price) or the quantity ordered (OrderDtl.Qty_ordered) is changed, we want to adjust the extended price column (OrderDtl.Extended_price). We will perform this update as part of the column-exiting process. When an item based on Qty_Ordered or Price is exited, Procedure Adjust_Display_Total will be called. This procedure will set the column value for Extended_Price based on the column values of Qty_Ordered and Price.

When the extended-price column is changed, all DEO items using this table and column will be updated. This keeps our display up-to-date.

It is instructive to see what actually happens to make this all work:

  1. The user exits an object (or item) in a DEO.

  2. As part of item exiting, the column-exit message for the DDO is called.

  3. The column-exit message calls a procedure that changes the value of another column.

  4. When the column value is changed, all DEOs using that column are updated with the new value.

We use this only to display the extended total. When the record is saved, the extended total is calculated again and this new value is saved. We do this because you cannot be certain that a view will contain the Qty_Ordered and Price columns and, if present, you cannot be certain that a user will enter and exit these columns before saving the record. You should never assume that a column will be entered or exited within a view. It is very important that you understand this.

Procedure Entering_Price Integer Field# Number nAmnt

If (nAmnt=0) Begin

Get File_Field_Current_Value File_Field Invt.Unit_Price To nAmnt

Set Field_Changed_Value Field# To nAmnt

Send Adjust_Display_Total

End

End_Procedure

A detail line is created by selecting an inventory item. The inventory item contains a unit price for the item. This is the suggested unit price. The actual unit price must be entered by the user. We would like to use this suggested price as our default price. We will do this by creating a column-entering message for OrderDtl.Price. When entering the control associated with the column, the program will check to see if the current column value is zero. If it is, it will assume that a price has not yet been assigned and set it to the inventory item’s unit price.

Procedure Entering_Price demonstrates the following:

  • We only update the value if the current value is zero. The current value is passed to the procedure.

  • We need to get a column value from a foreign table (i.e., the column is not part of the current Data-Dictionary; it is part of a parent-table DDO). When we do this, we must Get the File_field_current_value and not the Field_current_value. Also, we must use the file_field parameter and not the field parameter. When accessing values from a foreign DDO (or from within a DEO), you must remember to use the file_field_ prefix.

  • After setting the new column value (field_changed_value), we will send the message Adjust_Display_Total. This will adjust the extended-price column.

  • Note that all of the column-entry and exit messages perform actions that make data entry more convenient. They do not perform validation or integrity-checking operations. This is typical of column entering and exiting. Validations are performed by column-validation messages and by the validate_save function.

Now that you have added some methods, they will be available for selection in other areas of the Data-Dictionary builder. Back on the Column Settings - Other tab page, you can now select Adjust_Display_Total for the Exit Method of the Qty_Ordered and Price columns and you can select Entering_Price as the Entry Method of the Price column.

Save the table in the usual manner. Now print your Data-Dictionary Report and verify that it matches the following:

At this point, you have created all the database table and data-dictionary (.dd) files for the Order Entry application.

Checking Your Table Relationships


Checking Your Table Relationships

You will now check your required parent and child relationships for all tables using a predefined report in Database Builder. This will help you determine if the structure of your relational database is correct.

First, make sure that you close all tables. Next, select Check Relationships from the Report menu in Database Builder. Then click Select All, deselect the FlexErrs, CodeMast and CodeType tables, then click Start Checking.

You will see a report of all the relationships, which you can print out if you wish. Your report should look like the following:

If your report does not match this report, you must re-open your tables and make any required corrections. Most likely you have either not defined your required lists properly (go to the Structures tab page and click the magic wand button to correct this) or you have not defined your relationships properly on the Relationships tab page.

Changing Tables and Data Dictionaries


Changing Tables and Data Dictionaries

During the normal development process, you will need to make changes in your tables' structures and Data-Dictionaries. You will do this by re-opening Database Builder and opening the tables that you need to review or change. When a table is re-opened, it is opened in data dictionary only mode. This mode allows you to look at, but not change, the table information. It does allow you to make changes in the Data-Dictionary.

This is the "friendliest" mode in that it allows other applications (like the Studio or an end user application) to open and access the table. This mode can be used to make changes in your Data-Dictionaries, which is the most common type of change you will make.

Before you can change your table information (e.g., add a new field, change a relationship) you must verify that your open table is switched to exclusive mode. In other words, if you need to change information in the first four tab pages (Columns, Relationships, Index or Parameters), you must first switch the table to exclusive mode. You switch modes by clicking the red Lock button located in the top right corner of the table window. When this lock is red, the table is loaded in data dictionary only mode; when green, it is loaded in exclusive mode.

If Database Builder does not allow you to change modes it indicates that some other program has opened the table. If this happens, close the other programs and try again. When a table is opened in exclusive mode, no other programs or users will be able to open this table. Therefore, you want to keep a table opened in exclusive mode for a minimal period of time. After the change is made and saved, you should switch the out of exclusive mode.

Creating the Order Entry User Interface


Creating Windows Data Entry Components

Now that you have created your tables and Data-Dictionaries, you are ready to create the data-entry views for your application. These form the interface that users will see and will think of as "the program".

Data-entry views are composed primarily of two parts: data-entry objects and data-server objects. Data-entry objects (e.g., Entry Forms, Tables and Editors) allow users to examine, select, or manipulate data in the database. These are supported by pop-up lookups, validation comboboxes and the like. All visual interaction with the database occurs in data-entry objects. On the other hand, data-server objects (i.e., Data-Dictionaries) control what records users see when they are accessing the database.

The Order Entry application consists of a main source file, Order.src, which incorporates some standard objects (menu, status bar, etc.) and uses five views, which in turn use the Data-Dictionaries, which in turn use five lookups. Using the Studio, we will start by making the lookups. As you know, they are already referenced in the Data-Dictionaries you made earlier. Then we will create the main source file and some views to which we will then add, finishing by compiling and running the completed program.

Important!

In order to complete the pages in this tutorial section, you must have at least one Windows application in the OrderTutorial workspace. Create a Windows application named Order.src.

For a refresher on creating Windows applications, complete the Creating a Windows Application and Compiling and Running a Windows Application pages now, and then return to this section and continue where you left off.

This tutorial section will take you through the following steps:

  • Creating the Lookups

  • Creating the Views

  • Creating the Customer View

  • Creating the Sales Person View

  • Creating the Vendor View

  • Creating the Inventory Item View

  • Creating the Order Entry View

  • Customizing the Order Entry View


Creating the Lookups

You will now create lookup lists for most of the tables you have just created. Using the Lookup Wizard, this task should be quick, even for 5 lookup lists.

Verify that Order Entry Tutorial is still set as the current workspace in the Studio.

Following the same techniques described in Creating a Lookup List in Quick Start, make the five lookups as shown below.

Customer List

Create a Customer lookup list with object name Customer_sl, file name Customer and description Customer Lookup List. Add the Customer_DataDictionary and columns Customer_Number and Name to the list.

Sales Persons List

Create a Sales Persons lookup list with object name SalesP_sl, file name SalesP and description Sales Person Lookup List. Add the SalesP_DataDictionary and columns Id and Name to the list.

Vendor List

Create a Vendor lookup list with object name Vendor_sl, file name Vendor and description Vendor List. Add the Vendor_DataDictionary and columns Id and Name to the list.

Inventory List

Create an Inventory lookup list with object name Invt_sl, file name Invt and description Inventory Lookup List. Add the Invt_DataDictionary and columns Item_Id, Description, Unit_Price and On_Hand to the list.

Orders List

Create a Customer lookup list with object name OrderHea_sl, file name OrderHea and description Orders Lookup List. Add the OrderHea_DataDictionary and columns Order_Number, Customer.Customer_Number, Customer.Name, Order_Date and Order_Total to the list.

Creating the Views


Creating the Views

You will now create and customize the data entry views for the Order Entry sample application.

Before starting this section we assume that you have worked through the Creating Your First Windows Application section of Quick Start, up to and including Creating a Data Entry View. Having done this, you should be able to easily create the views in this section.

In Quick Start, you created the Customer Entry view using the Data Entry View Wizard. In this section, you are going to create one view within the Studio itself and the remaining views using the Data Entry View Wizard. While wizard generated views are very easy to build, sometimes it makes sense to build views directly within the Studio, in the case of very complex views, for example. This provides more flexibility and, once understood, is almost as easy to use.

The Order Entry view is the most complicated view in this tutorial. After the view is created with the wizard, you will need to add some custom code to various objects within the view. Step by step instructions for adding this custom code will be provided. An emphasis will be placed on why these changes are made and how they work.

It is not important that your views look exactly like the views shown. As you create these views, feel free to experiment to learn features of the development environment and the product that are not covered here.

Creating the Customer View


Creating the Customer View

The Creating a Data Entry View section of Quick Start showed you how to build a Customer Entry view using the Data Entry View Wizard. You are now going to learn how to build a view like this using the Studio.

The basic steps of how to create a view were already shown in detail in Creating Your First View.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the Data Entry View icon.

    The "Create a New Windows View Component" dialog will open. Enter oCustomerView as the object name. The filename will automatically change to CustomerView.vw. Accept the default directory path and click on the Ok button.

  2. In the Object Properties window, change the view’s label to Customer Entry View.

  3. Click on the DDO Explorer toolbar button.

    Right-click     inside the DDO Explorer window and select Add DDO from the context menu. Select the Data Dictionary you want (in this case Customer_DataDictionary) and click Select. Confirm that you want it to be the Main DDO.

  4. Back in DDO Explorer, expand the DDO Column Selector in the tree, then oCustomer_DD to display the columns in the Customer table. Select Customer_Number and Name and drag these onto your view.

  5. From the Data Containers group on the Class Palette, drag and drop a dbTabDialog onto the view.

  6. Right-click on the first tab button on the tab dialog and choose Append Tab Page from the context menu.

  7. Add another tab page to have a total of 3 tab pages on the dbTabDialog. Use the Object Properties window to change the label and other properties of a tab page; make sure the tab page is selected when you do so and not the surrounding dbTabDialog.

  8. Change the tab page labels as shown below.

  9. Next, from DDO Explorer, select, then drag and drop the following columns onto each tab page.

  10. So, let's test the completed view.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project.

    When the application runs, select oCustomerView from the View menu.

Creating the Sales Person View


Creating the Sales Person View

Creating the Sales Person Entry View

You will now create the Sales Person Entry view using the Data Entry View Wizard.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the Data Entry View Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, enter oSalesPersonView as the object name, SalesPersonView as the filename and Sales Person Entry View as the description and click Next.

  4. On the "Entry View Style" wizard page, select Create a Simple Form Entry View, then click Next.

  5. On the "Main Data Dictionary" wizard page, Click on SalesP - SalesP_DataDictionary to select it as the data dictionary to be used, then click Next.

  6. On the "Entry Fields" wizard page, add Id and Name columns using the Add button. Click Next.

  7. On the "Labels, Alignment and Preview" wizard page, you can click the Preview button to preview what your view is going to look like.

    Click the     X button in the upper right hand corner of the preview to close it.

  8. Click Finish on the last wizard page.

    You should now be back in the Studio, with the newly created Sales Person Entry View open in the visual designer.

Creating the Vendor View


Creating the Vendor View

You will now create the Vendor view using the Data Entry View Wizard.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the Data Entry View Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, enter oVendorView as the object name, VendorView as the filename and Vendor Entry View as the description and click Next.

  4. On the "Entry View Style" wizard page, select Create a Simple Form Entry View, then click Next.

  5. On the "Main Data Dictionary" wizard page, Click on Vendor - Vendor_DataDictionary to select it as the data dictionary to be used, then click Next.

  6. On the "Entry Fields" wizard page, add all columns by clicking the All button. Click Next.

  7. On the "Labels, Alignment and Preview" wizard page, you can click the Preview button to preview what your view is going to look like.

    Click the     X button in the upper right hand corner of the preview to close it.

  8. Click Finish on the last wizard page.

    You should now be back in the Studio, with the newly created Vendor Entry View open in the visual designer.

Creating the Inventory Item View


Creating the Inventory Item View

You will now create the Inventory Item view using the Data Entry View Wizard. After completing the wizard, you will make some minor modifications to the view in the Studio. This will familiarize you with some of the visual design features of the Studio.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the Data Entry View Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, enter oInventoryView as the object name, InventoryView as the filename and Inventory Item View as the description and click Next.

  4. On the "Entry View Style" wizard page, select Create a Simple Form Entry View, then click Next.

  5. On the "Main Data Dictionary" wizard page, Click on Invt - Invt_DataDictionary to select it as the data dictionary to be used, then click Next.

  6. On the "Entry Fields" wizard page, using the Add button, add Item_Id and Description from the Invt table, followed by Id and Name from the Vendor table. Next, add Vendor_Part_Id, Unit_Price and On_Hand from the Invt table. Click Next.

  7. On the "Labels, Alignment and Preview" wizard page, you can click the Preview button to preview what your view is going to look like.

  8. Click Finish on the last wizard page.

    You should now be back in the Studio, with the newly created Inventory Item View open in the visual designer.

    You are now going to make a few manual adjustments to the view in the Studio. You are going to add 2 dbGroup controls and move some of the data entry objects (DEOs) that were created by the wizard into those groups. This will break up the view into more logical groups of controls.

  9. While holding down the Ctrl key on the keyboard, select the Vendor Id, Vendor Name and Vendor Part Id controls.

  10. Press Ctrl+X to cut the controls.

  11. From the Data Containers group on the Class Palette, drag and drop a dbGroup control onto the view.

  12. With the dbGroup selected, press Ctrl+V to paste the controls into the dbGroup.

  13. Resize the view to be slightly larger to create some space on the bottom, then move the Unit Price and On Hand controls further down. Resize the dbGroup so that all 3 of the vendor controls fit properly into it.

  14. Now you should follow the same steps to move the Unit Price and On Hand controls into a dbGroup of their own.

    Move the On Hand control to the right, then use the context menu to align the tops of the 2 controls.

    Change the sizes of both dbGroups and the view to remove some of the excess space at the bottom.

    Change the label of the first dbGroup to Vendor and remove the label of the second dbGroup.

    Your Inventory Item View is now complete and look similar to this:

Creating the Order Entry View


Creating the Order Entry View

The Order Entry View is the main view of the program and also the most complex view. You will create the view with the Data Entry View Wizard, and then complete it in the Studio. You will probably need to move some fields around, change their sizes, and do some re-alignment. How you arrive at it isn’t important, as long as the end result is correct. Feel free to experiment with different features of the Studio to try to accomplish your goal.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the Data Entry View Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, enter oOrderEntryView as the object name, OrderEntryView as the filename and Order Entry View as the description and click Next.

  4. On the "Entry View Style" wizard page, select Create a Header Detail Entry View, then click Next.

  5. On the "Child Data Dictionary" wizard page, click on OrderDtl - Orderdtl_DataDictionary to select it as the data dictionary to be used, then click Next.

  6. On the "Header Data Dictionary" wizard page, click on OrderHea - Orderhea_DataDictionary to select it as the data dictionary to be used, then click Next.

  7. On the "Header/Form Entry Fields" wizard page, using the Add button, add the fields as shown in the image below in the order they are shown. If you want to add all of the fields from one table at a time, you can do so, then use the Move Down and Move Up buttons to put them in the correct order in the list. Click Next when all the fields are added and in the correct order.

Adding Parent Fields vs. Child Fields

The fields that we tell you to add are, if they are part of a relationship, always the related-to field from the parent table. If you use the related-from fields from the child table instead, the wizard(s) will automatically substitute the parent field for you, which is almost always the field that should be used.

  10. On the "Detail/Grid Entry Fields" wizard page, add Item_Id, Description and Unit_Price from the Invt table, followed by Price, Qty_Ordered and Extended_Price from the OrderDtl table. The completed list should look like the image below. Click Next.

  11. On the "Labels, Alignment and Preview" wizard page, make these adjustments on the Header/Form Fields tab page:

  • Check the checkboxes in the Same Line column for fields Customer Number, Order Date, Ordered By, State, Zip/Postal Code, Sales Person Id and Ship Via.

  • Change the Label of City to City/State/Zip and remove the labels State and Zip/Postal Code.

  • Change the Label Justification radio from Left to Right.

There are no adjustments needed on the "Detail/Grid Fields" tab page.

  12. Click on the Preview button and ensure that your view looks like the one below.

  13. Click Finish on the last wizard page.

    You should now be back in the Studio, with the newly created Order Entry View open in the visual designer.

    In the next section you will customize the view you have just created with the Data Entry View Wizard.

Customizing the Order Entry View


Customizing the Order Entry View

Now you are going to customize the Order Entry View in the Visual DataFlex Studio. In the process, you will learn what the code generated by the wizard does and how to add your own custom code to add features to the view that the wizard did not provide.

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 as desired. When this was 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 introduced in this section, do not worry. The main purpose is to show how programs may be modified and to give you an idea of the range of changes that can be made.

To add these changes, you can use the built-in editor in the Studio by double clicking on each object affected. To save typing, you can copy and paste these code segments from Order.Vw in the Order Entry sample workspace.

Completing the View's Layout

Let's start by rearranging the controls in the view to make the layout a bit nicer.

Select the oDetailGrid control, open the Object Properties window, and click on the Column Properties tab.

Set the Form_Width of the Invt.Item_Id column to 55. Select the Invt.Description column and set it's Form_Width to 119, Invt.Unit_Price to 55, OrderDtl.Price to 43, OrderDtl.Qty_Ordered to 43 and OrderDtl.Extendeed_Price to 55. Now resize the dbGrid control be only slightly wider than the resized columns.

Rearrange the rest of the controls in the view until they look more or less like this:

Extend the bottom edge of the view to create room for one additional row of controls. Here, you will place a button to print orders and a dbForm to display each order's total amount.

From the Base Controls group on the Class Palette, drag and drop a Button control into the bottom left corner of the view. Change the label of the button to Print Order, its name to oPrintBtn and its peAnchors property to anBottomLeft. Currently this button has no function; clicking it will do nothing. We will add functionality in the reporting section of this tutorial.

From the DDO Explorer, drag and drop the OrderHead.Order_Total field into the bottom right corner of the view. Change the size of the control to 13,60 and its peAnchors property to anBottomRight.

This concludes the layout of the view; all the controls have been placed onto the view and are in their final location. When you are done, the view should look more or less like this:

Next, you will add some custom code and study the code created for you by the wizard to understand what the code in this view does.

Disabling Entry in the Terms Combo-Form

We want to make the Terms combo-form object a non-edit list. Two types of combo forms are supported, a drop-down list and a drop-down-edit list. The edit list, which is the default, allows users to enter directly into the form or to select a value from the combo list. We want to only allow selection from the combo list. Setting the object's entry_state to False does this. Do so using the Object Properties window.

Custom Confirmation Messages

We want the save and delete prompts in the order header to be customized to "Save this Order?" and "Delete this Order?". In addition, we want to change the save confirmation so that it only asks for a confirmation when it is saving a new order record. We do this by creating two new confirmation functions and assigning the save- and delete-verification prompts to these functions. These new functions use the generic confirm function which allows us to ask any question we want. We can determine if an order is new by checking HasRecord of the view’s server (the OrderHea’s DDO).

The following is the code required supporting this change. These changes are added to the dbView object. This is the same level where the server is set to the order header Data-Dictionary. All objects in the view, except for the order-detail dbGrid object, will use these messages. DbGrids assign their own confirmation messages (no confirmation for a grid save, and a line confirmation for grid deletes).

The Data Entry Wizard has created the following code for you in the oOrderEntryView dbView object:

//-----------------------------------------------------------------------

// Change: Create custom confirmation messages for save and delete

// We must create the new functions and assign verify messages

// to them.

//-----------------------------------------------------------------------

Function ConfirmDeleteHeader Returns Boolean

Boolean bFail

Get Confirm "Delete Entire Header and all detail?" to bFail

Function_Return bFail

End_Function // ConfirmDeleteHeader

// Only confirm on the saving of new records

Function ConfirmSaveHeader Returns Boolean

Boolean bNoSave bHasRecord

Handle hoSrvr

Get Server to hoSrvr

Get HasRecord of hoSrvr to bHasRecord

If not bHasRecord Begin

Get Confirm "Save this NEW header?" to bNoSave

End

Function_Return bNoSave

End_Function // ConfirmSaveOrder

// Define alternate confirmation Messages

Set Verify_Save_MSG to GET_ConfirmSaveHeader

Set Verify_Delete_MSG to GET_ConfirmDeleteHeader

Disallow Customer Change on Existing Orders

Once an order is created, we want to disallow the changing of the order’s customer. The changing of an order’s customer does not affect integrity—all balances would be properly maintained. We have decided, however, that this type of change should not be allowed within the view. Double-click on the oCustomerCustomer_Number object to display the code for this object in the code editor. Add the following custom method to the object:

// If order record exists, disallow entry in customer window.

Procedure Refresh Integer iMode

Handle hoServer

Boolean bCurrent

Get Server to hoServer // get the DD

Get HasRecord of hoServer to bCurrent // has record in DD

// Set DisplayOnly to True if bCurrent is non-zero

Set Enabled_State to (not(bCurrent))

Forward Send Refresh iMode // do normal refresh

// don't leave us sitting on a DisplayOnly window

If (bCurrent and Focus(Self)=Self) Send Next

End_Procedure // Refresh

Anytime a new order record is found or cleared, the DDO sends the message refresh to all affected entry objects. Once this is understood, our job is much easier. We must augment the refresh message in the oCustomerCustomer_Name dbForm to check if the order is new or old. If new, we will allow entry into the form; if old, we will shadow the form. Note the following about this augmentation:

  1. The server property returns the object ID of the DDO used by the dbForm. This will be the OrderHea Data-Dictionary.

  2. HasRecord of the server will return True if the OrderHea Data-Dictionary has a record. If it is True, the record exists (it is old) and the form should be disabled. If it is False, the record is new and the form should be enabled.

  3. If we are disabling the form, we want to verify that it does not have the focus. If the object is disabled and it has the focus, we will send the next message to move the focus to the next object.

Changing the Normal Switching Behavior

We will be changing the dbGrid behavior so that entry will be denied if the order header is not properly saved. When users attempt to navigate from the ship-via object to the order-detail grid, the standard switch behavior will not act as desired.

The normal behavior of switch is to attempt to navigate to the next object. If this navigation fails, it will attempt to switch to the next object, and so on. In this case, we want to switch to either navigate to the grid or do nothing. We will override the switch message and have it send activate to the detail grid. If activation fails (the grid refuses to take the focus) the focus will not move. In addition, we will set the combo form’s entry_state to False as we did in the prior example.

Add the following custom code to the oOrderheaShip_Via dbComboForm object:

Procedure Switch

// the normal switch behavior is to attempt to keep

// keep looking for additional objects to switch to if. If

// we can't switch to the detail grid, we want to stop! So just

// do a simple activate.

Send Activate of oDetailGrid

End_Procedure // Switch

Restrict Grid Additions to the Bottom and Optimize Grid Refreshes

In the order-detail grid, new records will always get placed at the end of the grid (because the index contains a detail-item ID that is constantly incremented). To make this more intuitive, we want to change the behavior of the Insert Row key (F11). Normally, this inserts a new row. While this would work, it makes more sense to force this key to add a new row to the end of the grid (append instead of insert).

Since there is no dbGrid message to append a blank row, 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 row (send end_of_data) and then go down one more row (send down). Very often, when trying to create custom navigation events, it is best to send the same messages the keyboard would send when users press the required multi-key sequence.

If you add this change, it will not be possible for the grid to get out of order. This means that there is no need for the grid 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 grid navigation.

The Data Entry Wizard has created the following code for you in the oDetailGrid dbGrid object:

// Assign insert-row key append a row

// Create new behavior to support append a row

On_key kAdd_Mode send Append_a_Row // Hot Key for KAdd_Mode = Shift+F10

// Add new record to the end of the table.

Procedure Append_a_Row

Send End_Of_Data

Send Down

End_Procedure // Append_a_Row

Force Saves When Entering and Exiting Grids

This will be our most-complex change. We want two new behaviors. When exiting a grid, we want the grid to save the current row just as it does when users switch rows. This change is easy to make. By setting the property Child_Table_State to True, the grid will save the record (if required) when exiting the grid.

The entering behavior is more complicated. Here is what we want: Before entering the grid, we want to verify 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 grid. There is a tendency to try to handle this as part of the exiting behavior of the header object and not the entering behavior of the grid.

In an event-driven system, you do not know where you will exit the header to and you do not know from where you are entering the grid. The only safe event-driven rule is to say, “Certain conditions must be met before a grid 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 grid. If a non-zero value is returned, the grid will not be entered. Rather than checking the conditions of the grid, we will let the grid send a message to the header (the dbView object itself) 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 inform the grid that all is well. If the save fails or there was no record to save, we will return a failure. We must custom-code this.

Here is a summary:

  1. Set Child_Table_State of oDetailGrid to True.

  2. When the grid is being entered, the function Child_Entering is called. If it returns a non-zero value, the grid will not be entered.

  3. Child_Entering will call a function in the order header, which we have named Save_Header. This function will return non-zero 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 that the save did not proceed), or there is no current record in the header’s Data-Dictionary (indicating that there was nothing to save), we will return a non-zero value.

  5. When we attempt to save the header record, we do not want to clear the header after the save. We will use the save message Request_Save_No_Clear to accomplish this.

Below is the code in the dbView (the header) and the dbGrid (the detail grid) required to support these changes.

The Data Entry Wizard has created the following code for you in the oOrderEntryView dbView object:

//-------------------------------------------------------------------

// Table entry checking - attempt to save header record

// before entering a table (this is called by table. Return

// a non-zero if the save failed (i.e., do not enter table)

//-------------------------------------------------------------------

Function SaveHeader Returns Boolean

Integer iRec

Boolean bChanged bHasRecord

Handle hoSrvr

Get Server to hoSrvr // The Header DDO.

Get HasRecord of hoSrvr to bHasRecord // Is there a record?

Get Should_Save to bChanged // Are there any current changes?

// If there is no record and no changes we have an error.

If (not(bHasRecord) AND not(bChanged) ) Begin // no rec

Error DfErr_Operator "You must First Create & Save the Header"

Function_Return True

End

// Attempt to Save the current Record

// request_save_no_clear does a save without clearing.

Send Request_Save_No_Clear

// The save succeeded if there are now no changes, and we

// have a saved record. Should_save tells us if we've got changes.

// We must check the DDO's HasRecord property to see if

// we have a record. If it is false, we had no save.

Get Should_Save to bChanged // is a save still needed

Get HasRecord of hoSrvr to bHasRecord // is there a record after the save?

// if no record or changes still exist, return an error code of 1

If (not(bHasRecord) OR (bChanged)) begin

Function_Return true

End

End_Function // SaveHeader

The Data Entry Wizard has created the following code for you in the oDetailGrid dbGrid object:

// Setting child_table_state to true will

// cause the grid to save when exiting and

// attempt to save the header when entering.

Set Child_Table_State to True

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

Boolean bFail

// Check with header to see if it is saved.

Delegate Get SaveHeader to bFail

Function_Return bFail // if non-zero do not enter

End_Function // Child_Entering

Adding Items to the Grid Out of Order

The Data Entry Wizard has created the following code for you in the oDetailGrid dbGrid object:

// Often grids are set up, so that items can never be added out

// of order. New items are always added to the end of the table.

// By setting Auto_Regenerate_State to false we are telling the

// table to never bother reordering after adding records. This is

// a minor optimization.

//Set Auto_Regenerate_State to False // table is always in order.

Uncomment the last line of code (Set Auto_Regenerate_State to False). This will allow users to add rows to the grid anywhere, not just at the bottom.

Adding a SpinForm to a Grid Column

We want to use an embedded SpinForm in the order detail grid for the quantity column. Add the following custom code to the oDetailGrid dbGrid object:

Set Column_Button 4 to Form_Button_Spin // make qty column spinner

Set Column_Minimum_Position 4 to 0 // with range of 0 to 999

Set Column_Maximum_Position 4 to 999

Creating Reports


Creating Windows Report Components

In this section of the tutorial, you will create reports for the Order Entry example. Each report demonstrates a different programming technique:

  • WinPrint: this technique uses the Visual DataFlex WinPrint engine together with the Report Object to produce graphical reports (supporting different font styles, colors, bitmaps and graphics).

  • Crystal Reports: this technique uses the Crystal Reports report writer for producing graphical reports within a sophisticated GUI report writing environment.

You could use any one of these techniques for producing all three reports; however each technique has advantages and disadvantages when compared to the other two.

You will create a Customer Listing reports using cWinReport2. The second report will print orders by launching a Crystal Reports report that has already been prepared for this purpose.

Visual DataFlex reports are encapsulated within ReportView objects. Each ReportView has two major parts:

  • A simple user interface that allows the user to select the output device, sort order, a range of records to print, etc.

  • The report itself.

We will conclude this section by showing how a report may be added directly to a view. The order entry view contains a "Print Order" button. In this final section, we will add the code required to make this button print the current order. We will use a Crystal Reports report to accomplish this.

This tutorial section will take you through the following steps:

  • Creating the Customer Report (WinPrint)

  • Customizing the Customer Report

  • Creating the Order Report (Crystal)

  • Creating the Order Report View

  • Adding Print Support to the Order View

  • Reviewing Additional Report Samples


Creating the Customer Report (WinPrint)

Customer Report (using WinPrint)

You will now create a Customer report using the WinPrint2 Report wizard, using the specifications below. Afterwards, you will learn how to modify a wizard-generated Report View in the Studio.

Creating the User Interface

Our first report sample will be a customer listing based on the cWinReport2 class. This report you are going to build is going to be very similar to the WinPrint report that you built using the WinPrint2 Report wizard in the Creating a WinPrint Report section, but we are going to make some changes while running the wizard and some more changes in the Studio after the wizard has completed.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the WinPrint2 Report Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, enter oCustomerReport as the object name, CustomerReport as the filename and Customer Listing (WinPrint 2) as the description and click Next.

  4. On the "Main Data Dictionary" wizard page, Click on Customer - Customer_DataDictionary to select it as the data dictionary to be used, then click Next.

  5. On the "Reporting Order and Breakpoints" wizard page, select index 1:Customer_Number as the index to be used, then click Next.

  6. On the "Body Section Fields" wizard page, add the Customer_Number, Name, Address, City, State, and Zip fields by clicking on the Add button. Click Next.

  7. On the "Report Styles and Totals" wizard page, change the name of the Customer Name field to Name and adjust the Font Size from 10 to 8. Test run the report.

    Click the X button in the upper right hand corner of the preview to close the WinPrint report viewer.

  8. Back on the "Report Styles and Totals" wizard page, click Next.

  9. On the "Filter Fields" wizard page, do not add any fields. Click Next.

  10. Click Finish on the last wizard page.

    You should now be back in the Studio, with the newly created report view open in the visual designer.

  11. Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, you will notice that the running application has a Report menu next to the View menu, and it lists your newly created Report View.

Customizing the Customer Report


Creating the Order Report (Crystal)

Creating the Order Report (Crystal Reports)

You will now learn the concepts of interacting with a Crystal Reports report from Visual DataFlex.

A Crystal Reports report to print orders has been specially prepared for this exercise. You must verify that this file is copied into your workspace area. The file containing the Crystal Reports for DataFlex report that you want to run is named Orders.rpt. You will find a copy of this report in the \Data subfolder of the Order Entry sample workspace. Copy this file, along with files ShipVia.ttx and Terms.ttx, into the \Data subfolder of your workspace.

It is beyond the scope of this tutorial to teach you how to create Crystal Reports reports. However, you may want to start this exercise by looking at the Crystal Reports report that has been created.

Load the Crystal Reports report designer product. If you do not own this yet, you may purchase it via your distributor, along with Connectivity Kit for the embedded (DataFlex) database. Without this Connectivity Kit, you cannot access the embedded database from Crystal Reports.

Next, load the Crystal Reports report named Order1.rpt. Within Crystal Reports, click the Open button (or select Open from the File menu) and find the report. The report will be located in the workspace’s data folder.

Once selected, the Crystal Reports report can be displayed in one of two tab pages: Design and Preview. The design page is used to create and format the report. The Preview page will show you what your report will look like.

In this sample, you can see that we have designed a report that prints an order. You can make any changes to this report. If you make changes and save the report, the changes made will appear when the report is run from within Visual DataFlex.

Once a Crystal Reports report is created, it is added to a program by creating a report view that contains an object of class cCrystal. This object contains the name of the Crystal Reports report and has all the capabilities required to run the report.

Note: The report file you have copied is a Crystal XI report. Crystal Reports reports cannot be distributed to a customer without purchasing the proper Crystal Reports license. Contact your distributor to purchase the correct license.

Creating the Order Report View


Customizing the Customer Report

Now you are going to customize the Customer Report in the Visual DataFlex Studio. In the process, you will learn what the code generated by the wizard does and how to add your own custom code to add features to the ReportView that the wizard did not provide.

Completing the ReportView's Layout

Let's start by completing the controls we want to have in the completed ReportView.

The ReportView should look like this after the wizard completes:

  1. Enlarge the view vertically to make more room at the bottom of the view. Resize the Send Report to group horizontally so it only takes up about half the ReportView.

  2. Drag the Print, Printer Setup and Cancel buttons below the "Send Report to" group. Align the buttons next to each other from left to right, in this order: Print, Cancel, "Printer Setup". You can use the Align | Top and "Align with Container" | Left-To-Right options from the context menu to align the buttons. When you are done, the ReportView should look like this:

  3. Drag and drop a RadioGroup control onto the view, next to the existing "Send Report to" RadioGroup. By default, this RadioGroup will have 3 Radio controls in it. Delete the bottom Radio control. Rename the top Radio to oNumberRadio and change its label to Number. Rename the bottom Radio to oNameRadio and change its label to Name. Resize the new RadioGroup to be the same size as the "Send Report to" RadioGroup and line up the two RadioGroups horizontally. Change the name of the new RadioGroup to oOrder and its label to Report Order.

  4. Drag and drop a CheckBox control onto the view and place it beneath the "Report Order" RadioGroup. Change the CheckBox's name to oCommentsCkBx and its label to Print Comments. The ReportView should now look like this:

  5. You may notice that the Radio objects in the 2 RadioGroups are not necessarily aligned. You want to align them so that the Number Radio is at the same relative position inside the "Report Order" RadioGroup as the "Report Viewer" Radio inside the "Report Order" RadioGroup. There is no alignment tool to allow you to do this. The only way to do this is to copy the Location property of the "Report Viewer" Radio (it should be "12,6") to the Number Radio in the Object Properties window. Then copy the Location (it should be "24,6") of the Printer Radio to the Name Radio.

  6. Last, ensure that the object order of the objects in this view is correct. The order in which visible objects will be navigated to when the programs runs is the same as their order (from top to bottom) in Code Explorer. In Code Explorer, you can view the object order and adjust it by right-clicking on any object and selecting Move Up or Move Down from the context menu. Once complete, your object ordering should match the object order shown below.

This completes the layout of the ReportView; all the controls have been placed onto the ReportView and are in their final location.

Coding the ReportView

Next, we will study the code created for you by the wizard and add some custom code.

Determining which Radio is Selected

Double-click on the oPrintTo RadioGroup object to view its code. This object has one function named IsToPrinter:

Function IsToPrinter Returns boolean

integer iRadio

Get Current_radio to iRadio

Function_return (iRadio=1)

End_Function // IsToPrinter

This function gets the Current_Radio property of oPrintTo, which tells us which of the child Radio objects is currently selected. Since there are only 2 Radios in this RadioGroup, which determine if the report should print to the screen or the printer, the function then returns this as a Boolean result via this line:

Function_return (iRadio=1)

We will now create a similar function for the oOrder RadioGroup, which will return whether the report should be ordered by name or number. Delete the following code from the oOrder RadioGroup (this code was created when you dragged the control onto the ReportView from the Class Palette.

Procedure Notify_Select_State Integer iToItem Integer iFromItem

Forward Send Notify_Select_State iToItem iFromItem

//for augmentation

End_Procedure

//If you set Current_Radio, you must set it AFTER the

//radio objects have been created AND AFTER Notify_Select_State has been

//created. i.e. Set in bottom-code of object at the end!!

//Set Current_Radio To 0

Add the following function to object oOrder:

Function IsSortedByNumber Returns boolean

integer iRadio

Get Current_radio to iRadio

Function_return (iRadio=1)

End_Function // IsSortedByNumber

Starting the Report

Add the following line of code to the oCustomerReport ReportView object:

Property Boolean pbComments False

The value of this property will determine whether the report will print the Comments column of each Customer record or not.

Now, modify the existing StartReport method in oCustomerReport until the code looks as shown below:

The first block of code in StartReport:

// determine if direct print

Get IsToPrinter of oPrintTo to bToPrinter

Set OutPut_Device_Mode of oReport to (If(bToPrinter, PRINT_TO_PRINTER, PRINT_TO_WINDOW))

calls the IsToPrinter function in the oPrintTo RadioGroup to see whether the user wants to print the report to the screen or the printer. It then sets the Output_Device_Mode property of the oReport cWinReport2 object to Print_To_Printer or Print_To_Window, depending on the returned result of IsToPrinter.

The second block of code:

// determine if sort order is by number or name

Get IsSortedByNumber of oOrder to bSortByNumber

Set Ordering of oReport to (if(bSortByNumber, 2, 1))

does the same thing to tell the report object in which order to print the report.

The third block of code:

Get Checked_State of oCommentsCkBx to bComments

Set pbComments to bComments

sets the pbComments property based on whether the user has checked the "Print Comments" checkbox.

The last block of code:

// run the report

Send Run_Report of oReport

tells the report object to start processing the report.

The Report Object

Now, let's customize and review the code in the oReport cWinReport2 object.

Add this line of code declaring the pbLandscape property above Procedure Starting_Main_Report:

Property Boolean pbLandscape False

Starting_Main_Report is the main method for changing parameters in WinPrint2 reports. This is the place to change things like margins and paper orientation. Change the existing Function Starting_Main_Report to this:

Function Starting_Main_Report Returns Integer

Integer iIndex

Boolean bOn bErr

Send DFSetMetrics wpm_cm

Send DFSetmargins 1 111

Get pbComments to bOn

Send DFSetLandscape (if(bOn,True,False)) // This can be used to force a page orientation

Get DFGetLandscape to bOn

Set pbLandscape to bOn

Forward Get Starting_Main_Report To bErr

Function_Return bErr

End_Function

The customization here, from what the wizard generated for us, is that we determine if the user wants to print Customer.Comments, and if so, we change the paper orientation to Landscape.

Next, we are going to change Procedure Page_Top so that the page number prints on the left side of the page instead of the right. Replace the existing Procedure Page_Top with this one:

// Page_Top is printed first at the top margin of each page

Procedure Page_Top

string sFont

integer iFontSize iStyle

Move "arial" to sFont

Move 8 to iFontSize

Move (Font_Default) to iStyle

DFFont sFont

DFFontSize iFontSize

DFBeginHeader DFPageTop

DFHeaderFrame Hdr_NoFrame

DFHeaderPos Hdr_Left

DFWriteLn ("Page:" * "#pagecount#") iStyle

DFEndHeader

End_Procedure

We could also have simply changed the (Font_Right) in the original line of code to (Font_Default), but using a variable for the style makes it easier if we later want to change the style on more than one line of code in this procedure.

Next, modify the existing Procedure Page_Title to add a column header (title) for the Customer.Comments column if the user has selected to print this column via the checkbox. The complete code for Procedure Page_Title should look like this:

Procedure Page_Title

string sFont

integer iFontSize iHeaderStyle iFill iBorder

Boolean bOn

Get pbLandscape to bOn

Move "arial" to sFont

Move 8 to iFontSize

Move (Font_Bold + rgb_dBlue) to iHeaderStyle

Move (rgb_Grey) to iFill

Move (rgb_Grey) to iBorder

DFFont sFont

DFFontSize iFontSize

DFBeginHeader DFPageTitle

DFHeaderPos Hdr_Left

DFHeaderFrame Hdr_Margins 0 iBorder iFill

DfHeaderMargin HM_TopInner 0.01

DfHeaderMargin HM_BottomInner 0.01

DFHeaderMargin HM_BottomOuter 0.16

DfWritePos "Number" 0.1 (iHeaderStyle)

DfWritePos "Customer Name" 2 (iHeaderStyle)

DfWritePos "Address" 7 (iHeaderStyle)

DfWritePos "City" 12 (iHeaderStyle)

DfWritePos "St." 15 (iHeaderStyle)

DfWritePos "Zip" 17 (iHeaderStyle)

If bOn begin

DfWritePos "Comments" 19 (iHeaderStyle)

end

DfWriteln

DFEndHeader

End_Procedure // Page_Title

This block of code:

If bOn begin

DfWritePos "Comments" 19 (iHeaderStyle)

end

prints the Comments column header if the user has checked the "Print comments" checkbox.

The next method to modify is Procedure Body. Replace the existing, wizard created, method with this modified one:

Procedure Body

string sFont

integer iFontSize iStyle

Boolean bOn

Send Update_Status (String(Customer.Customer_number))

Get pbLandscape to bOn

Move "arial" to sFont

Move 8 to iFontSize

Move (font_default) to iStyle

DFFont sFont

DFFontSize iFontSize

DFLineCheck 5

DfWritePos Customer.Customer_Number 0.8 (iStyle + Font_Right) 0

DfWritePos Customer.Name 2 iStyle -1 4.98

DfWritePos Customer.Address 7 iStyle -1 4.98

DfWritePos Customer.City 12 iStyle -1 3.98

DfWritePos Customer.State 15 iStyle -1 0.98

DfWritePos Customer.Zip 17 iStyle -1 1.98

If bOn begin

DfWritePos Customer.Comments 19 iStyle -1 0

dfWriteln

end

dfWriteln

End_Procedure // Body

Just as in Procedure Page_Title, we check to see if the user wants to print the Customer.Comments column. Here, we will print the contents of the column if the checkbox is checked. There are 2 additional customizations in this code: the first is this line:

Send Update_Status (String(Customer.Customer_number))

This updates the WinPrint 2 Report Viewer to display the current record's customer number as records are being processed. With the limited number of records in the sample customer table, you may not see this happening, but if you create a report like this for a large table with thousands or millions of records, you will want to display something like this to your users while the report is processing.

The second customization is this line of code:

DFLineCheck 5

DFLineCheck checks that the indicated number of lines (in this case 5) will fit on the page. If they do not, the report will insert a page break and print the next line on the new page. This is done here because Customer.Comments is a text column that may wrap over several lines. This ensures that each record is printed completely on a page and not split onto 2 pages.

Next Step

Creating the Order Report (Crystal)


Creating the Order Report View

You will now learn how to create a Report View that interacts with an existing Crystal Reports report from Visual DataFlex.

Creating the User Interface

You are going to create a ReportView that integrates with a Crystal Reports report. The ReportView will act as a "front end" for the Crystal Reports report that you have created using the Crystal Reports report writer. From the ReportView, you will also be able to send arguments to the Crystal Report to customize it a bit. For example, you can pass selection criteria to the report to limit or specify the records it displays.

  1. Click on the Create New button on the Studio’s toolbar. Click on the View / Report tab of the Create New... dialog. Double-click the Crystal RDC Report Integration Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the "Crystal Reports report" wizard page, select the Orders.rpt report file from the data subfolder of your workspace. When you click Next you will see a status window telling you that the wizard is loading the report. At this time, the wizard opens the report and analyzes it, among other things, for which tables it uses.

  4. On the Names wizard page, enter oOrdersCR as the object name, OrdersCR as the filename (the .rv extension will be added automatically) and Crystal - Orders as the description and click Next.

  5. On the "Selection Fields" wizard page, do not add any fields and click Next.

  6. On the "Sort Fields" wizard page, do not add any fields and click Next.

  7. On the "Options" wizard page, uncheck the Export to File/Application/Email checkbox, then click Next.

  8. Click Finish on the last wizard page.

You should now be back in the Studio, with the newly created report view open in the visual designer.

Adding Print Support to the Order View


Adding Print Support to the Order View

Here, you will learn how to add print options to a data entry view, instead of a Report View, from which reports are usually launched.

Adding a Report to an Entry View

If the order entry view is not currently loaded, you should, once again, open this view.

When the order entry view was created, we added a "Print Order" button. Currently that button serves no purpose. We will now add the code required to make this button actually print the current order. To do this we must do the following:

  • Add a cCrystal object to the view. This object will support a public interface to print a single order. We will use the same Crystal Reports order report (Orders.rpt) from our previous sample.

  • Add a message (and its supporting procedure) to the order view which will print the report. It will do this by sending a message to the report object, passing the order number to print.

  • Add code to the print button to start the report process.

  • Add code to the view to disable the print button when no order exists.

  • Add a method to the view that prints the current order.

// print the current order. This message will be sent

// by the print button

Procedure PrintCurrentOrder

Integer hDD iNum

Get Server to hDD // this will be the orderhea DD

If (HasRecord(hDD)) Begin // only do this if record exists

Get Field_Current_Value of hDD Field Orderhea.Order_Number to iNum

Send PrintOrder of oOrder_Report iNum

End

End_Procedure

Adding the cCrystal Object to the View

  1. The code we are going to add will call method CheckCrystalEnvironment in object oCheckForCrystal. to ensure that the necessary Crystal Reports components are installed to run the Crystal Report. This object and method already exist in the Order Entry sample application. Copy CheckForCrystal.dg from the Order Entry sample workspace's \AppSrc\Crystal folder into the AppSrc folder of the tutorial workspace.

  2. Add the following Use statement to the top of the OrderEntryView.vw source code file, below the other Use statements already in place:

Use CheckForCrystal.dg

  3. Open the OrderEntryView in the Studio.

    Add the following custom code to the oOrderEntryView object:

// print the current order. This message will be sent

// by the print button

Procedure PrintCurrentOrder

Integer hDD iNum

Get Server to hDD // this will be the orderhea DD

If (HasRecord(hDD)) Begin // only do this if record exists

Get Field_Current_Value of hDD Field Orderhea.Order_Number to iNum

Send PrintOrder of oOrder_Report iNum

End

End_Procedure

  4. Creating the cCrystal object:

    oOrder_Report     is a cCrystal object. In creating this object, we will demonstrate two important techniques: creating a custom public interface, and customizing a Crystal Reports report within Visual DataFlex.

    Drag and drop a     cCrystal object from the Othersgroup of the Class Paletteonto the oOrderEntryView object. Rename this object to oOrder_Report. Remove the commented out code in the object and replace it with the following code:

Set psReportName to "Orders.rpt"

Property Integer piOrderNumber 0

// Procedure : OnInitializeReport

// Purpose : This is a hook message sent by the Open_report procedure. You may use this

// procedure to set selection values, print options, etc. This procedure is

// intended for augmentation; it has no action by default.

Procedure OnInitializeReport Handle hoReport

Integer iOrder

String sSelection

Handle hoTerms hoShipVia

Variant[][2] vTerms

Variant[][2] vShipVia

Forward Send OnInitializeReport hoReport

Get CreateCDO of hoReport "Terms.ttx" to hoTerms

If (hoTerms) Begin

Get TableData of Terms_table to vTerms

Send AppendCDOData of hoReport hoTerms vTerms

End

Get CreateCDO of hoReport "ShipVia.ttx" to hoShipVia

If (hoShipVia) Begin

Get TableData of Ship_Table to vShipVia

Send AppendCDOData of hoReport hoShipVia vShipVia

End

Get piOrderNumber to iOrder

// Set the selection formula to print the one order.

Move ("{OrderHea.Order_Number} = " + String(iOrder)) to sSelection

Set ComRecordSelectionFormula of hoReport to sSelection

End_Procedure // OnInitializeReport

// pass order to print

Procedure PrintOrder Integer iNum

Boolean bCrystalOK

Set piOrderNumber to iNum

// check for Crystal

Get CheckCrystalEnvironment of oCheckForCrystal to bCrystalOK

If (bCrystalOK) Begin

Send RunReport

End

Else Begin

Send DisplayDialog of oCheckForCrystal

End

End_Procedure

  5. Creating a custom public interface:

A cCrystal object’s standard public interface is to send RunReport. Here we need a different interface one that allows us to specify the order number to be printed. Our new public interface will send PrintOrder iNum, where the parameter iNum is the integer order number value. The PrintOrder procedure (which we must create) will set the property piOrderNumber (which we must also create) and then run the report by sending the message RunReport.

  6. Customizing a Crystal Reports report within Visual DataFlex:

We need to change Orders.rpt so that it only prints a single order. We do this by changing the report’s selection formula. Before a Crystal Reports report is actually run, the report object's OnInitializeReport is called. This method, which by default does nothing, gives us the chance to customize the report. In this case we will:

  • Get the order number to print (which we have stored in the property piOrderNumber)

  • Construct a selection formula based on this number and place this formula in the ComRecordSelectionFormula property.

This type of customization requires that you understand how to create Crystal Reports reports and that you understand the Crystal Reports interface. This information may be found in Using Crystal Reports in Applications.

Adding a Procedure to Print the Order

The PrintCurrentOrder procedure is our interface for printing a report. The print button will send this message to the order entry view. If we wanted, this message could be sent via other means as well. For example, we could assign an accelerator key (e.g., Alt+P) to this method by addling the following line to the view’s code area:

On_Key Key_Alt+Key_P Send PrintCurrentOrder

This procedure needs to do the following:

  1. Get the object ID of the OrderHea data dictionary.

  2. If the OrderHea dictionary contains a current order (i.e., if the DD’s HasRecord method returns true) it will get the current order number from the Data Dictionary and send the message PrintOrder to the cCrystal object (oOrder_Report).

Adding Print Support to the "Print Order" Button

Add the following custom code to the oPrintBtn object:

Procedure OnClick

Delegate Send PrintCurrentOrder // defined in view object

End_Procedure // OnClick

When the print button is selected, the message PrintOrder will be called in the button’s parent, the view object.

The delegate command was not really needed, since the button object would not have understood the message and would have delegated the message anyway. The delegate command was used because it makes the programmer’s intent clearer.

Enabling /Disabling the Print Button

When the order view contains an order record, we want the print button to be enabled. When the order view is empty, or the current information is not yet saved, we want the print button to be disabled.

As demonstrated earlier, every time a record is found or cleared, the message Refresh is sent to all data-aware objects. By augmenting this message in one of the data-aware objects, we will be able to enable or disable the print button as needed. Add the following code the oOrderhea_Order_Number object:

// We want to disable the print button if there is no

// current record. The DD notifies all DEOs of any record

// change. We can augment any DEO's refresh message to see

// if a current record exists and set the enabled_state of

// print button accordingly.

Procedure Refresh integer iMode

Boolean bHasRecord

Handle hDD

Forward Send Refresh iMode

// if record exists, enable the print button.

Get Server to hDD

Get HasRecord of hDD to bHasRecord

Set Enabled_State of oPrintBtn to bHasRecord

End_Procedure // Refresh

As you can see, we are checking to see if the OrderHea table’s Data Dictionary contains a current record. If a record exists, we enable the button; if not, we disable it.

Note that we could have augmented any of the data-aware controls. We chose the order number control because it was first. Save the Order Entry view.

Reviewing Additional Report Samples


Reviewing Additional Report Samples

If you look at the Order Entry sample provided with Visual DataFlex, you will notice that several other reports are included in the order entry sample. These reports demonstrate some advanced VDF development techniques and we will not be showing you how to create these report views in this tutorial. We do however, encourage you to study them. Before reviewing these samples. you may want to look to CrystalReport class documentation.

You can read more about what the additional report samples, as well as all of the Visual DataFlex samples, do, in Learning from the Examples.

Next Step

This concludes the creation of the order entry system. Next, you will learn how to create web report components: Creating Web Report Components


Creating Web Report Components

In this section, you will learn how to create some reports like those in the Web Order sample application. These reports will not be exactly like those in the Web Order sample application, but they will duplicate the functionality of the sample reports.

In the last two topics you will learn how to integrate reports with each other, so that you can reuse the same reports for multiple purposes, including "drill down" functionality.

Important!

In order to run web reports, you must create a web application for the OrderTutorial workspace. If you have not done so already, please create a web application for this workspace now.

You can view the topic Creating a Web Application to aid you in doing so, then return here.

These are the reports you will learn to create:

  • Customer Listing

  • Sales Person Listing

  • Vendor Listing

  • Inventory Items Listing

  • List Customers Drill Down Report

  • List Orders Drill Down Report

  • Orders Detail Report

  • Integrating Multiple Drill Down Reports


Customer Listing

The Creating a Web Report topic of the Creating Web Components book will show you how to create the Customer Listing web report. Please complete that page now, then return to the next page, Sales Person Listing.

Sales Person Listing


Sales Person Listing

This page is going to show you how to create the Sales Person Listing web report.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Report Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, Enter oSalesP as the object name, SalesP as the filename and Sales Person Listing as the description and click Next.

  4. On the "Main Data Dictionary" wizard page, click on SalesP - SalesP_DataDictionary to select it as the data dictionary to be used, then click Next.

  5. On the "Entry Fields" wizard page, add all columns (there are only 2 columns in the sales person table: Id and Name), then click Next.

  6. On the Index wizard page, leave the default selection of Create index combo - design time control selected and click Next.

  7. On the "Selection Fields" wizard page, do not add any columns and click Next.

  8. On the "Records per Page / Drill Down Report" wizard page, enter 10 as the number of records per page and click Next.

  9. On the "Drill Down" wizard page, select Salesp.Id from the combo form. Click on the Use existing ASP file for the zoom, entry or report radio and type SalesPEntry.asp into the file name form. Click Next.

  10. On the "Style sheet options" wizard page, simply accept the default Cascading Style Sheet (CSS) and click Next.

  11. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly SalesP.wo and SalesP.asp pages open in the Code Editor.

  12. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page.

  13. Click on the Sales Person Listing link.

  14. Click on the Run Report button.

  15. Close your browser to return to the Studio.

Vendor Listing


Vendor Listing

This page is going to show you how to create the Vendor Listing web report.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Report Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, Enter oVendor as the object name, Vendor as the filename and Vendor Listing as the description and click Next.

  4. On the "Main Data Dictionary" wizard page, click on Vendor - Vendor_DataDictionary to select it as the data dictionary to be used, then click Next.

  5. On the "Entry Fields" wizard page, add all columns, then click Next.

  6. On the Index wizard page, leave the default selection of Create index combo - design time control selected and click Next.

  7. On the "Selection Fields" wizard page, do not add any columns and click Next.

  8. On the "Records per Page / Drill Down Report" wizard page, enter 10 as the number of records per page and click Next.

  9. On the "Drill Down" wizard page, select Vendor.Id from the combo form. Click on the Use existing ASP file for the zoom, entry or report radio and type VendorEntry.asp into the file name form. Click Next.

  10. On the "Style sheet options" wizard page, simply accept the default Cascading Style Sheet (CSS) and click Next.

  11. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly Vendor.wo and Vendor.asp pages open in the Code Editor.

  12. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page.

  13. Click on the Vendor Listing link.

  14. Click on the Run Report button.

  15. Close your browser to return to the Studio.

Inventory Items Listing


Inventory Items Listing

This page is going to show you how to create the Inventory Items Listing web report.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Report Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, Enter oInventoryItems as the object name, InventoryItems as the filename and Inventory Items Listing as the description and click Next.

  4. On the "Main Data Dictionary" wizard page, click on Invt - Invt_DataDictionary to select it as the data dictionary to be used, then click Next.

  5. On the "Entry Fields" wizard page, note that the Vendor table is also listed, not just Invt. This is because it is a parent table of Invt. Add columns Invt.Item_Id, Invt.Description, Vendor.Id, Vendor.Name, Invt.Vendor_Part_Id, Invt.Unit_Price and Invt.On_Hand and click Next.

  6. On the Index wizard page, leave the default selection of Create index combo - design time control selected and click Next.

  7. On the "Selection Fields" wizard page, do not add any columns and click Next.

  8. On the "Records per Page / Drill Down Report" wizard page, enter 10 as the number of records per page and click Next.

  9. On the "Drill Down" wizard page, select Invt.Item_Id from the combo form. Click on the Use existing ASP file for the zoom, entry or report radio and type InventoryEntry.asp into the file name form. Click Next.

  10. On the "Style sheet options" wizard page, simply accept the default Cascading Style Sheet (CSS) and click Next.

  11. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly InventoryItems.wo and InventoryItems.asp pages open in the Code Editor.

  12. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page.

  13. Click on the Inventory Items Listing link.

  14. Click on the Run Report button.

  15. Close your browser to return to the Studio.

List Customers Drill Down Report


List Customers Drill Down Report

This page is going to show you how to create the Customer Drill Down web report. This report is a customer report that allows you to "drill down" into the details of each customer record.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Report Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, Enter oCustomerDrillDownReport as the object name, CustomerDrillDownReport as the filename and Customer Drill Down Report as the description and click Next.

  4. On the "Main Data Dictionary" wizard page, click on Customer - Customer_DataDictionary to select it as the data dictionary to be used, then click Next.

  5. On the "Entry Fields" wizard page, add columns Customer_Number, Name, Phone_Number, Balance and Status from the Customer table, then click Next.

  6. On the Index wizard page, leave the default selection of Create index combo - design time control selected and click Next.

  7. On the "Selection Fields" wizard page, add column Customer.Customer_Number and click Next.

  8. On the "Records per Page / Drill Down Report" wizard page, leave the default (50) as the number of records per page and click Next.

  9. On the "Drill Down" wizard page, leave Customer.Customer_Number selected in the combo form. Also leave the default Create a new zoom page radio selected. Click Next.

  10. On the "Zoom page fields" page, add all columns from the Customer table, then remove Status.

  11. On the "Style sheet options" wizard page, simply accept the default Cascading Style Sheet (CSS) and click Next.

  12. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly CustomerDrillDownReport.wo and CustomerDrillDownReport.asp pages open in the Code Editor.

  13. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page.

  14. Click on the Customer Drill Down Report link.

  15. Click on the Run Report button.

  16. You can click the Next Page link to see the next 10 records in the report. You can click the New Report link to reset the report. If you click on any of the hyperlinks in the Number column, you will see the "Customer Drill Down Report (Zoom)" page.

  17. Close your browser to return to the Studio.

    You will now add a minor customization to the Customer Drill Down Report. Right now, you can only click on the Number column of the report to drill down to the zoom page. Since this column is often narrow and not that easy to click on, you are going to allow the user to click on the "Customer Name" column as well, to drill down to the zoom page.

  18. In the Code Explorer view of CustomerDrillDownReport.wo, expand the treeview to the oReport object. Expand it, too and double click on OnBody to display its code in the code editor.

    Scroll down in Procedure OnBody until the block of code between "Send WriteHtmlRowBegin" and "Send WriteHtmlRowEnd" is displayed in Code Explorer. Take a look at this code:

Send WriteHtmlRowBegin

Get AddRowIdLink (FormatNumber (sCustomerCustomer_Number,0)) To sText

Send WriteHtmlCell sText 'class="Data" align="right"'

Send WriteHtmlCell sCustomerName 'class="Data" align="left"'

Send WriteHtmlCell sCustomerPhone_Number 'class="Data" align="left"'

Send WriteHtmlCell (FormatNumber (sCustomerBalance,2)) 'class="Data" align="right"'

Send WriteHtmlCell sCustomerStatus 'class="Data" align="left"'

Send WriteHtmlRowEnd

This is the block of code that writes out each record in the Customer Drill Down Report. The first line inside the block (Get AddRowLink...) is the line of code that creates a link to the zoom page from the Customer.Customer_Number field.

To create a link from the Customer.Name field, you need to apply the same code to this field as is applied to the Customer.Customer_Number field. Some minor differences to keep in mind are: since the customer name is an ASCII field, you do not need to call the FormatNumber function and it will be left-aligned.

  19. Change the block of code to this:

Send WriteHtmlRowBegin

Get AddRowIdLink (FormatNumber (sCustomerCustomer_Number,0)) To sText

Send WriteHtmlCell sText 'class="Data" align="right"'

Get AddRowIdLink sCustomerName To sText

Send WriteHtmlCell sText 'class="Data" align="left"'

Send WriteHtmlCell sCustomerName 'class="Data" align="left"'

Send WriteHtmlCell sCustomerPhone_Number 'class="Data" align="left"'

Send WriteHtmlCell (FormatNumber (sCustomerBalance,2)) 'class="Data" align="right"'

Send WriteHtmlCell sCustomerStatus 'class="Data" align="left"'

Send WriteHtmlRowEnd

  20. So, let's test the report with this change. Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page. Click on the Customer Drill Down Report link.

  21. Click on the Run Report button. As you will see, you can now click on the Customer Name column, as well as the Number column to drill down to the zoom page (test it if you'd like).

  22. Close your browser to return to the Studio.

List Orders Drill Down Report


List Orders Drill Down Report

This page is going to show you how to create the List Orders Drill Down web report. This report will list all orders broken down by customer and allow the user to "drill down" into the details of each order.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Child Report Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, Enter oOrdersByCustomer as the object name, OrdersByCustomer as the filename and Orders By Customer as the description and click Next.

  4. On the "Main Data Dictionary" wizard page, click on OrderHea - OrderHea_DataDictionary to select it as the data dictionary to be used, then click Next.

  5. On the "Header Data Dictionary" wizard page, click on Customer - Customer_DataDictionary to select it as the data dictionary to be used. This is the DataDictionary for the "header" table, which will supply the records for the report header. Leave the default index selection, which is 2: <FAST> Customer_Number,Order_Number and click Next.

Fast Report Indexes

As indicated by <FAST>, index 2 is a fast index for this report, because its segments are the primary index of the header table, immediately followed by the primary index of the child table. Since the child table is constrained to the header table in a child report, this index is perfect since it can easily optimize this constraint.

  6. On the "Report Header Fields" wizard page, add columns Customer.Customer_Number and Customer.Name, then click Next.

  7. On the "Report Body Fields" wizard page, add columns OrderHea.Order_Number, OrderHea.Order_Date, SalesP.Id and OrderHea.Order_Total, then click Next.

  8. On the "Report Subtotal Fields" wizard page, add column OrderHea.Order_Total, then click Next.

  9. On the "Records per Page / Drill Down Report" wizard page, enter 10 as the number of records per page and click Next.

  10. On the "Drill Down" wizard page, select OrderHea.Order_Number from the combo form. Click on the Use existing ASP file for the zoom, entry or report and type OrderDtlReport.asp into the file name form. Click Next.

  11. On the "Style sheet options" wizard page, simply accept the default Cascading Style Sheet (CSS) and click Next.

  12. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly OrdersByCustomer.wo and OrdersByCustomer.asp pages open in the Code Editor.

  13. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page.

  14. Click on the Orders By Customer link.

  15. Close your browser to return to the Studio.

Orders Detail Report


Orders Detail Report

This page is going to show you how to create the Orders Detail web report. Just like the Orders Drill Down report, this is a header/child report. This report will list an order and all line items for that order.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Child Report Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. On the Names wizard page, Enter oOrderDtlReport as the object name, OrderDtlReport as the filename and Order Detail Report as the description and click Next.

  4. On the "Main Data Dictionary" wizard page, click on OrderDtl - OrderDtl_DataDictionary to select it as the data dictionary to be used, then click Next.

  5. On the "Header Data Dictionary" wizard page, click on OrderHea - OrderHea_DataDictionary to select it as the data dictionary to be used. This is the DataDictionary for the "header" table, which will supply the records for the report header. Leave the default index selection, which is 2: <FAST> Order_Number,Detail_Number and click Next.

  6. On the "Report Header Fields" wizard page, add columns OrderHea.Order_Number, OrderHea.Order_Date, Customer.Customer_Number, Customer.Name, Customer.Address, Customer.City, Customer.State, Customer.Zip, Customer.Phone_Number, OrderHea.Terms, OrderHea.Ship_Via, OrderHea.Ordered_By. SalesP.Id and SalesP.Name, then click Next.

  7. On the "Report Body Fields" wizard page, add columns Invt.Item_Id, Invt.Description, OrderDtl.Qty_Ordered, OrderDtl.Price and OrderDtl.Extended_Price, then click Next.

  8. On the "Report Subtotal Fields" wizard page, add column OrderDtl.Extended_Price, then click Next.

  9. On the "Records per Page / Drill Down Report" wizard page, leave 50 (the default) as the number of records per page. Uncheck the Support drill-down on body records checkbox, since this report represents the child-most records we want to see. Click Next.

  10. On the "Style sheet options" wizard page, simply accept the default Cascading Style Sheet (CSS) and click Next.

  11. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly OrderDtlReport.wo and OrderDtlReport.asp pages open in the Code Editor.

  12. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page.

  13. Click on the Order Detail Report link. You will see the new report list the first 50 orders.

    What really makes this interesting is that this report can now be fully integrated with the Orders Drill Down Report. Go back in the browser to the TestContent.htm page that lists all of the reports. Click on the Orders By Customer link. You will now see the Orders By Customer Report as before.

    Now click on any of the hyperlinks in the Order Number column. Click on the hyperlink for order 125, for example. You will see the Order Detail Report for just this order.

  14. Close your browser to return to the Studio.

Integrating Multiple Drill Down Reports


Integrating Multiple Drill Down Reports

In the previous two topics you learned how to create Order and Order Detail header/child reports and how the Order Detail report can be easily integrated with the Order report so a user can quickly and intuitively see all orders and "drill down" to see the details of that order.

You are now going to complete the "drill down" concept for the List Orders Drill Down Report by adding the Orders Drill Down report to this report. Once completed, users will be able to run the customer report, "drill down" to the details for each customer, including all of that customer's orders, and then "drill down" again to view the details for each order.

  1. In the Studio, click the Open File(s) toolbar button:

    Navigate to the AppHtml folder of the OrderTutorial workspace, select CustomerDrillDownReportZoom.asp and click the Open button.

  2. Scroll down to the bottom of this file until you see the end of an HTML table, marked by </table>. Below the end of this table, you are going to add code that will call the Orders Drill Down report.

    Add     the code below on the line below the </table> line.

<% dim ZoomURL, EndRowId

ZoomURL = "OrderDtlReport.asp" ' name of zoom file. If blank none.

oOrdersByCustomer.call "msg_SetHRefName", ZoomUrl

EndRowId = oOrdersByCustomer.call("get_RunOrdersByCustomer", RowId)

%>

  3. The completed code should look like this:

  4. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will run your project (there is no VDF code to recompile). When the application runs, your browser should display the testcontent.htm page.

  5. Click on the Customer Drill Down Report link, then click the Run Report button.

  6. Click on the link for customer Access Miles. You will see the Customer Details and now also all orders for this customer.

  7. Click on order number 125. You will see the Order Detail Report for order 125.

Creating Web Data Entry Components


Creating Web Data Entry Components

In this section, you will learn how to create some date entry web pages like those in the Web Order sample application. These web pages will not be exactly like those in the Web Order sample application, but they will duplicate the functionality of the sample pages.

Important!

In order to run web pages, you must create a web application for the OrderTutorial workspace. If you have not done so already, please create a web application for this workspace now.

You can view the topic Creating a Web Application to aid you in doing so, then return here.

These are the reports you will learn to create:

  • Customer Entry web page

  • Sales Person Entry web page

  • Vendor Entry web page

  • Inventory Entry web page


Customer Entry web page

The Creating a Data Entry Web Page topic of the Creating Database Application Components book will show you how to create the Customer Entry web page. Please complete that page now, then return to the next page, Sales Person Entry web page.

Sales Person Entry web page


Sales Person Entry web page

Next, you will create the Sales Person data entry web page.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Entry Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. Accept the default selection on the "Component Types" page. This will allow you to create a both a WBO and an ASP page that accesses the WBO. Click Next.

  4. On the Names wizard page, Enter oSalesPEntry as the object name, SalesPEntry as the filename and Sales Person Entry as the description and click Next.

  5. On the "Main Data Dictionary" wizard page, click on SalesP - SalesP_DataDictionary to select it as the data dictionary to be used, then click Next.

    You have now completed the part of the wizard that creates the WBO. Next, you will go through the wizard steps that define the ASP page.

  6. On the "Description ASP/HTML Page", leave the default of Sales Person Entry as the description and click Next.

  7. On the "Entry Fields" wizard page, click on the All button to add all fields from the SalesP table to the data entry Web page. Click Next.

  8. On the Buttons wizard page, leave all of the default checkboxes as they are. Enter SalesP.asp in the ASP selection list form (this is the report you created in a previous section, Sales Person Listing, if you completed the Creating Web Report Components book). Click Next.

  9. On the "Index Finds in your ASP/HTML page" wizard page, leave the default selection of Create index combo - design time control selected and click Next.

  10. On the "Labels in your ASP/HTML page" wizard page, use the default selections and click Next.

    On the "Input Controls in your ASP/HTML page" wizard page, use the default selections and click Next.

    On the "Style sheet options" wizard page, leave the default style sheet that is filled in and click Next.

  11. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly SalesPEntry.wo and SalesPEntry.asp pages open in the Code Editor.

  12. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page. Click on the Sales Person Entry link.

  13. Now the browser loads the "Sales Person Entry" data entry web page you built.

  14. Close your browser to return to the Studio.

Vendor Entry web page


Vendor Entry web page

Next, you will create the Vendor data entry web page.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Entry Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. Accept the default selection on the "Component Types" page. This will allow you to create a both a WBO and an ASP page that accesses the WBO. Click Next.

  4. On the Names wizard page, Enter oVendorEntry as the object name, VendorEntry as the filename and Vendor Entry as the description and click Next.

  5. On the "Main Data Dictionary" wizard page, click on Vendor -Vendor_DataDictionary to select it as the data dictionary to be used, then click Next.

    You have now completed the part of the wizard that creates the WBO. Next, you will go through the wizard steps that define the ASP page.

  6. On the "Description ASP/HTML Page", leave the default of Vendor Entry as the description and click Next.

  7. On the "Entry Fields" wizard page, click on the All button to add all columns from the SalesP table to the data entry Web page. Click Next.

  8. On the Buttons wizard page, leave all of the default checkboxes as they are. Enter Vendor.asp in the ASP selection list form (this is the report you created in a previous section, Vendor Listing, if you completed the Creating Web Report Components book). Click Next.

  9. On the "Index Finds in your ASP/HTML page" wizard page, leave the default selection of Create index combo - design time control selected and click Next.

  10. On the "Labels in your ASP/HTML page" wizard page, use the default selections and click Next.

    On the "Input Controls in your ASP/HTML page" wizard page, use the default selections and click Next.

    On the "Style sheet options" wizard page, leave the default style sheet that is filled in and click Next.

  11. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly SalesPEntry.wo and SalesPEntry.asp pages open in the Code Editor.

  12. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page. Click on the Vendor Entry link.

  13. Now the browser loads the "Vendor Entry" data entry web page you built.

  14. Close your browser to return to the Studio.

Inventory Entry web page


Inventory Entry web page

Last, you will create the Inventory Items data entry web page.

  1. Click on the Create New button on the Studio’s toolbar. Click on the Web Object tab of the Create New... dialog. Double-click the WBO Entry Wizard icon.

  2. Read the explanations on the first wizard page of what this wizard will do and click Next.

  3. Accept the default selection on the "Component Types" page. This will allow you to create a both a WBO and an ASP page that accesses the WBO. Click Next.

  4. On the Names wizard page, Enter oInventoryEntry as the object name, InventoryEntry as the filename and Inventory Entry as the description and click Next.

  5. On the "Main Data Dictionary" wizard page, click on Invt -Invt_DataDictionary to select it as the data dictionary to be used, then click Next.

    You have now completed the part of the wizard that creates the WBO. Next, you will go through the wizard steps that define the ASP page.

  6. On the "Description ASP/HTML Page", leave the default of Inventory Entry as the description and click Next.

  7. On the "Entry Fields" wizard page, click on the All button to add columns add Vendor.Name, Invt.Item_Id, Invt.Description, Invt.Vendor_Part_Id, Invt.Unit_Price and Invt.On_Hand to the data entry Web page. Click Next.

  8. On the Buttons wizard page, leave all of the default checkboxes as they are. Enter InventoryItems.asp in the ASP selection list form (this is the report you created in a previous section, Inventory Items Listing, if you completed the Creating Web Report Components book). Click Next.

  9. On the "Index Finds in your ASP/HTML page" wizard page, leave the default selection of Create index combo - design time control selected and click Next.

  10. On the "Labels in your ASP/HTML page" wizard page, use the default selections and click Next.

    On the "Input Controls in your ASP/HTML page" wizard page, use the default selections and click Next.

    On the "Style sheet options" wizard page, leave the default style sheet that is filled in and click Next.

  11. Click Finish on the last wizard page.

    You should now be back in the Studio, with the outline of the newly SalesPEntry.wo and SalesPEntry.asp pages open in the Code Editor.

  12. So, let's test our completed report.

    Click on the Run button on the Studio's toolbar. The Studio will compile, then run your project. When the application runs, your browser should display the testcontent.htm page. Click on the Inventory Entry link.

  13. Now the browser loads the "Inventory Person Entry" data entry web page you built.

  14. Close your browser to return to the Studio.

Adding ActiveX Controls to the Order Entry System


Adding ActiveX Controls to the Order Entry System

In this section, you will learn how to import ActiveX controls and add them to exiting applications. You will add an ActiveX data-aware calendar control to the Order Entry view.

Important!

This section assumes that you have been going through the Creating a Complete Order Entry System Tutorial step by step.

If you skipped the Creating Windows Data Entry Components part of the tutorial, and, more specifically, Creating the Order Entry View, you should complete that section now and return here when you have completed it.

  1. Open the Visual DataFlex Studio to the OrderTutorial workspace.

  2. Click on the Create New button on the Studio’s toolbar. Click on the Class tab of the Create New... dialog. Double-click the Import COM ActiveX icon.

  3. After the list of available ActiveX controls on your PC populates, select Microsoft Calendar Control 8.0 (version 7.0). The version of the control may vary slightly with your operating system.

  4. Check the checkbox in the Data-Aware column. Accept the defaults for the remaining settings in this dialog and click Ok.

  5. You should see a message box that informs you that the control has imported successfully. After clicking Ok on the message box dialog, the newly created Visual DataFlex package for the control should load in the Studio.

  6. Open the Order Entry view in the visual designer.

  7. Extend the width of the view control to the right.

  8. Drop a cComDbCalendar control onto the view from the ActiveX group of the Class Palette. Resize it to look more or less like this:

  9. Right-click on the calendar control and select ActiveX Properties from the context menu.

  10. This opens the "ActiveX Control Properties" dialog, which allows you to view and change properties specific to any ActiveX control. This dialog will display different properties for every ActiveX control imported into the Studio.

  11. Uncheck the Month/Year Title checkbox and click Ok.

  12. Change the peAnchors property of the oComDbCalendar1 control to anTopBottomRight.

  13. Still in the Object Properties window, click on the Data Bindings tab.

  14. Since this is a database-aware control, we want to connect the control to a database table and column. Click on the prompt (...) button for the Data Source (Entry_Item).

  15. In the DDO Column Selection dialog select the Order_Date column from the OrderHea table and click Ok.

  16. You can now test compile and run the Order Entry view and see the new calendar control in action. Click on the Run button on the Studio's toolbar to compile and run project Order.src.

    When the application runs, click on the View menu and then Order Entry View to open the view. Find any existing Order and see that the calendar control displays the correct date for the current order.

You see how easy it is to add ActiveX controls and even data-aware ActiveX control to your Visual DataFlex applications.