[Длинный пост, извинения]
Я ищу подтверждение относительно CL_GUI_TIMER
: Должна ли каждая группа программ (из внутреннего сеанса ) иметь свой собственный выделенный экземпляр объекта CL_GUI_TIMER
?
Я обнаружил, что если ссылка на объект CL_GUI_TIMER
используется совместно с другой группой программ, то вызов run()
из второй группы программ не вызовет событие finished
?
Я постараюсь обобщить соответствующий код:
Существует класс, который реализует таймер (чтобы покинуть основную программу, когда она истекает). Примечание. Ниже класса исключается проверка ошибок, но в реальном коде во время создания экземпляров или вызовов методов не возникает ошибок / исключений:
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.
Группа функций Z_FGROUP
имеет функциональный модуль Z_CS_SET_GUI_TIMEOUT
со статическим экземпляром класса выше ( примечание: поведение такое же, если вместо статической переменной сделать группу функций "глобальной" ) :
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.
Группа функций Z_FGROUP
также имеет другой функциональный модуль Z_FGROUP_CALL_SCREEN
, который вызывает экран 100
, определенный в Z_FGROUP
. В PBO этого экрана у нас есть модуль
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.
Теперь основная программа, скажем, Z_MAIN
, также имеет собственный экран 200
, с тем же вызовом Z_CS_SET_GUI_TIMEOUT
в ее 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.
В этой последовательности выполнения:
Z_MAIN
вызывает свой экран 200
тогда возможно
Z_MAIN
вызывает функциональный модуль Z_FGROUP_CALL_SCREEN
(который затем вызывает его экран 100
)
первый шаг правильно запускает таймер. Если вы не выполните шаг № 2, у этого первого таймера истечет LEAVE PROGRAM
, как и предполагалось.
Но если вы также выполните шаг № 2 (очевидно, до истечения таймера № 1), то произойдет то, что никакое событие таймера не будет запущено для шага № 2. Тогда вы можете оставаться на экране 100
столько, сколько пожелаете. Между тем таймер, который был запущен с # 1, истекает «тихо», то есть не запускает завершенное событие, которое может быть обработано, пока вы находитесь на экране 100
.
Если в приведенном выше коде вы измените экран Z_MAIN
200
timer для вызова своего собственного CL_GUI_TIMER
экземпляра (вместо экземпляра группы функций):
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.
тогда все работает правильно, и на обоих экранах появляется таймер (запускающий событие finished
).
Кроме того, после ответа Сандры, указывающего на SAP-ноту 2679117. Программа демонстрирует, что основной таймер продолжает работать, и сработает, если модальное диалоговое окно закрыто до истечения срока действия:
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( ).