之前常常會遇到批量上傳或修改數據到自建表的需求,因此在想是否能夠作一個動態的程序,全部的自建表均可以用這個動態程序來維護。微信
因而就打算試着寫動態的程序。app
程序的要求:動態顯示自建表ALVfrontend
動態下載Excel模板ide
根據這個Excel模板批量上傳數據oop
可新增修改刪除數據。優化
首先給一個屏幕輸入表名,並且要求是Z開頭的自建表,由於若是容許標準表修改,準備跑路吧。ui
下面是定義的變量和屏幕,ALV用OO來實現,也定義類spa
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: <dyn_table> type standard table, <dyn_table_excel> type standard table, <dyn_table_upload> type standard table, <dyn_wa>, <dyn_wa_upload>, <fs_fcat> 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是系統定義練習用的表。excel
判斷表名code
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 <dyn_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 <fs_fcat>. if <fs_fcat>-reptext is initial. if <fs_fcat>-scrtext_s is not initial. <fs_fcat>-scrtext_l = <fs_fcat>-reptext = <fs_fcat>-scrtext_s. else. "獲取字段的描述 select single ddtext from dd03t into <fs_fcat>-reptext where tabname = p_tname and fieldname = <fs_fcat>-fieldname and ddlanguage = sy-langu. <fs_fcat>-scrtext_l = <fs_fcat>-reptext. endif. endif. <fs_fcat>-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 <fs_fcat>. <fs_fcat>-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 <dyn_table>. "上傳用的內表 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 <dyn_table_upload>. create data dyn_wa_upload like line of <dyn_table_upload>. assign dyn_wa_upload->* to <dyn_wa_upload>. 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 = <dyn_table> 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(<fs_row>). read table <dyn_table> assigning <dyn_wa> index <fs_row>-index. if sy-subrc eq 0. delete (p_tname) from <dyn_wa>. 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.
效果如圖
動態下載模板
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 <fs_fcat> where fieldname ne 'MANDT'. if <fs_fcat>-scrtext_l is initial. <fs_fcat>-scrtext_l = <fs_fcat>-coltext. endif. concatenate wa_excel-lines <fs_fcat>-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 <fs_fcat> 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 <fs_fcat>-scrtext_l into fields_string separated by space. endloop. condense fields_string. if <dyn_table_excel> 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 <dyn_table_excel>. else. clear: <dyn_table_excel>, <dyn_table_upload>. 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 = <dyn_table_excel> exceptions conversion_failed = 1 others = 2. "判斷上傳的Excel是否跟模板相同 field-symbols: <dyn_field_name>, <dyn_field_name_upload>. read table <dyn_table_excel> assigning field-symbol(<wa_excel>) index 1. "拼接上傳的Excel列標題 do number times. add 1 to index. assign component index of structure <wa_excel> to <dyn_field_name>. concatenate fields_string_new <dyn_field_name> 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 <dyn_table_excel> 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 <dyn_table_excel> assigning <wa_excel>. do number times. add 1 to index. add 1 to new_index. assign component index of structure <wa_excel> to <dyn_field_name>. assign component new_index of structure <dyn_wa_upload> to <dyn_field_name_upload>. "判斷字段是否有轉換例程 * describe field <dyn_field_name_upload> edit mask data(r_mask). * if r_mask is not initial. * write <dyn_field_name> to <dyn_field_name_upload> using edit mask r_mask . * clear r_mask. * endif. "判斷數據類型,日期時間格式須要轉換 describe field <dyn_field_name_upload> type data(field_type). if field_type = 'D'. perform convert_date using <dyn_field_name> changing r_date. <dyn_field_name_upload> = r_date. clear r_date. elseif field_type = 'T'. perform convert_time using <dyn_field_name> changing r_time. <dyn_field_name_upload> = r_time. clear r_time. elseif field_type = 'P' or field_type = 'I'. "金額千位有逗號,須要刪除掉 replace ',' in <dyn_field_name> with ''. <dyn_field_name_upload> = <dyn_field_name>. else. <dyn_field_name_upload> = <dyn_field_name>. endif. enddo. append <dyn_wa_upload> to <dyn_table_upload>. 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 = <dyn_table_upload> it_fieldcatalog = gt_fieldcat_upload. else. perform refresh_upload_alv. endif. endform.
保存上傳的數據到自建表
form save_data . data: new_dyn_wa type ref to data. field-symbols: <new_dyn_wa>, <new_dyn_field>. create data new_dyn_wa like line of <dyn_table>. assign new_dyn_wa->* to <new_dyn_wa>. "上傳的數據複製到新的結構中再執行Modify loop at <dyn_table_upload> assigning field-symbol(<dyn_table_wa>). move-corresponding <dyn_table_wa> to <new_dyn_wa>. modify (p_tname) from <new_dyn_wa>. if sy-subrc eq 0. commit work. assign component 1 of structure <dyn_table_wa> to <new_dyn_field>."更新狀態燈 <new_dyn_field> = 3. assign component 2 of structure <dyn_table_wa> to <new_dyn_field>."更新信息 <new_dyn_field> = '保存成功'. else. rollback work. assign component 1 of structure <dyn_table_wa> to <new_dyn_field>. <new_dyn_field> = 1. assign component 2 of structure <dyn_table_wa> to <new_dyn_field>. <new_dyn_field> = '保存失敗'. endif. endloop. perform refresh_upload_alv. endform.
點擊上傳
新增一條或多條數據
form set_alv_create . clear: <dyn_table>. perform get_selected_rows."根據選擇行數,顯示新增的行數 if lines( gt_row ) > 1. do g_row_count times. append initial line to <dyn_table>. enddo. else. append initial line to <dyn_table>. 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 <dyn_table> assigning <dyn_wa>. l_index = sy-tabix. if <dyn_wa> is initial. delete <dyn_table> index l_index. endif. endloop. if lines( <dyn_table> ) <= 0. message '沒有數據能夠保存' type 'S'. exit. endif. modify (p_tname) from table <dyn_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(<wa_row>) index 1. loop at <dyn_table> assigning <dyn_wa>. l_index = sy-tabix. if l_index <> <wa_row>-index. delete <dyn_table> index l_index. <wa_row>-index = <wa_row>-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.
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 set_alv_create .
clear: <dyn_table>.
perform get_selected_rows."根據選擇行數,顯示新增的行數
if lines( gt_row ) > 1.
do g_row_count times.
append initial line to <dyn_table>.
enddo.
else.
append initial line to <dyn_table>.
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 ECC虛擬環境,以及開發或業務視頻教程 本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。