ABAP:ON CHANGE OF的坑

(1/7)背景


由于AT NEW field会判断field和它前面的所有字段,而ON CHANGE OF没有这个要求,所以后者就有了登上舞台的空间。

(2/7)正常情况


现在有一个内表GT_TAB,包括一个字段FIELD1,内容如下:


FIELD1的值
11
21
3
2

LOOP GT_TAB时,ON CHANGE OF GT_TAB-FIELD1会在第一和第三行被触发。

(3/7)非正常情况


GT_TAB内容如下:


FIELD1的值
11
21

没有疑问,第一次LOOP GT_TAB时,ON CHANGE OF GT_TAB-FIELD1会在第一行被触发。

可是,如果第二次LOOP呢?

答案是:不会触发ON CHANGE OF。

而且,即便你清空GT_TAB的内表或工作区再重新赋值,都没有用。

(4/7)示例说明


为此我做了一个示例,包含的功能如下:

(连续的两次循环时,内表的值都是无重复的,我们重点关注第二次循环是否触发ON CHANGE OF的情况)

操作
内表是否触发
构建新内表,首次循环全局内表

触发

第二次循环
全局内表不触发
清空内表后重新赋值并循环
全局内表不触发
清空工作区后重新循环
全局内表不触发
清空内表+工作区后重新赋值并循环
全局内表不触发
调用FORM循环局部内表
局部内表

触发

再次调用FORM循环局部内表
局部内表

不触发

换一个FORM2,同名局部内表
局部内表

触发

再次调用FORM2循环局部内表
局部内表

不触发

这是一个比较隐蔽的坑,因为在某些情况下,我们不能预知GT_TAB-FIELD1会不会一定都是多个值的。如果某一次循环的时候,我们判断的字段没有重复值,那么下次循环的时候,如果内表中的首条记录恰巧与我们上一次循环的值相同,ON CHANGE OF就不会被触发。

而且,不管是全局变量还是局部变量,都有这样的情况。

(5/7)示例代码


有兴趣的同学,可以自己修改代码以测试一下这样的情况:

1、首次循环,内表中是1 1两条数据;

2、再次循环,内表中是1 2 两条数据

REPORT ztest_abap_ll.


SELECTION-SCREEN PUSHBUTTON /10(40) clear1 USER-COMMAND clear1.
SELECTION-SCREEN SKIP 1.
SELECTION-SCREEN PUSHBUTTON /10(40) clear2 USER-COMMAND clear2.
SELECTION-SCREEN SKIP 1.
SELECTION-SCREEN PUSHBUTTON /10(40) create USER-COMMAND create.
SELECTION-SCREEN SKIP 1.
SELECTION-SCREEN PUSHBUTTON /10(40) loop1 USER-COMMAND loop1.
SELECTION-SCREEN SKIP 1.
SELECTION-SCREEN PUSHBUTTON /10(40) loop2 USER-COMMAND loop2.
SELECTION-SCREEN SKIP 1.
SELECTION-SCREEN PUSHBUTTON /10(40) loop3 USER-COMMAND loop3.


TYPES:BEGIN OF ty_tab,
        field1 TYPE string,
      END OF ty_tab,
      tyt_tab TYPE TABLE OF ty_tab.
DATA: gt_tab TYPE tyt_tab WITH HEADER LINE,
      g_msg TYPE string,
      g_msgty TYPE c.


INITIALIZATION.
  clear1 = '清空内表'.
  clear2 = '清空工作区'.
  create = '向内表中插入两条数据'.
  loop1 = '循环全局内表'.
  loop2 = '全局内表放入局部内表后再循环'.
  loop3 = '全局内表放入另一个FORM的同名局部内表后再循环'.


AT SELECTION-SCREEN.
  CASE sy-ucomm.
    WHEN 'CLEAR1'.
      CLEAR: gt_tab[].
    WHEN 'CLEAR2'.
      CLEAR: gt_tab.
    WHEN 'CREATE'.
      "插入两条数据
      gt_tab-field1 = '1'.
      APPEND gt_tab.
      APPEND gt_tab.
    WHEN 'LOOP1'.
      PERFORM loop1.
    WHEN 'LOOP2'.
      PERFORM loop2.
    WHEN 'LOOP3'.
      PERFORM loop3.
  ENDCASE.
FORM loop1.
  LOOP AT gt_tab.
    ON CHANGE OF gt_tab-field1.
      g_msg = '当前索引' && sy-tabix && ',触发了ON CHANGE OF'.
      g_msgty = 'S'.
    ELSE.
      g_msg = '当前索引' && sy-tabix && ',没有触发ON CHANGE OF'.
      g_msgty = 'E'.
    ENDON.
    MESSAGE g_msg TYPE 'I' DISPLAY LIKE g_msgty.
  ENDLOOP.
ENDFORM.
FORM loop2.
  DATA: lt_tab TYPE tyt_tab WITH HEADER LINE.
  lt_tab[] = gt_tab[].
  LOOP AT lt_tab.
    ON CHANGE OF lt_tab-field1.
      g_msg = '当前索引' && sy-tabix && ',触发了ON CHANGE OF'.
      g_msgty = 'S'.
    ELSE.
      g_msg = '当前索引' && sy-tabix && ',没有触发ON CHANGE OF'.
      g_msgty = 'E'.
    ENDON.
    MESSAGE g_msg TYPE 'I' DISPLAY LIKE g_msgty.
  ENDLOOP.
ENDFORM.
FORM loop3.
  DATA: lt_tab TYPE tyt_tab WITH HEADER LINE.
  lt_tab[] = gt_tab[].
  LOOP AT lt_tab.
    ON CHANGE OF lt_tab-field1.
      g_msg = '当前索引' && sy-tabix && ',触发了ON CHANGE OF'.
      g_msgty = 'S'.
    ELSE.
      g_msg = '当前索引' && sy-tabix && ',没有触发ON CHANGE OF'.
      g_msgty = 'E'.
    ENDON.
    MESSAGE g_msg TYPE 'I' DISPLAY LIKE g_msgty.
  ENDLOOP.
ENDFORM.

(6/7)原因分析


ada4c7a1623a09c681335d06c8682fab.png

根据F1里的说明,可以看到对于ON CHANGE OF的事件,在系统里是有一个类似于帮助变量的东西在支撑的,而且这个帮助变量的生命周期是比我们的FORM、FUNCTION等代码块的周期更长的。

F1里面没有提到的是,它的生命周期与全局变量的生命周期谁更长。不过实践证明了,除非程序退出,否则这个帮助变量是不会消失的。

(7/7)如何规避


个人觉得,用ON CHANGE OF,不如自己定义一个变量,记录一下上次循环的值,当本次的值与上次不一致时,即形同ON CHANGE OF的事件。

如下:

DATA: l_field1 type string.

loop at gt_tab.

if l_field1 <> gt_tab-field1.

"形同ON CHANGE OF

else.

l_field1 = gt_tab-field1.

endif.

endloop.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值