Understanding Inheritance

About this chapter

This chapter describes how to use inheritance to build PowerBuilder objects.

About inheritance

One of the most powerful features of PowerBuilder is inheritance. It enables you to build windows, user objects, and menus that derive from existing objects.

Using inheritance has a number of advantages:

  • When you change an ancestor object, the changes are reflected in all the descendants. You do not have to make manual changes in the descendants, as you would in a copy. This saves you coding time and makes the application easier to maintain.

  • The descendant inherits the ancestor's scripts, so you do not have to re-enter the code to add to the script.

  • You gain consistency in the code and objects in your applications.

This chapter describes how inheritance works in PowerBuilder and how to use it to maximize your productivity.

Opening ancestors and descendants

To enforce consistency, PowerBuilder does not let you open an ancestor object until you have closed any descendants that are open, or open a descendant object when its ancestor is open.

Creating new objects using inheritance

You use the Inherit From Object dialog box to create a new window, user object, or menu using inheritance.

To create a new object using inheritance:

  1. Click the Inherit button in the PowerBar, or select File>Inherit from the menu.

  2. In the Inherit From Object dialog box, select the object type (menu, user object, or window) from the Objects of Type drop-down list, and then select the target as well as the library or libraries you want to look in. Finally, select the object from which you want to inherit the new object.

    Displaying objects from many libraries

    To find an object more easily, you can select more than one library in the Libraries list. Use Ctrl+click to toggle selected libraries and Shift+click to select a range.

  3. Click OK.

    The new object, which is a descendant of the object you chose to inherit from, opens in the appropriate painter.

The inheritance hierarchy

When you build an object that inherits from another object, you are creating a hierarchy (or tree structure) of ancestor objects and descendant objects. Working with Windows, uses the example of creating two windows, w_customer and w_employee, that inherit their properties from a common ancestor, w_ancestor. In this example, w_employee and w_customer are the descendants.

The object at the top of the hierarchy is a base class object, and the other objects are descendants of this object. Each descendant inherits information from its ancestor. The base class object typically performs generalized processing, and each descendant modifies the inherited processing as needed.

Multiple descendants

An object can have an unlimited number of descendants, and each descendant can also be an ancestor. For example, if you build three windows that are direct descendants of the w_ancestor window and three windows that are direct descendants of the w_employee window, the hierarchy looks like this:

Object hierarchy example

Browsing the class hierarchy

PowerBuilder provides a Browser that can show the hierarchy of the built-in PowerBuilder system objects and the hierarchy of ancestor and descendant windows, menus, and user objects you create. In object-oriented terms, these are called class hierarchies: each PowerBuilder object defines a class.

Regenerating objects

The Browser also provides a convenient way to regenerate objects and their descendants. For more information, see Regenerating library entries.

To browse the class hierarchy of PowerBuilder system objects:

  1. Click the Browser button in the PowerBar.

  2. Choose the System tab to show the built-in PowerBuilder objects.

  3. In the left pane, scroll down the object list and select the powerobject.

  4. Display the pop-up menu for the powerobject and choose Show Hierarchy.

  5. Select Expand All from the pop-up menu and scroll to the top.

    The hierarchy for the built-in PowerBuilder objects displays.


Getting context-sensitive Help in the Browser

To get context-sensitive Help for an object, control, or function, select Help from its pop-up menu.

To display the class hierarchy for other object types:

  1. Choose the Menu, Window, or User Object tab.

    If you choose any other object type, there is no inheritance for the object type, so you cannot display a class hierarchy.

  2. In the left pane, select an object and choose Show Hierarchy from its pop-up menu.

  3. Select an object and choose Expand All from its pop-up menu.

    PowerBuilder shows the selected object in the current application. Descendant objects are shown indented under their ancestors.

    For example, if your application uses the PBDOM PowerBuilder extension object, the pbdom_object displays on the User Object page. You can select Show Hierarchy and Expand All from its pop-up menu to display its descendant objects.

Working with inherited objects

This section describes:

  • Working in a descendant object

  • Working in an ancestor object

  • Resetting properties in a descendant

Working in a descendant object

You can change descendant objects to meet specialized needs. For example, you can:

  • Change properties of the descendant object

  • Change properties of inherited controls in the object

  • Add controls to a descendant window or user object

  • Add menu items to a menu

You cannot copy a control on a descendant window or visual user object if the control inherits from the ancestor object, because the resulting inheritance hierarchy cannot be maintained consistently. You can copy a control on a descendant object if the control does not inherit from the object's ancestor.

For specifics about what you can do in inherited windows, user objects, and menus, see Working with Windows, Working with User Objects, and Working with Menus and Toolbars.

Working in an ancestor object

When you use inheritance to build an object, the descendant is dependent on the definition of the ancestor. Therefore you should not delete the ancestor without deleting the descendants. You should also be careful when you change the definition of an ancestor object. You may want to regenerate descendant objects if you do any of the following:

  • Delete or change the name of an instance variable in the ancestor

  • Modify a user-defined function in the ancestor

  • Delete a user event in an ancestor

  • Rename or delete a control in an ancestor

When you regenerate the descendants, the compiler will flag any references it cannot resolve so you can fix them. For information about regenerating objects, see Working with Libraries.

About local changes

If you change a property in an ancestor object, the property also changes in all descendants—if you have not already changed that property in a descendant, in which case the property in the descendant stays the same. In other words, local changes always override inherited properties.

Using inherited scripts

In the hierarchy formed by ancestors and descendants, each descendant inherits its event scripts from its immediate ancestor. If an inherited event does not have a script, you can write a script for the event in the descendant. If the inherited event does have a script, the ancestor script will execute in the descendant unless you extend the script or override it. You can:

  • Extend the ancestor script—build a script that executes after the ancestor script

  • Override the ancestor script—build a script that executes instead of the ancestor script

You cannot delete or modify an ancestor script from within a descendant.

Extending or overriding a script

The Extend Ancestor Script item on the Edit menu or the pop-up menu in the Script view determines whether the script is extended or overridden. If the menu item is selected (a check mark displays next to it), the ancestor script is extended. If there is no check mark, the ancestor script is overridden.

When there is no script for the descendant, the Extend Ancestor Script menu item is selected and disabled. You cannot clear the menu item unless you add a script to the descendant. When you have added a script, the menu item is enabled and you can choose to override the ancestor script by clearing the menu item, or to extend it by leaving the menu item selected.

If you delete the script in the descendant

If, after adding a script to the descendant and clearing the Extend Ancestor Script menu item, you delete the script, the menu item returns to its default state: selected and disabled. A message displays in the status bar warning you that this has occurred. If you then add a new script, the menu item is reenabled. You must remember to clear the Extend Ancestor Script menu item if you want to override the ancestor script.

Executing code before the ancestor script

To write a script that executes before the ancestor script, first override the ancestor script and then in the descendant script explicitly call the ancestor script at the appropriate place. For more information, see Calling an ancestor script.

Getting the return value of the ancestor script

To get the return value of an ancestor script, you can use the AncestorReturnValue variable. This variable is always available in descendant scripts that extend an ancestor script. It is also available if you override the ancestor script and use the CALL syntax to call the ancestor event script. For more information, see the section called “Return values from ancestor scripts” in Application Techniques.

Viewing inherited scripts

If an inherited object or control has a script defined only in an ancestor, no script displays in the Script view.

Script icons in the second drop-down list

The second drop-down list in the Script view indicates which events have scripts written for an ancestor as follows:

  • If the event has a script in an ancestor only, the script icon next to the event name in the second drop-down list is displayed in color.

  • If the event has a script in an ancestor as well as in the object you are working with, the script icon is displayed half in color.

Script icons in the third drop-down list

The third drop-down list in the Script view shows the current object followed by each of its ancestors in ascending order. The icons next to object names indicate whether the object has a script for the event selected in the second drop-down list as follows:

  • If an object is the highest class in the hierarchy to have a script, a transparent script icon displays next to its name. No icon displays next to the names of any of its ancestors.

  • If an object does not have a script for the event but it has an ancestor that has a script for the event, the script icon next to its name is displayed in color.

  • If an object has a script for the event, and it has an ancestor that also has a script for the event, the script icon next to its name is displayed half in color.

To view an ancestor script

  1. In the Script view for an inherited object, select the object itself or a control in the first drop-down list, and the event whose script you want to see in the second drop-down list.

    The Script view does not display the script for the ancestor. No script displays.

  2. In the third drop-down list in the Script view, select an ancestor object that has a script for the selected event.

    The Script view displays any script defined in the ancestor object.

  3. To climb the inheritance hierarchy, in the third drop-down list, select the script for the grandparent of the current object, great-grandparent, and so on until you display the scripts you want.

    The Script view displays the scripts for each of the ancestor objects. You can traverse the entire inheritance hierarchy using the third drop-down list.

Extending a script

When you extend an ancestor script for an event, PowerBuilder executes the ancestor script, then executes the script for the descendant when the event is triggered.

To extend an ancestor script

  1. In the first drop-down list in the Script view, select the object or a control, and in the second drop-down list, select the event for which you want to extend the script.

  2. Make sure that Extend Ancestor Script on the Edit menu or the pop-up menu in the Script view is selected.

    Extending the ancestor script is the default.

  3. In the Script view, enter the appropriate statements.

    You can call the script for any event in any ancestor as well as call any user-defined functions that have been defined for the ancestor. For information about calling an ancestor script or function, see Calling an ancestor script and Calling an ancestor function.

Example of extending a script

If the ancestor script for the Clicked event in a button beeps when the user clicks the button without selecting an item in a list, you might extend the script in the descendant to display a message box in addition to beeping.

Overriding a script

To override an ancestor script

  1. In the first drop-down list in the Script view, select the object or a control, and in the second drop-down list, select the event for which you want to override the script.

  2. Code a script for the event in the descendant.

    You can call the script for any event in any ancestor as well as call any user-defined functions that have been defined for the ancestor.

    For information about calling an ancestor script or function, see Calling an ancestor script and Calling an ancestor function.

    Override but not execute

    To override a script for the ancestor but not execute a script in the descendant, enter only a comment in the Script view.

  3. Select Extend Ancestor Script on the Edit menu or the pop-up menu to clear the check mark.

    Clearing the Extend Ancestor Script item means that you are overriding the script.

    At runtime, PowerBuilder executes the descendant script when the event is triggered. The ancestor script is not executed.

Example of overriding a script

If the script for the Open event in the ancestor window displays employee files and you want to display customer files in the descendant window, select Override Ancestor Script and create a new script for the Open event in the descendant to display customer files.

Calling an ancestor script

When you write a script for a descendant object or control, you can call scripts written for any ancestor. You can refer by name to any ancestor of the descendant object in a script, not just the immediate ancestor (parent). To reference the immediate ancestor (parent), you can use the Super reserved word.

For more information about calling scripts for an event in an ancestor window, user object, or menu, and about the Super reserved word, see the section called “Calling functions and events in an object's ancestor” in PowerScript Reference.

Calling an ancestor function

When you write a script for a descendant window, user object, or menu, you can call user-defined functions that have been defined for any of its ancestors. To call the first function up the inheritance hierarchy, just call the function as usual:

function ( arguments )

If there are several versions of the function up the inheritance hierarchy and you do not want to call the first one up, you need to specify the name of the object defining the function you want:

ancestorobject::function ( arguments )

This syntax works only in scripts for the descendant object itself, not in scripts for controls or user objects in the descendant object or in menu item scripts. To call a specific version of an ancestor user-defined function in a script for a control, user object, or menu item in a descendant object, do the following:

  1. Define an object-level user-defined function in the descendant object that calls the ancestor function.

  2. Call the function you just defined in the descendant script.

For more information about calling an ancestor function, see the the section called “Calling functions and events in an object's ancestor” in PowerScript Reference.