动态内表

一、应用场景

当创建报表遇到行转列,或根据查询到的数据,确定显示ALV列时,可以使用动态内表,在运行是确定列数。

本实例,当查询的采购订单时,根据每个采购订单最大的行数,作为要显示的最大列,将每个采购订单的行,一列一列的显示,而不是一行行显示。

二、代码详解

1、查询数据

获取采购订单,获取采购订单最多有多少行,将来就要展示多少列

"-----------------------------@斌将军-----------------------------
FORM frm_get_data.

  DATA:lv_count TYPE i.

  SELECT
    ebeln
    ebelp
    matnr"物料
  FROM ekpo
  INTO TABLE gt_alv
  WHERE ebeln IN s_ebeln.

  IF gt_alv IS NOT INITIAL.
    SORT gt_alv BY ebeln ebelp.
    
    "判断最大的列
    CLEAR:gv_line.
    LOOP AT gt_alv INTO DATA(ls_alv).
      CLEAR:gs_alv.
      gs_alv = ls_alv.
      lv_count = lv_count + 1.
      AT END OF ebeln.
        IF gv_line < lv_count.
          gv_line = lv_count.
        ENDIF.
        CLEAR:lv_count.
      ENDAT.
    ENDLOOP.
  ELSE.
    MESSAGE '没有数据' TYPE 'S' DISPLAY LIKE 'E'.
    STOP.
  ENDIF.
ENDFORM. " FRM_GET_DATA
"-----------------------------@斌将军-----------------------------

2、通过fieldcat设置报表列

"-----------------------------@斌将军-----------------------------
  init_fill_fcat 'CHECKBOX' '状态栏' '' '' '' '' '' '' ''.
  init_fill_fcat 'EBELN' '采购订单' '' '' '' '' '' 'X' ''.
  "循环最多行项目的行数
  DO gv_line TIMES.
    CLEAR:lv_fieldname.
    lv_fieldname = 'EBELP' && sy-index.
    init_fill_fcat lv_fieldname '行号' '' '' '' '' '' 'X' ''.

    CLEAR:lv_fieldname.
    lv_fieldname = 'MATNR' && sy-index.
    init_fill_fcat lv_fieldname '物料编号' '' '' '' '' '' 'X' ''.
  ENDDO.
"-----------------------------@斌将军-----------------------------

3、根据fieldcat生成要展示的ALV内表结构

"-----------------------------@斌将军-----------------------------  
CALL METHOD cl_alv_table_create=>create_dynamic_table
    EXPORTING
      it_fieldcatalog = gt_fieldcat
    IMPORTING
      ep_table        = dy_table.

  ASSIGN dy_table->* TO <dyn_alv>.    " 用表类型指针 <dyn_table> 指向 数据对象的内容.

  CREATE DATA gs_line LIKE LINE OF <dyn_alv>.  " 建立一个与动态内表结构相同的数据对象,且数据对象为是一个结构

  ASSIGN gs_line->* TO <dyn_wa>. " 用<dyn_wa>指针指向该结构
"-----------------------------@斌将军-----------------------------

4、根据查询的数据,将行项目和物料对应到每行的列上

"-----------------------------@斌将军-----------------------------
CLEAR:lv_count.
  LOOP AT gt_alv INTO DATA(ls_alv).
    CLEAR:gs_alv.
    gs_alv = ls_alv.
    MOVE-CORRESPONDING gs_alv TO <dyn_wa>.

    lv_count = lv_count + 1.

    CLEAR:lv_fieldname.
    lv_fieldname = 'EBELP' && lv_count.
    CONDENSE lv_fieldname NO-GAPS.
    ASSIGN COMPONENT lv_fieldname OF STRUCTURE <dyn_wa> TO <dyn_field>.
    IF sy-subrc EQ 0.
      <dyn_field> = gs_alv-ebelp.
    ENDIF.

    CLEAR:lv_fieldname.
    lv_fieldname = 'MATNR' && lv_count.
    CONDENSE lv_fieldname NO-GAPS.
    ASSIGN COMPONENT lv_fieldname OF STRUCTURE <dyn_wa> TO <dyn_field>.
    IF sy-subrc EQ 0.
      <dyn_field> = gs_alv-matnr.
    ENDIF.

    AT END OF ebeln.
      APPEND <dyn_wa> TO <dyn_alv>.
      CLEAR:<dyn_wa>.
      CLEAR:lv_count.
    ENDAT.
    CLEAR:ls_alv.
  ENDLOOP.
"-----------------------------@斌将军-----------------------------

5、去掉选择框,为了获取选择框的列需要在fieldcat中添加,因为又在layout中声明了,所以要将fieldcat中的选择框去掉

"-----------------------------@斌将军----------------------------- 
 "在layout中已经定义,不需要再fieldcat中定义
  DELETE gt_fieldcat WHERE fieldname = 'CHECKBOX'.
"-----------------------------@斌将军-----------------------------

6、动态内表排序

"-----------------------------@斌将军-----------------------------  
"针对动态内表排序
  ls_sort-name = 'EBELN'.
  ls_sort-descending = ''.
  APPEND ls_sort TO lt_sort.
  SORT <dyn_alv> BY (lt_sort).
"-----------------------------@斌将军-----------------------------

三、效果展示

四、源代码

"-----------------------------@斌将军-----------------------------
REPORT ylcctest039.

*----------------------------------------------------------------------*
*表声明
*----------------------------------------------------------------------*
TABLES:sscrfields,ekpo."

*----------------------------------------------------------------------*
*类型池声明
*----------------------------------------------------------------------*
TYPE-POOLS:slis.

*----------------------------------------------------------------------*
* 类型定义
*----------------------------------------------------------------------*

TYPES:BEGIN OF ty_alv,
        ebeln    TYPE ekpo-ebeln, "采购凭证编号
        ebelp    TYPE ekpo-ebelp, "采购凭证编行号
        matnr    TYPE ekpo-matnr, "物料

        checkbox TYPE char1, "复选框
      END OF ty_alv.

*----------------------------------------------------------------------*
* 声明内表和工作区
*----------------------------------------------------------------------*
DATA:gt_alv TYPE STANDARD TABLE OF ty_alv,
     gs_alv TYPE ty_alv.

DATA:gv_line TYPE i.

DATA:dy_table TYPE REF TO data,
     gs_line  TYPE REF TO data.

FIELD-SYMBOLS:<dyn_alv>   TYPE STANDARD TABLE,
              <dyn_wa>,
              <dyn_field>.
*----------------------------------------------------------------------*
*ALV参数声明
*----------------------------------------------------------------------*

DATA: gt_fieldcat TYPE lvc_t_fcat, "字段目录内表
      gs_fieldcat TYPE lvc_s_fcat, "字段目录工作区
      gs_layout   TYPE lvc_s_layo. "用于定义ALV表单的相关格式、属性

*----------------------------------------------------------------------*
*选 择 屏 幕 定 义 块
*----------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK blk0 WITH FRAME TITLE TEXT-001.
  SELECT-OPTIONS:s_ebeln FOR ekpo-ebeln."采购凭证编号
SELECTION-SCREEN END OF BLOCK blk0.

*&---------------------------------------------------------------------*
*&  AT SELECTION-SCREEN OUTPUT:在屏幕输出前
*&---------------------------------------------------------------------*
AT SELECTION-SCREEN OUTPUT.
*  LOOP AT SCREEN.
*    IF SCREEN-GROUP1 = 'S'.
*      IF P_HTCS = 'X'.
*        IF SCREEN-GROUP1 = 'S'.
*          SCREEN-ACTIVE = '0'.
*        ENDIF.
*      ELSE.
*        IF SCREEN-GROUP1 = 'S'.
*          SCREEN-ACTIVE = '1'.
*        ENDIF.
*      ENDIF.
*    ENDIF.
*
*    IF SCREEN-NAME = 'P_WERKS'.
*      SCREEN-REQUIRED = '2'."外观上打钩必输,但不自动校验
*    ENDIF.
*    MODIFY SCREEN.
*ENDLOOP.
*----------------------------------------------------------------------*
* ALV逻辑流
*----------------------------------------------------------------------*
START-OF-SELECTION.

  "屏幕检查
  PERFORM frm_check_srceen.

  "权限检查
  PERFORM frm_check_authority.

  "获取取数
  PERFORM frm_get_data.

  "设置字段属性
  PERFORM frm_set_fieldcat.

  "设置输出格式
  PERFORM frm_set_layout.

  "创建动态内表
  PERFORM frm_create_table.

  "显示ALV
  PERFORM frm_display_alv.

*&---------------------------------------------------------------------*
*&      Form  FRM_CHECK_SRCEEN
*&---------------------------------------------------------------------*
*       text 检查必输字段
*----------------------------------------------------------------------*
FORM frm_check_srceen.
ENDFORM.

*&---------------------------------------------------------------------*
*&      Form  FRM_CHECK_AUTHORITY
*&---------------------------------------------------------------------*
*       text 权限检查
*----------------------------------------------------------------------*
FORM frm_check_authority.
*  DATA:LV_MESSAGE TYPE CHAR200.
*
*  AUTHORITY-CHECK OBJECT 'M_MSEG_WMB' ID 'WERKS' FIELD P_WERKS.
*  IF SY-SUBRC <> 0.
*    CONCATENATE '你没有' P_WERKS '工厂的权限' INTO LV_MESSAGE.
*    MESSAGE LV_MESSAGE TYPE 'S' DISPLAY LIKE 'E'.
*    STOP.
*  ENDIF.
ENDFORM.

*&---------------------------------------------------------------------*
*&      Form  FRM_GET_DATA
*&---------------------------------------------------------------------*
*       text 获取数据
*----------------------------------------------------------------------*
FORM frm_get_data.

  DATA:lv_count TYPE i.

  SELECT
    ebeln
    ebelp
    matnr"物料
  FROM ekpo
  INTO TABLE gt_alv
  WHERE ebeln IN s_ebeln.

  IF gt_alv IS NOT INITIAL.
    SORT gt_alv BY ebeln ebelp.

    "判断最大的列
    CLEAR:gv_line.
    LOOP AT gt_alv INTO DATA(ls_alv).
      CLEAR:gs_alv.
      gs_alv = ls_alv.
      lv_count = lv_count + 1.
      AT END OF ebeln.
        IF gv_line < lv_count.
          gv_line = lv_count.
        ENDIF.
        CLEAR:lv_count.
      ENDAT.
    ENDLOOP.
  ELSE.
    MESSAGE '没有数据' TYPE 'S' DISPLAY LIKE 'E'.
    STOP.
  ENDIF.
ENDFORM. " FRM_GET_DATA

*&---------------------------------------------------------------------*
*&      Form  FRM_SET_FIELDCAT
*&---------------------------------------------------------------------*
*       text 字段属性定义
*----------------------------------------------------------------------*
FORM frm_set_fieldcat .
  REFRESH gt_fieldcat.
  DEFINE  init_fill_fcat.
    CLEAR gs_fieldcat.
  gs_fieldcat-fieldname  = &1.
    gs_fieldcat-coltext    = &2.
    gs_fieldcat-scrtext_l  = &2.
    gs_fieldcat-scrtext_m  = &2.
    gs_fieldcat-scrtext_s  = &2.
    gs_fieldcat-reptext    = &2.
    gs_fieldcat-ref_table  = &3.
    gs_fieldcat-ref_field = &4.
    gs_fieldcat-f4availabl = &5.
    gs_fieldcat-icon   = &6.
    gs_fieldcat-edit = &7.
    gs_fieldcat-no_zero  = &8.
    gs_fieldcat-inttype  = &9.
    APPEND gs_fieldcat TO gt_fieldcat.
  END-OF-DEFINITION.

  DATA:lv_fieldname TYPE char30.

  init_fill_fcat 'CHECKBOX' '状态栏' '' '' '' '' '' '' ''.
  init_fill_fcat 'EBELN' '采购订单' '' '' '' '' '' 'X' ''.
  "循环最多行项目的行数
  DO gv_line TIMES.
    CLEAR:lv_fieldname.
    lv_fieldname = 'EBELP' && sy-index.
    init_fill_fcat lv_fieldname '行号' '' '' '' '' '' 'X' ''.

    CLEAR:lv_fieldname.
    lv_fieldname = 'MATNR' && sy-index.
    init_fill_fcat lv_fieldname '物料编号' '' '' '' '' '' 'X' ''.
  ENDDO.
ENDFORM. " FRM_SET_FIELDCAT

*&---------------------------------------------------------------------*
*&      Form  FRM_SET_LAYOUT
*&---------------------------------------------------------------------*
*       text  界面格式属性
*----------------------------------------------------------------------*
FORM frm_set_layout .
  CLEAR gs_layout.
  gs_layout-sel_mode   = 'A'.     "选择行模式
  gs_layout-cwidth_opt = 'A'.     "优化列宽设置
  gs_layout-zebra      = 'X'.     "设置斑马线
  gs_layout-box_fname = 'CHECKBOX'.
ENDFORM. " FRM_SET_LAYOUT

*&---------------------------------------------------------------------*
*&      Form  frm_create_table
*&---------------------------------------------------------------------*
*      创建动态内表
*----------------------------------------------------------------------*
FORM frm_create_table.

  DATA:lt_sort TYPE abap_sortorder_tab,
       ls_sort TYPE abap_sortorder.

  DATA:lv_count     TYPE i,
       lv_fieldname TYPE char30,
       lv_coltext   TYPE char40.

  CALL METHOD cl_alv_table_create=>create_dynamic_table
    EXPORTING
      it_fieldcatalog = gt_fieldcat
    IMPORTING
      ep_table        = dy_table.

  ASSIGN dy_table->* TO <dyn_alv>.    " 用表类型指针 <dyn_table> 指向 数据对象的内容.

  CREATE DATA gs_line LIKE LINE OF <dyn_alv>.  " 建立一个与动态内表结构相同的数据对象,且数据对象为是一个结构

  ASSIGN gs_line->* TO <dyn_wa>. " 用<dyn_wa>指针指向该结构

  CLEAR:lv_count.
  LOOP AT gt_alv INTO DATA(ls_alv).
    CLEAR:gs_alv.
    gs_alv = ls_alv.
    MOVE-CORRESPONDING gs_alv TO <dyn_wa>.

    lv_count = lv_count + 1.

    CLEAR:lv_fieldname.
    lv_fieldname = 'EBELP' && lv_count.
    CONDENSE lv_fieldname NO-GAPS.
    ASSIGN COMPONENT lv_fieldname OF STRUCTURE <dyn_wa> TO <dyn_field>.
    IF sy-subrc EQ 0.
      <dyn_field> = gs_alv-ebelp.
    ENDIF.

    CLEAR:lv_fieldname.
    lv_fieldname = 'MATNR' && lv_count.
    CONDENSE lv_fieldname NO-GAPS.
    ASSIGN COMPONENT lv_fieldname OF STRUCTURE <dyn_wa> TO <dyn_field>.
    IF sy-subrc EQ 0.
      <dyn_field> = gs_alv-matnr.
    ENDIF.

    AT END OF ebeln.
      APPEND <dyn_wa> TO <dyn_alv>.
      CLEAR:<dyn_wa>.
      CLEAR:lv_count.
    ENDAT.
    CLEAR:ls_alv.
  ENDLOOP.

  "在layout中已经定义,不需要再fieldcat中定义
  DELETE gt_fieldcat WHERE fieldname = 'CHECKBOX'.

  "针对动态内表排序
  ls_sort-name = 'EBELN'.
  ls_sort-descending = ''.
  APPEND ls_sort TO lt_sort.
  SORT <dyn_alv> BY (lt_sort).
ENDFORM. "

*&---------------------------------------------------------------------*
*&      Form  FRM_DISPLAY_ALV
*&---------------------------------------------------------------------*
*       text  界面显示
*----------------------------------------------------------------------*
FORM frm_display_alv .

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
    EXPORTING
      i_callback_program = sy-repid
      is_layout_lvc      = gs_layout
*     i_callback_pf_status_set = 'FRM_SET_STATUS'
*     i_callback_user_command  = 'FRM_USER_COMMAND'
      it_fieldcat_lvc    = gt_fieldcat
      i_save             = 'A'
    TABLES
      t_outtab           = <dyn_alv>
    EXCEPTIONS
      program_error      = 1
      OTHERS             = 2.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
    WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
ENDFORM. " FRM_DISPLAY_ALV
"-----------------------------@斌将军-----------------------------

 

定期更文,欢迎关注

 
posted @ 2022-05-01 11:43  斌将军  阅读(131)  评论(0编辑  收藏  举报