一、应用场景
当创建报表遇到行转列,或根据查询到的数据,确定显示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
"-----------------------------@斌将军-----------------------------