ABAP动态自建表维护程序Dynamin Process

  以前经常会遇到批量上传或修改数据到自建表的需求,所以在想是否可以做一个动态的程序,所有的自建表都可以用这个动态程序来维护。

于是就打算试着写动态的程序。

程序的要求:动态显示自建表ALV

      动态下载Excel模板

      根据这个Excel模板批量上传数据

      可新增修改删除数据。

首先给一个屏幕输入表名,而且要求是Z开头的自建表,因为如果允许标准表修改,准备跑路吧。

下面是定义的变量和屏幕,ALV用OO来实现,也定义类

data: g_table_name    type string,"表名
      g_table_name_zh type string,"表中文描述
      p_ename         type rlgrap-filename."Excel文件路径名

data: gt_fieldcat type lvc_t_fcat,
      gs_layout   type lvc_s_layo.

data: gt_fieldcat_excel type lvc_t_fcat."上传用的ALV

*ALV
data: g_container type ref to cl_gui_docking_container,
      g_alv_grid  type ref to cl_gui_alv_grid.

data: it_exclud_button type ui_functions."删除的按钮

**********************************************Upload Excel ALV上传用
data: g_custom_container type ref to cl_gui_custom_container,
      g_alv_grid_excel   type ref to cl_gui_alv_grid.

constants: g_custom_container_name type char20 value 'G_CUSTOM_CONTAINER'.

data: gt_fieldcat_upload type lvc_t_fcat,
      gs_layout_upload   type lvc_s_layo.

data: gt_row  type lvc_t_row,"选择行
      gt_roid type lvc_t_roid.

data: g_row_count type i."总行数



*******************************************************************

"data: g_is_show_button."是否显示批量上传按钮

data: ok_code type sy-ucomm.

data: dyn_table        type ref to data,
      dyn_table_excel  type ref to data,
      dyn_table_upload type ref to data,
      dyn_wa_upload    type ref to data.


field-symbols:         type standard table,
                 type standard table,
                type standard table,
               ,
               ,
                         type                 lvc_s_fcat.

***********************OLE
data: application type ole2_object,
      workbook    type ole2_object,
      sheet       type ole2_object,
      cell1       type ole2_object,
      cell2       type ole2_object,
      cell        type ole2_object,
      border      type ole2_object,
      merge       type ole2_object,
      column      type ole2_object,
      entirecol   type ole2_object,
      range       type ole2_object,
      row         type ole2_object,
      color       type ole2_object.

data: begin of wa_excel,
        lines(4096),
      end of wa_excel,
      it_excel like table of wa_excel.

data: g_separator,"水平分隔符
      g_rc        type i.

**************************************

***********************定义ALV事件类
class lcl_event_receiver definition deferred.

class lcl_event_receiver definition.
  public section.
    methods:
      handle_toolbar
                    for event toolbar of cl_gui_alv_grid
        importing e_object e_interactive,

      handle_user_command
                    for event user_command of cl_gui_alv_grid
        importing e_ucomm,

      handle_after_refresh
         for event  after_refresh of cl_gui_alv_grid.

endclass.

class lcl_event_receiver implementation.
  method handle_toolbar.
    perform delete_old_toolbar using e_object e_interactive.
    perform build_toolbar using e_object e_interactive.
  endmethod.

  method handle_user_command.
    perform user_command using e_ucomm.
  endmethod.

  method handle_after_refresh.
    perform user_command using 'HAREF'."刷新之后的事件
  endmethod.
endclass.

data: event_receiver type ref to lcl_event_receiver.

**************************************

*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
selection-screen begin of block b1 with frame title t1.
parameters p_tname type tabname obligatory
                                default 'SPFLI'
                                visible length 16.
selection-screen end of block b1.

SPFLI 和 SFLIGHT是系统定义练习用的表。

判断表名

form check_table_name .
  if p_tname+0(1) <> 'Z' and
     p_tname <> 'SPFLI'  and
     p_tname <> 'SFLIGHT'.
    message '只可输入自建表表名' type 'S'.
    stop.
  endif.

  data: l_exists.

  call function 'DEV_CHECK_TABLE_EXISTS'
    exporting
      i_tabname = p_tname
    importing
      e_exists  = l_exists.

  if l_exists eq ''.
    message '表名不存在' type 'S'.
    stop.
  endif.

  "获取表的中文描述
  select single ddtext from dd02t into g_table_name_zh
    where tabname = p_tname
      and ddlanguage = sy-langu.

endform. 

获取表数据

form get_table_data .
  select * from (p_tname) into corresponding fields of table .
endform.

动态创建Fieldcatlog

form create_fieldcat .

  data: structure_name type dd02l-tabname,
        ls_fieldcat    type lvc_s_fcat.

  structure_name = p_tname.

  call function 'LVC_FIELDCATALOG_MERGE'
    exporting
      i_structure_name = structure_name
    changing
      ct_fieldcat      = gt_fieldcat.

  "如果内表字段定义是用数据类型,reptext可能为空,给reptext赋值,scrtext_l为Excel输出标题使用
  loop at gt_fieldcat assigning .
    if -reptext is initial.
      if -scrtext_s is not initial.
        -scrtext_l = -reptext = -scrtext_s.
      else.
        "获取字段的描述
        select single ddtext from dd03t into -reptext
          where tabname    = p_tname
            and fieldname  = -fieldname
            and ddlanguage = sy-langu.
        -scrtext_l = -reptext.
      endif.
    endif.
    -edit = 'X'.
  endloop.

  "创建上传用的字段目录
  ls_fieldcat-fieldname = 'LIGHT'.
  ls_fieldcat-coltext = '状态'.
  ls_fieldcat-col_pos = 1.
  append ls_fieldcat to gt_fieldcat_upload.

  clear ls_fieldcat.
  ls_fieldcat-fieldname = 'MSG'.
  ls_fieldcat-coltext = '信息'.
  ls_fieldcat-col_pos = 1.
  append ls_fieldcat to gt_fieldcat_upload.

  append lines of gt_fieldcat to gt_fieldcat_upload.

  loop at gt_fieldcat_upload assigning .
    -edit = ''.
  endloop.

endform. 

动态创建内表

form create_dynamic_table .

  "创建第一个内表
  call method cl_alv_table_create=>create_dynamic_table
    exporting
      it_fieldcatalog = gt_fieldcat
    importing
      ep_table        = dyn_table.

  assign dyn_table->* to .

  "上传用的内表
  call method cl_alv_table_create=>create_dynamic_table
    exporting
      it_fieldcatalog = gt_fieldcat_upload
    importing
      ep_table        = dyn_table_upload.

  assign dyn_table_upload->* to .
  create data dyn_wa_upload like line of .
  assign dyn_wa_upload->*  to .

endform.  

创建OOALV

form alv_pbo .

  if g_alv_grid is initial.
    create object g_container
      exporting
        repid     = sy-repid
        dynnr     = sy-dynnr
        side      = cl_gui_docking_container=>dock_at_top
        extension = 1000.

    create object g_alv_grid
      exporting
        i_parent = g_container.

    create object event_receiver.
    set handler event_receiver->handle_toolbar       for g_alv_grid.
    set handler event_receiver->handle_user_command  for g_alv_grid.
    set handler event_receiver->handle_after_refresh for g_alv_grid.

    call method g_alv_grid->set_table_for_first_display
      exporting
*       i_buffer_active               =
*       i_bypassing_buffer            =
*       i_consistency_check           =
*       i_structure_name              =
*       is_variant                    =
        i_save                        = 'A'
        i_default                     = 'X'
        is_layout                     = gs_layout
*       is_print                      =
*       it_special_groups             =
        it_toolbar_excluding          = it_exclud_button
*       it_hyperlink                  =
*       it_alv_graphics               =
*       it_except_qinfo               =
*       ir_salv_adapter               =
      changing
        it_outtab                     = 
        it_fieldcatalog               = gt_fieldcat
*       it_sort                       =
*       it_filter                     =
      exceptions
        invalid_parameter_combination = 1
        program_error                 = 2
        too_many_lines                = 3
        others                        = 4.

    call method g_alv_grid->set_ready_for_input
      exporting
        i_ready_for_input = 0.
  else.
    perform refresh_alv.
  endif.

endform.  

定义OOALV按钮

form build_toolbar using p_object type ref to cl_alv_event_toolbar_set
                          p_interactive.

  data: ls_button type          stb_button,
        lt_button type table of stb_button.

  define %%add_button.
    clear ls_button.
    ls_button-function = &1.
    ls_button-icon = &2.
    ls_button-quickinfo = &3.
    ls_button-text = &4.
    append ls_button to p_object->mt_toolbar.
  end-of-definition.

  define %%add_shu_xian.
    clear ls_button.
    ls_button-butn_type = 3."竖线
    append ls_button to p_object->mt_toolbar.
  end-of-definition.

  if g_alv_grid->is_ready_for_input( ) = 0.
    %%add_shu_xian.
    %%add_button 'REFRESH' icon_refresh '刷新数据' '刷新数据'.
    %%add_shu_xian.
    %%add_button 'UPLOAD'  icon_import  '批量导入' '批量导入'.
    %%add_shu_xian.
    %%add_button 'CREATE'   icon_create      '可新增多行'     '新增'.

    %%add_button 'MODIFY'   icon_change_text '可更改一行'     '更改'.
*  %%add_button 'EDIT'     icon_change_text      '编辑'     '编辑'.
    %%add_button 'DELETE'   icon_delete           '删除'     '删除'.
  elseif g_alv_grid->is_ready_for_input( ) = 1.
    %%add_shu_xian.
    %%add_button 'SAVE_DATA' icon_system_save  '保存' '保存'.
    %%add_button 'CANCEL'    icon_system_undo  '取消' '取消'.
  endif.

endform.   

按钮动作

form user_command  using p_ucomm.

  ok_code = p_ucomm.
  case p_ucomm.
    when 'REFRESH'."刷新数据
      perform refresh_alv.
      call method g_alv_grid->set_ready_for_input
        exporting
          i_ready_for_input = 0.

    when 'UPLOAD'."上传Excel
      perform upload_excel.

    when 'CREATE'.
      perform set_alv_create.

    when 'DELETE'."删除
      data: lt_rows type lvc_t_row,
            lt_no   type lvc_t_roid,
            l_code.

      "获取所选行
      call method g_alv_grid->get_selected_rows
        importing
          et_index_rows = lt_rows
          et_row_no     = lt_no.

      if lines( lt_rows ) = 0.
        message '请选择至少一个记录行' type 'S'.
        exit.
      endif.

      call function 'POPUP_TO_CONFIRM_STEP'
        exporting
          textline1      = '确定?'
          textline2      = '确定要删除吗?'
          titel          = '删除'
          cancel_display = ''
        importing
          answer         = l_code.

      check l_code eq 'J'.

      loop at lt_rows assigning field-symbol().
        read table  assigning  index -index.
        if sy-subrc eq 0.
          delete (p_tname) from .
          if sy-subrc eq 0.
            commit work.
            message '删除成功' type 'S'.
            perform refresh_alv.
          else.
            rollback work.
            message '删除失败' type 'S'.
          endif.
        endif.
      endloop.

    when 'SAVE_DATA'.
      perform save_table_data.

    when 'MODIFY'.
      perform modify_table_data.

    when 'CANCEL'.
      perform refresh_alv.
  endcase.

endform. 

效果如图

ABAP动态自建表维护程序Dynamin Process_第1张图片

动态下载模板

form download_template_by_ole .

  data: sheet_name(10) type c,"工作表名称
        col            type i.           "列数

  sheet_name = g_table_name_zh.
  col = lines( gt_fieldcat ) - 1."不输出Client

  create object application 'Excel.Application'. "创建Excel
  set property of application 'Visible' = 0.        "设置显示
  call method of application 'WorkBooks' = workbook."获取工作簿对象
  call method of workbook 'Add'. "创建工作簿

  call method of application 'WorkSheets' = sheet   "获取第一个工作表(默认有3个)
    exporting
      #1 = 1.
  call method of sheet 'Activate'.
  set property of sheet 'Name' = sheet_name."命名工作表

  g_separator = cl_abap_char_utilities=>horizontal_tab."获取水平分隔符

  "拼接列标题
  loop at gt_fieldcat assigning  where fieldname ne 'MANDT'.
    if -scrtext_l is initial.
      -scrtext_l = -coltext.
    endif.
    concatenate wa_excel-lines -scrtext_l into wa_excel-lines separated by g_separator.
  endloop.

  shift wa_excel-lines left deleting leading g_separator."去除第一个水平分隔符
  append wa_excel to it_excel.

  "输出到剪切板
  call method cl_gui_frontend_services=>clipboard_export
    importing
      data                 = it_excel
    changing
      rc                   = g_rc
    exceptions
      cntl_error           = 1
      error_no_gui         = 2
      not_supported_by_gui = 3
      others               = 4.

  call method of sheet 'Cells' = cell"设置单元格位置
    exporting
      #1 = 1
      #2 = 1.
  call method of cell 'Select'."选择单元格
  call method of sheet 'Paste'."粘贴剪切板的内容

  "设置所有列为文本格式
  call method of sheet 'Columns' = column.
  call method of column 'AutoFit'.
  set property of column 'NumberFormatLocal' = '@'.

  """"""""""""""""""""画边框、背景颜色
  call method of sheet 'Cells' = cell1
    exporting
      #1 = 1
      #2 = 1.

  call method of sheet 'Cells' = cell2
    exporting
      #1 = 1
      #2 = col.

  call method of sheet 'Range' = cell
    exporting
      #1 = cell1
      #2 = cell2.

  "设置上下左右边框
  perform set_border using '1'.
  perform set_border using '2'.
  perform set_border using '3'.
  perform set_border using '4'.

  call method of cell 'Interior' = color.
  set property of color 'Color' = 5296274."绿色
  set property of color 'Pattern' = '1'.  "底纹
  """""""""""""""""""""""""""""""""""""""""""

  set property of application 'Visible' = 1.
  set property of application 'ScreenUpdating' = 1."屏幕刷新

  free object: application, workbook, sheet, cell, cell1, cell2, range, border.
  clear: it_excel[], wa_excel.

endform.   

其实就是根据字段目录输出,效果如图

批量上传的代码,上传是需要注意日期和时间类型,Excel转换会变成数字,所以Excel列的格式都为文本:

form read_excel.

  clear gt_fieldcat_excel[].
  free: g_custom_container.

  data: lt_raw    type truxs_t_text_data,
        number    type string value '0',
        index     type i,
        new_index type i,
        new_field type string,
        ls_fcat   type lvc_s_fcat.

  data: fields_string     type string,
        fields_string_new type string.

  "根据内表创建Excel的字段目录
  loop at gt_fieldcat assigning  where fieldname ne 'MANDT'.
    add 1 to number.
    new_field = 'COL' && number.
    ls_fcat-fieldname = new_field.
    ls_fcat-datatype = 'STRG'.
    append ls_fcat to gt_fieldcat_excel.
    clear ls_fcat.

    "拼接所有的字段名,用于判断上传的Excel是否符合内表的字段
    concatenate fields_string -scrtext_l into fields_string separated by space.
  endloop.
  condense fields_string.

  if  is not assigned.
    "动态创建Excel数据的内表
    call method cl_alv_table_create=>create_dynamic_table
      exporting
        it_fieldcatalog           = gt_fieldcat_excel
      importing
        ep_table                  = dyn_table_excel
      exceptions
        generate_subpool_dir_full = 1
        others                    = 2.

    assign dyn_table_excel->* to .
  else.
    clear: , .
  endif.

  "读取Excel
  call function 'TEXT_CONVERT_XLS_TO_SAP'
    exporting
      i_line_header        = ''
      i_tab_raw_data       = lt_raw
      i_filename           = p_ename
    tables
      i_tab_converted_data = 
    exceptions
      conversion_failed    = 1
      others               = 2.

  "判断上传的Excel是否跟模板相同
  field-symbols: ,
                 .
  read table  assigning field-symbol() index 1.

  "拼接上传的Excel列标题
  do number times.
    add 1 to index.
    assign component index of structure  to .
    concatenate fields_string_new  into fields_string_new separated by space.
  enddo.
  condense fields_string_new.

  "判断文件是否符合上传要求.
  if fields_string ne fields_string_new.
    message '上传文件里面的列标题跟内表的字段描述不一致,请使用模板上传!' type 'S' display like 'E'.
    exit.
  endif.

  "删除标题行
  delete  index 1.
  index = 0.

  "把动态的Excel数据 写入到 动态的新内表中
  new_index = 3."前3位不用赋值:灯、信息、集团
  data r_date type sy-datum.
  data r_time type sy-uzeit.
  "data r_mask type
  loop at  assigning .
    do number times.
      add 1 to index.
      add 1 to new_index.
      assign component index of structure  to .
      assign component new_index of structure  to .

      "判断字段是否有转换例程
*      describe field  edit mask data(r_mask).
*      if r_mask is not initial.
*        write  to  using edit mask r_mask .
*        clear r_mask.
*      endif.

      "判断数据类型,日期时间格式需要转换
      describe field  type data(field_type).
      if field_type = 'D'.
        perform convert_date using  changing r_date.
         = r_date.
        clear r_date.
      elseif field_type = 'T'.
        perform convert_time using  changing r_time.
         = r_time.
        clear r_time.
      elseif field_type = 'P' or field_type = 'I'.
        "金额千位有逗号,需要删除掉
        replace ',' in  with ''.
         = .
      else.
         = .
      endif.
    enddo.
    append  to .
    index = 0.
    new_index = 3.
  endloop.

  perform create_excel_alv.

endform. 

根据上传的数据显示第二个OOALV

form create_excel_alv .

  if g_alv_grid_excel is initial.
    create object g_custom_container
      exporting
        container_name = g_custom_container_name
        repid          = sy-repid
        dynnr          = sy-dynnr.

    create object g_alv_grid_excel
      exporting
        i_parent = g_custom_container.

    call method g_alv_grid_excel->set_table_for_first_display
      exporting
        is_layout       = gs_layout_upload
      changing
        it_outtab       = 
        it_fieldcatalog = gt_fieldcat_upload.
  else.
    perform refresh_upload_alv.
  endif.

endform.  

ABAP动态自建表维护程序Dynamin Process_第2张图片

 

保存上传的数据到自建表

form save_data .

  data: new_dyn_wa type ref to data.
  field-symbols: ,
                 .

  create data new_dyn_wa like line of .
  assign new_dyn_wa->* to .

  "上传的数据复制到新的结构中再执行Modify
  loop at  assigning field-symbol().
    move-corresponding  to .
    modify (p_tname) from .
    if sy-subrc eq 0.
      commit work.
      assign component 1 of structure  to ."更新状态灯
       = 3.
      assign component 2 of structure  to ."更新信息
       = '保存成功'.
    else.
      rollback work.
      assign component 1 of structure  to .
       = 1.
      assign component 2 of structure  to .
       = '保存失败'.
    endif.
  endloop.
  perform refresh_upload_alv.

endform.      

 点击上传

ABAP动态自建表维护程序Dynamin Process_第3张图片

新增一条或多条数据

form set_alv_create .

  clear: .
  perform get_selected_rows."根据选择行数,显示新增的行数
  if lines( gt_row ) > 1.
    do g_row_count times.
      append initial line to .
    enddo.
  else.
    append initial line to .
  endif.

  call method g_alv_grid->set_ready_for_input
    exporting
      i_ready_for_input = 1.

  call method g_alv_grid->refresh_table_display.
  call method cl_gui_cfw=>dispatch.

endform.  

保存数据

form save_table_data .

  data: l_index type i.

  "先清空空行
  loop at  assigning .
    l_index = sy-tabix.
    if  is initial.
      delete  index l_index.
    endif.
  endloop.
  if lines(  ) <= 0.
    message '没有数据可以保存' type 'S'. exit.
  endif.

  modify (p_tname) from table .
  if sy-subrc eq 0.
    commit work.
    perform refresh_alv.
    message '保存成功' type 'S'.
  else.
    rollback work.
    message '保存失败,请检查数据是否有误' type 'S'.
  endif.

endform.   

最后就是修改单条数据,这里以后可以优化为多条

form modify_table_data .

  data: l_index type i.
  perform get_selected_rows.
  if lines( gt_row ) > 0.

    "只获取第一条记录用作修改,此功能待优化为可多条修改
    read table gt_row assigning field-symbol() index 1.
    loop at  assigning .
      l_index = sy-tabix.
      if l_index <> -index.
        delete  index l_index.
        -index = -index - 1.
      endif.
    endloop.
  else.
    message '请选择一个记录行' type 'S'. exit.
  endif.

  call method g_alv_grid->refresh_table_display.
  call method g_alv_grid->set_ready_for_input
    exporting
      i_ready_for_input = 1.
  call method cl_gui_cfw=>dispatch.

endform.  

 

form build_toolbar using p_object type ref to cl_alv_event_toolbar_set
                          p_interactive.

  datals_button type          stb_button,
        lt_button type table of stb_button.

  define %%add_button.
    clear ls_button.
    ls_button-function &1.
    ls_button-icon &2.
    ls_button-quickinfo &3.
    ls_button-text &4.
    append ls_button to p_object->mt_toolbar.
  end-of-definition.

  define %%add_shu_xian.
    clear ls_button.
    ls_button-butn_type 3."竖线
    append ls_button to p_object->mt_toolbar.
  end-of-definition.

  if g_alv_grid->is_ready_for_input0.
    %%add_shu_xian.
    %%add_button 'REFRESH' icon_refresh '刷新数据' '刷新数据'.
    %%add_shu_xian.
    %%add_button 'UPLOAD'  icon_import  '批量导入' '批量导入'.
    %%add_shu_xian.
    %%add_button 'CREATE'   icon_create      '可新增多行'     '新增'.

    %%add_button 'MODIFY'   icon_change_text '可更改一行'     '更改'.
*  %%add_button 'EDIT'     icon_change_text      '编辑'     '编辑'.
    %%add_button 'DELETE'   icon_delete           '删除'     '删除'.
  elseif g_alv_grid->is_ready_for_input1.
    %%add_shu_xian.
    %%add_button 'SAVE_DATA' icon_system_save  '保存' '保存'.
    %%add_button 'CANCEL'    icon_system_undo  '取消' '取消'.
  endif.

endform.   

form set_alv_create .

  clear.
  perform get_selected_rows."根据选择行数,显示新增的行数
  if linesgt_row 1.
    do g_row_count times.
      append initial line to .
    enddo.
  else.
    append initial line to .
  endif.

  call method g_alv_grid->set_ready_for_input
    exporting
      i_ready_for_input 1.

  call method g_alv_grid->refresh_table_display.
  call method cl_gui_cfw=>dispatch.

endform.  

 

个人感觉这个程序并不难,各位可以写一下,或许会比我的更好更实用,或者有什么更好的建议可以留言、加wx交流。

作者:明光烁亮
出处:http://www.cnblogs.com/hezhongxun/
微信号:HEme922 欢迎加好友一起交流SAP!可以加入SAP开发交流群,共同分享经验!
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

你可能感兴趣的:(ABAP动态自建表维护程序Dynamin Process)