Try OpenEdge Now
skip to main content
Object-oriented Programming
Getting Started with Classes, Interfaces, and Objects : Using the CLASS construct : Defining events within a class : DEFINE EVENT statement
 
DEFINE EVENT statement
This is the syntax for defining a class event using the DEFINE EVENT statement.

Syntax

DEFINE [event-modifiers] EVENT event-name
   {[ SIGNATURE ] VOID ( [parameter[ , parameter]...] )
    |[ DELEGATE ][ CLASS ]dotNet-delegate-type} .
Element descriptions for this syntax diagram follow:
event-modifiers
A list of options that modify the behavior of the event. They can appear in any order as specified in the following syntax:
[ PRIVATE | PROTECTED | PUBLIC ][ STATIC | ABSTRACT ]
[ OVERRIDE ]
[ PRIVATE | PROTECTED | PUBLIC ]
The access mode for the event, which determines the context where you can subscribe event handlers to the event. The default access mode is PUBLIC. You can subscribe an event handler to a PRIVATE event from within the class that defines the event. An instance can also subscribe an event handler to a PRIVATE event of another instance if both instances are from the same class. You can subscribe an event handler to a PROTECTED event from within the class that defines the event and from within any class that inherits the defining class. An instance can subscribe an event handler to a PROTECTED event from a second instance if the first instance is in the same class as the second instance or from a subclass of the second instance. You can subscribe an event handler to a PUBLIC event from within the class that defines the event, from within any class that inherits the defining class, and from any class or procedure that references the defining class. For more information on subscribing event handlers to class events, see Specifying handler subscriptions for class events.
An abstract event prototype cannot be defined as PRIVATE, and an interface event prototype can only be defined as PUBLIC.
[ STATIC ]
Specifies the scope of the event. By default, events of a class are instance events, meaning that a given event is defined and available for each instance of the class in which it is defined. However, class events can also be defined as static using this keyword. ABL defines a given static class event on first reference to the class type in which it is defined, scopes that event to the class type, and makes it available through that class type for the duration of the ABL session. Unless specified otherwise, a reference to an event in this manual is assumed to be a reference to an instance event.
You cannot define a static event as abstract.
For more information on static events, see Using static members of a class.
[ ABSTRACT ]
Declares the event as abstract using an abstract event prototype. Each event prototype is declared by a single DEFINE EVENT statement, with a signature. Abstract events can be defined as either PROTECTED or PUBLIC. These event prototypes cannot specify the STATIC option. An abstract event can only be an instance event.
An abstract event must be implemented in some class (abstract or non-abstract) that derives from the class that defines the abstract event. The class that inherits and implements this abstract event must define and override the event with a definition that matches this abstract event prototype, but without the ABSTRACT option. The implemented event can also have a less restrictive access mode, if available (PUBLIC if the inherited abstract method is PROTECTED). Note that you cannot use the Publish( ) event method to publish a class event that has been defined as abstract, but only from within the class definition that inherits and implements the abstract event.
Thus, defining an event as abstract ensures that the event is inherited by some other class, and that only the class that implements the inherited abstract event can publish it. An abstract event can also be inherited by another abstract class without implementing it. You can override and redefine an inherited abstract event within an abstract class without implementing it in order to specify a less restrictive access mode for the event. You can also subscribe event handlers to any accessible abstract event within or outside of the class that defines the event, because the event is always implemented by an inheriting class at run time.
You can only define an abstract event in an abstract class definition.
[ OVERRIDE ]
Specifies that the event definition overrides an inherited abstract event. This definition can implement the inherited abstract event, or it can redefine the event as abstract as long as the defining class is also abstract. The compiler verifies that this event definition has the same name, the same or a less restrictive access mode, and the same number, modes, and data types for its parameters as the overridden abstract event. Event parameters can also be specified using two different syntax models, and the overriding event must use the same syntax model to specify its parameters as the inherited abstract event.
Note that you cannot override any implemented event that you inherit. Also, if the current class definition is abstract, it is not necessary to override an inherited abstract event that you want to remain abstract, unless you want to specify a less restrictive access mode to be implemented by a subclass. If any of these tests fail, the compiler generates an error.
event-name
The name of the class event. This event-name must be unique within the class hierarchy according to its particular class member namespace. A class event name must be unique within a namespace that includes the names of properties, variable data members, and class events. For more information, see Namespaces for naming class members.
Events defined within a class can be named the same as an ABL reserved keyword. In general, you only reference an event name to either publish the event or to subscribe or unsubscribe an event handler to the event. In all contexts, an event whose name is a reserved keyword must be qualified when referenced, either by an object reference (which can be THIS-OBJECT) or if it is static, with a static type name. For more information on publishing and managing event handler subscriptions to events, see Publishing and subscribing to class events. For more information on using static type-name syntax to reference static events, see Accessing static members.
[ SIGNATURE ] VOID [parameter[ , parameter]...]
Defines a signature for the class event specified as an ABL method signature. This signature specifies how to pass parameters to event handlers when you publish the event. This signature is type checked at compile-time, like any other method signature, but the signatures of internal procedures that you subscribe as event handlers are checked for compatibility only at run time. Note that a class event signature is always VOID, which means that any method subscribed as an event handler must also be defined as VOID. For more information on the syntax of parameter and how to define ABL method signatures, see the Parameter definition syntax reference entry in OpenEdge Development: ABL Reference. For more information on how data flows through the signatures of published class events, see Publishing class events.
[ DELEGATE ][ CLASS ]dotNet-delegate-type
Defines a signature for the class event specified as a .NET event signature. You must specify a .NET event signature using a .NET delegate type (dotNet-delegate-type), which is a special .NET class type that .NET uses to define the signatures of all .NET events. The primary use for defining ABL class events with .NET event signatures is to override and implement .NET abstract events or to implement events declared in .NET interfaces. However, you can also define ABL class events with .NET event signatures that have no particular connection to a .NET event. An ABL class event signature defined with a .NET delegate type is type checked at compile-time, as with any ABL class event signature, and the corresponding signatures of event handlers must be similarly run-time compatible. Note that you cannot implement an abstract event defined with an ABL method signature using a class event defined with a .NET event signature, nor the reverse, even if the signatures pass corresponding parameters of the same mode and type. For more information on defining and using ABL class events that have .NET event signatures, see the information on working with .NET events in OpenEdge Development: GUI for .NET Programming.
The following modified fragments from the sample classes show the addition of an OutputGenerated class event and its use, starting with its definition, in the CommonObj abstract class, as an abstract event together with an abstract method (PublishOutputGenerated( )) for publishing the event:
CLASS acme.myObjs.Common.CommonObj ABSTRACT:

...

  DEFINE PUBLIC ABSTRACT EVENT OutputGenerated
    SIGNATURE VOID (pcOutputType AS CHARACTER).

  METHOD PROTECTED ABSTRACT VOID PublishOutputGenerated
    (INPUT pcOutputType AS CHARACTER).

...

END CLASS.
The CustObj derived class implements both the event and its publishing method, which it also calls to publish the event. The listed printObj( ) method can call Publish( ) directly because the event is defined and implemented in the same class definition. However, another class derived from CustObj (NECustObj, not shown) must call PublishOutputGenerated( ) in order to publish the event. So, CustObj also calls PublishOutputGenerated( ) for consistency, which also helps the entire class hierarchy take advantage of any updates to how the event is published in the future:
USING acme.myObjs.*.
USING acme.myObjs.Common.*.
USING acme.myObjs.Interfaces.*.

CLASS acme.myObjs.CustObj INHERITS CommonObj:

...

  DEFINE PUBLIC OVERRIDEEVENT OutputGenerated
    SIGNATURE VOID (pcOutputType AS CHARACTER).

  METHOD PROTECTED OVERRIDE VOID PublishOutputGenerated
    (INPUT pcOutputType AS CHARACTER):
    OutputGenerated:Publish(pcOutputType).
  END METHOD.

...

  METHOD PUBLIC VOID printObj ( ):
    OUTPUT TO PRINTER.
    DISPLAY dtTimestamp.
    FOR EACH ttCustomer:
      DISPLAY ttCustomer.
    END.
    OUTPUT CLOSE.
    PublishOutputGenerated("One copy of report sent to printer").
  END METHOD.

...

END CLASS.
The Main class instantiates CustObj, subscribes its own event handler for the OutputGenerated event, and calls the printObj( ) method that publishes the event (through a call to PublishOutputGenerated( )):
USING acme.myObjs.*.
USING acme.myObjs.Common.*.
USING acme.myObjs.Interfaces.*.

CLASS Main:

...

  DEFINE PRIVATE VARIABLE rCustObj AS CLASS CustObj NO-UNDO.

...

  CONSTRUCTOR PUBLIC Main ( ):

...

    /* Create an instance of the CustObj class */
    rCustObj = NEW CustObj ( )

    /* Subscribe OutputGenerated event handler for CustObj */
    rCustObj:OutputGenerated:Subscribe(OutputGenerated_CustObjHandler).
  END CONSTRUCTOR.

  /* Event handlers for each Customer class instance */
  METHOD PRIVATE VOID OutputGenerated_CustObjHandler
       (pcOutputType AS CHARACTER):
    MESSAGE pcOutputType "for all customers." VIEW-AS ALERT-BOX.
  END METHOD.

...

  /* ObjectInfo processes information about the Customer object */
  METHOD PUBLIC VOID ObjectInfo (piInfoCount AS INTEGER):

  ...

    IF piInfoCount <> ? AND piInfoCount > 1 THEN
      rCustObj:printObj(piInfoCount).
    ELSE
      rCustObj:printObj( ).

  ...

  END METHOD.
END CLASS.