【发布时间】:2023-03-17 09:41:01
【问题描述】:
[冗长的帖子,道歉]
我正在寻找关于CL_GUI_TIMER 的确认:必须每个program group(internal session)有自己的专用实例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,在其PBO 中对Z_CS_SET_GUI_TIMEOUT 进行相同的调用:
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 计时器更改为调用它自己的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 事件)。
另外,在 Sandra 的回答指向 SAP note 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( ).
【问题讨论】: