[Lengthy post, apologies]
I am looking for confirmation regarding CL_GUI_TIMER
: Must each program group (of an internal session) have its own dedicated instance of a CL_GUI_TIMER
object?
I am finding that if the reference to the CL_GUI_TIMER
object is shared with another program group, then calling run()
from within the second program group will not trigger a finished
event?
I will try to summarize the relevant code:
There is a class that implements a timer (to leave the main program when it expires). Note: Below the class is stripped of the error-checking, but no errors/exceptions occur in the actual code during instantiation or method calls:
CLASS zcl_cs_gui_timer_leave_prog DEFINITION.
PUBLIC SECTION.
METHODS constructor.
METHODS set_timer.
PROTECTED SECTION.
DATA go_gui_timer TYPE REF TO cl_gui_timer .
CONSTANTS c_default_timeout_seconds TYPE i VALUE 6 ##NO_TEXT.
PRIVATE SECTION.
METHODS timer_handler FOR EVENT finished OF cl_gui_timer .
ENDCLASS.
CLASS zcl_cs_gui_timer_leave_prog IMPLEMENTATION.
METHOD constructor.
go_gui_timer = NEW #( ).
SET HANDLER me->timer_handler FOR go_gui_timer.
go_gui_timer->interval = c_default_timeout_seconds.
ENDMETHOD.
METHOD set_timer.
go_gui_timer->cancel( ).
go_gui_timer->run( ).
ENDMETHOD.
METHOD timer_handler.
MESSAGE 'Transaction ended due to inactivity' TYPE 'S'.
LEAVE PROGRAM.
ENDMETHOD.
ENDCLASS.
Function group Z_FGROUP
has a function module Z_CS_SET_GUI_TIMEOUT
with a static instance of the class above (note: behaviour is the same if you make the static variable a function group "global" instead):
FUNCTION z_cs_set_gui_timeout.
STATICS lo_zcs_gui_timer TYPE REF TO zcl_cs_gui_timer_leave_prog.
TRY.
IF NOT lo_zcs_gui_timer IS BOUND.
lo_zcs_gui_timer = NEW #( ).
ENDIF.
lo_zcs_gui_timer->set_timer( ).
CATCH cx_abap_context_info_error INTO DATA(go_exc).
MESSAGE |{ go_exc->get_longtext( ) }| TYPE 'S'.
ENDTRY.
ENDFUNCTION.
The function group Z_FGROUP
also has another function module, Z_FGROUP_CALL_SCREEN
which calls screen 100
, defined in Z_FGROUP
. In the PBO of that screen we have the module
MODULE set_gui_timeout_100 OUTPUT.
* actually is in a subroutine (not the module), skipping for brevity:
CALL FUNCTION 'Z_CS_SET_GUI_TIMEOUT'.
ENDMODULE.
Now a main program, say Z_MAIN
also has its own screen 200
, with the same call to Z_CS_SET_GUI_TIMEOUT
in its PBO:
MODULE set_gui_timeout_200 OUTPUT.
* actually is in a subroutine (not the module), skipping for brevity:
CALL FUNCTION 'Z_CS_SET_GUI_TIMEOUT'.
ENDMODULE.
In this execution sequence:
Z_MAIN
calls its screen200
then possibly,Z_MAIN
calls function moduleZ_FGROUP_CALL_SCREEN
(which then calls its screen100
)
the first step does properly start the timer. If you don't do step #2, this first timer will expire causing a LEAVE PROGRAM
as intended.
But if you also do step #2 (obviously before the #1 timer expiration) what will happen is that no timer event gets triggered for step #2. So then you can stay on screen 100
for as long as you wish. Meanwhile the timer that was started with #1 expires "silently", i.e., does not trigger a finished event which can be handled while you are on screen 100
.
If in the code above you change Z_MAIN
's screen 200
timer to call its own CL_GUI_TIMER
instance (instead of the function group's one):
MODULE set_gui_timeout_200 OUTPUT.
* actually is in a subroutine (not the module), skipping for brevity:
** CALL FUNCTION 'Z_CS_SET_GUI_TIMEOUT'.
STATICS lo_zcs_gui_timer TYPE REF TO zcl_cs_gui_timer_leave_prog.
TRY.
IF NOT lo_zcs_gui_timer IS BOUND.
lo_zcs_gui_timer = NEW #( ).
ENDIF.
lo_zcs_gui_timer->set_timer( ).
CATCH cx_abap_context_info_error INTO DATA(go_exc).
MESSAGE |{ go_exc->get_longtext( ) }| TYPE 'S'.
ENDTRY.
ENDMODULE.
then everything works properly and both screens get a timer (that triggers the finished
event).
Addition, following Sandra's answer pointing to SAP note 2679117. Program demonstrates that an underlying timer keeps running and will trigger if a modal dialog is closed prior to expiration:
PROGRAM ztimer_event.
* +-------------------------------------------------------------------------------------------------+
PARAMETERS:
* +-------------------------------------------------------------------------------------------------+
p_time TYPE i DEFAULT '6'.
* +-------------------------------------------------------------------------------------------------+
CLASS zcl_cs_gui_timer_leave_prog DEFINITION.
PUBLIC SECTION.
METHODS:
constructor,
set_timer.
CONSTANTS:
c_default_timeout_seconds TYPE i VALUE 6 ##NO_TEXT.
DATA:
lo_gui_timer TYPE REF TO cl_gui_timer .
PRIVATE SECTION.
METHODS timer_handler FOR EVENT finished OF cl_gui_timer .
ENDCLASS.
CLASS zcl_cs_gui_timer_leave_prog IMPLEMENTATION.
METHOD constructor.
lo_gui_timer = NEW #( ).
SET HANDLER me->timer_handler FOR lo_gui_timer.
lo_gui_timer->interval = COND #( WHEN p_time <= 0 THEN c_default_timeout_seconds
ELSE p_time ).
ENDMETHOD.
METHOD set_timer.
lo_gui_timer->cancel( ).
lo_gui_timer->run( ).
ENDMETHOD.
METHOD timer_handler.
MESSAGE 'Timer was triggered' TYPE 'I'.
* LEAVE PROGRAM.
ENDMETHOD.
ENDCLASS.
* +-------------------------------------------------------------------------------------------------+
* +-------------------------------------------------------------------------------------------------+
START-OF-SELECTION.
* +-------------------------------------------------------------------------------------------------+
TYPES:
BEGIN OF t_alv_row,
text TYPE string,
END OF t_alv_row.
DATA:
lr_salv TYPE REF TO cl_salv_table,
lt_alv TYPE STANDARD TABLE OF t_alv_row.
DATA(go_timer) = NEW zcl_cs_gui_timer_leave_prog( ).
go_timer->set_timer( ).
lt_alv = VALUE #( ( text = |Timer is running. To let it expire silently:| )
( text = |Wait { go_timer->lo_gui_timer->interval } |
& |seconds before closing this popup'| ) ).
cl_salv_table=>factory(
EXPORTING
list_display = abap_false
IMPORTING
r_salv_table = lr_salv
CHANGING
t_table = lt_alv ).
lr_salv->set_screen_popup(
start_column = 10
end_column = 60
start_line = 5
end_line = 9 ).
WRITE: / |This will not time out if approximately { go_timer->lo_gui_timer->interval } seconds |
& |passed before you closed the popup.|,
/ |It will timeout (at approximately { go_timer->lo_gui_timer->interval } |
& |seconds from execution) if you closed the popup earlier|.
lr_salv->display( ).