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 librariespre-built classes that you can easily reuse throughout applications. I also discuss how
to add functionality to objects through user-defined properties and methods.
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.
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.
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.
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 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.
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 classsuch as changing the button's label, color, or Click() methodare 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.
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.
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.
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()
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.
|