How to handle multiple widgets at once?

Posted by jpatel7 on 09-Jan-2018 17:14

I have multiple widgets on the screen. For example, proc-1, proc-2, ..., proc-10. I need to write the same code for triggers of each of them.I have other 10 widgets procName-1, procName-2,...,procName-10. Now, I need to do this for each of them:

ON LEAVE OF proc-1 IN FRAME f-main
DO:

   procName-1:screen-value = getProcName(1, self:screen-value).

END.

Here, getProcName is a method where I am getting procName beased on proc values. Similarly, I have many sets of similar widget groups. Is there anyway I can make it generic and reduce my code? Can I make a function which contains code something like this:

procName-{index}:screen-value = getProcName(index, self:screen-value).




Posted by Patrick Tingen on 10-Jan-2018 07:05

The easiest way in this case would be to combine the triggers and use a generic name, like this:

ON LEAVE OF proc-1 IN FRAME f-main
, proc-2 IN FRAME f-main
, proc-3 IN FRAME f-main
DO:
  DEFINE VARIABLE hProcName AS HANDLE NO-UNDO.

  CASE self:name:
    WHEN 'proc-1' THEN hProcName = hProcName-1:HANDLE.
    WHEN 'proc-2' THEN hProcName = hProcName-2:HANDLE.
    WHEN 'proc-3' THEN hProcName = hProcName-3:HANDLE.
  END CASE.
  
  hProcName:SCREEN-VALUE = getProcName(1, SELF:SCREEN-VALUE).
 
END.

An alternative would be to define an array and assign the appropriate handles of the fields to that on startup of the program. Then do some fiddling with the SELF:NAME to find out which element you need:

/* Startup */
DEFINE VARIABLE hProc AS HANDLE EXTENT 5.

DO WITH FRAME f-main:
  hProc[1] = hProcName-1:HANDLE.
  hProc[2] = hProcName-2:HANDLE.
  hProc[3] = hProcName-3:HANDLE.
END.

ON LEAVE OF 
  proc-1 IN FRAME f-main
, proc-2 IN FRAME f-main
, proc-3 IN FRAME f-main
DO:
  DEFINE VARIABLE i AS INTEGER NO-UNDO.
  i = INTEGER(ENTRY(2,SELF:NAME,'-')).
  hProc[i]:SCREEN-VALUE = getProcName(1, SELF:SCREEN-VALUE).
 
END.

Even fancier would be to define a function that you pass the name of the widget and which will walk the widget tree of the window to find that widget and return its handle. But beware, because it will add a lot of overhead, although on modern hardware this will probably not even be noticable.

FUNCTION getWidgetHandle RETURNS HANDLE
  ( pcWidgetName AS CHARACTER ) :

  DEFINE VARIABLE hWidget AS HANDLE  NO-UNDO.
  hWidget = FRAME {&FRAME-NAME}:FIRST-CHILD:FIRST-CHILD. 

  REPEAT WHILE VALID-HANDLE(hWidget):
    IF hWidget:NAME = pcWidgetName THEN RETURN hWidget.
    hWidget = hWidget:NEXT-SIBLING.
  END. 

  RETURN ?.
END FUNCTION. /* getWidgetHandle */

ON LEAVE OF 
  proc-1 IN FRAME f-main
, proc-2 IN FRAME f-main
, proc-3 IN FRAME f-main
DO:
  getWidgetHandle( REPLACE(SELF:NAME,'proc-', 'procName-')):SCREEN-VALUE = getProcName(1, SELF:SCREEN-VALUE).
END.

All Replies

Posted by Matt Gilarde on 10-Jan-2018 04:22

You can write a trigger which handles events for all widgets in a frame using the ANYWHERE keyword.

ON LEAVE OF FRAME f-main ANYWHERE

I can think of a few ways to associate one widget with another. For example, you could store the handle of the secondary widget in the primary widget's PRIVATE-DATA attribute. PRIVATE-DATA is a string which can be used for whatever purpose you want. In this case you could store a handle, like this. You would do this initialization after the frame is defined.

proc-1:PRIVATE-DATA = STRING(procName-1:HANDLE).

Then in the trigger you could retrieve the handle like this:

DEFINE VARIABLE procX AS HANDLE NO-UNDO.

procX = HANDLE(SELF:PRIVATE-DATA).

procX:SCREEN-VALUE = getProcName(SELF:SCREEN-VALUE).

Posted by Patrick Tingen on 10-Jan-2018 07:05

The easiest way in this case would be to combine the triggers and use a generic name, like this:

ON LEAVE OF proc-1 IN FRAME f-main
, proc-2 IN FRAME f-main
, proc-3 IN FRAME f-main
DO:
  DEFINE VARIABLE hProcName AS HANDLE NO-UNDO.

  CASE self:name:
    WHEN 'proc-1' THEN hProcName = hProcName-1:HANDLE.
    WHEN 'proc-2' THEN hProcName = hProcName-2:HANDLE.
    WHEN 'proc-3' THEN hProcName = hProcName-3:HANDLE.
  END CASE.
  
  hProcName:SCREEN-VALUE = getProcName(1, SELF:SCREEN-VALUE).
 
END.

An alternative would be to define an array and assign the appropriate handles of the fields to that on startup of the program. Then do some fiddling with the SELF:NAME to find out which element you need:

/* Startup */
DEFINE VARIABLE hProc AS HANDLE EXTENT 5.

DO WITH FRAME f-main:
  hProc[1] = hProcName-1:HANDLE.
  hProc[2] = hProcName-2:HANDLE.
  hProc[3] = hProcName-3:HANDLE.
END.

ON LEAVE OF 
  proc-1 IN FRAME f-main
, proc-2 IN FRAME f-main
, proc-3 IN FRAME f-main
DO:
  DEFINE VARIABLE i AS INTEGER NO-UNDO.
  i = INTEGER(ENTRY(2,SELF:NAME,'-')).
  hProc[i]:SCREEN-VALUE = getProcName(1, SELF:SCREEN-VALUE).
 
END.

Even fancier would be to define a function that you pass the name of the widget and which will walk the widget tree of the window to find that widget and return its handle. But beware, because it will add a lot of overhead, although on modern hardware this will probably not even be noticable.

FUNCTION getWidgetHandle RETURNS HANDLE
  ( pcWidgetName AS CHARACTER ) :

  DEFINE VARIABLE hWidget AS HANDLE  NO-UNDO.
  hWidget = FRAME {&FRAME-NAME}:FIRST-CHILD:FIRST-CHILD. 

  REPEAT WHILE VALID-HANDLE(hWidget):
    IF hWidget:NAME = pcWidgetName THEN RETURN hWidget.
    hWidget = hWidget:NEXT-SIBLING.
  END. 

  RETURN ?.
END FUNCTION. /* getWidgetHandle */

ON LEAVE OF 
  proc-1 IN FRAME f-main
, proc-2 IN FRAME f-main
, proc-3 IN FRAME f-main
DO:
  getWidgetHandle( REPLACE(SELF:NAME,'proc-', 'procName-')):SCREEN-VALUE = getProcName(1, SELF:SCREEN-VALUE).
END.

This thread is closed