ABAP动态生成选择屏幕字段(动态生成代码)

文章探讨了在SAPABAP环境中如何动态生成选择屏幕字段以满足类似VK11的定价批导需求。通过分析标准程序如SE16,作者发现并分享了动态生成屏幕的实现方式,包括READREPORT和GENERATEREPORT等语法的应用,同时警告了DELETE相关语法的潜在风险。提供的代码示例展示了如何创建动态选择屏幕和处理模板下载与上传。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近项目成员碰到一个需求,有一个关于定价批导的需求,期望是能像VK11前台一样,输入条件类型后,自动显示所有的关键字组合,并根据选择的组合来动态下载模板及上传,因为每种组合的Key字段都不一样,模板也会不一样。

其实这个问题难点只在于如何动态生成选择屏幕字段,动态下载模板借助OLE可以轻松实现,动态上传借助指针也可以轻松实现。我之前的帖子中有可以达到类似效果的参考代码:

通过ABAP代码实现批导创建SAP表/结构/数据元素/域(SE11/BAPI)https://blog.csdn.net/DeveloperMrMeng/article/details/128257812?spm=1001.2014.3001.5501MD61计划独立需求导入BAPI【按日维度/动态模板/动态字段】https://blog.csdn.net/DeveloperMrMeng/article/details/125024469?spm=1001.2014.3001.5501虽然那个需求最终并没有选择进行动态编程,但我还是比较好奇这个需求应该如何实现,其实SAP有一些标准事务也有类似的效果,比如SE16,在输入表名后,回车显示的选择屏幕就是动态生成的。

做完手头工作后,我对这个标准程序进行了DEBUG,最终在函数RS_TABLE_LIST_CREATE中发现其生成原理,在该函数中还可以窥探到动态生成屏幕的原理,这里不多赘述。

实现该功能的核心语法如下:


READ REPORT prog INTO itab [MAXIMUM WIDTH INTO wid].

DELETE REPORT prog.

INSERT REPORT prog FROM itab
              [MAXIMUM WIDTH INTO wid]
              { [KEEPING DIRECTORY ENTRY]
              | { [PROGRAM TYPE pt]
                  [FIXED-POINT ARITHMETIC fp]
                  [VERSION vs] }
              | [DIRECTORY ENTRY dir] }.

GENERATE REPORT prog [error_handling].

READ TEXTPOOL prog INTO itab LANGUAGE lang.

DELETE TEXTPOOL prog LANGUAGE lg.

INSERT TEXTPOOL prog FROM itab LANGUAGE lang.


以下为demo效果:

 实现原理:

注:通过F1查看其中一些语法说明可以发现,涉及到 DELETE 的语法通常会标注仅用于SAP内部使用,不建议在实际生产中进行使用,应该是担心误删掉一些标准代码,所以本文只是对这种实现方式进行测试及说明,如需实际使用,一定要慎重,并且搭配SYNTAX-CHECK语法或者一些错误检查附加项进行使用。

实现源码:

程序ZGENERATE_SELECSCREEN:

*&---------------------------------------------------------------------*
*& REPORT ZGENERATE_SELECSCREEN
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zgenerate_selecscreen.

DATA:
  gv_error TYPE flag.

SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
  PARAMETERS:p_type TYPE t682i-kozgf MODIF ID m3.
SELECTION-SCREEN END OF BLOCK b1.

*&---------------------------------------------------------------------*
*& AT SELECTION-SCREEN OUT
*&---------------------------------------------------------------------*
AT SELECTION-SCREEN.
* Generate selection screen
  PERFORM frm_genarate_selscr.

START-OF-SELECTION.

*&---------------------------------------------------------------------*
*& Form frm_genarate_selscr
*&---------------------------------------------------------------------*
*& Generate selection screen
*&---------------------------------------------------------------------*
FORM frm_genarate_selscr .
  DATA:
    lt_prog        TYPE STANDARD TABLE OF string,
    lt_prog_new    TYPE STANDARD TABLE OF string,
    lt_text_pool   TYPE STANDARD TABLE OF textpool,
    ls_text_pool   TYPE textpool,
    lv_prog        TYPE sy-repid,
    lv_bt_name     TYPE string,
    ls_new_code    TYPE string,
    lv_ucomm       TYPE string,
    lv_symbol      TYPE char1 VALUE '.',
    lv_begin_tabix TYPE sy-tabix,
    lv_end_tabix   TYPE sy-tabix,
    lv_text_symbol TYPE numc3.

  lv_prog = 'ZDYNAMICS_SCREEN'.

  SELECT a~kvewe,
         a~kappl,
         a~kozgf,
         a~kolnr,
         b~gstru,
         b~gstxt
    FROM t682i AS a
    LEFT OUTER JOIN tmc1t AS b
      ON concat( a~kvewe,a~kotabnr ) = b~gstru
     AND b~spras = @sy-langu
   WHERE a~kozgf = @p_type
     AND a~kvewe = 'A'
     AND a~kappl = 'V'
  INTO TABLE @DATA(lt_condtype_info).

  SORT lt_condtype_info BY gstru ASCENDING.
  DELETE ADJACENT DUPLICATES FROM lt_condtype_info COMPARING gstru.

  DATA(lv_lines) = lines( lt_condtype_info ).

  IF lt_condtype_info IS INITIAL.
    gv_error = abap_on.
    MESSAGE 'Error Condition Type' TYPE 'E'.
  ELSE.
*   Get source code
    READ REPORT lv_prog INTO lt_prog.

*   Get text pool
    READ TEXTPOOL lv_prog INTO lt_text_pool LANGUAGE sy-langu.

    LOOP AT lt_prog INTO DATA(ls_prog).
      IF ls_prog CS '*DYNAMIC SCREEN BEGIN*'.
        lv_begin_tabix = sy-tabix.
      ENDIF.
      IF ls_prog CS '*DYNAMIC SCREEN END*'.
        lv_end_tabix = sy-tabix.
        EXIT.
      ENDIF.
    ENDLOOP.

    LOOP AT lt_prog INTO ls_prog.
      IF sy-tabix > lv_begin_tabix AND sy-tabix < lv_end_tabix.
        CONTINUE.
      ENDIF.
      APPEND ls_prog TO lt_prog_new.
    ENDLOOP.

    IF lines( lt_condtype_info ) > 1.
*     Add Begin Block
      ls_new_code = 'SELECTION-SCREEN BEGIN OF BLOCK b3 WITH FRAME TITLE TEXT-003.'.
      lv_begin_tabix = lv_begin_tabix + 1.
      INSERT ls_new_code INTO lt_prog_new INDEX lv_begin_tabix.

      ls_text_pool-id     = 'I'.
      ls_text_pool-key    = '003'.
      ls_text_pool-entry  = TEXT-003.
      ls_text_pool-length = 50.
      DELETE lt_text_pool WHERE id = 'I' AND key = '003'.
      APPEND ls_text_pool TO lt_text_pool.
      CLEAR ls_text_pool.

      lv_text_symbol = 900.

*     Add Radiobutton
      LOOP AT lt_condtype_info INTO DATA(ls_condtype_info).
        IF sy-tabix = 1.
          lv_ucomm = ` DEFAULT 'X'`.
        ELSE.
          lv_ucomm = ''.
        ENDIF.

        lv_bt_name = 'RB_' && ls_condtype_info-gstru.

        ls_new_code = 'SELECTION-SCREEN BEGIN OF LINE.'.
        lv_begin_tabix = lv_begin_tabix + 1.
        INSERT ls_new_code INTO lt_prog_new INDEX lv_begin_tabix.

        ls_new_code = 'PARAMETERS:rb_' && ls_condtype_info-gstru &&
                      ' RADIOBUTTON GROUP grp2' && lv_ucomm && lv_symbol.
        lv_begin_tabix = lv_begin_tabix + 1.
        INSERT ls_new_code INTO lt_prog_new INDEX lv_begin_tabix.

        ADD 1 TO lv_text_symbol.
        ls_new_code = 'SELECTION-SCREEN COMMENT 5(79) TEXT-' && lv_text_symbol && ` FOR FIELD ` && lv_bt_name &&  '.'.
        lv_begin_tabix = lv_begin_tabix + 1.
        INSERT ls_new_code INTO lt_prog_new INDEX lv_begin_tabix.

        ls_new_code = 'SELECTION-SCREEN END OF LINE.'.
        lv_begin_tabix = lv_begin_tabix + 1.
        INSERT ls_new_code INTO lt_prog_new INDEX lv_begin_tabix.

        ls_text_pool-id      = 'I'.
        ls_text_pool-key     = lv_text_symbol.
        ls_text_pool-entry   = ls_condtype_info-gstxt.
        ls_text_pool-length  = 100.
        DELETE lt_text_pool WHERE id = 'I' AND key = lv_text_symbol.
        APPEND ls_text_pool TO lt_text_pool.

************************************************************************
*       The standard selection text has a maximum length of 30 characters
************************************************************************
*        ls_new_code = 'PARAMETERS:rb_' && ls_condtype_info-gstru &&
*                      ' TYPE char1 RADIOBUTTON GROUP grp2' && lv_ucomm && lv_symbol.
*
*        lv_begin_tabix = lv_begin_tabix + 1.
*        INSERT ls_new_code INTO lt_prog_new INDEX lv_begin_tabix.
*
*        ls_text_pool-id      = 'S'.
*        ls_text_pool-key     = lv_bt_name.
*        ls_text_pool-entry+8 = ls_condtype_info-gstxt.
*        ls_text_pool-length  = 50.
*        DELETE lt_text_pool WHERE id = 'S' AND key = lv_bt_name.
*        APPEND ls_text_pool TO lt_text_pool.
************************************************************************

        CLEAR:
          ls_new_code,
          ls_text_pool.
      ENDLOOP.

*     Add End Block
      ls_new_code = 'SELECTION-SCREEN END OF BLOCK b3.'.
      lv_begin_tabix = lv_begin_tabix + 1.
      INSERT ls_new_code INTO lt_prog_new INDEX lv_begin_tabix.
    ENDIF.

    DELETE REPORT lv_prog.

    DELETE TEXTPOOL lv_prog LANGUAGE sy-langu.

    INSERT REPORT lv_prog FROM lt_prog_new.

    INSERT TEXTPOOL lv_prog FROM lt_text_pool LANGUAGE sy-langu.

    GENERATE REPORT lv_prog MESSAGE DATA(lv_err).

    SUBMIT (lv_prog) WITH p_type = p_type VIA SELECTION-SCREEN AND RETURN.
  ENDIF.
ENDFORM.

程序ZDYNAMICS_SCREEN:

*&---------------------------------------------------------------------*
*& Report ZDYNAMICS_SCREEN
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zdynamics_screen.

SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
  PARAMETERS:p_type TYPE t682i-kozgf MODIF ID m3.
SELECTION-SCREEN END OF BLOCK b1.

*************************DYNAMIC SCREEN BEGIN***************************
* ...
**************************DYNAMIC SCREEN END****************************

SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE TEXT-002.
  PARAMETERS:rb_down TYPE char1 RADIOBUTTON GROUP grp1 USER-COMMAND cre,
             rb_upld TYPE char1 RADIOBUTTON GROUP grp1 DEFAULT 'X'.
  PARAMETERS:p_path TYPE rlgrap-filename MODIF ID m2 MEMORY ID m1.
SELECTION-SCREEN END OF BLOCK b2.


AT SELECTION-SCREEN OUTPUT.
* Screen modify
  PERFORM frm_modify_screen.

START-OF-SELECTION.
* Get which on radiobutton has be choosed.
  PERFORM frm_get_sel_bt.

*&---------------------------------------------------------------------*
*& Form FRM_MODIFY_SCREEN
*&---------------------------------------------------------------------*
*& Screen Modify
*&---------------------------------------------------------------------*
FORM frm_modify_screen .
  LOOP AT SCREEN.
    IF screen-name = 'P_TYPE'.
      screen-input = 0.
    ENDIF.
    IF screen-group1 = 'M2'.
      IF rb_upld = abap_on.
        screen-active = 1.
      ELSE.
        screen-active = 0.
      ENDIF.
    ENDIF.
    MODIFY SCREEN.
  ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_GET_SEL_BT
*&---------------------------------------------------------------------*
*& Get which on radiobutton has be choosed.
*&---------------------------------------------------------------------*
FORM frm_get_sel_bt .
  DATA:
    lv_bt_name TYPE string,
    lv_msg     TYPE string.

  SELECT a~kvewe,
         a~kappl,
         a~kozgf,
         a~kolnr,
         b~gstru,
         b~gstxt
    FROM t682i AS a
    LEFT OUTER JOIN tmc1t AS b
      ON concat( a~kvewe,a~kotabnr ) = b~gstru
     AND b~spras = @sy-langu
   WHERE a~kozgf = @p_type
     AND a~kvewe = 'A'
     AND a~kappl = 'V'
  INTO TABLE @DATA(lt_condtype_info).

  SORT lt_condtype_info BY gstru ASCENDING.
  DELETE ADJACENT DUPLICATES FROM lt_condtype_info COMPARING gstru.

  DATA(lv_lines) = lines( lt_condtype_info ).

  IF lines( lt_condtype_info ) > 1.
    LOOP AT lt_condtype_info INTO DATA(ls_condtype_info).
      lv_bt_name = 'RB_' && ls_condtype_info-gstru.
      ASSIGN (lv_bt_name) TO FIELD-SYMBOL(<fs_bt>).
      IF <fs_bt> IS ASSIGNED.
        IF <fs_bt> = 'X'.
          lv_msg = |You choose the button { lv_bt_name }|.
          EXIT.
        ENDIF.
      ENDIF.
    ENDLOOP.
  ELSE.
    READ TABLE lt_condtype_info INTO ls_condtype_info INDEX 1.
    lv_bt_name = 'RB_' && ls_condtype_info-gstru.
    lv_msg = |You choose the button { lv_bt_name }|.
  ENDIF.

  WRITE lv_msg.
ENDFORM.

由于标准的Selection Text的长度只有30位,而本例中按钮描述超过了30位,所以可以采用SELECTION-SCREEN BEGIN OF LINE的方式去进行选择屏幕生成。

以下为选择不同条件类型后,实际生成的动态代码:

以上。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeveloperMrMeng

觉得有用的佛系投币哦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值