原文:Small Fire · 报表开发<OO ALV> · ABAP 子专栏 · Small Fire 技术笔记

OO ALV

ALV GRID CONTROL 使用了控制器技术以实现屏幕显示,和所有的控制器一样,ALV GRID CONTROL 通过系统中的一个全局的类提供了方法,以响应它的动作.

使用了 ABAP 的对象以后,列表是通过 ALV 的一个实例 (INSTANCE) 来显示的,可以使用 ABAP 对象的事件管理.

ALV GRID继承结构 继承结构

相关类

  • CL_GUI_CUSTOM_CONTAINER:用户自己定义控件区域
  • CL_GUI_DOCKING_CONTAINER:动态创建容器,不需要在创建时绑定到预先绘制好的自定义控件中
  • CL_GUI_SPLITTER_CONTAINER:可在同一屏幕创建多个ALV显示
  • CL_GUI_ALV_GRID:ALV控制类
  • CL_GUI_CONTAINER:容器接口
  • LVC_T_FCAT:ALV显示参照字段表
  • LVC_S_FCAT:ALV显示参照字段结构
  • LVC_T_SORT: 排序条件字段

定义

​ DATA obj_wcl_container TYPE REF TO CL_GUI_CUSTOM_CONTAINER. :控制容器类

​ DATA obj_wcl_alv TYPE REF TO CL_GUI_ALV_GRID . :ALV控制类

​ DATA GS_LAYOUT1 TYPE LVC_S_LAYO. :布局结构

​ DATA GT_FIELDCAT TYPE LVC_T_FCAT. :存放字段目录的内表

​ DATA GS_FIELDCAT TYPE LVC_S_FCAT. :存放字段目录的结构

​ DATA lt_exclude TYPE ui_functions. :alv不需要的图标按钮

控制区域、Container、Grid关系

先在屏幕绘制一个用户自定义控件区域,然后以自定义区域为基础创建 CL_GUI_CUSTOM_CONTAINER 容器实例,最后以此容器实例来创建 CL_GUI_ALV_GRID 实例。首先要在程序内创建一个屏幕,并在程序中定义一个Customer Control。

屏幕定义

DATA: obj_wcl_container TYPE REF TO cl_gui_custom_container, "控制容器类"
      obj_wcl_alv TYPE REF TO cl_gui_alv_grid . "ALV控制类"
"创建SAP容器实例"
IF obj_wcl_alv IS INITIAL.
 CREATE OBJECT obj_wcl_container
	EXPORTING
      container_name  =  'CONTAINER'. "自定义控件名称"
	EXCEPTONS
      cntl_error      = 1
	  others          = 6.
  IF sy-subrc <> 0.
	MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
		WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENEIF.
"创建ALV GRID实例"
 CREATE OBJECT obj_wcl_alv
    EXPORTING
      i_parent  = obj_wcl_container.
    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.

一个屏幕创建多个ALV:

DATA:G_SPLITTER TYPE REF TO CL_GUI_SPLITTER_CONTAINER,
     G_CONTAINER_2000L TYPE REF TO CL_GUI_CONTAINER,
     G_CONTAINER_2000R TYPE REF TO CL_GUI_CONTAINER.
IF g_splitter IS INITIAL.
    CREATE OBJECT g_splitter  "定义一个屏幕包含两个ALV"
      EXPORTING
        parent  = cl_gui_container=>screen0
        rows    = 2
        columns = 1.
    CALL METHOD g_splitter->set_border
      EXPORTING
        border = cl_gui_cfw=>false.
    g_container_2000l = g_splitter->get_container( row = 1 column = 1 ).
    g_container_2000r = g_splitter->get_container( row = 2 column = 1 ).
    g_splitter->set_row_height( id = 1 height = 20 ).
    g_splitter->set_row_height( id = 2 height = 80 ).
ENDIF.

FieldCat

设置显示数据的 FieldCat。

宏定义

DEFINE M_FIELDCAT.
  CLEAR: &1.
  &1-FIELDNAME = &2 .
  &1-COLTEXT   = &3 .
  &1-CHECKBOX  = &4 .
  &1-REPREP    = &5 .
  &1-EDIT      = &6 .
  &1-OUTPUTLEN = &7 .
  &1-DECIMALS  = &8 .
  APPEND &1.
END-OF-DEFINITION.
DATA: alv1_fieldcat type standard table of lvc_s_fcat with header line.
M_FIELDCAT:
  alv1_fieldcat  'DATUM'  'Plan.Date' '' '' '' '' '',
  alv1_fieldcat  'UZEIT'  'Plan.Time' '' '' '' '' '',
  alv1_fieldcat  'STATUS' 'Status'    '' '' '' '' ''.

通过调用BAPI完成

FORM prepare_field_catalog CHANGING pt_fieldcat TYPE lvc_t_fcat .
  DATA ls_fcat type lvc_s_fcat .
  CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
    EXPORTING
      i_structure_name = 'SFLIGHT'
	CHANGING
      ct_fieldcat = pt_fieldcat[]
	EXCEPTIONS
	  inconsistent_interface = 1
	  program_error = 2
	  OTHERS = 3.
	IF sy-subrc <> 0.
	  Exception handling
	ENDIF.

  LOOP AT pt_fieldcat INTO ls_fcat .
	CASE pt_fieldcat-fieldname .
	  WHEN 'CARRID' .
		ls_fcat-outpulen = '10' .
		ls_fcat-coltext = 'Airline Carrier ID' .
		ls_fcat-edit = 'X'.
	    MODIFY pt_fieldcat FROM ls_fcat .
	  WHEN 'PAYMENTSUM' .
		ls_fcat-no_out = 'X' .
		MODIFY pt_fieldcat FROM ls_fcat .
	ENDCASE .
  ENDLOOP .
ENDFORM .

Layout

设置布局

FORM prepare_layout CHANGING ps_layout TYPE lvc_s_layo.
  ps_layout-zebra = 'X' .
  ps_layout-grid_title = 'Flights' .
  ps_layout-smalltitle = 'X' .
ENDFORM. "prepare_layout"

排除不必要的按钮

  • 自定义按钮

    DATA: lt_excl TYPE slis_t_extab.
      APPEND 'CLOSE' TO lt_excl.
      APPEND 'SALL.PUL' TO lt_excl.
      APPEND 'UALL.PUL' TO lt_excl.
    SET PF-STATUS 'STATUS' EXCLUDING lt_excl .
    SET TITLEBAR 'TITLE'.
    
  • 系统标准按钮

    FORM exclude_tb_functions CHANGING pt_exclude TYPE ui_functions .
      DATA ls_exclude TYPE ui_func.
      ls_exclude = cl_gui_alv_grid=>mc_fc_maximum .
      APPEND ls_exclude TO pt_exclude.
      ls_exclude = cl_gui_alv_grid=>mc_fc_minimum .
      APPEND ls_exclude TO pt_exclude.
      ls_exclude = cl_gui_alv_grid=>mc_fc_subtot .
      APPEND ls_exclude TO pt_exclude.
      ls_exclude = cl_gui_alv_grid=>mc_fc_sum .
      APPEND ls_exclude TO pt_exclude.
      ls_exclude = cl_gui_alv_grid=>mc_fc_average .
      APPEND ls_exclude TO pt_exclude.
      ls_exclude = cl_gui_alv_grid=>mc_mb_sum .
      APPEND ls_exclude TO pt_exclude.
      ls_exclude = cl_gui_alv_grid=>mc_mb_subtot .
      APPEND ls_exclude TO pt_exclude.
    ENDFORM .
    

ALV显示

显示 ALV

CL_GUI_ALV_GRID 重要方法 set_table_for_first_display。

CALL METHOD obj_wcl_alv->set_table_for_first_display
   EXPORTING
     i_structure_name             = 'XXXX'       "参照表结构字段显示"
     is_variant                    = ls_variant  "指定布局变式"
     is_layout                     = ls_layout   "布局设置"
     i_save                        = 'A'         "保存表格布局"
     it_toolbar_excluding          = lt_exclude  "排除的按钮"
   CHANGING
     it_outtab                     = gt_list[]   "需要显示的内表数据"
     it_fieldcatalog               = lt_fieldcat "结构字段"
   EXCEPTIONS
     invalid_parameter_combination = 1
     program_error                 = 2
     too_many_lines                = 3
     OTHERS                        = 4.

刷新 ALV

REFRESH_TABLE_DISPLAY

  • IS_STABLE:有行列两个参数,如果设置了相应的参数,对应的行或列属性就不会滚动。刷新的稳定性,就是滚动条保持不动。
  • I_SOFT_REFRESH:软刷新,为了显示数据而设置的过滤都将保持不变。临时给 ALV 创建的合计,排序,等保持不变。
CALL METHOD obj_wcl_alv->refresh_table_display
  EXPORTING
  	"IS_STABLE = "
	I_SOFT_REFRESH = 'X'
  EXCEPTIONS
	finished = 1
	OTHERS = 2 .
IF sy-subrc <> 0.
  "Exception handling"
ENDIF.

给ALV对象注册事件

(1) HANDLE_TOOLBAR:这个事件用于给ALV加自定义工具条按钮。

(2) HANDLE_CLICK:用于给ALV点击其中一行后处理代码段。

(3) HANDLE_COMMAND:事件用于接收用户按了自定义按钮后,触发的代码段。

(4) HANDLE_DOUBLE_CLICK:双击事件

(5) DATA_CHANGED:可编辑字段的数据发生变化时触发,可用来检查数据的输入正确性

(6) DATA_CHANGED_FINISHED:当数据修改完成后触发,数据没有被修改,当失去焦点或回车时触发

……

定义事件

CLASS cl_event_receiver DEFINITION.
  PUBLIC SECTION.
    "声明单击事件的方法"
    METHODS handle_hotspot_click
      FOR EVENT hotspot_click OF cl_gui_alv_grid
      IMPORTING e_row_id e_column_id.
    "声明双击事件方法"
    METHODS handle_double_click
      FOR EVENT double_click OF cl_gui_alv_grid
      IMPORTING e_row e_column.
    "声明 Toolbar 事件方法"
    METHODS handle_toolbar
      FOR EVENT toolbar OF cl_gui_alv_grid
      IMPORTING e_object e_interactive.
    "声明 USER-COMMAND 事件方法"
    METHODS handle_command
      FOR EVENT user_command OF cl_gui_alv_grid
      IMPORTING e_ucomm.
ENDCLASS.                    "cl_event_receiver DEFINITION"

事件执行的方法代码

CLASS cl_event_receiver IMPLEMENTATION.
  "单击事件方法的实现"
  METHOD handle_hotspot_click.
    CONDENSE e_row_id     NO-GAPS.
    CONDENSE e_column_id  NO-GAPS.
    MESSAGE i001(00) WITH ' 单击事件 -> 行号:' e_row_id  '、列名:' e_column_id.
  ENDMETHOD.                    "handle_HOTSPOT_CLICK"
  "双击事件方法的实现"
  METHOD handle_double_click.
    CONDENSE e_row     NO-GAPS.
    CONDENSE e_column  NO-GAPS.
    MESSAGE i001(00) WITH ' 双击事件 -> 行号:' e_row  '、列名:' e_column.
  ENDMETHOD.                    "handle_double_click"
  "实现 Toolbar 事件方法"
  METHOD handle_toolbar.
    DATA: ls_toolbar TYPE stb_button.
    CLEAR: ls_toolbar.
    ls_toolbar-butn_type = 3.   "分隔符"
    APPEND ls_toolbar TO e_object->mt_toolbar.
    CLEAR: ls_toolbar.
    ls_toolbar-function = 'DISP'.    "功能码"
    ls_toolbar-icon = icon_display.  "图标名称"
    ls_toolbar-quickinfo = ' 显示'.   "图标的提示信息"
    ls_toolbar-butn_type = 0.        "0 表示正常按钮"
    ls_toolbar-disabled = ''.        "X 表示灰色,不可用"
    ls_toolbar-text = 'btn1'.      "按钮上显示的文本"
    APPEND ls_toolbar TO e_object->mt_toolbar.
  ENDMETHOD.                    "handle_toolbar"
  "实现 USER-COMMAND 事件方法"
  METHOD handle_command.
    CASE e_ucomm.
    WHEN 'DISP'.
       MESSAGE i001(00) WITH 'Toolbar 事件 + USER-COMMAND 事件 '.
    ENDCASE.
  ENDMETHOD.                    "HANDLE_COMMAND"
ENDCLASS.                    "cl_event_receiver IMPLEMENTATION"

注册事件

在创建GRID实例后注册事件:

CREATE OBJECT event_receiver.
  "注册事件 handler 方法"
   SET HANDLER event_receiver->handle_hotspot_click  FOR g_grid01.
   SET HANDLER event_receiver->handle_double_click   FOR g_grid01.
   SET HANDLER event_receiver->handle_toolbar FOR g_grid01.
   SET HANDLER event_receiver->handle_command FOR g_grid01.

单元格编辑

设置FIELDCAT的 EDIT 属性。还需要在显示ALV前添加触发数据改变事件:

CALL METHOD ALV_GRID->REGISTER_EDIT_EVENT
  EXPORTING
    I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVT_MODIFIED. "必须设置一种触发方式"
  • 按回车触发:I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVENT_ENTER.
  • 单元格失去焦点触发:I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVENT_MODIFIES.

第一次显示后修改 Field Catalog 或 Layout

  • Field Catalog

    • get_frontend_fieldcatalog
    • set_frontend_fieldcatalog
  • Layout

    • get_frontend_layout
    • set_frontend_layout
DATA ls_fcat TYPE lvc_s_fcat .
DATA lt_fcat TYPE lvc_t_fcat .
DATA ls_layout TYPE lvc_s_layo .
"Field Cattalog"
CALL METHOD gr_alvgrid->get_frontend_fieldcatalog
  IMPORTING
    et_fieldcatalog = lt_fcat[] .
LOOP AT lt_fcat INTO ls_fcat .
  IF ls_fcat-fieldname = 'Field_name' .
    ls_fcat-no_out = space .
    MODIFY lt_fcat FROM ls_fcat .
  ENDIF .
ENDLOOP .
CALL METHOD gr_alvgrid->set_frontend_fieldcatalog
  EXPORTING
    it_fieldcatalog = lt_fcat[] .
"Layout"
CALL METHOD gr_alvgrid->get_frontend_layout
  IMPORTING
    es_layout = ls_layout .
    ls_layout-grid_title = 'Title name' .
CALL METHOD gr_alvgrid->set_frontend_layout
  EXPORTING
    is_layout = ls_layout .

排序

初始化排序功能,在set_table_for_first_display中添加参数IT_SORT.如果排序字段在Field catalog会出现Dump。

FORM prepare_sort_table CHANGING pt_sort TYPE lvc_t_sort .
  DATA ls_sort TYPE lvc_s_sort .
  ls_sort-spos = '1' .
  ls_sort-fieldname = 'XXXX' .
  ls_sort-up = 'X' . "A to Z"
  ls_sort-down = space .
  APPEND ls_sort TO pt_sort .
  ls_sort-spos = '2' .
  ls_sort-fieldname = 'XXXX' .
  ls_sort-up = space .
  ls_sort-down = 'X' . "Z to A"
  APPEND ls_sort TO pt_sort .
ENDFORM. "prepare_sort_table"