[SAP-ABAP-DOI技术的优化与说明]
阅后感:
不错的一篇文章,自己收藏下,顺带分享给众人
看完本文章后,大家也可以学习下:DOI 的API文档。当有需求直接下载本地时,可以应用CALL i_oi_document_proxy的一个方法SAVE_AS,就可以把你的文件存到本地。其实,在应用DOI时,也无需专门定制一个容器,inplace这个参数设置成SPACE,它就会自动打开。也可以在程序中直接代码定义一个容器,而且会随着屏幕大小自动调节比例,比在屏幕中定义的更好。
不过整体来说,原作者对DOI总结的例子还是比较简洁易懂,代码整体规划还是不错的,值得推荐。
文章出处:
[转载http://blog.sina.com.cn/s/blog_4d1570de0100rsxp.html]
原文正文:
应以前一个公司的邀请,对ABAP程序使用DOI技术输出EXCEL文件的程序进行优化处理。此公司的问题是,DOI输出的EXCEL太难看了。X系列的THINKPAD看程序要来回滚动,而现在的大屏幕的台式机上的EXCEL又局限在一个小小的角落。从我的角度来看,那批程序也是太难看了。
DOI技术的优点,就不用说了!速度快,可定制EXCEL模板。缺点呢,缺点是我们ABAP顾问都太懒了,直接在网上搜到相关的程序,搞个例程下来,修理修理就成自己的了。我也在网上搜了一下,N个人的博客写的程序大同小异,甚至就是直接把别人的东西挂到自己的博客上。声讨一下,然后挂出我本人优化后的一个程序。
优化如下:
1、创建一个空屏幕上,只在屏幕上激活PAI、PBO事件下的FUNCTION MOUDLE。干嘛非要在屏幕上放一个CONTAINER组件呢,固定后那么难看。完全可以动态创建吗?动态创建使用CL_GUI_CONTAINER这个类。动态创建的好处在于,CONTAINER的大小不是固定的,完全随着屏幕的大小而创建。
2、本人发发善心,把夹杂在代码中的乱七八糟的内表与变量统统移到外面,定义成全局变量。在程序中随意定义代码的缺点都知道,就是没有人来给整理一下。本人还给这部分全局变量统计了命名规则,内表、变量、工作区分别用不同的前导符做区分。
3、把代码重新划分到不同的子程序里。通常百度出来的代码真是太乱了,我受不了。在我的项目中,非把他们开掉不可(哦,我只是一个小兵,没这个权力)。
4、OAOR上传模版这些基本知识就说了,不知道的请百度一下。
说明一下,我在程序指定了固定的区域输出数据时,不带边框;除去这一部分外,其他的部分数据输出时都加了边框,请各位兄弟姐妹们使用时注意。具体位置请搜索“CALL METHOD cl_spreadsheet->set_frame”。
废说少说,上代码:
&---------------------------------------------------------------------
*& Report ZTRAINING26 事件的使用与说明 *
*& *
&---------------------------------------------------------------------
*& Created by Xavery Hsueh on 2009-05-09. *
*& *
&---------------------------------------------------------------------
REPORT ztraining26 NO STANDARD PAGE HEADING.
** 声明数据库表 Declaration of database **
TABLES:mara. "物料主数据
** 定义结构类型 Define the structure’s type **
结果内表结构
TYPES:BEGIN OF typ_result,
matnr TYPE matnr, "物料编号
werks TYPE werks_d, "工厂
lgort TYPE lgort_d, "库存地点
charg TYPE charg_d, "批次
box TYPE c,
END OF typ_result.
** 定义变量与内表 Define the variants and Internal tables **
DATA:gt_result TYPE TABLE OF typ_result WITH HEADER LINE. "结果内表
@---------------------------------------------------------------------
*调用相关对象使用的变量
TYPE-POOLS:vrm, sbdst, soi.
定位EXCEL的单元格,
TYPES:BEGIN OF typ_excel,
row TYPE kcd_ex_row_n,
col TYPE kcd_ex_col_n,
value TYPE char50,
END OF typ_excel.
DATA:gt_tabcontent TYPE TABLE OF typ_excel.
DATA:wa_tabcontent TYPE typ_excel.
TYPES: typ_url LIKE bapiuri-uri.
TYPES: BEGIN OF typ_docu_descr,
document_name(40),
document_id(64),
END OF typ_docu_descr.
TYPES:BEGIN OF typ_area_excel,
areano(2) TYPE n,
tabcontent LIKE gt_tabcontent,
END OF typ_area_excel.
SAP Desktop Office Integration Interfaces
DATA: cl_container TYPE REF TO cl_gui_container,
cl_splitter TYPE REF TO cl_gui_splitter_container,
cl_control TYPE REF TO i_oi_container_control,
cl_docu_proxy TYPE REF TO i_oi_document_proxy,
cl_spreadsheet TYPE REF TO i_oi_spreadsheet,
cl_error TYPE REF TO i_oi_error,
cl_errors TYPE REF TO i_oi_error OCCURS 0 WITH HEADER LINE.
spreadsheet interface structures for Excel data input
DATA:wa_cellitem TYPE soi_generic_item,
wa_rangeitem TYPE soi_range_item,
gt_ranges TYPE soi_range_list,
gt_excel_input TYPE soi_generic_table,
wa_excel_input TYPE soi_generic_item,
g_initialized type c,
g_retcode TYPE soi_ret_string,
gt_excel_format TYPE soi_format_table,
wa_format LIKE LINE OF gt_excel_format.
DATA:gt_itab TYPE TABLE OF alsmex_tabline WITH HEADER LINE,
gt_imt_tab TYPE TABLE OF typ_area_excel,
wa_imt_tab LIKE LINE OF gt_imt_tab,
g_macro TYPE text100,
g_sheet(10) TYPE c,
g_cell_fit TYPE c.
DATA:cl_bds_instance TYPE REF TO cl_bds_document_set,
gt_doc_signature TYPE sbdst_signature,
wa_doc_signature LIKE LINE OF gt_doc_signature,
gt_doc_components TYPE sbdst_components,
gt_doc_uris TYPE sbdst_uri,
wa_doc_uris LIKE LINE OF gt_doc_uris.
DATA:g_app TYPE vrm_id,
gt_applist TYPE vrm_values,
g_excel TYPE text80 VALUE ‘Excel.Sheet’, "EXCEL的表单
g_docu_type TYPE text80,
g_url(256) TYPE c,
g_has_activex TYPE c,
g_col TYPE i, "字段所在的列数
g_row TYPE i. "字段所在的行数
*以下三个值为Tcode:OAOR里面新建模板文件的参数
DATA: g_classname TYPE sbdst_classname VALUE ‘HRFPM_EXCEL_STANDARD’,
g_classtype TYPE sbdst_classtype VALUE ‘OT’,
g_object_key TYPE sbdst_object_key VALUE ‘ZMB51_FZ’.
** 宏定义 Define the macro **
DEFINE m_value.
clear &1.
&1-key = &2.
&1-text = &3.
append &1.
END-OF-DEFINITION.
** 选择屏幕 Customize the selection-screen **
SELECTION-SCREEN BEGIN OF BLOCK xavery WITH FRAME TITLE text-001.
SELECT-OPTIONS:s_matnr FOR mara-matnr MEMORY ID mat. "物料编号
SELECTION-SCREEN END OF BLOCK xavery.
** 执行程序事件 Executing the program’s events **
INITIALIZATION.
START-OF-SELECTION.
PERFORM sub_query_mara.
END-OF-SELECTION.
PERFORM sub_process_excel.
CALL SCREEN 0100.
&---------------------------------------------------------------------
*& Form sub_query_mara
&---------------------------------------------------------------------
从物料主数据表MARA中取数
----------------------------------------------------------------------
FORM sub_query_mara .
** Dialog Modules PBO and PAI
MODULE status_0100 OUTPUT.
DATA: wa_tab TYPE typ_area_excel.
DATA: its_tab TYPE TABLE OF typ_excel.
SET PF-STATUS ‘XAVERY_HSUEH’.
SET TITLEBAR ‘TIT_100’ WITH ‘活动界面示例’.
PERFORM sub_create_basic_object.
LOOP AT gt_imt_tab INTO wa_tab.
REFRESH gt_itab.
gt_itab[] = wa_tab-tabcontent[].
PERFORM sub_set_cell.
ENDLOOP.
IF g_cell_fit = ‘X’.
CALL METHOD cl_spreadsheet->fit_widest
EXPORTING
name = space
no_flush = ‘X’.
ENDIF.
EXPORTING
g_macro = g_macro
** SCRIPT_NAME = ‘Open_text’
** NO_FLUSH = ’ ’
IMPORTING
cl_error = cl_errorS.
** CALL METHOD C_OI_ERRORS=>SHOW_MESSAGE
** EXPORTING
** TYPE = ‘E’.
创建相关的对象
----------------------------------------------------------------------
FORM sub_create_basic_object .
CHECK g_initialized IS INITIAL.
CALL FUNCTION ‘GUI_HAS_ACTIVEX’
IMPORTING
return = g_has_activex.
IF g_has_activex IS INITIAL.
MESSAGE e007(demoofficeintegratio).
ENDIF.
first get the SAP DOI i_oi_container_control interface
CALL METHOD
c_oi_container_control_creator=>get_container_control
IMPORTING
control = cl_control
error = cl_error.
check no errors occured
CALL METHOD cl_error->raise_message
EXPORTING
type = ‘E’.
创建CONTIANER
CREATE OBJECT cl_splitter
EXPORTING
parent = cl_gui_container=>screen0
rows = 1
columns = 1.
CALL METHOD cl_splitter->set_border
EXPORTING
border = cl_gui_cfw=>false.
cl_container = cl_splitter->get_container( row = 1 column = 1 ).
initialize the SAP DOI Container, tell it to run in the container
specified above and tell it to run Excel in-place
CALL METHOD cl_control->init_control
EXPORTING
r3_application_name = ‘RBasis’ "#EC NOTEXT
inplace_enabled = ‘X’
inplace_scroll_documents = ‘X’
parent = cl_container
register_on_close_event = ‘X’
register_on_custom_event = ‘X’
no_flush = ‘X’
IMPORTING
error = cl_errors.
save error object in collection
APPEND cl_errors.
CALL METHOD cl_gui_cfw=>dispatch.
wa_doc_signature-prop_name = ‘DESCRIPTION’.
g_app = ‘excel’. "
IF g_app = ‘excel’.
g_docu_type = g_excel.
wa_doc_signature-prop_value = ‘PP_REPORT’.
ELSE.
ENDIF.
APPEND wa_doc_signature TO gt_doc_signature.
CREATE OBJECT cl_bds_instance.
CALL METHOD cl_bds_instance->get_info
EXPORTING
classname = g_classname
classtype = g_classtype
object_key = g_object_key
CHANGING
components = gt_doc_components
signature = gt_doc_signature
EXCEPTIONS
nothing_found = 1
error_kpro = 2
internal_error = 3
parameter_error = 4
not_authorized = 5
not_allowed = 6.
CALL METHOD cl_bds_instance->get_with_url
EXPORTING
classname = g_classname
classtype = g_classtype
object_key = g_object_key
CHANGING
uris = gt_doc_uris
signature = gt_doc_signature.
FREE cl_bds_instance.
ask the SAP DOI container for a i_oi_document_proxy for Excel
CALL METHOD cl_control->get_document_proxy
EXPORTING
document_type = ‘Excel.Sheet’
no_flush = ‘X’
REGISTER_CONTAINER = 'X'
IMPORTING
document_proxy = cl_docu_proxy
error = cl_errors.
APPEND cl_errors.
open a document saved in business document service.
READ TABLE doc_uris INTO wa_doc_uris INDEX 1.
LOOP AT gt_doc_uris INTO wa_doc_uris. " WHERE uri CP ‘ZSDR17.xls’.
g_url = wa_doc_uris-uri.
ENDLOOP.
CALL METHOD cl_docu_proxy->open_document
EXPORTING
open_inplace = ‘X’
NO_FLUSH = 'X'
document_url = g_url
IMPORTING
error = cl_errors.
STARTUP_MACRO = g_macro.
DATA: has TYPE i.
CALL METHOD cl_docu_proxy->has_spreadsheet_interface
EXPORTING
no_flush = ‘X’
IMPORTING
is_available = has
error = cl_errors.
APPEND cl_errors.
CALL METHOD cl_docu_proxy->get_spreadsheet_interface
EXPORTING
no_flush = ‘X’
IMPORTING
sheet_interface = cl_spreadsheet
error = cl_errors.
APPEND cl_errors.
Activate sheet 1
g_sheet = ‘物料’.
DATA: g_def_active_sheetname(50) VALUE ‘REPORT’.
CALL METHOD cl_spreadsheet->select_sheet
EXPORTING
name = g_sheet
IMPORTING
error = cl_errors.
APPEND cl_errors.
LOOP AT cl_errorS.
CALL METHOD cl_errorS->RAISE_MESSAGE
EXPORTING
TYPE = 'E'.
ENDLOOP.
FREE cl_errors.
g_initialized = ‘X’.
ENDFORM. " FRM_CREATE_BASIC_OBJECT
&---------------------------------------------------------------------
*& Form SUB_SET_CELL
&---------------------------------------------------------------------
根据数据设置 EXCEL 表的属性
----------------------------------------------------------------------
FORM sub_set_cell .
DATA: i_top TYPE i, i_left TYPE i,
i_rows TYPE i, i_cols TYPE i,
t_row TYPE i, t_col TYPE i,
s_row TYPE i, s_col TYPE i.
SORT gt_itab BY row col.
READ TABLE gt_itab INDEX 1.
IF sy-subrc = 0.
MOVE gt_itab-row TO i_top.
MOVE gt_itab-col TO i_left.
ENDIF.
SORT gt_itab BY row DESCENDING col DESCENDING.
READ TABLE gt_itab INDEX 1.
IF sy-subrc = 0.
i_rows = gt_itab-row - i_top + 1.
i_cols = gt_itab-col - i_left + 1.
ENDIF.
SORT gt_itab BY row col.
CALL METHOD cl_spreadsheet->insert_range_dim
EXPORTING
name = ‘cell’
no_flush = ‘X’
top = i_top
left = i_left
rows = i_rows
columns = i_cols
IMPORTING
error = cl_errors.
APPEND cl_errors.
REFRESH gt_ranges.
wa_rangeitem-name = ‘cell’.
wa_rangeitem-columns = i_cols.
wa_rangeitem-rows = i_rows.
wa_rangeitem-code = 4.
APPEND wa_rangeitem TO gt_ranges.
PERFORM sub_fill_blank USING i_top i_left i_rows i_cols .
REFRESH gt_excel_input.
REFRESH gt_excel_format.
LOOP AT gt_itab.
wa_excel_input-column = gt_itab-col - i_left + 1.
wa_excel_input-row = gt_itab-row - i_top + 1.
MOVE gt_itab-value TO wa_excel_input-value.
UPDATING = '1'
no_flush = 'X'
IMPORTING 将数据填充到 EXCEL 表中
----------------------------------------------------------------------
FORM sub_fill_blank USING i_top TYPE i
i_left TYPE i
i_rows TYPE i
i_cols TYPE i .
DATA: inx_col(4) TYPE n,
inx_row(4) TYPE n.
DATA: BEGIN OF it_row OCCURS 0,
row(4) TYPE n,
END OF it_row.
MOVE i_top TO inx_row.
DO i_rows TIMES.
MOVE i_left TO inx_col.
DO i_cols TIMES.
READ TABLE gt_itab WITH KEY row = inx_row
col = inx_col.
IF sy-subrc <> 0.
MOVE inx_row TO gt_itab-row.
MOVE inx_col TO gt_itab-col.
MOVE ‘’ TO gt_itab-value.
APPEND gt_itab.
ENDIF.
ADD 1 TO inx_col.
ENDDO.
ADD 1 TO inx_row.
ENDDO.
SORT gt_itab BY row col.
ENDFORM. " SUB_FILL_BLANK
&---------------------------------------------------------------------
*& Form sub_process_excel
&---------------------------------------------------------------------
处理结果内表
----------------------------------------------------------------------
FORM sub_process_excel .
g_row = 3.
CLEAR g_col.
将数据添充到EXCEL内表中
REFRESH gt_tabcontent.
LOOP AT gt_result.
g_col = 1.
m_excel_cell gt_result-matnr.
m_excel_cell gt_result-werks.
m_excel_cell gt_result-lgort.
m_excel_cell gt_result-charg.
g_row = g_row + 1.
ENDLOOP.
wa_imt_tab-areano = 2.
wa_imt_tab-tabcontent = gt_tabcontent.
APPEND wa_imt_tab TO gt_imt_tab.
g_col = 1.
m_excel_cell ‘执行日期’.
m_excel_cell sy-datum.
m_excel_cell ‘登录用户’.
m_excel_cell sy-uname.
wa_imt_tab-areano = 1.
wa_imt_tab-tabcontent = gt_tabcontent.
APPEND wa_imt_tab TO gt_imt_tab.
ENDFORM. " sub_process_excel