我们都知道 ABAP Object 比传统的 ABAP 非常强大。在这里,我想分享我使用 ABAP 对象克服 SALV mdoel 限制的最佳实验之一。
起源
最初,我在 SCN 上发布了这篇文章 – ABAP 对象的强大功能:克服 SALV 模型的限制,它也受到了很多批评和赞扬。当 SCN 迁移到新系统时,代码片段格式丢失。所以,我决定将其与格式一起移动到此处。
背景
我正在阅读 CL_SALV_TABLE
上的帮助,以更深入地了解如何有效地使用这个新的 SALV 模型。当我看到 Recommendation and Restriction 部分时,我惊讶地读到“Tables displayed with ALV are not ready for input”。
我很难理解这个限制,因为:新的 SALV 模型是统一的面向对象模型,它有某种包装类,最终将 FM 称为 REUSE_ALV_GRID_DISPLAY
或 REUSE_ALV_LIST_DISPLAY
;类 GL_GUI_ALV_GRID
等。那么,如果使用 CL_GUI_ALV_GRID
创建的 ALV 可以准备好输入,为什么使用 SALV 模型创建的 ALV 不能是“准备好输入”呢?这促使我分析如何将 ALV 全屏设置为“Set ready for Input”。
寻找解决方案的旅程
通过设置断点和调试,我了解到,当我尝试生成全屏 ALV 时,它会调用 FM REUSE_ALV_GRID_DISPLAY
,而该 FM 反过来使用类 CL_GUI_ALV_GRID
来生成 ALV。
几个月前,我遇到了一个非常强大的函数模块 GET_GLOBALS_FROM_SLVC_FULLSCR
它为我们提供了 GL_GUI_ALV_GRID
类型的对象,该对象是为了生成全屏 ALV 而创建的。我已经在几个程序中使用了这个 FM 来实现一些使用 FM REUSE_ALV_GRID_DISPLAY
无法实现的功能。包括了如下这些:
- 通过在全屏 ALV 中按 Enter 键将光标移动到下一行
- 全屏 ALV:禁用键盘的 DELTE 键
- 全屏 ALV:更改小计
- 回复:我们可以滚动到 alv 网格的最后一页吗?
基本上,为了实现全屏 ALV 的这种无法实现的功能,我使用 FM GET_GLOBALS_FROM_SLVC_FULLSCR
获取对象,并使用 CL_GUI_GRID_DISPLAY
中可用的方法,然后使用 refresh
方法来刷新 ALV。
基于假设 – 如果我从 SALV 模型获取 ALV 对象,那么我可以将 SALV 模型 ALV 设置为“Set Ready for input” – 我已开始在 SALV 模型中搜索 ALV 对象。在 SALV 模型 CL_SALV_MODEL
的最顶层节点,我得到了可以为我提供 ALV Grid 对象的方法 (GET_GRID
)。
UML 图包含 SALV 层次结构和R_CONTROLLER的可见性:
类 CL_SALV_MODEL
有一个 protected 属性 R_CONTROLLER
它包含我访问 GRID 对象所需的一切。所以,我尝试直接访问该属性,但显然我没有工作,因为我没有 CL_SALV_MODEL
的对象引用。到这个时候,我已经尝试了所有正常的方法来访问R_CONTROLLER
- 比如 Feild 符号从内存中访问对象,但这也不起作用。
解决方法
我知道我必须以不同的方式思考,我尝试从 CL_SALV_MODEL_LIST
类继承该类,将 ALV 模型传递给该类,并尝试访问 R_CONTROLLER
和 BINGO
——我能够访问我继承的类中的 R_CONTROLLER
。
UML 图显示了 iherited 类以及现有的 SALV 模型:
要遵循的步骤:
- 从
CL_SALV_MODEL_LIST
继承到本地类LCL_SALV_MODEL
- 生成 SALV 模型以生成 ALV 对象
- 使 narrow casting 从 ALV 对象获取
CL_SALV_MODEL
对象 - 将此
CL_SALV_MODEL
对象传递给继承的类LCL_SALV_MODEL
。由于LCL_SALV_MODEL
是从CL_SALV_MODEL_LIST
继承的,因此它允许我访问CL_SALV_MODEL
的R_CONTROLLER
。 - 从对象
MODEL -> Controller -> Adapter -> Grid
获取 GRID 对象。 - 为 EDIT 设置布局并刷新 ALV。
当我们运行报告时,ALV 不会直接进入输入模式:
一旦我们按下“My Function”按钮,ALV 就会变成可编辑的 ALV。此 ALV 将具有其单独的 GUI 状态,其中包含可编辑 ALV 所需的所有按钮。
UML 图
代码片段的 UML 图:
以下是我用于从 SALV 模型获取 GRID 对象访问权限并使 ALV 可编辑的代码。在这里,我使用了报告程序 SALV_DEMO_TABLE_EVENTS
中提供的 PF-STATUS,以便轻松运行此演示报表。
*&---------------------------------------------------------------------*
*& Report ZTEST_NP_EDIT_SALV
*& Overcome the restriction of the SALV model using the power of the
*& Object Oriented ABAP
*&---------------------------------------------------------------------*
REPORT ztest_np_edit_salv.
*----------------------------------------------------------------------*
* Define the Local class inheriting from the CL_SALV_MODEL_LIST
* to get an access of the model, controller and adapter which inturn
* provides the Grid Object
*----------------------------------------------------------------------*
CLASS lcl_salv_model DEFINITION INHERITING FROM cl_salv_model_list.PUBLIC SECTION.DATA: o_control TYPE REF TO cl_salv_controller_model,o_adapter TYPE REF TO cl_salv_adapter.METHODS:grabe_modelIMPORTINGio_model TYPE REF TO cl_salv_model,grabe_controller,grabe_adapter.PRIVATE SECTION.DATA: lo_model TYPE REF TO cl_salv_model.
ENDCLASS. "LCL_SALV_MODEL DEFINITION
*----------------------------------------------------------------------*
* Event handler for the added buttons
*----------------------------------------------------------------------*
CLASS lcl_event_handler DEFINITION.PUBLIC SECTION.METHODS:on_user_command FOR EVENT added_function OF cl_salv_eventsIMPORTING e_salv_function.
ENDCLASS. "lcl_event_handler DEFINITION
*----------------------------------------------------------------------*
* Local Report class - Definition
*----------------------------------------------------------------------*
CLASS lcl_report DEFINITION.PUBLIC SECTION.TYPES: ty_t_sflights TYPE STANDARD TABLE OF sflights.DATA: t_data TYPE ty_t_sflights.DATA: o_salv TYPE REF TO cl_salv_table.DATA: o_salv_model TYPE REF TO lcl_salv_model.METHODS:get_data,generate_output.
ENDCLASS. "lcl_report DEFINITION
*----------------------------------------------------------------------*
* Global data
*----------------------------------------------------------------------*
DATA: lo_report TYPE REF TO lcl_report.
*----------------------------------------------------------------------*
* Start of selection
*----------------------------------------------------------------------*
START-OF-SELECTION.CREATE OBJECT lo_report.lo_report->get_data( ).lo_report->generate_output( ).
*----------------------------------------------------------------------*
* Local Report class - Implementation
*----------------------------------------------------------------------*
CLASS lcl_report IMPLEMENTATION.METHOD get_data.
* test dataSELECT * FROM sflightsINTO TABLE me->t_dataUP TO 30 ROWS.ENDMETHOD. "get_dataMETHOD generate_output.
*...New ALV Instance ...............................................TRY.cl_salv_table=>factory(EXPORTING
* r_container = w_alv1list_display = abap_falseIMPORTINGr_salv_table = o_salvCHANGINGt_table = t_data ).CATCH cx_salv_msg. "#EC NO_HANDLERENDTRY.
*...PF Status.......................................................
* Add MYFUNCTION from the report SALV_DEMO_TABLE_EVENTSo_salv->set_screen_status(pfstatus = 'SALV_STANDARD'report = 'SALV_DEMO_TABLE_EVENTS'set_functions = o_salv->c_functions_all ).
*...Event handler for the button.....................................DATA: lo_events TYPE REF TO cl_salv_events_table,lo_event_h TYPE REF TO lcl_event_handler.
* event objectlo_events = o_salv->get_event( ).
* event handlerCREATE OBJECT lo_event_h.
* setting up the event handlerSET HANDLER lo_event_h->on_user_command FOR lo_events.
*...Get Model Object ...............................................DATA: lo_alv_mod TYPE REF TO cl_salv_model.
* Narrow castinglo_alv_mod ?= o_salv.
* object for the local inherited class from the CL_SALV_MODEL_LISTCREATE OBJECT o_salv_model.
* grabe model to use it laterCALL METHOD o_salv_model->grabe_modelEXPORTINGio_model = lo_alv_mod.
*...Generate ALV output ...............................................o_salv->display( ).ENDMETHOD. "generate_output
ENDCLASS. "lcl_report IMPLEMENTATION
*----------------------------------------------------------------------*
* LCL_SALV_MODEL implementation
*----------------------------------------------------------------------*
CLASS lcl_salv_model IMPLEMENTATION.METHOD grabe_model.
* save the modello_model = io_model.ENDMETHOD. "grabe_modelMETHOD grabe_controller.
* save the controllero_control = lo_model->r_controller.ENDMETHOD. "grabe_controllerMETHOD grabe_adapter.
* save the adapter from controllero_adapter ?= lo_model->r_controller->r_adapter.ENDMETHOD. "grabe_adapter
ENDCLASS. "LCL_SALV_MODEL IMPLEMENTATION
*----------------------------------------------------------------------*
* Event Handler for the SALV
*----------------------------------------------------------------------*
CLASS lcl_event_handler IMPLEMENTATION.METHOD on_user_command.DATA: lo_grid TYPE REF TO cl_gui_alv_grid,lo_full_adap TYPE REF TO cl_salv_fullscreen_adapter.DATA: ls_layout TYPE lvc_s_layo.CASE e_salv_function.
* Make ALV as Editable ALVWHEN 'MYFUNCTION'.
* ContorllerCALL METHOD lo_report->o_salv_model->grabe_controller.
* AdapterCALL METHOD lo_report->o_salv_model->grabe_adapter.
* Fullscreen Adapter (Down Casting)lo_full_adap ?= lo_report->o_salv_model->o_adapter.
* Get the Gridlo_grid = lo_full_adap->get_grid( ).
* Got the Grid .. ?IF lo_grid IS BOUND.
* Editable ALVls_layout-edit = 'X'.
* Set the front layout of ALVCALL METHOD lo_grid->set_frontend_layoutEXPORTINGis_layout = ls_layout.
* refresh the tableCALL METHOD lo_grid->refresh_table_display.ENDIF.ENDCASE.ENDMETHOD. "on_user_command
ENDCLASS. "lcl_event_handler IMPLEMENTATION