ALV合并单元格
1、文章说明
在开发一些报表时,需要显示双层的标题,或者合并单元格的数据,归根结底就是要实现类似EXCEL合并单元格的需求。如图所示
网上的资料,很多根据国外某大神的方法实现:https://tricktresor.de/blog/zellen-verbinden/
本文章在测试该方法时,发现了一些问题,并根据个人实现习惯,加以优化和修改:
优化问题:
1、优化源代码只能对第1列进行垂直合并。
2、解决源代码垂直合并中,将导致下一列字段内容被清空。
本文章通过不画CONTAINER的OOALV方式实现ALV报表,虽然解决了一些BUG,但实现方法仍有很大的优化空间,读者可动手持续优化。
2、实现过程
首先创建9000屏幕
程序中根据超类,创建新的类
定义ALV对象
在ALV中预留要显示标题的空行
并去掉fieldcat自动带出来的列名
调用ALV显示方法后,开始合并单元格
垂直合并,outputlen表示向下合并几行(包含本行)
水平合并,outputlen表示向右合并到第几列
设置对应单元格的名称
3、源代码参考
"--------------------@斌将军-------------------- REPORT ybintest018. *----------------------------------------------------------------------* *表声明 *----------------------------------------------------------------------* TABLES:sscrfields." *----------------------------------------------------------------------* *类型池声明 *----------------------------------------------------------------------* TYPE-POOLS:slis. INCLUDE <cl_alv_control>. *----------------------------------------------------------------------* * 类型定义 *----------------------------------------------------------------------* TYPES:BEGIN OF ty_alv, xm TYPE char20, hsl01 TYPE acdoca-hsl, hsl02 TYPE acdoca-hsl, hsl03 TYPE acdoca-hsl, hsl04 TYPE acdoca-hsl, hsl05 TYPE acdoca-hsl, hsl06 TYPE acdoca-hsl, hsl07 TYPE acdoca-hsl, hsl08 TYPE acdoca-hsl, hsl09 TYPE acdoca-hsl, hsl10 TYPE acdoca-hsl, hsl11 TYPE acdoca-hsl, hsl12 TYPE acdoca-hsl, hz TYPE char20, END OF ty_alv. *----------------------------------------------------------------------* * 声明内表和工作区 *----------------------------------------------------------------------* DATA:gt_alv TYPE TABLE OF ty_alv, gs_alv TYPE ty_alv. FIELD-SYMBOLS:<fs_gs_alv> TYPE ty_alv. *----------------------------------------------------------------------* * ALV层级关系定义 *----------------------------------------------------------------------* CLASS zcl_gui_alv_grid DEFINITION DEFERRED. *创建ALV屏幕 DATA:g_grid_9000 TYPE REF TO zcl_gui_alv_grid, "ALV容器的实例 g_container_9000 TYPE REF TO cl_gui_docking_container, "ALV容器 不用画屏幕容器 gs_variant_9000 TYPE disvariant, gs_style TYPE lvc_s_styl, gt_fieldcat_9000 TYPE lvc_t_fcat, gs_fieldcat TYPE lvc_s_fcat, gs_layout_9000 TYPE lvc_s_layo. "ALV 控制: 布局结构 DATA:r_ucomm LIKE sy-ucomm, ok_code TYPE sy-ucomm, save_code TYPE sy-ucomm. *&---------------------------------------------------------------------* * CLASS DEFINITION 定义类/Definition class *&---------------------------------------------------------------------* CLASS zcl_gui_alv_grid DEFINITION INHERITING FROM cl_gui_alv_grid. PUBLIC SECTION. "水平合并 METHODS z_set_merge_horiz IMPORTING row TYPE i CHANGING tab_col_merge TYPE lvc_t_co01. "垂直合并 METHODS z_set_merge_vert IMPORTING row TYPE i CHANGING tab_col_merge TYPE lvc_t_co01. "标题文本 METHODS z_set_title_value IMPORTING row TYPE i col TYPE i value TYPE lvc_value. "清空单元格样式 METHODS z_init_cell_styles. "单元格样式 METHODS z_set_cell_style IMPORTING row TYPE i OPTIONAL col TYPE i OPTIONAL style TYPE lvc_style style2 TYPE lvc_style OPTIONAL. "冻结行列 METHODS z_set_fixed_col_row IMPORTING row TYPE i col TYPE i. "显示 METHODS z_display. ENDCLASS. "ZCL_GUI_ALV_GRID DEFINITION *&---------------------------------------------------------------------* * CLASS IMPLEMENTATION 实现类/Implementation class *&---------------------------------------------------------------------* CLASS zcl_gui_alv_grid IMPLEMENTATION. "水平合并 METHOD z_set_merge_horiz. * ROW - Zeile deren Spalten zusammengef�hrt werden sollen * tab_col_merge - Spalten, die zusammengef�hrt werden sollen FIELD-SYMBOLS <fs_cols> TYPE lvc_s_co01. FIELD-SYMBOLS <fs_data> TYPE lvc_s_data. DATA outputlen TYPE i. SORT tab_col_merge. * Die Spalten, die zusammengef�hrt werden sollen LOOP AT tab_col_merge ASSIGNING <fs_cols>. * ein paar Pr�fungen IF <fs_cols>-col_id LE 0. CONTINUE. ENDIF. IF <fs_cols>-outputlen LE <fs_cols>-col_id. CONTINUE. ENDIF. outputlen = <fs_cols>-outputlen - <fs_cols>-col_id. LOOP AT mt_data ASSIGNING <fs_data> WHERE row_pos = row AND ( col_pos BETWEEN <fs_cols>-col_id AND <fs_cols>-outputlen ). * Setze wie weit soll gemerged werden Von Spalte in L�nge * und zwar wird bei der 1 Spalte angefangen IF <fs_data>-col_pos = <fs_cols>-col_id. <fs_data>-mergehoriz = outputlen. * bei allen anderen, die zusammangeh�ren * muss der Wert raus, da er aus der 1. Spalte kommt * und das mergekennzeichen muss auch weg ! ELSE. CLEAR <fs_data>-mergehoriz. CLEAR <fs_data>-value. ENDIF. ENDLOOP. ENDLOOP. ENDMETHOD. "垂直合并 METHOD z_set_merge_vert. * ROW - Zeile deren Spalten zusammengef�hrt werden sollen * tab_col_merge - Spalten, die zusammengef�hrt werden sollen FIELD-SYMBOLS <fs_cols> TYPE lvc_s_co01. FIELD-SYMBOLS <fs_data> TYPE lvc_s_data. DATA:outputlen TYPE i, lv_row_end TYPE i. SORT tab_col_merge. * Die Spalten, die zusammengef�hrt werden sollen LOOP AT tab_col_merge ASSIGNING <fs_cols>. * ein paar Pr�fungen IF <fs_cols>-col_id LE 0. CONTINUE. ENDIF. * IF <fs_cols>-outputlen LE <fs_cols>-col_id. CONTINUE. ENDIF. * outputlen = <fs_cols>-outputlen - <fs_cols>-col_id. outputlen = <fs_cols>-outputlen - 1. lv_row_end = row + outputlen. LOOP AT mt_data ASSIGNING <fs_data> WHERE ( row_pos BETWEEN row AND lv_row_end ) AND col_pos = <fs_cols>-col_id. * ( col_pos BETWEEN <fs_cols>-col_id AND * <fs_cols>-outputlen ). * Setze wie weit soll gemerged werden Von Spalte in L�nge * und zwar wird bei der 1 Spalte angefangen * IF <fs_data>-col_pos = <fs_cols>-col_id. IF <fs_data>-row_pos = row. <fs_data>-mergevert = outputlen. * bei allen anderen, die zusammangeh�ren * muss der Wert raus, da er aus der 1. Spalte kommt * und das mergekennzeichen muss auch weg ! ELSE. CLEAR <fs_data>-mergevert. CLEAR <fs_data>-value. ENDIF. ENDLOOP. ENDLOOP. ENDMETHOD. "标题文本 METHOD z_set_title_value. FIELD-SYMBOLS <fs_data> TYPE lvc_s_data. LOOP AT mt_data ASSIGNING <fs_data> WHERE row_pos = row AND col_pos = col. <fs_data>-value = value. ENDLOOP. ENDMETHOD. "z_set_title_value "清空单元格样式 METHOD z_init_cell_styles. FIELD-SYMBOLS <fs_data> TYPE lvc_s_data. * Nur Spalte setze komplette Spalte LOOP AT mt_data ASSIGNING <fs_data>. <fs_data>-style = 0. ENDLOOP. ENDMETHOD. "单元格样式 METHOD z_set_cell_style. FIELD-SYMBOLS <fs_data> TYPE lvc_s_data. IF row IS INITIAL. IF col IS INITIAL. * Beides leer -> nichts zu tun. EXIT. ELSE. * Nur Spalte setze komplette Spalte LOOP AT mt_data ASSIGNING <fs_data> WHERE col_pos = col. <fs_data>-style = <fs_data>-style + style. <fs_data>-style2 = <fs_data>-style2 + style2. ENDLOOP. ENDIF. ELSE. IF col IS INITIAL. * Nur Zeile eingegeben -> komplette Zeile setzen LOOP AT mt_data ASSIGNING <fs_data> WHERE row_pos = row. <fs_data>-style = <fs_data>-style + style. <fs_data>-style2 = <fs_data>-style2 + style2. ENDLOOP. ELSE. READ TABLE mt_data ASSIGNING <fs_data> WITH KEY row_pos = row col_pos = col. IF sy-subrc EQ 0. <fs_data>-style = <fs_data>-style + style. <fs_data>-style2 = <fs_data>-style2 + style2. ELSE. EXIT. ENDIF. ENDIF. ENDIF. ENDMETHOD. "冻结行列 METHOD z_set_fixed_col_row. me->set_fixed_cols( col ). me->set_fixed_rows( row ). ENDMETHOD. "显示 METHOD z_display. DATA lv_stable TYPE lvc_s_stbl. DATA lv_soft TYPE c. **** Prepare refresh * lv_stable-row = 'X'. * lv_stable-col = 'X'. * lv_soft = 'X'. * **** Refresh table because Z_SET_CELL_STYLE adds style-values **** Refresh initializes mt_data * CALL METHOD refresh_table_display * EXPORTING * is_stable = lv_stable * i_soft_refresh = lv_soft * EXCEPTIONS * OTHERS = 1. * Jetzt noch �bertragen der ge�nderten Daten CALL METHOD me->set_data_table CHANGING data_table = mt_data[]. CALL METHOD set_auto_redraw EXPORTING enable = 1. ENDMETHOD. ENDCLASS. "ZCL_GUI_ALV_GRID IMPLEMENTATION *&---------------------------------------------------------------------* *& START-OF-SELECTION:程序运行所处理的代码 *&---------------------------------------------------------------------* START-OF-SELECTION. "获取取数 PERFORM frm_get_data. CALL SCREEN 9000. *&---------------------------------------------------------------------* *& Form FRM_GET_DATA *&---------------------------------------------------------------------* * text 获取数据 *----------------------------------------------------------------------* FORM frm_get_data. APPEND INITIAL LINE TO gt_alv. APPEND INITIAL LINE TO gt_alv. "第3行 CLEAR gs_alv. gs_alv-xm = '成本'. gs_alv-hsl01 = '10'. gs_alv-hsl02 = '20'. gs_alv-hsl03 = '30'. gs_alv-hsl04 = '40'. gs_alv-hsl05 = '50'. gs_alv-hsl06 = '60'. gs_alv-hsl07 = '70'. gs_alv-hsl08 = '80'. gs_alv-hsl09 = '90'. gs_alv-hsl10 = '100'. gs_alv-hsl11 = '110'. gs_alv-hsl12 = '120'. gs_alv-hz = '780'. APPEND gs_alv TO gt_alv. "第4行 CLEAR gs_alv. gs_alv-xm = '利润'. gs_alv-hsl01 = '110'. gs_alv-hsl02 = '120'. gs_alv-hsl03 = '130'. gs_alv-hsl04 = '140'. gs_alv-hsl05 = '150'. gs_alv-hsl06 = '160'. gs_alv-hsl07 = '170'. gs_alv-hsl08 = '180'. gs_alv-hsl09 = '190'. gs_alv-hsl10 = '1100'. gs_alv-hsl11 = '1110'. gs_alv-hsl12 = '1120'. gs_alv-hz = '4680'. APPEND gs_alv TO gt_alv. ENDFORM. " FRM_GET_DATA *&---------------------------------------------------------------------* *& Form FRM_ALV_LAYOUT_9000 *&---------------------------------------------------------------------* FORM frm_alv_layout_9000. CLEAR gs_layout_9000. gs_layout_9000-sel_mode = 'A'. "选择行模式 gs_layout_9000-cwidth_opt = 'A'. "优化列宽设置 gs_layout_9000-zebra = 'X'. "设置斑马线 gs_layout_9000-no_toolbar = 'X'. gs_layout_9000-no_headers = 'X'."不显示列名 ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_ALV_FIELDCAT_9000 *&---------------------------------------------------------------------* FORM frm_alv_fieldcat_9000. DATA:lv_times TYPE i, lv_count TYPE i, lv_fieldname TYPE lvc_fname, lv_coltext TYPE lvc_txtcol. REFRESH:gt_fieldcat_9000. 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-col_pos = &3. * gs_fieldcat-do_sum = &3. * gs_fieldcat-hotspot = &4. gs_fieldcat-icon = &4. gs_fieldcat-hotspot = &5. gs_fieldcat-no_zero = &6. gs_fieldcat-edit = &7. gs_fieldcat-datatype = &8. gs_fieldcat-inttype = &9. APPEND gs_fieldcat TO gt_fieldcat_9000. END-OF-DEFINITION. init_fill_fcat 'XM' '项目' '' '' '' '' '' '' ''. init_fill_fcat 'HSL01' 'HSL01' '' '' '' '' '' '' ''. init_fill_fcat 'HSL02' 'HSL02' '' '' '' '' '' '' ''. init_fill_fcat 'HSL03' 'HSL03' '' '' '' '' '' '' ''. init_fill_fcat 'HSL04' 'HSL04' '' '' '' '' '' '' ''. init_fill_fcat 'HSL05' 'HSL05' '' '' '' '' '' '' ''. init_fill_fcat 'HSL06' 'HSL06' '' '' '' '' '' '' ''. init_fill_fcat 'HSL07' 'HSL07' '' '' '' '' '' '' ''. init_fill_fcat 'HSL08' 'HSL08' '' '' '' '' '' '' ''. init_fill_fcat 'HSL09' 'HSL09' '' '' '' '' '' '' ''. init_fill_fcat 'HSL10' 'HSL10' '' '' '' '' '' '' ''. init_fill_fcat 'HSL11' 'HSL11' '' '' '' '' '' '' ''. init_fill_fcat 'HSL12' 'HSL12' '' '' '' '' '' '' ''. init_fill_fcat 'HZ' '汇总' '' '' '' '' '' '' ''. ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_CREATE_CONTAINER_9000 *& 创建容器 *&---------------------------------------------------------------------* FORM frm_create_container_9000. CREATE OBJECT g_container_9000 EXPORTING repid = sy-repid dynnr = '9000' * side = cl_gui_docking_container=>dock_at_right ”ALV贴屏幕右边,从屏幕右边开始算宽度 side = cl_gui_docking_container=>dock_at_top "ALV贴屏幕左边,从左边算屏幕宽度, extension = 1000 "屏幕宽度 * ratio = 95 "屏幕比例 小于5大于95会报cntl_error异常 style = cl_gui_control=>ws_child "可选参数,设置ALV是否可用手动拖动大小 EXCEPTIONS cntl_error = 1 cntl_system_error = 2 create_error = 3 lifetime_error = 4 lifetime_dynpro_dynpro_link = 5 OTHERS = 6. IF sy-subrc <> 0. MESSAGE s001(00) WITH '屏幕初始化失败'. LEAVE LIST-PROCESSING. ENDIF. * 创建容器实例 CREATE OBJECT g_grid_9000 EXPORTING i_parent = g_container_9000 EXCEPTIONS error_cntl_create = 1 error_cntl_init = 2 error_cntl_link = 3 error_dp_create = 4 OTHERS = 5. 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. *&---------------------------------------------------------------------* *& Form FRM_ALV_DISPLAY_9000 *&---------------------------------------------------------------------* FORM frm_alv_display_9000. CALL METHOD g_grid_9000->set_table_for_first_display EXPORTING is_variant = gs_variant_9000 * i_save = 'A' is_layout = gs_layout_9000 * it_toolbar_excluding = gt_exclude_9000 CHANGING it_fieldcatalog = gt_fieldcat_9000 " it_outtab = gt_alv "输出数据的内表 * it_sort = gt_sort * it_filter = gt_filt EXCEPTIONS invalid_parameter_combination = 1 program_error = 2 too_many_lines = 3 OTHERS = 4. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. "合并单元格 "垂直合并 PERFORM frm_merge_vert. "水平合并 PERFORM frm_merge_horiz. "设置标题 PERFORM frm_title_value. "设置样式 PERFORM frm_cell_style. "合并单元格后显示 g_grid_9000->z_display( ). ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_MERGE_VERT 垂直合并 *&---------------------------------------------------------------------* FORM frm_merge_vert. DATA:lt_col_merge TYPE lvc_t_co01, ls_col_merge TYPE lvc_s_co01. "纵向合并 REFRESH:lt_col_merge. CLEAR:ls_col_merge. ls_col_merge-col_id = 1. ls_col_merge-outputlen = 2."向下合并多少行(含本行) APPEND ls_col_merge TO lt_col_merge. CLEAR:ls_col_merge. ls_col_merge-col_id = 14. ls_col_merge-outputlen = 2."向下合并多少行(含本行) APPEND ls_col_merge TO lt_col_merge. "第1行的纵向合并单元格 CALL METHOD g_grid_9000->z_set_merge_vert "纵向合并 EXPORTING row = 1 CHANGING tab_col_merge = lt_col_merge. ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_MERGE_HORIZ 水平合并 *&---------------------------------------------------------------------* FORM frm_merge_horiz. DATA:lt_col_merge TYPE lvc_t_co01, ls_col_merge TYPE lvc_s_co01. "水平合并 REFRESH:lt_col_merge. CLEAR:ls_col_merge. ls_col_merge-col_id = 2. ls_col_merge-outputlen = 4."水平合并到第几列 APPEND ls_col_merge TO lt_col_merge. CLEAR:ls_col_merge. ls_col_merge-col_id = 5. ls_col_merge-outputlen = 7. APPEND ls_col_merge TO lt_col_merge. CLEAR:ls_col_merge. ls_col_merge-col_id = 8. ls_col_merge-outputlen = 10. APPEND ls_col_merge TO lt_col_merge. CLEAR:ls_col_merge. ls_col_merge-col_id = 11. ls_col_merge-outputlen = 13. APPEND ls_col_merge TO lt_col_merge. "第1行的水平合并单元格 CALL METHOD g_grid_9000->z_set_merge_horiz "水平合并 EXPORTING row = 1 CHANGING tab_col_merge = lt_col_merge. ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_CELL_STYLE 设置样式 *&---------------------------------------------------------------------* FORM frm_cell_style. "设置值效果:加粗 居中 主键颜色 gs_style-style = alv_style_font_bold + alv_style_align_center_center + alv_style_color_heading. "第1行 第1列 CALL METHOD g_grid_9000->z_set_cell_style EXPORTING row = 1 col = 1 style = gs_style-style. CALL METHOD g_grid_9000->z_set_cell_style EXPORTING row = 1 col = 2 style = gs_style-style. CALL METHOD g_grid_9000->z_set_cell_style EXPORTING row = 1 col = 5 style = gs_style-style. CALL METHOD g_grid_9000->z_set_cell_style EXPORTING row = 1 col = 8 style = gs_style-style. CALL METHOD g_grid_9000->z_set_cell_style EXPORTING row = 1 col = 11 style = gs_style-style. CALL METHOD g_grid_9000->z_set_cell_style EXPORTING row = 1 col = 14 style = gs_style-style. "冻结行和列 g_grid_9000->z_set_fixed_col_row( EXPORTING col = 1 row = 2 ). ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_TITLE_VALUE 设置标题 *&---------------------------------------------------------------------* FORM frm_title_value. CALL METHOD g_grid_9000->z_set_title_value EXPORTING row = 1 col = 1 value = '项目'. CALL METHOD g_grid_9000->z_set_title_value EXPORTING row = 1 col = 2 value = '1季度'. CALL METHOD g_grid_9000->z_set_title_value EXPORTING row = 1 col = 5 value = '2季度'. CALL METHOD g_grid_9000->z_set_title_value EXPORTING row = 1 col = 8 value = '3季度'. CALL METHOD g_grid_9000->z_set_title_value EXPORTING row = 1 col = 11 value = '4季度'. CALL METHOD g_grid_9000->z_set_title_value EXPORTING row = 1 col = 14 value = '汇总'. DATA:lv_fname TYPE lvc_value, lv_index TYPE sy-index. DO 12 TIMES. lv_fname = sy-index && '月'. lv_index = sy-index + 1. CALL METHOD g_grid_9000->z_set_title_value EXPORTING row = 2 col = lv_index value = lv_fname. ENDDO. ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_REFRESH_ALV_9000 *&---------------------------------------------------------------------* FORM frm_refresh_alv. DATA: lt_celltab TYPE lvc_t_styl, ls_celltab TYPE lvc_s_styl, ls_stable TYPE lvc_s_stbl. ls_stable-row = 'X'. "固定行 ls_stable-col = 'X'. "固定列 CHECK g_grid_9000 IS NOT INITIAL. CALL METHOD g_grid_9000->refresh_table_display EXPORTING is_stable = ls_stable * I_SOFT_REFRESH = 'X' EXCEPTIONS finished = 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. CALL METHOD cl_gui_cfw=>flush. ENDFORM. *&---------------------------------------------------------------------* *& 屏幕流 *&---------------------------------------------------------------------* MODULE status_9000 OUTPUT. SET PF-STATUS 'STANDARD_FULLSCREEN'. ENDMODULE. *&---------------------------------------------------------------------* *& 屏幕流 *&---------------------------------------------------------------------* MODULE display_alv_9000 OUTPUT. IF g_container_9000 IS INITIAL. PERFORM frm_create_container_9000. PERFORM frm_alv_fieldcat_9000. PERFORM frm_alv_layout_9000. PERFORM frm_alv_display_9000. ELSE. PERFORM frm_refresh_alv. ENDIF. ENDMODULE. *&---------------------------------------------------------------------* *& 屏幕流 *&---------------------------------------------------------------------* MODULE user_command_9000 INPUT. save_code = ok_code. CLEAR ok_code. CASE save_code. WHEN '&BACK'."设置功能键返回按钮单击事件 LEAVE TO SCREEN 0. WHEN '&EXIT'. LEAVE PROGRAM. ENDCASE. ENDMODULE. "--------------------@斌将军--------------------
4、结语
以上就是关于ALV合并单元格的介绍,希望对您有所帮助。
在总结过程中,也参考学习了以下文章:
http://t.csdnimg.cn/zAWea
定期更文,欢迎关注