* 第1步: 定义内表和工作区 TYPES: BEGIN OF ty_sflight, carrid TYPE sflight-carrid, "航空公司 connid TYPE sflight-connid, "航班号 fldate TYPE sflight-fldate, "日期 price TYPE sflight-price, "价格 currency TYPE sflight-currency, "货币 seatsmax TYPE sflight-seatsmax, "最大座位 seatsocc TYPE sflight-seatsocc, "已占座位 END OF ty_sflight.
DATA: gt_flights TYPE STANDARD TABLE OF ty_sflight, gs_flight TYPE ty_sflight.
* 第2步: 取数 SELECT carrid connid fldate price currency seatsmax seatsocc FROM sflight INTO TABLE gt_flights UP TO 100 ROWS.
FORM user_command USING pv_ucomm TYPE sy-ucomm ps_selfield TYPE slis_selfield.
CASE pv_ucomm. " 双击事件(默认功能码 &ETA 或 F2) WHEN '&ETA' OR '&IC1'. READ TABLE gt_flights INTO gs_flight INDEX ps_selfield-tabindex. IF sy-subrc = 0. MESSAGE |你双击了: { gs_flight-carrid }-{ gs_flight-connid }| TYPE 'I'. ENDIF.
" 在 USER_COMMAND 中处理 FORM user_command USING pv_ucomm TYPE sy-ucomm ps_selfield TYPE slis_selfield. IF ps_selfield-fieldname = 'CARRID' AND ps_selfield-value IS NOT INITIAL. " 跳转到航空公司详情(事务码 SE16 查看) SET PARAMETER ID 'CAR' FIELD ps_selfield-value. CALL TRANSACTION 'SAPBC400_FLIGHTS_CAR' AND SKIP FIRST SCREEN. ENDIF. ENDFORM.
" 方式二:在 USER_COMMAND 中判断 FORM user_command USING pv_ucomm TYPE sy-ucomm ps_selfield TYPE slis_selfield. IF pv_ucomm = '&ETA' OR pv_ucomm = '&IC1'. " ps_selfield-tabindex = 行号 " ps_selfield-fieldname = 列名 " ps_selfield-value = 单元格值 READ TABLE gt_flights INTO gs_flight INDEX ps_selfield-tabindex. IF sy-subrc = 0. " 显示详细信息 CALL FUNCTION 'POPUP_TO_DISPLAY_TEXT' EXPORTING titel = '详细信息' textline1 = |航空公司: { gs_flight-carrid }| textline2 = |航班号: { gs_flight-connid }| textline3 = |价格: { gs_flight-price }|. ENDIF. ENDIF. ENDFORM.
第六部分:ALV 可编辑与数据回写
6.1 整列可编辑
在 Fieldcat 中设置 edit = 'X':
LOOP AT gt_fieldcat INTO gs_fieldcat. CASE gs_fieldcat-fieldname. WHEN 'PRICE' OR 'SEATSOCC'. gs_fieldcat-edit = 'X'. "这些列可编辑 WHEN OTHERS. gs_fieldcat-edit = ''. "其他列只读 ENDCASE. MODIFY gt_fieldcat FROM gs_fieldcat. ENDLOOP.
6.2 单元格动态可编辑
通过内表中的样式字段控制每个单元格是否可编辑:
" 1. 定义内表时增加样式字段 TYPES: BEGIN OF ty_flights, carrid TYPE sflight-carrid, connid TYPE sflight-connid, price TYPE sflight-price, fldate TYPE sflight-fldate, cellstyles TYPE lvc_t_styl, "单元格样式表 END OF ty_flights.
DATA: gt_flights TYPE STANDARD TABLE OF ty_flights, gs_flight TYPE ty_flights, gs_style TYPE lvc_s_styl.
" 2. 填充数据后,设置样式 LOOP AT gt_flights INTO gs_flight. CLEAR gs_flight-cellstyles.
CASE pv_ucomm. WHEN 'SAVE'. LOOP AT gt_flights INTO gs_flight WHERE sel = 'X'. " 执行保存逻辑 UPDATE sflight SET price = gs_flight-price seatsocc = gs_flight-seatsocc WHERE carrid = gs_flight-carrid AND connid = gs_flight-connid AND fldate = gs_flight-fldate. ENDLOOP. IF sy-subrc = 0. COMMIT WORK. MESSAGE '保存成功' TYPE 'S'. ENDIF.
FORM set_status USING pt_extab TYPE slis_t_extab. " 隐藏不需要的标准按钮 DATA: lt_excl TYPE TABLE OF sy-ucomm.
APPEND '&ODN' TO lt_excl. "隐藏升序排序 APPEND '&OUP' TO lt_excl. "隐藏降序排序 APPEND '&SUM' TO lt_excl. "隐藏汇总按钮
SET PF-STATUS 'STANDARD_FULLSCREEN' EXCLUDING lt_excl. ENDFORM.
7.3 标准按钮功能码速查
功能码
说明
&ETA
双击/详细
&OUP
降序排序
&ODN
升序排序
&SUM
汇总
&RNT_PREV
打印预览
&XXL
导出到 Excel
&ABC
ABC 分析
&GRAPH
图形显示
&INFO
信息
&SORT_ASC
升序
&SORT_DSC
降序
&FILTER
过滤
&FIND
查找
&REFRESH
刷新
第八部分:ALV 颜色控制
ALV 支持三种粒度的颜色控制:行颜色、列颜色、单元格颜色。
8.1 行颜色
在内表中增加一个字段存储颜色代码,通过 Layout 的 info_fieldname 指定:
" 1. 定义内表时增加颜色字段 TYPES: BEGIN OF ty_flights, carrid TYPE sflight-carrid, connid TYPE sflight-connid, price TYPE sflight-price, rowcolor TYPE char4, "行颜色字段 END OF ty_flights.
" 2. 设置颜色值 " 颜色格式: Cxyz " C = 颜色标识(固定) " x = 颜色 (0-7): 0=无, 1=灰蓝, 2=正蓝, 3=蓝绿, 4=绿, 5=黄, 6=红, 7=粉 " y = 强化 (0=正常, 1=强化) " z = 反转 (0=背景色, 1=前景/字体色) LOOP AT gt_flights INTO gs_flight. IF gs_flight-price > 1000. gs_flight-rowcolor = 'C610'. "红色强化前景 ELSEIF gs_flight-price > 500. gs_flight-rowcolor = 'C510'. "黄色强化前景 ENDIF. MODIFY gt_flights FROM gs_flight. ENDLOOP.
" 1. 定义内表 TYPES: BEGIN OF ty_flights, carrid TYPE sflight-carrid, connid TYPE sflight-connid, price TYPE sflight-price, cellcolors TYPE lvc_t_scol, "单元格颜色表 END OF ty_flights.
DATA: gs_color TYPE lvc_s_scol.
" 2. 设置单元格颜色 LOOP AT gt_flights INTO gs_flight. CLEAR gs_flight-cellcolors.
*----------------------------------------------------------------------* * 类型定义 *----------------------------------------------------------------------* TYPES: BEGIN OF ty_sflight, carrid TYPE sflight-carrid, connid TYPE sflight-connid, fldate TYPE sflight-fldate, price TYPE sflight-price, currency TYPE sflight-currency, seatsmax TYPE sflight-seatsmax, seatsocc TYPE sflight-seatsocc, END OF ty_sflight.
*----------------------------------------------------------------------* * 全局变量 *----------------------------------------------------------------------* DATA: gt_flights TYPE STANDARD TABLE OF ty_sflight, gt_fcat TYPE lvc_t_fcat, gs_layout TYPE lvc_s_layo.
DATA: go_container TYPE REF TO cl_gui_custom_container, go_grid TYPE REF TO cl_gui_alv_grid.
*----------------------------------------------------------------------* * 事件处理类定义 *----------------------------------------------------------------------* CLASS lcl_event_handler DEFINITION. PUBLIC SECTION. " 双击事件 METHODS handle_double_click FOR EVENT double_click OF cl_gui_alv_grid IMPORTING e_row e_column es_row_no.
" 数据修改完成事件 METHODS handle_data_changed FOR EVENT data_changed_finished OF cl_gui_alv_grid IMPORTING e_modified et_good_cells.
" 工具栏按钮点击事件 METHODS handle_toolbar FOR EVENT toolbar OF cl_gui_alv_grid IMPORTING e_object e_interactive.
" 用户命令事件 METHODS handle_user_command FOR EVENT user_command OF cl_gui_alv_grid IMPORTING e_ucomm. ENDCLASS.
*----------------------------------------------------------------------* * 事件处理类实现 *----------------------------------------------------------------------* CLASS lcl_event_handler IMPLEMENTATION.
METHOD handle_double_click. READ TABLE gt_flights INTO DATA(ls_flight) INDEX e_row-index. IF sy-subrc = 0. MESSAGE |双击了第{ e_row-index }行, 列:{ e_column-fieldname }, 值:{ ls_flight-carrid }-{ ls_flight-connid }| TYPE 'I'. ENDIF. ENDMETHOD.
" 注册事件处理器 DATA: lo_event TYPE REF TO lcl_event_handler. CREATE OBJECT lo_event. SET HANDLER lo_event->handle_double_click FOR go_grid. SET HANDLER lo_event->handle_data_changed FOR go_grid. SET HANDLER lo_event->handle_toolbar FOR go_grid. SET HANDLER lo_event->handle_user_command FOR go_grid.
*----------------------------------------------------------------------* * Module: PAI *----------------------------------------------------------------------* MODULE user_command_0100 INPUT. CASE sy-ucomm. WHEN 'BACK' OR 'EXIT' OR 'CANCEL'. go_grid->free( ). go_container->free( ). LEAVE TO SCREEN 0. ENDCASE. ENDMODULE.
*----------------------------------------------------------------------* * Form: 取数 *----------------------------------------------------------------------* FORM get_data. REFRESH gt_flights. SELECT carrid connid fldate price currency seatsmax seatsocc FROM sflight INTO TABLE gt_flights UP TO 200 ROWS. ENDFORM.
*----------------------------------------------------------------------* * Form: 构建 Fieldcat *----------------------------------------------------------------------* FORM build_fieldcat. DATA: ls_fcat TYPE lvc_fcat.
CATCH cx_salv_msg INTO DATA(lx_msg). MESSAGE lx_msg->get_text( ) TYPE 'E'. ENDTRY.
10.3 SALV 事件处理类
CLASS lcl_salv_handler DEFINITION. PUBLIC SECTION. METHODS on_double_click FOR EVENT if_salv_events_actions_table~double_click OF cl_salv_events_table IMPORTING row column. ENDCLASS.
CLASS lcl_salv_handler IMPLEMENTATION. METHOD on_double_click. DATA: lt_flights TYPE STANDARD TABLE OF sflight.
" 定义主表和子表类型 TYPES: BEGIN OF ty_vbak, vbeln TYPE vbak-vbeln, erdat TYPE vbak-erdat, ernam TYPE vbak-ernam, netwr TYPE vbak-netwr, END OF ty_vbak.
TYPES: BEGIN OF ty_vbap, vbeln TYPE vbap-vbeln, posnr TYPE vbap-posnr, matnr TYPE vbap-matnr, kwmeng TYPE vbap-kwmeng, netwr TYPE vbap-netwr, END OF ty_vbap.
DATA: lt_vbak TYPE STANDARD TABLE OF ty_vbak, lt_vbap TYPE STANDARD TABLE OF ty_vbap.
" 取数 SELECT vbeln erdat ernam netwr FROM vbak INTO TABLE lt_vbak UP TO 20 ROWS. IF lt_vbap IS NOT INITIAL. SELECT vbeln posnr matnr kwmeng netwr FROM vbap INTO TABLE lt_vbap FOR ALL ENTRIES IN lt_vbak WHERE vbeln = lt_vbak-vbeln. ENDIF.
" 关联绑定 DATA: lt_binding TYPE salv_t_hierseq_binding. APPEND VALUE #( master = 'VBELN' slave = 'VBELN' ) TO lt_binding.
CATCH cx_salv_data_error cx_salv_not_found INTO DATA(lx). MESSAGE lx->get_text( ) TYPE 'E'. ENDTRY.
第十一部分:多表格 ALV(Block List)
在一个屏幕中显示多个独立表格:
REPORT zdemo_alv_block.
DATA: gt_flights TYPE STANDARD TABLE OF sflight, gt_bookings TYPE STANDARD TABLE OF sbook, gt_fieldcat1 TYPE slis_t_fieldcat_alv, gt_fieldcat2 TYPE slis_t_fieldcat_alv.
" 取数 SELECT * FROM sflight INTO TABLE gt_flights UP TO 20 ROWS. SELECT * FROM sbook INTO TABLE gt_bookings UP TO 30 ROWS.
DATA: gt_spfli TYPE STANDARD TABLE OF spfli, gt_sflight TYPE STANDARD TABLE OF sflight, go_tree TYPE REF TO cl_gui_alv_tree_simple, go_cont TYPE REF TO cl_gui_custom_container, gt_fcat TYPE lvc_t_fcat, gt_sort TYPE lvc_t_sort.
SELECT * FROM spfli INTO TABLE gt_spfli UP TO 20 ROWS. SELECT * FROM sflight INTO TABLE gt_sflight UP TO 100 ROWS.
TYPES: BEGIN OF ty_data, bukrs TYPE bukrs, ebeln TYPE ebeln, ebelp TYPE ebelp, matnr TYPE matnr, menge TYPE menge_d, status TYPE char4, "状态图标 message TYPE char100, "消息 END OF ty_data.
DATA: gt_excel TYPE TABLE OF alsmex_tabline, gt_output TYPE STANDARD TABLE OF ty_data, gs_output TYPE ty_data.
PARAMETERS: p_file TYPE rlgrap-filename OBLIGATORY.
" 文件选择 AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file. CALL FUNCTION 'F4_FILENAME' IMPORTING file_name = p_file.
" 将 Excel 行列数据转为结构化内表 SORT gt_excel BY row col. LOOP AT gt_excel INTO DATA(ls_excel). CASE ls_excel-col. WHEN 1. gs_output-bukrs = ls_excel-value. WHEN 2. gs_output-ebeln = ls_excel-value. WHEN 3. gs_output-ebelp = ls_excel-value. WHEN 4. gs_output-matnr = ls_excel-value. WHEN 5. gs_output-menge = ls_excel-value. ENDCASE.
AT END OF row. " 数据校验 IF gs_output-bukrs IS INITIAL OR gs_output-ebeln IS INITIAL. gs_output-status = icon_led_red. gs_output-message = '公司代码和采购订单不能为空'. ELSE. gs_output-status = icon_led_green. gs_output-message = '校验通过'. ENDIF. APPEND gs_output TO gt_output. CLEAR gs_output. ENDAT. ENDLOOP.
" ALV 显示 DATA: gt_fieldcat TYPE slis_t_fieldcat_alv. CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE' EXPORTING i_structure_name = 'ZEXCEL_UPLOAD_S' CHANGING ct_fieldcat = gt_fieldcat.
DATA: lo_struct TYPE REF TO cl_abap_structdescr, lo_table TYPE REF TO cl_abap_tabledescr, lt_comp TYPE cl_abap_structdescr=>component_table, ls_comp LIKE LINE OF lt_comp, lo_data TYPE REF TO data, lo_line TYPE REF TO data.
" 1. SELECT 时指定字段,避免 SELECT * SELECT carrid connid fldate price FROM sflight INTO TABLE gt_flights WHERE carrid IN s_carrid.
" 2. 使用 FOR ALL ENTRIES 替代嵌套 SELECT IF gt_flights IS NOT INITIAL. SELECT vbeln posnr matnr FROM vbap INTO TABLE gt_vbap FOR ALL ENTRIES IN gt_flights WHERE vbeln = gt_flights-vbeln. ENDIF.
" 3. 大数据量时使用分页或限制行数 SELECT ... INTO TABLE gt_data UP TO p_max ROWS.
" 4. 避免在 LOOP 中调用 FM/BAPI " 错误示范: LOOP AT gt_data INTO gs_data. CALL FUNCTION 'SOMETHING' ... "每行调一次,性能极差 ENDLOOP.
" 正确示范:批量处理 CALL FUNCTION 'SOMETHING_BATCH' "一次传入整批数据 TABLES it_data = gt_data.
" 5. ALV 显示前做 SORT SORT gt_flights BY carrid connid.