- 45

- Libraries, User-Defined Properties and Methods, and Classes

- Overview of Libraries

- Creating and Using Libraries

- Overview of User-Defined Properties and Methods

- Using User-Defined Properties and Methods
- Method Overloading

- Overview of Classes

- Creating Classes
- Making Dynamic Classes
- Making Self-Contained Classes

- Summary

#
45

## Libraries, User-Defined Properties and Methods, and Classes

Without a doubt, the area of Oracle Power Objects with the most potential is its user-definable, reusable components. Developers can increase their productivity through the capability to create classes that can be reused, shared in libraries, and extended beyond the normal set of properties and methods. This chapter demonstrates how to share objects across multiple applications through the use of libraries—pre-built classes that you can easily reuse throughout applications. I also discuss how to add functionality to objects through user-defined properties and methods.

### Overview of Libraries

Libraries are similar to applications in that they contain other objects. You use libraries to store user-definable classes and bitmaps that applications can share. You can reuse objects within a library in any number of forms, applications, or other classes. Sharing objects in libraries is useful for minimizing storage requirements and reducing the need to reimplement objects multiple times. For a single developer, a workgroup, or even an MIS department, libraries provide the means for standardizing object implementation within Oracle Power Objects.

#### Creating and Using Libraries

You create a library by clicking the New Library toolbar button or by selecting the File | New Library menu command. In the Main window, a library is represented by an icon of a book. Double-clicking a library's icon opens a library window, which is shown in Figure 45.1.

Figure 45.1. The library window.

The library window displays the objects contained in the library. You can add objects to the library by creating new objects or by dropping existing objects onto the library.

You add a new bitmap object to the library by selecting the File | Import BMP menu command. This invokes the Import Bitmap dialog box, which is shown in Figure 45.2.

Figure 45.2. The Import Bitmap dialog box.

To specify a bitmap, locate and select the desired BMP file. A new bitmap object appears in the library window. The name of the new bitmap object is automatically set to the BMP's filename. If the name assigned to the bitmap object is a reserved word in Oracle Power Objects, such as open, the New Object Name dialog box appears, as shown in Figure 45.3. This dialog box asks you to enter a different name for the bitmap object.

Figure 45.3. The New Object Name dialog box.

Because a bitmap object's name is usually generated automatically and cannot be changed, it's difficult to provide meaningful names for bitmap objects.

To get around the limitation on naming bitmaps, you can use the following trick. Before importing a bitmap, change the file name of the BMP to one of Power Objects' reserved words, such as open.bmp, or to a name such as 1mybmp.bmp (1mybmp.bmp is a valid DOS file name but not a valid OPO object name). Either of these file names invokes the New Object Name dialog box, enabling you to enter your own name for the bitmap object when you import it.

### Overview of User-Defined Properties and Methods

User-defined properties (UDP) and user-defined methods (UDM) are properties and methods that you can add to the normal set of properties and methods for any application object. You use UDPs and UDMs to extend the functionality and flexibility of Oracle Basic. You can use UDPs to globally store and track variables. UDMs provide a method where developers can program Basic code that is not directly related to any of Oracle Power Objects' event methods. UDMs also permit modular coding and method overloading. I discuss method overloading later in this section.

#### Using User-Defined Properties and Methods

UDPs and UDMs appear on the property sheet. You add, delete, and manage an object's UDPs and UDMs through the toolbar buttons on the property sheet. The property sheet's toolbar buttons are shown in Figure 45.4.

Figure 45.4. The property sheet's toolbar.

To add UDPs or UDMs, click the Add a New Property or Method toolbar button on the property sheet. This invokes the User Properties window, which is shown in Figure 45.5.

Figure 45.5. The User Properties window.

Enter the name, type, data type, and list of arguments that specify the method or property to be added. You create overloaded methods by specifying methods with the same name and different numbers of arguments. When you make a call to an overloaded UDM, Power Objects examines the number of arguments and references the appropriate method.

You attach UDPs and UDMs to objects by dragging and dropping them from the User Properties window to the object itself or the object's property sheet. You detach them by selecting the UDP or UDM on the property sheet and clicking the Delete Current Property or Method toolbar button on the property sheet. Once you attach them to an object, you can use UDPs and UDMs just like any other property or method.

You use UDPs to associate special values with an object. You can also use them in place of globals. Unlike globals, which are single instances, a UDP has an instance associated with each object to which it is attached.

#### Method Overloading

Method overloading is a process whereby you can invoke a user-defined method using different parameters types or a different number of parameters. Power Objects supports the latter process using a different number of parameters. For example, you can define UDMs called udmClick() and udmClick( pMsg AS String ). Create a form with a button on it and add the two new UDMs to the button. Place the following code in each respective UDM.

    Sub udmClick()

    MSGBOX( "udmClick()" )

    Sub udmClick(pMsg AS String)

    MSGBOX( pMsg )

If you place the following code in the Click() method of a button on a form and run the form, you will observe that the appropriate method gets called based on the number of parameters passed.

    Sub Click()

    udmClick()

    udmClick( "This is a test" )

First, a message box displays udmClick(), followed by a second message box that displays This is a test.

Although you can write UDMs to overload OPO defined methods, the OPO environment does not call these; however, you can call these UDMs through Basic code from the OPO standard methods or any method, for that matter.

### Overview of Classes

Classes are some of the most powerful objects within Oracle Power Objects. A class is a collection of application objects that work together to perform specific tasks. Once you create a class, you can share and reuse it in other classes, forms, reports, or applications. Classes are custom controls that extend Power Objects' functionality, enable modular development, and increase productivity.

Power Objects ships with several sample class objects in the CLASSES library as examples of the flexibility, power, and productivity associated with classes. These classes include a form control class (clsFormControl) with print, help, and exit buttons; a record manager control class (clsRecControl) with insert row, delete row, query refresh, commit work, and rollback work buttons; a progress meter class (clsMeter) displaying percent complete; an Oracle Mobile Agents (OMA) class (clsOMA) to facilitate working with OMA; a tab class (clsTab) for building applications requiring a tabbed folder look and feel; and a calendar class (clsSmCalendar) for viewing months and selecting a date. Each of these class objects is covered in detail in the OPO online documentation, and each is used in at least one of the OPO sample applications.

An important aspect of classes is that they are object-oriented. This means that you can create and then instance a single class into other forms or classes. Instancing a class creates a copy of that class that is linked back to the class definition. Each instance of the class has the same objects, properties, and methods as those of the parent class; however, you can customize the class instance by changing any of its objects, properties, or methods.

A simple example of a class is an exit button that appears on every form of an application. You could copy this button from form to form; however, editing the properties or methods of the button would require the developer to edit the button on each of the application's forms. A better solution is to create a class, clsExitBtn, that contains the exit button. Set the script of the button's Click() method to the following generic script:

    Self.GetTopContainer().CloseWindow()

Instance the clsExitBtn class onto each form. Any changes you make to the clsExitBtn class—such as changing the button's label, color, or Click() method—are reflected in the instances of that class. Additionally, you can customize each of the instances. Perhaps one of the exit buttons performs specific tasks before it exits, or maybe buttons on particular screens are a different color or have a different label.

#### Creating Classes

To create a new class, first select the application or library that will contain the class. Next, click the New Class toolbar button or select the File | New Class menu command. When you create a new class or open an existing class, you see the Class Editor, as shown in Figure 45.6.

Figure 45.6. The Class Editor.

The Class Editor looks just like the Form Editor. In fact, a class is actually a modular, reusable form. Classes are designed like forms, they can contain the same objects as forms, and they have almost the same set of properties and methods as forms.

An example of a simple class to build is a 3-D panel as shown in Figure 45.6. To build this class, create a new class and set its name and label to cls3DPanel. Set the ColorFill to light gray and the HasBorder to FALSE. Also, resize the class so that it's about one inch square. Next, add four line objects, named line1 to line4, to the class. Reposition and resize each line so that it covers a different edge of the class. The lines should border the class. Set the ColorBrdr of the left and top lines to white. Set the ColorBrdr of the right and bottom lines to dark gray. After saving it, you can use this cls3DPanel to create raised panels, which is a control that is not inherent to Oracle Power Objects.

#### Making Dynamic Classes

Although classes are extremely useful for Rapid Application Development (RAD), they can become cumbersome when you attempt to reorient the objects within the class to fit the current form. When possible, it is best to create classes that you can dynamically change based on UDPs when they're loaded. Take the example of the cls3DPanel; although it's a time-saving control for creating raised panels, how much work is required to change the size of the panel? It would be nice if the panel could reposition its lines or change its orientation when the class was resized. You can do this during run time in the OnLoad() method. First, create the following user properties and attach them to the class:

udpStyle | Property | String
udmSetLine | Sub | pObj As Object, pX,pY,pW,pH,pC,pO As Integer

Set the udpStyle property to raised. Next, set the method udmSetLine() to the following code:

    ' Description:

    ' Given a pointer to a line object: set its x-y position, x-y size,

    ' color and direction.

    ' Parameter(s):

    ' pObj         Object   pointer to a line object

    ' pX           Integer  new PositionX

    ' pY           Integer  new PositionY

    ' pW           Integer  new SizeX

    ' pH           Integer  new SizeY

    ' pC           Integer  new ColorBrdr

    ' pO           Integer  new Direction

    ' Return: <nothing>

    pObj.PositionX = pX

    pObj.PositionY = pY

    pObj.SizeX = pW

    pObj.SizeY = pH

    IF pC >= 0 THEN pObj.ColorBrdr = pC

    IF pO >= 0 THEN pObj.Direction = pO

Lastly, the OnLoad() method fires when the class is first loaded into the application at run time. You can put the following code into the OnLoad() method to redraw the class's lines to respect the size and udpStyle of the class:

    ' This method is crucial to correctly drawing the Panel instance.

    ' This method calls the appropriate user-defined methods so the Panel

    ' instance will draw based on the user defined parameters.

    ' line1 refers to the line on the top

    ' line2 refers to the line on the left

    ' line3 refers to the line on the right

    ' line4 refers to the line on the bottom

    vShade = 11

    vHilite = 1

    'Process the user-defined style parameter.

    IF LCASE( udpStyle ) = "inset" THEN

      vDirection = DIRECTION_UPPER_LEFT_TO_LOWER_RIGHT

      udmSetLine( line1, 0, 0, SizeX + 1, 1, vShade, vDirection)

      udmSetLine( line2, 0, 0, 1, SizeY + 1, vShade, vDirection)

      udmSetLine( line3, SizeX - 1, 0, 1, SizeY + 1, vHilite, vDirection)

      udmSetLine( line4, 0, SizeY - 1, SizeX + 1, 1, vHilite, vDirection)

    ELSE ' style is defaulted to raised

      vDirection = DIRECTION_UPPER_LEFT_TO_LOWER_RIGHT

      udmSetLine( line1, 0, 0, SizeX + 1, 1, vHilite, vDirection)

      udmSetLine( line2, 0, 0, 1, SizeY + 1, vHilite, vDirection)

      udmSetLine( line3, SizeX - 1, 0, 1, SizeY + 1, vShade, vDirection)

      udmSetLine( line4, 0, SizeY - 1, SizeX + 1, 1, vShade, vDirection)

    END IF

Upon instancing the class, you can change the size of the class and set the udpStyle to inset or raised. When the class is drawn during run time, the lines are redrawn based on the class's size and udpStyle. This creates the appropriately sized inset or raised 3-D panel.

#### Making Self-Contained Classes

The real power of Oracle Power Objects classes is their capability to be self-contained modules that you can share, reuse, and even distribute. To make a class self-contained, it is often necessary to used generic object references within any of the class's Basic code. The generic object references enable the code to refer to the class itself, the class's container, the class's form, and methods for stepping through all the other form's objects. Table 45.1 describes the generic object references available in Oracle Basic code.

Table 45.1. The Oracle Basic generic object references.

    Reference
    Description
Self | The object making the reference.
Container | The container of the object making this reference. Container is a keyword that is evaluated at compile time. It is useful for generically setting a scrollbar's ScrollObj property or specifying a class's RecordSource to be shared with its container's RecordSource (for example, =Container).
TopContainer | The highest level container, the form of class, that contains the object making this reference. TopContainer is a keyword that is evaluated at compile time.
GetContainer() | The container of the object making this reference. GetContainer() is a method that is evaluated at run time.
GetTopContainer() | The highest level container, the form, that contains the object making this reference. GetTopContainer() is a method that is evaluated at run time.
FirstChild() | This method returns a reference to the first object contained within the object that calls this method.
NextControl() | Subsequent calls to this method return a reference to each of the objects contained within the object that calls this method.
GetFirstForm() | This method returns a reference to the first form within an application.
GetNextForm() | Subsequent calls to this method return a reference to each of the forms within an application.

You can use each of these generic object references to create Basic code that does not rely on specific object identifiers. This type of coding should enable you to distribute a class to other developers, who could then drop the class into their applications without any modifications. Using generic object references is good; however, sometimes it more efficient to create a UDP of data type object and set its value to the container or form. You can use this UDP in the code to refer to the parent object or objects contained in the parent.

Using some of the generic object references also makes it easy to tie several objects on the same form together. You could use several cls3DPanels on the same form like a set of radio buttons. When a raised panel is clicked, any panels that are inset are redrawn as raised and the selected panel is redrawn as inset. Adding ChildClick( Self ) to the Click() method of the cls3DPanel, and the following code to the ChildClick() method of the cls3DPanel enables a group of cls3DPanels at the same object containment level to act as radio buttons:

    DIM vAnyObj AS Object

    ' Initialize to the first object within the same containment level.

    vAnyObj = Self.GetContainer().FirstChild()

    ' Process all of the objects at the same containment level.

    DO

      ' If the Object is a User-defined Class.

      IF vAnyObj.ControlType = 10 THEN

        ' If the Object is a 3dpanel class

        IF INSTR( LCASE( vAnyObj.Label ), "cls3dpanel" ) <> 0 THEN

          IF vAnyObj.udpStyle = "inset" THEN

            vAnyObj.udpStyle = "raised"

            vAnyObj.OnLoad()

            EXIT DO

          END IF

        END IF

      END IF

      ' Determine if all objects have been tested.

      IF IsNull( vAnyObj.NextControl() ) THEN

        EXIT DO

      ' Get the next control

      ELSE

        vAnyObj = vAnyObj.NextControl()

      END IF

    LOOP

    ' Redraw self as inset

    Self.udpStyle = "inset"

    Self.OnLoad()

### Summary

Classes provide a powerful way to extend application development in Oracle Power Objects. They enable you to create, reuse, share, and easily redistribute new objects. Classes, in conjunction with libraries and user-defined methods and properties, are useful RAD tools within the Power Objects environment. Classes provide a way to create an object once, use it many times, and customize each instance of the class.