Kbase P53346: Dynamics. How to retrieve a Lookup handle.
Autor |
  Progress Software Corporation - Progress |
Acesso |
  Público |
Publicação |
  11/11/2003 |
|
Status: Unverified
GOAL:
Dynamics. How to retrieve a Lookup handle.
FACT(s) (Environment):
Dynamics 2.0A
FIX:
For basic objects such as fill-in fields or buttons, the handle is a Progress WIDGET-HANDLE. For fields represented as SmartDataFields, such as dynamic Lookups and Combos, which are actually 4GL procedures, the handle is the procedure handle of the SmartDataField. Since the lists are in the same order, the position of a handle in the second list matches the position of the name in the first, so you can easily identify the handle of any object from its name.
If you are writing a custom super procedure to support a single Viewer, such as a Customer Viewer, then the super procedure needs to retrieve these attribute values just once, on startup. The values do not change because the running instance of the super procedure will always be associated with the same Viewer instance. To add code to the startup of an object, you create a local version of the initializeObject procedure. Here you can retrieve these two attribute values and store them in variables scoped to the procedure, so that they are always available. The local procedure must RUN SUPER first, because the values of the attributes are established by the standard initializeObject code. In addition, the procedure can run a standard internal procedure where any validation checks can be coded, so that the checks are executed properly on the first row to be displayed:
PROCEDURE initializeObject:
/*-------------------------------------------------------------------------
Purpose: Retrieve the list of field names and handles for later lookups.
Parameters: <none>
Notes:
-------------------------------------------------------------------------*/
RUN SUPER.
/* Establish the list of fields and handles. */
{get AllFieldNames gcFields}. /* gcFields and gcHandles are */
{get AllFieldHandles gcHandles}. /* defined in the Definitions section. */
RUN rowDisplay NO-ERROR.
END PROCEDURE
Now you can retrieve the handle of any widget in the Viewer by locating its name in the gcFields list and then retrieving the corresponding item in the gcHandles list. Since you will need to do this from many different bits of code, it is good to put everything into a single function and call it widgetHandle:
FUNCTION widgetHandle RETURNS HANDLE
( pcWidget AS CHARACTER ) :
/*-------------------------------------------------------------------------
Purpose: Returns the widget handle of any object in the Target-Procedure
Params: INPUT pcWidget -- widget name
Returns: widget handle of the object
-------------------------------------------------------------------------*/
DEFINE VARIABLE iFieldPos AS INTEGER NO-UNDO.
iFieldPos = LOOKUP(pcWidget, gcFields).
RETURN IF iFieldPos NE 0 THEN
WIDGET-HANDLE(ENTRY(iFieldPos, gcHandles))
ELSE ?. /* If the field wasn't found. */
END FUNCTION.
Note that the WIDGET-HANDLE function is used to return the handle from the list in the proper form (converted from a character string), and this will work for both simple widgets such as fields as well as for objects represented as SmartDataFields, where the handle will actually be a procedure handle. (The WIDGET-HANDLE syntax is in fact an artifact of the evolution of the Progress language. Progress had widgets, or basic objects, before it had procedure handles. The keyword did not change as the language was extended.)
If you want to write code that highlights the Balance field if it is too close to the Credit Limit, you need to write code that uses the new widgetHandle function to get at the handles of objects in the Viewer. While you·re at it, you can turn the highlight operation itself into a standard function, so that the color choice used for highlighting is always consistent. So here is a highlightWidget function that changes the Background Color for you:
FUNCTION highlightWidget RETURNS LOGICAL
( pcField AS CHARACTER ) :
/*----------------------------------------------------.---------------------
Purpose: Highlights the specified field.
Params: pcField AS CHARACTER.
Notes: The color choice for highlight could also be a property.
-------------------------------------------------------------------------*/
DEFINE VARIABLE hField AS HANDLE NO-UNDO.
hField = widgetHandle(pcField).
IF VALID-HANDLE(hField) AND CAN-SET(hField,'BGCOLOR') THEN
DO:
hField:BGCOLOR = 14.
RETURN TRUE.
END.
ELSE RETURN FALSE.
END FUNCTION.
The function takes the name of the object as input, which is meaningful to the application developer using the function; converts it to a handle; and applies the operation by changing the BGCOLOR widget attribute. It first checks to make sure that this attribute can be set. If the object is, for example, a SmartDataField such as a dynamic Lookup, then the BGCOLOR cannot directly be set. The SmartDataField would need to support a procedure to highlight the field in some way meaningful to that field. This represents an extension to the current default behavior that is not explored here, but the point is that isolating the code in one place allows you to extend the behavior of the highlight function to support more kinds of objects in a standard way. The complete API introduced later will accommodate SmartDataFields as well as basic widgets.
The widgetValue function returns the SCREEN-VALUE for any field:
FUNCTION widgetValue RETURNS CHARACTER
( pcField AS CHARACTER ) :
/*-------------------------------------------------------------------------
Purpose: Returns the value of a field on the screen
Notes:
-------------------------------------------------------------------------*/
DEFINE VARIABLE hField AS HANDLE NO-UNDO.
hField = widgetHandle(pcField).
IF VALID-HANDLE(hField) THEN
RETURN hField:SCREEN-VALUE.
ELSE RETURN ?.
END FUNCTION.
Now you can write a simple procedure called rowDisplay to do the calculation. It uses both the highlightWidget function and a parallel unhighlightWidget function, which sets the BGCOLOR back to its default of unknown (·?·):
PROCEDURE rowDisplay:
/*-------------------------------------------------------------------------
Purpose: Flag the balance field visually if it's too close to the
Credit Limit.
Parameters: none
Notes:
-------------------------------------------------------------------------*/
IF DECIMAL(widgetValue('CreditLimit')) -
DECIMAL(widgetValue('Balance')) < 5000
THEN highlightWidget('Balance').
ELSE unhighlightWidget('Balance').
END PROCEDURE.
The rowDisplay procedure is run from initializeObject to catch the initial screen display. It must also be run from a local version of displayFields to perform the check on each row that is displayed:
/*-------------------------------------------------------------------------
Purpose: Runs any record-check procedures each time a record
is displayed.
Parameters: pcColValues -- values to display for the current record.
Notes:
-------------------------------------------------------------------------*/
DEFINE INPUT PARAMETER pcColValues AS CHARACTER NO-UNDO.
RUN SUPER (INPUT pcColValues).
IF gcFields NE "" THEN /* This may happen once before initialization. */
RUN rowDisplay NO-ERROR.
END PROCEDURE..