13 - Clarion Language Lesson

Top  Previous  Next

Clarion the Programming Language

The foundation of the Clarion application development environment is the Clarion programming language. Clarion is a 4th Generation Language (4GL) that is both business-oriented and general-purpose. It is business-oriented in that it contains data structures and commands that are highly optimized for data file maintenance and business programming needs. It is also general-purpose because it is fully compiled (not interpreted) and has a command set that is functionally comparable to other 3GL langauges (such as C/C++, Modula-2, Pascal, etc.).

By now, you should have completed all the Application Generator lessons in the preceding sections. The purpose of this language lesson is to introduce you to the fundamental aspects of the Clarion language—particularly as it relates to business programming using the Windows event-driven paradigm. Clarion language keywords are in ALL CAPS and this lesson concentrates on explaining the specific use of each keyword and its interaction with other language elements only in the specific context within which it is used. You should always refer to the Language Reference for a more complete explanation of each individual keyword and its capabilities.

When you complete this lesson, you will be familiar with:

·

The basic structure of a Clarion procedural program.

·

The most common event-handling code structure.

·

How to compile and link hand-coded programs.

 

Event-driven Programming

Windows programs are event-driven. The user causes an event by CLICKing the mouse on a screen control or pressing a key. Every such user action causes Windows to send a message (an event) to the program which owns the window telling it what the user has done.

Once Windows has sent the message signaling an event to the program, the program has the opportunity to handle the event in the appropriate manner. This basically means the Windows programming paradigm is exactly opposite from the DOS programming paradigm—the operating system (Windows) tells the program what the user has done, instead of the program telling the operating system what to do.

This is the most important concept in Windows programming—that the user is in control (or should be) at all times. Therefore, Windows programs are reactive rather than proactive; they always deal with what the user has done instead of directing the user as to what to do next. The most common example of this is the data entry dialog. In most DOS programs, the user must follow one path from field to field to enter data. They must always enter data in one field before they can go on to the next (and they usually can only go on to a specific "next" entry field). This makes data validation code simple—it simply executes immediately after the user has left the field.

In Windows programs, the user may use a mouse or an accelerator key to move from control to control, at any given time, in no particular order, skipping some controls entirely. Therefore, data validation code should be called twice to ensure that it executes at least once: once when the user leaves the entry control after entering data, and again when the user presses OK to leave the dialog. If it isn’t executed on the OK button, required data could be omitted. This makes Windows programs reactive rather than proactive.

Hello Windows

Traditionally, all programming language lessons begin by creating a "Hello World" type of program—and so does this one.

 

Starting Point:

The Clarion environment should be open. The LCLESSON.APP should now be closed.

 

You should not need to type any code in this lesson. Simply COPY what you need directly from this help file into the appropriate areas.

 

Create the Source file

1.

Using the appropriate tool in your operating system (File Manager, Explorer, etc.), create a new folder called Language under the CLARION7 folder.

2.

Return to the Clarion IDE.

3.

Choose File  New  Solution, Project or Application.

The New Project dialog appears. It’s a special dialog, allowing you to change the directory and type in the filename.

4.

Type Hello in the Name entry.

5.

In the Location field, select the \CLARION7\LANGUAGE folder.

6.

Uncheck the Auto create project subdir check box.

7.

Press the Create button.

This creates an empty HELLO.CLW (.CLW is the standard extension for Clarion source code files) and places you in the Text Editor.

 

Examine the Project System

The Clarion Win32/Clarion# project system has been updated and upgraded to use the MSBuild project engine. MSBuild is the new extensible, XML-based build engine that ships with the .NET Framework 2.0 and higher. MSBuild simplifies the process of creating and maintaining build scripts, and formalizes the steps required to institute a formal build process.

All Clarion Win32 projects use a default extension of *.CWPROJ.

All projects compiled in Clarion Win32 are stored in solution files (*.SLN). These files can store multiple projects, and allow multiple resources to be referenced and included.

These files are identified in the Solution Explorer, shown here:

 

 

1.

RIGHT-CLICK on the Hello project, and select the Properties item in the popup menu.

The Project Properties dialog appears. Every Clarion Win32 project is divided into 4 project areas: Application, Compiling, Debug, and Build Events.

2.

Type ".\" (without the quotes) in the Output Path box (or use the ellipsis button to select the directory from the Browse for Folder dialog).

3.

Verify that the default Output type is set to Exe. This controls the type of file that the Build action will create.

4.

Verify that the default Link Mode is set to Dll. This controls the files needed with the Output Type, and the default uses the necessary runtime libraries.

5.

Save your project changes by pressing the Save button on the IDE toolbar, and close the Project Properties by pressing the Close ( X ) button.

The HELLO.CLW file in the Text Editor now has focus.

Notice that the environment’s title bar text now reads: Hello [Clarion Version] (Debug) - Clarion.

 

Write the Program

1.

Replace the default code in Hello.clw with the following:

 

PROGRAM

MAP

END

MyWin  WINDOW('Hello Windows'),SYSTEM

      END

CODE

OPEN(MyWin)

ACCEPT

END

 

 

This code begins with the PROGRAM statement. This must be the first non-comment statement in every Clarion program. Notice that the keyword PROGRAM is indented in relation to the word MyWin. In Clarion, the only statements that begin in column one (1) of the source code file are those with a statement label. A label must begin in column one (1), by definition. The PROGRAM statement begins the Global data declaration section.

Next there is an empty MAP structure. The END statement is a required terminator of the MAP data structure. A MAP structure contains prototypes which define parameter data types, return data types, and various other options that tell the compiler how to deal with your procedure calls (this is all covered later in this lesson). A MAP structure is required when you break up your program’s code into PROCEDUREs. We haven’t done that yet, but we still need it because there is an OPEN statement in the executable code.

When the compiler processes a MAP structure, it automatically includes the prototypes in the \CLARION7\LIBSRC\BUILTINS.CLW file. This file contains prototypes for almost all of the Clarion language built-in procedures (including the OPEN statement). If the empty MAP structure were not in this code, the compiler would generate an error on the OPEN statement.

MyWin is the label of the WINDOW data structure (the "M" must be in column one). In Clarion, windows are declared as data structures, and not dynamically built by executable code statements as in some other languages. This is one of the aspects of Clarion that makes it a 4GL. Although Clarion can dynamically build dialogs at runtime, it is unnecessary to do so. By using a data structure, the compiler creates the Windows resource for each dialog, enabling better performance at runtime.

The ('Hello Windows') parameter on the WINDOW statement defines the title bar text for the window. The SYSTEM attribute adds a standard Windows system menu to the window. The END statement is a required terminator of the WINDOW data structure. In Clarion, all complex structures (both data and executable code) must terminate with an END or a period (.). This means the following code is functionally equivalent to the previous code:

 

PROGRAM

MAP.

MyWin  WINDOW('Hello Windows'),SYSTEM.

CODE

OPEN(MyWin)

ACCEPT.

 

Although functionally equivalent, this code would become much harder to read as soon as anything is added into the MAP, WINDOW, or ACCEPT structures. By convention, we use the END statement to terminate multi-line complex statements, placing the END in the same column as the keyword it is terminating while indenting everything within the structure. We only use the period to terminate single-line structures, such as IF statements with single THEN clauses. This convention makes the code easier to read, and any missing structure terminators much easier to find.

The CODE statement is required to identify the beginning of the executable code section. Data (memory variables, data files, window structures, report structures, etc.) are declared in a data section (preceding the CODE statement), and executable statements may only follow a CODE statement.

Since this program does not contain any PROCEDUREs (we’ll get to them in the next chapter), it only has a Global Data section followed by three lines of executable code. Variables declared in the Global Data section are visible and available for use anywhere in a program.

The OPEN(MyWin) statement opens the window, but does not display it. The window will only appear on screen when a DISPLAY or ACCEPT statement executes. This feature allows you to dynamically change the properties of the window, or any control on the window, before it appears on screen.

ACCEPT is the event processor. Most of the messages (events) from Windows are automatically handled internally for you by ACCEPT. These are the common events handled by the runtime library (screen re-draws, etc.). Only those events that actually may require program action are passed on by ACCEPT to your Clarion code. This makes your programming job easier by allowing you to concentrate on the high-level aspects of your program.

The ACCEPT statement has a terminating END statement, which means it is a complex code structure. ACCEPT is a looping structure, "passing through" all the events that the Clarion programmer might want to handle (none, in this program—we’ll get back to this shortly), then looping back to handle the next event.

An ACCEPT loop is required for each window opened in a Clarion program. An open window "attaches" itself to the next ACCEPT loop it encounters in the code to be its event processor.

For this program, ACCEPT internally handles everything the system menu (placed on the window by the SYSTEM attribute) does. Therefore, when the user uses the system menu to close the window, ACCEPT automatically passes control to any statement immediately following its terminating END statement. Since there is no other explicit Clarion language statement to execute, the program ends. When any Clarion program reaches the end of the executable code, an implicit RETURN executes, which, in this case, returns the user to the operating system.

 

2.

CLICK on the Build and Run button .

The program compiles and links, then executes. The window’s title bar displays the "Hello Windows" message, and you must close the window with the system menu.

 

 

 

Hello Windows with Controls

The program you just created is close to the smallest programs possible to create in Clarion. Now we’ll expand on it a bit to demonstrate adding some controls to the window and handling the events generated by those controls.

Change the Source code

1.

Edit the code to read:

 

PROGRAM

MAP

END

MyWin  WINDOW('Hello Windows'),AT(,,100,100),SYSTEM      !Changed

       STRING('Hello Windows'),AT(26,23),USE(?String1)  !Added

       BUTTON('OK'),AT(34,60),USE(?Ok),DEFAULT          !Added

      END

CODE

OPEN(MyWin)

ACCEPT

 IF ACCEPTED() = ?Ok THEN BREAK.                        !Added

END

 

 

The Window Designer is available to you in the Text Editor, just as it is in the Application Generator. To call the Window Designer, place the insertion point anywhere within the WINDOW structure then press CTRL+F. The only restrictions are that the Control Template and Dictionary Field tools are unavailable (they are specific to the Application Generator).

 

The change is the addition of the STRING and BUTTON controls to the WINDOW structure. The STRING places constant text in the window, and the BUTTON adds a command buttton.

The only other addition is the IF ACCEPTED() = ?Ok THEN BREAK. statement. This statement detects when the user has pressed the OK button and BREAKs out of the ACCEPT loop, ending the program. The ACCEPTED statement returns the field number of the control for which EVENT:Accepted was just generated (EVENT:Accepted is an EQUATE contained in the \CLARION7\LIBSRC\EQUATES.CLW file, which the compiler automatically includes in every program).

?Ok is the Field Equate Label of the BUTTON control, defined by the control’s USE attribute (see Field Equate Labels in the Language Reference). The compiler automatically equates ?Ok to the field number it assigns the control (using Field Equate Labels helps make the code more readable).

When the ACCEPTED procedure returns a value equal to the compiler-assigned field number for the OK button, the BREAK statement executes and terminates the ACCEPT loop.

2.

CLICK on the Build and Run button .

The program compiles and links, then executes. The window’s title bar still displays the "Hello Windows" message, and now, so does the constant text in the middle of the window. You can close the window either with the system menu, or the OK button.

 

 

Common form Source code

There are other ways to write the code in the ACCEPT loop to accomplish the same thing. We’ll go straight to the most common way, because this is more similar to the style of code that the Application Generator generates for you from the Clarion ABC Templates.

 

1.

Edit the code to read:

 

PROGRAM

MAP

END

MyWin  WINDOW('Hello Windows'),AT(,,100,100),SYSTEM

       STRING('Hello Windows'),AT(26,23),USE(?String1)

       BUTTON('OK'),AT(34,60),USE(?Ok),DEFAULT

      END

CODE

OPEN(MyWin)

ACCEPT

 CASE FIELD()         !Added

 OF ?Ok               !Added

  CASE EVENT()         !Added

  OF EVENT:Accepted   !Added

   BREAK               !Added

  END                 !Added

 END                   !Added

END

 

In this code you have one CASE structure nested within another. A CASE structure looks for an exact match between the expression immediately following the keyword CASE and another expression immediately following an OF clause (although these only show one OF clause each, a CASE structure may have as many as necessary).

The CASE FIELD() structure determines to which control the current event applies. When the FIELD procedure returns a value equal to the field number of the OK button (the ?Ok Field Equate Label) it then executes the CASE EVENT() structure.

The CASE EVENT() structure determines which event was generated. When the EVENT procedure returns a value equal to EVENT:Accepted (an EQUATE contained in the \CLARION7\LIBSRC\EQUATES.CLW file) it then executes the BREAK statement.

Nesting CASE EVENT() within CASE FIELD() allows you to put all the code associated with a single control in one place. You could just as easily nest a CASE FIELD() structure within a CASE EVENT() structure, reversing the code, but this would scatter the code for a single control to multiple places.

2.

CLICK on the Build and Run button .

 

Again, you can close the window either with the system menu, or the OK buttton, just as with the previous code, but now the code is structured in a common style.

 

Hello Windows with Event Handling

There are two types of events passed on to the program by ACCEPT: Field-specific and Field-independent events.

A Field-specific event occurs when the user does anything that may require the program to perform a specific action related to a single control. For example, when the user presses tab after entering data in a control, the field-specific EVENT:Accepted generates for that control.

A Field-independent event does not relate to any one control but may require some program action (for example, to close a window, quit the program, or change execution threads).

Nesting two CASE structures as we just discussed is the most common method of handling field-specific events. The most common method of handling field-independent events is a non-nested CASE EVENT() structure, usually placed immediately before the CASE FIELD() structure.

 

Change the Source code

 

1.

Edit the code to read:

 

PROGRAM

MAP

END

MyWin  WINDOW('Hello Windows'),AT(,,100,100),SYSTEM

       STRING('Hello Windows'),AT(26,23),USE(?String1)

       BUTTON('OK'),AT(34,60),USE(?Ok),DEFAULT

      END

CODE

OPEN(MyWin)

ACCEPT

 CASE EVENT()               !Added

 OF EVENT:OpenWindow       !Added

  MESSAGE('Opened Window') !Added

 OF EVENT:GainFocus         !Added

  MESSAGE('Gained Focus')   !Added

 END                       !Added

 CASE FIELD()

 OF ?Ok

  CASE EVENT()

  OF EVENT:Accepted

   BREAK

  END

 END

END

 

The new CASE EVENT( ) structure handles two field-independent events: EVENT:OpenWindow and EVENT:GainFocus. The MESSAGE procedure used in this code is just to visually display to you at runtime that the event was triggered. Instead of the MESSAGE procedure, you would add here any code that your program needs to execute when the user triggers these events.

This demonstrates the basic logic flow and code structure for procedural window procedures—an ACCEPT loop containing a CASE EVENT() structure to handle all the field-independent events, followed by a CASE FIELD() structure with nested CASE EVENT() structures to handle all field-specific events.

2.

CLICK on the Build and Run button .

Notice that EVENT:OpenWindow generates when the window first displays (in that order). EVENT:GainFocus will generate when you ALT+TAB to another application then ALT+TAB back to Hello Windows.

 

 

Adding a PROCEDURE

In Hello Windows we have an example of a very simple program. Most modern business programs are not that simple—they require the use of Structured Programming techniques. This means you break up your program into functional sections, where each performs a single logical task. In the Clarion language these functional sections are called PROCEDUREs.

First, we’ll add a PROCEDURE to the Hello Windows program.

 

Change the Source code

1.

Edit the code to read:

 

 

PROGRAM

MAP

Hello PROCEDURE                             !Added

END

CODE                                       !Added

Hello                                      !Added

 

Hello   PROCEDURE                           !Added

MyWin  WINDOW('Hello Windows'),AT(,,100,100),SYSTEM

       STRING('Hello Windows'),AT(26,23),USE(?String1)

       BUTTON('OK'),AT(34,60),USE(?Ok),DEFAULT

      END

CODE

OPEN(MyWin)

ACCEPT

 CASE EVENT()

 OF EVENT:OpenWindow

  MESSAGE('Opened Window')

 OF EVENT:GainFocus

  MESSAGE('Gained Focus')

 END

 CASE FIELD()

 OF ?Ok

  CASE EVENT()

  OF EVENT:Accepted

   BREAK

  END

 END

END

 

The only changes are at the beginning of the program. Inside the MAP structure we now see the Hello PROCEDURE statement which prototypes the Hello procedure. A prototype is the declaration of the procedure for the compiler, telling the compiler what to expect when your code calls the procedure. This prototype indicates that the procedure takes no parameters and does not return a value. All PROCEDUREs in your program must be prototyped in a MAP structure. See PROCEDURE prototypes in the Language Reference for more on prototypes.

The keyword CODE immediately following the MAP structure terminates the Global data section and marks the beginning of the Global executable code section, which only contains the Hello statement—a call to execute the Hello procedure. A PROCEDURE which does not return a value is always called as a single