什么是CL_GUI_TIMER的“范围”?

时间:2019-07-08 08:12:18

标签: abap sap-gui

[冗长的帖子,道歉]

我正在寻找有关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.

在此执行顺序中:

  1. Z_MAIN调用其屏幕200
    然后可能,
  2. 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注释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( ).

2 个答案:

答案 0 :(得分:3)

在SAP注释2679117 - CL_GUI_TIMER: Timer is aborted when a dialog is opened in SAP GUI中对此进行了解释:

  

CL_GUI_TIMER不能在计时器运行时处理切换屏幕。

据我了解,SAP说他们不再支持此类。

因此,这意味着“不确定的行为,使用后果自负”。

对不起!

答案 1 :(得分:1)

在上述Sandra的回答之后,SAP注释中提到了“模式对话框”:

事实证明程序组与问题无关。每个程序组创建一个新的CL_GUI_TIMER实例恰好解决了该问题,因为它只是为单独的GUI控件创建了一个新的系统事件绑定。参考我的示例代码,此单独的控件对应于功能组的Z_FGROUP屏幕100。在不同的“ popup level”(使用CALL SCREEN 0100 STARTING AT ...)处调用了此屏幕。事实证明,这个被忽视的细节是关键:

control framework中,系统事件被注册: enter image description here

大概CL_GUI_TIMER是通过GUI控件实现的。但是每个GUI控件都绑定到一个弹出级别。如果控件需要“容器控件”,则容器也将绑定到“弹出级别”。当GUI处于不同的弹出级别时,属于另一个级别的任何控件都是“不可见的”。

因此,我猜想,自动化控制器将为任何此类不可见的控件(“超出当前弹出级别”)(容器)触发系统事件。但是控制框架不会调用处理程序,因为弹出级别不是当前的。计时器一直在运行,因此,如果您及时回到正确的弹出窗口级别,则自动化控制器将触发事件并将其推送到控制框架(这解释了我问题的后半部分的行为)。

该控制框架旨在处理用户交互,并且该假设似乎是当出现弹出窗口时,其他级别(包括主窗口CL_GUI_CONTAINER=>screen0)上的事件是不相关或必须被抑制的。

Thomas Jung拥有一个古老的blog post,这为CFW事件的内部运作提供了一些启示。另外,CL_GUI_CFW中的“ stackpos”似乎很重要。