In addition to altering an application's look by manipulating properties, there are many ObjectPAL commands that can have an effect on an application. For example, you can change the look of the desktop with the procedures hideToolbar() and showToolbar(). They hide and show the toolbar. For example:
1: hideToolbar() ;Hide Toolbar.
2: sleep(1000) ;Wait for 1 second.
3: showToolbar() ;Show toolbar.
Notice how descriptive ObjectPAL is. It uses real words that describe what you're doing. Sounds easy so far, right? Well, that's because it is easy. The reason ObjectPAL has such a steep learning curve is that it's so rich in commands. Every procedure and method is as easy to understand as the previous examples; however, because there are so many procedures, methods, and properties, it takes a while just to get a handle on ObjectPAL.
Basic Language Elements and ObjectPAL
Now that you have looked at ObjectPAL from the big picture, this next section introduces basic programming elements common to most programming languages and relates these common elements to ObjectPAL. If you have programmed in another language before, then you will particularly like this section.
Note: If you want to type and run the examples in this section, then use the pushButton method of a button and type the code, run the form, and select the button. (There is no need to type the comments.)
A variable is a place in memory used to store data temporarily. You first declare a variable and then you use it. For example, a string is an alphanumeric value or an expression consisting of alphanumeric characters. You can convert a number to a string with string(x) or you can declare a string variable and use it as the following code demonstrates. For example, line 2 that follows declares s as a string:
1: var ;Begin variable block.
2: s String ;Declare s as a String.
3: endVar ;End variable block.
4:
5: s = "Press OK to continue." ;Set s to String value.
6: message(s) ;Display value stored in s.
An operator is a symbol that represents an operation to be performed on a value or values. For example, the + operator represents addition, and the * operator represents multiplication. Line 8 in the code that follows multiplies x and y and then displays the result on the status line.
1: var ;Start variable block.
2: x Number ;Declare x as a number.
3: y Number ;Declare y as a number.
4: endVar ;End variable block.
5:
6: x = 10 ;Set x to 10.
7: y = 5 ;Set y to 5.
8: message(x * y) ;Displays 50 on the status line.
When you concatenate two values, you combine two or more alphanumeric values with the + operator. For example, line 9 that follows concatenates two strings and then assigns the value to s2:
1: var ;Begin variable block.
2: s1 String ;Declare s1 as a String.
3: s2 String ;Declare s2 as a String.
4: endVar ;End variable block.
5:
6: s1 = "Enter name here" ;Set s1 to String.
7: s1.view("What is your name?") ;View s1 in a view box.
8:
9: s2 = "Hello " + s1 ;Set s2 to String plus s1.
10: message(s2) ;Display s2 on status line.
Comparison operators are symbols used to compare two values in a query, in a calculated field, or in an ObjectPAL expression. The comparison operators are <, >, <=, >=, and =. For example, lines 11--13 compare x and y. Depending on which value is greater, a different message is displayed.
1: var ;Begin variable block.
2: x Number ;Declare x as a number.
3: y Number ;Declare y as a number.
4: endVar ;End variable block.
5: x = 0 ;Set x to 0.
6: x.view("Enter value for x") ;View x in a view box.
7: y = 0 ;Set y to 0.
8: y.view("Enter value for y") ;View y in a view box.
9:
10: switch ;Begin switch block.
11: case x > y : message("x is bigger") ;Is x > y?
12: case y > x : message("y is bigger") ;Is y > x?
13: case x = y : message("They are equal");Is x = Y?
14: endSwitch ;End switch block.
A constant is a specific, unchanging value. ObjectPAL uses two types of constants: those used in calculations and defined in the Const window of an object and constants predefined by ObjectPAL. For example, line 2 that follows uses a user-set constant that sets the value of pi to 8 decimal points:
1: const ;Begin constant block.
2: pi = 3.14159265 ;Set the permanent value of pi.
3: endConst ;End constant block.
4:
5: ;Display the square root of pi.
6: message("The square root of pi is ", sqrt(pi))
You already have used predefined constants; all property values are actually predefined constants. For example, in the previous example, you used self.color = Red. Red is a constant that represents a number ObjectPAL associates with the color red. You use constants as values that you pass to methods and procedures, such as DataNextRecord, DarkBlue, and FieldForward. Examples of passing constants to methods include fieldName.action(DataNextRecord), fieldName.font.color = DarkBlue, and active.action(FieldForward).
The following line of code shows the numeric equivalent to the constant Red:
message("The numeric value of Red is ", SmallInt(Red))
Although it is academically interesting to understand the numbers behind the built-in ObjectPAL constants, always use the constants in your own coding. Never use the numbers, for they get renumbered in a future version.
A branch transfers program control to an instruction other than the next sequential instruction. When you used the switch block in the example for comparison operators, you branched to one line of code or another depending on a comparison. Normally, a programming language executes line after line in sequential order. This is true whether the language is a line-oriented language, such as BASIC, or a statement-oriented language, such as ObjectPAL, Object Pascal, or C++.
In programming languages, a control structure is a set of keywords used to branch or loop. With control structures, you can alter the sequence of execution and add logic to your code. A loop is a set of instructions that is repeated a predetermined number of times or until a specified condition is met. For example, lines 6 and 7 in the code that follows are repeated 10 times as indicated in line 5.
1: var ;Begin variable block.
2: x Number ;Declare x as a number.
3: endVar ;End variable block.
4:
5: for x from 1 to 10 ;Begin loop.
6: message(x) ;Display x.
7: sleep(500) ;Wait 1/2 second.
8: endFor ;End Loop.
A logical value is a True or False value that is assigned to an expression when it is evaluated. Logical operators are operators used in queries, in calculated fields, and in ObjectPAL methods. The three logical operators are and, or, and not. For example, line 2 in the code that follows declares l as a logical variable, and line 6 uses the not logical operator to display the opposite of l in a view box:
1: var ;Begin variable block.
2: l Logical ;Declare l as a logical.
3: endVar ;End variable block.
4:
5: l = True ;Set l to True.
6: view(not l) ;Display False in view box.
A subroutine is a sequence of instructions that performs a specific task, usually more than once in a program. The sequence may be invoked many times by the current program or by multiple applications. Although ObjectPAL doesn't have actual subroutines, you can think of custom methods and custom procedures as subroutines.
Hiding the Desktop
At one point or another, most users want to create a form that hides the Paradox desktop. To do this, the application type has two usefull methods: hide() and show(). To use them, you need to define an Application variable and use that variable with the hide() and show() methods, as in the following example:
1: var
2: app Application ;App is now an application variable.
3: endVar
4: app.hide() ;Hide the desktop.
5: sleep(5000) ;Wait 5 seconds.
6: app.show() ;Show the desktop.
Unless you have defined your form as a dialog box and have reopened it, your form will disappear with the desktop. At first, hide the desktop only for a period of time; for example, five seconds. Note that even though hide() and show() don't have a parameter passed to them, you still use parentheses. Parentheses are part of the basic syntax for all methods and procedures. Contrast this with properties, which never use parentheses.
To cause a delay, you can use sleep() from the system type. In line 5, you use the sleep() procedure to sleep for 5,000 milliseconds (5 seconds). You can tell that sleep() is a procedure and not a method because it has no object on which to work. A method requires an object on which to work; a procedure does not.
After a variable is defined as an application, you can use any of the application-type methods on it. In addition to hide() and show(), you can use and manipulate an application variable with the following methods: bringToTop(), getPosition(), getTitle(), isMaximized(), isMinimized(), isVisible(), maximize(), minimize(), setPosition(), setTitle(), windowClienthandle(), and windowHandle().
First Database Routines
All this programming theory and manipulating properties and the desktop is necessary and useful, but it probably isn't the reason you purchased Paradox. This section discusses some of the basic commands used to edit data.
In ObjectPAL, you often have several ways to do something. For example, to go to the beginning of a table, you could use either a method or an action constant. The following two lines of code are equivalent:
1: MyField1.nextRecord()
2: MyField1.action(DataNextRecord)
These two methods represent two techniques for maneuvering through a table. Both of these methods move the pointer from the current record to the next record. The first line requires less typing and is my preferred usage. The second line represents more clearly what ObjectPAL is doing, however. The action() method sends a constant to the event action. When the constant DataNextRecord reaches the action event, action knows to move the table cursor to the next record. In addition to nextRecord(), there is a whole set of table-related methods, including home(), end(), and priorRecord().
In addition to using the object variable self, which refers to the object the code is attached to, you can use active, which represents the object with focus. You can combine these with the two distinctly different techniques for positioning the pointer, as in the following example:
1: self.nextRecord() ;Move to the next record.
2: active.nextRecord() ;Move to the next record.
3: self.action(DataNextRecord) ;Move to the next record.
4: active.action(DataNextRecord) ;Move to the next record.
These two groups of code use the self and active built-in object variables. self refers to the object that executes the code and active refers to the object that has focus.
Using edit() and endEdit()
When you go into edit mode (with a command such as edit()), it is important to note that you put the whole form into edit mode. In other words, you can go to any field of any table on any page and enter or edit values. When you issue an endEdit() command, the whole form is taken out of edit mode. Since the edit() method is a method of an object (self) that also has a TableName property, the edit() method can use that property to put the correct table into edit mode. active refers to the object that currently has the focus. In a multitable form, you could use active to move the record pointer to the table that is attached to the selected object.
Basic Database Buttons
Suppose that you want to put eight buttons on a form that do simple database tasks: Top, Bottom, Previous, Next, Edit, Store, New, and Delete. This example introduces you to the following ObjectPAL methods: home(), end(), priorRecord(), nextRecord(), edit(), postRecord(), endEdit(), insertRecord(), and deleteRecord(). It also introduces the if structure.
On The Net: http://prestwood.com/forums/paradox/books/official/files/OV-LIKE.FSL form.
Step By Step
1. Make your working directory Paradox's Samples directory and create a new form with the CUSTOMER.DB table in its data model.
2. Place eight buttons on the form. Change their labels to Top, Bottom, Previous, Next, Edit, Store, New, and Delete, as shown here:
3. Add line 3 to the button labeled Top. Line 3 issues the home() command, which takes you to the beginning of the active table.
1: ;OV-LIKE :: btnTop :: pushButton
2: method pushButton(var eventInfo Event)
3: active.home() ;Move to the first record.
4: endMethod
4. Add line 3 to the button labeled Bottom. Line 3 issues the end() command, which takes you to the last record in the table.
1: ;OV-LIKE :: btnBottom :: pushButton
2: method pushButton(var eventInfo Event)
3: active.end() ;Move to the last record.
4: endMethod
5. Add line 3 to the button labeled Previous. Line 3 uses priorRecord() to move the pointer back one record.
1: ;OV-LIKE :: btnPrevious :: pushButton
2: method pushButton(var eventInfo Event)
3: active.priorRecord() ;Move to the previous record.
4: endMethod
6. Add line 3 to the button labeled Next. Line 3 uses nextRecord() to move the pointer forward one record.
1: ;OV-LIKE :: btnNext :: pushButton
2: method pushButton(var eventInfo Event)
3: active.nextRecord() ;Move to the next record.
4: endMethod
7. Add line 3 to the button labeled Edit. Line 3 puts the form in edit mode with edit().
1: ;OV-LIKE :: btnEdit :: pushButton
2: method pushButton(var eventInfo Event)
3: edit() ;Put form into edit mode.
4: endMethod
8. Add lines 3 and 4 to the button labeled Store. Lines 3 and 4 commit the user's changes to the record and end the edit session. Both postRecord() and endEdit() were used in this example to explicitly post the change to the table and end the edit mode. Note, however, that this was done just to introduce the method postRecord(). In a real application, ending edit mode with endEdit() automatically sends DataPostRecord to the built-in action event (changes, if any, to a record are committed when you end an edit session).
1: ;OV-LIKE :: btnStore :: pushButton
2: method pushButton(var eventInfo Event)
3: active.postRecord() ;Write the record to the table.
4: endEdit() ;End edit mode.
5: endMethod
9. Add lines 3--5 to the button labeled New. With the New button, you want to get the form ready for the user edit. Move the focus to the upper-left field using the MoveTopLeft action constant with action(MoveTopLeft). Go into edit mode and insert a record with edit() and insertRecord().
1: ;OV-LIKE :: btnNew :: pushButton
2: method pushButton(var eventInfo Event)
3: action(MoveTopLeft) ;Move to first field on form.
4: edit() ;Put form into edit mode.
5: active.insertRecord() ;Insert a new blank record.
6: endMethod
10. Add lines 3--7 to the button labeled Delete. The syntax of the Delete button deserves special attention. There are times when deleteRecord() is not a valid command. Therefore, you need to do some error checking. deleteRecord() returns a logical True or False in an if structure. If deleteRecord() is successful, the message in line 4 is sent to the status bar. deleteRecord() sometimes fails--for example, when the user isn't in edit mode or when deleteRecord() interferes with referential integrity. Whenever deleteRecord() fails, a different message is sent to the message box in line 6.
1: ;OV-LIKE :: btnDelete :: pushButton
2: method pushButton(var eventInfo Event)
3: if deleteRecord() then
4: message("Record deleted")
5: else
6: message("Could not delete record.
Perhaps detail records exist.")
7: endIf
8: endMethod
11. Check the syntax, save the form as OV-LIKE.FSL, and run it. Try out all the various buttons. The completed form is shown here:
Referring to Objects with active and By Name
The techniques shown in the previous example used the object variable active and a method. They are useful for single-table forms. Most often, however, you'll create multitable forms. Therefore, you must be more precise. In the next example, you learn how to use a method on a single table in a multitable form.
Using insertRecord() and deleteRecord() with a Multi-Table Form
Until now, you've seen how to use database-type methods on a form with a single table in the data model. But what if you want to delete a record from only one table in a 1:M relationship? You can use the name of an object to refer to the underlying table, as in the following example:
1: Last_Name.insertRecord() ;Insert a new blank record.
2: LineItem.DeleteRecord() ;Delete current record.
Using the name of an object enables you to specify the table with which you want to work, which is crucial when you work with multiple tables. This example puts the commands together.
Example of Using a UIObject Name to Refer to the Underlying Table
Suppose that you wish to set up a button on a 1:M form that deletes only the currently selected detail record. This example shows you how to use dot notation in combination with a method. It also introduces the procedure msgQuestion(), which displays a message question dialog box.
On The Net: http://prestwood.com/forums/paradox/books/official/files/DELETE.FSL.
Step By Step
1. Create a new form with a 1:M relationship between ORDERS.DB and LINEITEM.DB, and place a button on the form. Change the button's label to Delete Line Item, as shown here:
Note: All of the examples in this book that use tables, use the tables that come with Paradox. You need to change your working directory to the Samples subdirectory in the Paradox home directory.
2. Alter the button's pushButton method to look like the following. In line 3, the msgQuestion() procedure is used to ask the user whether he or she really wants to delete the record. If the answer is yes, lines 4 and 5 delete the record. Otherwise, the if statement ends at line 6. To delete the record, you put the form into edit mode in line 4. In line 5, you use the name of an object to signify the table from which to delete a record. Just as easily, you could have used any other object that is connected to the table, or even the name of the table frame. Remember that when you use the name of an object with a method that uses a table, the method will use the table to which that object is connected.
1: ;DELETE :: btnDeleteLine :: pushButton
2: method pushButton(var eventInfo Event)
3: if msgQuestion("Warning",
"Are you sure you wish to Delete the current item?")
= "Yes" then
4: edit()
5: Stock_No.deleteRecord()
6: endIf
7: endMethod
3. Test your syntax, correct any errors if necessary, save the form as DELETE.FSL, run the form, and click the button to delete a record in the detail table:
OOP and ObjectPAL
ObjectPAL isn't a true object-oriented programming language. It is, however, object-based programming (OBP). Take a look at objects, the three elements of object-oriented programming (OOP), and see how both relate to ObjectPAL. First up is a discussion of objects.
What Are Objects?
The biggest advantage of using object-based programming rather than procedural programming is that you can cut independent objects from one place or container and paste them to another place or container without affecting any other objects (at least in most cases). This makes your code highly portable. For example, if you create a button that launches the Windows Calculator, you can copy it from one form to another form without affecting other objects or code. With ObjectPAL, you can reuse code more easily than you can with a procedural language such as PAL, Basic, C, or Pascal. With ObjectPAL, you can develop self-contained smart objects once and reuse them.
Another advantage of object-based programming is that it is easier to maintain than a procedural programming language. Your code is contained in objects. Therefore, if something goes wrong, it generally affects only one module or part of your application. If you develop with a group of programmers, you will appreciate that each programmer's code is protected from the others' code. For example, code in one form generally will not affect code in another form.
The Six Categories of Objects
When you study a subject as broad as the more than 1,800 ObjectPAL methods and procedures and their variations, it helps to study them by object type. The ObjectPAL methods and procedures act on objects. The objects on which the methods and procedures act fall into six categories:
Data types
Display managers
Data model objects
Design objects
System data objects
Event objects
Following is an overview of each of the object categories. They are discussed in detail throughout this book.
Data Types and ObjectPAL
You use data type objects to store data. For example, Date, DateTime, Logical, Graphic, LongInt, and SmallInt are examples of data types that store specific types of data in memory. After you store data in a particular type of variable, you can manipulate the data by using the methods associated with that type of variable.
Display Managers
The display manager objects manage how objects are displayed. ObjectPAL has the following five display managers:
Application object
Form object
TableView object
Report object
Script object
The Application display manager is the Paradox desktop. It manages the display of the other display managers: Form, TableView, Report, and Script. A Form display manager manages all the objects that you put on it. The form is the center of every ObjectPAL application. A TableView display manager manages and displays tables. A Report display manager manages the formatted display and how table information is printed. A Script is a special display manager that has no UIObjects on it but can display information on the status bar and in message boxes. In general, you deal with display managers in ObjectPAL as a complete unit. For example, you might maximize, minimize, or hide any of the display managers except for a Script.
Data Model Objects
You use data model objects to manipulate data in tables and databases. ObjectPAL has five types of data model objects:
Database object
Query object
SQL object
Table object
TCursor object
You use the Database object's methods and procedures on a database--a set of tables in a directory. For example, with Database methods and procedures, you can open a database or delete a table. You use the Query object's methods and procedures to execute and manipulate queries.
The Table object's methods and procedures represent the table itself and are distinct from a TCursor's methods and procedures. A TCursor object is a pointer to the data while a Table object points to the whole table. It also is distinct from a TableFrame and a TableView, which are objects that display the data. Use the Table methods and procedures to add, copy, create, and index tables, to do column calculations, and to get information about a table's structure. Don't use Table methods to edit records, however. Use a TCursor or a table frame--a UIObject--instead.
Design Objects
Design object methods and procedures are commands used to manipulate menus, pop-up menus, and UIObjects. The three types of design objects are as follows:
Menu
PopUpMenu
UIObject
You use Menu and PopUpMenu methods and procedures to build and manipulate menus. Similarly, you use UIObject--short for user interface object--methods and procedures to manipulate UIObjects. For example, when you change the color of a box to red or when you set the value of a field, you manipulate UIObject properties. UIObject methods and procedures add to this functionality. For example, they enable you to set the position of an object.
Scripts, libraries, forms, and UIObjects are the only objects that have events. The form, for example, is a display manager that is also a UIObject. A form has events to which you can attach code, and it responds to events. There also are methods and procedures that you can use to manipulate a form.
Many of the UIObject methods are duplicated among the TCursor methods. For example, insertRecord() works on both a UIObject and a TCursor. The UIObject methods that work with tables work on the underlying table by means of a visible object. Actions directed to the UIObject that affect a table are immediately visible in the object to which the table is bound. On the other hand, TCursor methods work with a table behind the scenes as if another user were making the changes.
System Data Objects
The types of system data objects are as follows:
DDE object
Library object
FileSystem object
Script object
Session object
System object
TextStream object
You use the Dynamic Data Exchange (DDE) object's methods and procedures with DDE. DDE enables you to send and receive data between Windows applications. The Library object's methods and procedures work with libraries. A library is a place to store code. TextStream object's methods and procedures manipulate streams of text.
The other three categories--FileSystem, Session, and System--are used for objects outside Paradox, such as DOS-level or Windows-level procedures. FileSystem methods and procedures enable you to manipulate a FileSystem variable to provide access to and information about disk files, drives, and directories. A FileSystem variable provides a handle; that is, a variable you use in an ObjectPAL statement in order to work with a directory or a file. Session methods and procedures give you a channel to the BDE. For example, you can add and delete aliases by using Session methods. You use System procedures to display messages, find out about the user's system, get a filename with the file browser, and work with the help system.
Event Objects
Events are packets of information sent from one object to another. You use the methods and procedures to manipulate that packet. The following ten types of methods and procedures manipulate the various eventInfo variables:
Event MouseEvent
ActionEvent MoveEvent
ErrorEvent StatusEvent
KeyEvent TimerEvent
MenuEvent ValueEvent
As an example, the following paragraphs discuss the Event, ActionEvent, ErrorEvent, and KeyEvent categories. The Event category is the base type from which the other event types are derived. Many of the methods listed in this section are used by the other event types.
You generate an ActionEvent primarily by editing and navigating in a table. ActionEvents and procedures enable you to get and set information in the action event.
An ErrorEvent eventInfo message is sent to the built-in error event. Use the error event to add to the built-in error-trapping behavior.
You use KeyEvents methods and procedures to manipulate and retrieve information about keystroke events in keyPhysical and keyChar.
MenuEvents methods and procedures enable you to retrieve and set data in the MenuEvent event packet that is related to menu selections in the application menu bar--in other words, menu constants. For example, when the user chooses an item from the toolbar, it triggers the menuAction event by sending it the appropriate menu constant. You use the methods in the MenuEvent class to manipulate the MenuEvent eventInfo packet.
Tip: To print your own reference sheet, create and run the following one-line script:
enumRTLMethods("RTL.DB")
This script creates a table that lists all the run-time library methods and procedures and their variations. That's more than 1,800 commands. By using the RTL.DB, you can create and print elaborate reports and use them as reference sheets. You also can query the table to view the methods in various ways.
Is ObjectPAL OOP?
Now that you have a firm grasp of the various objects used in ObjectPAL, look at the three elements of object-oriented programming (OOP) and see how they relate to ObjectPAL. The three elements are encapsulation, polymorphism, and inheritance.
Encapsulation and ObjectPAL
In OOP, encapsulation is the bundling of methods and variables within an object so that access to the variables is permitted only through the object's published interface. ObjectPAL supports encapsulation. It was used to create Paradox and is surfaced nicely in ObjectPAL. The TCursor has a lot of code associated with it that allows us programmers to manipulate data, but only the published interface is available to us. The details of how it does things is hidden within the TCursor object. The code you write is stored with the object that triggers it. The code is completely independent of other objects and other code. In other words, if the object is moved inside another object or to another form, the code goes with it. If you compile a form, the code is hidden and only the published interface is available to others. This is encapsulation.
The key benefit of encapsulation is that your code is self-contained and protected from other objects. If another object needs to access variables inside your object, you can grant access through a custom method. If a group of people develop an ObjectPAL application, each programmer needs to be concerned only with his or her particular section. A section in ObjectPAL means a group of objects (typically a form with objects on it). If an external object needs access to something in the current object, the current object must have a method to allow it to be accessed.
For example, a team of programmers could designate one programmer to be in charge of the library for an application. (The library is where generic code is put.) When another programmer wants a routine to be included in the library, that person gives the programmer in charge of the library the specifications for the custom method; that is, what the custom method should be passed and what it should do and return. When another programmer wants to add to or alter that custom method, the programmer in charge of the library decides whether the modification is possible given what the method already does.
Encapsulation makes it possible to bring foreign code together. With a traditional procedural language, a team of programmers must be sure not to use the same function and variable names. Because ObjectPAL supports encapsulation, you don't have to worry about the names of methods, procedures, objects, or variables. Each programmer can use his or her own variable-naming convention and not worry about the other programmers. When it comes time to bring all the sections of an application together, you simply have to worry about how the objects communicate. If you are an individual programmer, this means that you can reuse more of your code.
The capability to have duplicate names for variables and custom methods is a great relief to a programmer. For example, you can have a variable called Counter that belongs to two different objects or two objects could both have a custom method called cmRoutine().
Dot Notation and Encapsulation
The dot notation syntax of ObjectPAL supports encapsulation and enables you to grab values from other objects. For example, from an object of one form, you can open another form and (using the public or published interface) grab the value of one of its objects. For example:
1: var
2: f2 Form
3: endVar
4:
5: f2.open("form2")
6: field1.value = f2.field1.value
The rules for when you can use duplicate names and about which code can see other code refer to scope, which will be discussed in the next chapter.
Polymorphism and ObjectPAL
In OOP, the capability of the same command to be interpreted differently when used with or received by different objects is called polymorphism. In ObjectPAL, polymorphism is the capability of an object to act differently depending on the context in which it is being used. For example, methods require an object with which to work. Depending on the object's type, the method does different things. The following expression opens the object named Orders, depending on how varName is defined:
1: varName.open("Orders") ;varName is an object.
Orders can be a table, a form, a script, or many other objects. What ObjectPAL tries to open depends on what variable type you declare varName as. You can define varName to be a database, a DDE link, a form, a library, a report, a session, a TableView, a TCursor, a TextStream, or something else. As the programmer using this object-based language, you don't need to concern yourself with the details of opening these various objects. You write code that is based on this simple formula:
var
object ObjectType ;First declare a variable.
endVar
object.open ( parameterList) ;Then use the variable.
ObjectPAL takes over and handles the details. For example, to open another form, you could use the following:
1: var
2: tempVar Form ;tempVar is a form variable.
3: endVar
4:
5: tempVar.open("Orders") ;Open form.
TCursors and Polymorphism
A TCursor (table cursor) is a tool used to manipulate the data in a table and is a pointer to a record in a table. If you change the variable type of tempVar, the same open() method can open something else, such as a TCursor:
1: var
2: tempVar TCursor ;tempVar is a TCursor.
3: endVar
4:
5: tempVar.open("ORDERS.DB") ;Open a TCursor to Orders.db.
In the future, when another type of object that can be opened is added, you won't need to learn the new syntax; you'll need to learn only the new characteristics of the object. This certainly beats learning syntax for 10 to 15 different open routines.
Inheritance; Well, Actually, Delegation
In OOP, a mechanism for automatically sharing methods and data types among objects is called inheritance. Typically, you would create a base class followed by creating descendant classes. Each descendant class would have all the properties, methods, procedures, and events of its parent class, plus added functionality. ObjectPAL does not support true inheritance. This is not a drawback, it just means ObjectPAL has its own mechanisms for storing and reusing code.
In ObjectPAL, an object inherits all the variables, types, and custom procedures of the objects by which it is contained. Also, the fact that methods and procedures from one object type are derived--inherited--from other types shows the existence of inheritance in ObjectPAL. In Paradox's online help for the Report Type, the help shows the methods and procedures for the report types that are derived (or inherited) from the Form object type.
Paradox UIObjects--objects you place on a form--inherit characteristics (default behavior) from the objects that the Paradox development team created. For example, when you place a TableFrame on a form, it has a lot of built-in properties, methods, procedures, and events that are inherited from the base TableFrame object. Since you can't inherit down another level, I call this delegation and not true inheritance. Every object in Paradox supports delegation. When you copy an object, the copy is delegated the properties and methods of the parent. Be careful when you use Design | Copy to Toolbar. If the object that you copy to the toolbar has ObjectPAL code on it, the code is copied, too.
Summary
This chapter introduced you to the basics of ObjectPAL. You learned a little about all the various aspects of programming in ObjectPAL. You learned that programming in an event-driven environment is about attaching code to objects. You learned the basics of ObjectPAL syntax and to refer to the properties and methods of objects using dot notation. In addition to containing properties and methods, you also learned that objects can contain procedures and events.
This is a definite improvement over the twenty-year-old documentation that came with Paradox X5. I was completely lost with the print materials provided. This sets me on a learning path again.
The following are practice certification questions with answers highlighted. These questions were prepared by Mike Prestwood and are intended to stress an important aspect of this KB post. All our practice questions are intended to prepare you generally for passing any certification test as well as prepare you for professional work.