前面介绍了OLE输出EXCEL有个最大的特点就是慢,因为其是基于单元格层次的一个个操作去填充数据,而DOI技术采用面向对象的方法实现,解决了这个问题。至于为什么能解决,有兴趣的可以慢慢研究。
既然是使用面向对象的方法实现,当然离不开类与接口,下面介绍DOI中最常用的4种类与接口。
1.容器类:目前作者常用的两种类是CL_GUI_CONTAINER和CL_GUI_CUSTOMER_CONTAINER,在不画屏幕容器,直接使用整个屏幕作为容器时使用CL_GUI_CONTAINER创建容器实例,在画屏幕容器时使用CL_GUI_CUSTOM_CONTAINER创建容器实例。
2.控制器接口:I_OI_CONTAINER_CONTROL,这个接口的实例主要用来与屏幕容器绑定和创建参照接口I_OI_DOCUMENT_PROXY 的实例。
3.文档接口:I_OI_DOCUMENT_PROXY ,参照这个接口的实例主要用来打开和保存文件,还有创建参照接口I_OI_SPREADSHEET 的实例。
4.SHEET页接口:I_OI_SPREADSHEET,参照这个接口的实例主要用来在SHEET页层级填充数据,设置格式等。
最后给出一个简单的DEMO。
输出目标:
创建的屏幕100:
源代码:
*&---------------------------------------------------------------------* *& Report Z15540_DOI1 *&---------------------------------------------------------------------* *& *&---------------------------------------------------------------------* REPORT Z15540_DOI1. TYPE-POOLS:SOI. "数据定义 DATA:BEGIN OF GS_DATA, WERKS TYPE MARD-WERKS, LGORT TYPE MARD-LGORT, MATNR TYPE MARD-MATNR, MAKTX TYPE MAKT-MAKTX, LABST TYPE MARD-LABST, MEINS TYPE MARA-MEINS, END OF GS_DATA. DATA GT_DATA LIKE TABLE OF GS_DATA. "DOI相关定义 DATA:LCL_CONTAINER TYPE REF TO CL_GUI_CONTAINER, "容器引用对象 LCL_CONTROL TYPE REF TO I_OI_CONTAINER_CONTROL, "容器控制器引用对象 LCL_DOCUMENT TYPE REF TO I_OI_DOCUMENT_PROXY, "对应EXCEL文档层次引用对象 LCL_SHEET TYPE REF TO I_OI_SPREADSHEET. "对应SHEET层次操作的接口引用对象 START-OF-SELECTION. CALL SCREEN 100. *&---------------------------------------------------------------------* *& Form FRM_CONTAINER *&---------------------------------------------------------------------* *& text *&---------------------------------------------------------------------* *& --> p1 text *& <-- p2 text *&---------------------------------------------------------------------* FORM FRM_CONTAINER . "将CL_GUI_CONTAINER的静态属性SCREEN0付给LCL_CONTAINER,相当于以当前系统显示的整个屏幕创建一个容器实例,该例中则以屏幕100创建实例 LCL_CONTAINER = CL_GUI_CONTAINER=>SCREEN0. ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_CONTAINER_CONTROL *&---------------------------------------------------------------------* *& text *&---------------------------------------------------------------------* *& --> p1 text *& <-- p2 text *&---------------------------------------------------------------------* FORM FRM_CONTAINER_CONTROL . "实例化容器控制器 CALL METHOD C_OI_CONTAINER_CONTROL_CREATOR=>GET_CONTAINER_CONTROL IMPORTING CONTROL = LCL_CONTROL. "绑定容器与容器控制器,并初始化控制器设定 CALL METHOD LCL_CONTROL->INIT_CONTROL EXPORTING * DYNPRO_NR = SY-DYNNR * GUI_CONTAINER = ' ' INPLACE_ENABLED = 'X' "EXCEL可嵌入容器 * INPLACE_MODE = 0 * INPLACE_RESIZE_DOCUMENTS = ' ' INPLACE_SCROLL_DOCUMENTS = 'X' "可滚动 * INPLACE_SHOW_TOOLBARS = 'X' "是否展示工具栏以上 * NO_FLUSH = 'X' * PARENT_ID = cl_gui_cfw=>dynpro_0 R3_APPLICATION_NAME = 'DOI TEST' REGISTER_ON_CLOSE_EVENT = 'X' "注册关闭事件 REGISTER_ON_CUSTOM_EVENT = 'X' "注册定制事件 * REP_ID = SY-REPID * SHELL_STYLE = 1384185856 PARENT = LCL_CONTAINER * NAME = * AUTOALIGN = 'x' * IMPORTING * ERROR = * RETCODE = EXCEPTIONS JAVABEANNOTSUPPORTED = 1 OTHERS = 2. IF SY-SUBRC <> 0. * Implement suitable error handling here ENDIF. ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_CREATE_EXCEL *&---------------------------------------------------------------------* *& text *&---------------------------------------------------------------------* *& --> p1 text *& <-- p2 text *&---------------------------------------------------------------------* FORM FRM_CREATE_EXCEL . "实例化LCL_DOCUMENT CALL METHOD LCL_CONTROL->GET_DOCUMENT_PROXY EXPORTING * DOCUMENT_FORMAT = 'NATIVE' DOCUMENT_TYPE = 'EXCEL.SHEET' "应用类型 NO_FLUSH = 'X' * REGISTER_CONTAINER = ' ' IMPORTING DOCUMENT_PROXY = LCL_DOCUMENT * ERROR = * RETCODE = . "创建EXCEL文件 CALL METHOD LCL_DOCUMENT->CREATE_DOCUMENT EXPORTING * CREATE_VIEW_DATA = ' ' DOCUMENT_TITLE = 'DOI TEST' * NO_FLUSH = 'X' OPEN_INPLACE = 'X' "嵌入显示 * OPEN_READONLY = 'X' "只读 * ONSAVE_MACRO = 'X' * STARTUP_MACRO = 'X' * IMPORTING * ERROR = * RETCODE = . ENDFORM. *&---------------------------------------------------------------------* *& Form FRM_SET_DATA *&---------------------------------------------------------------------* *& text *&---------------------------------------------------------------------* *& --> p1 text *& <-- p2 text *&---------------------------------------------------------------------* FORM FRM_SET_DATA . DATA LV_ROW TYPE I."填充数据的行数 DATA:LS_RANGE TYPE SOI_RANGE_ITEM, LT_RANGE TYPE TABLE OF SOI_RANGE_ITEM, "为SET_RANGE_DATA方法标明填充数据的范围名及其行列数 LS_CONTENT TYPE SOI_GENERIC_ITEM, LT_CONTENT TYPE TABLE OF SOI_GENERIC_ITEM, "为SET_RANGE_DATA方法提供填充数据 LS_FORMATTABLE TYPE SOI_FORMAT_ITEM, "设置范围格式 LT_FORMATTABLE TYPE TABLE OF SOI_FORMAT_ITEM. "设置范围格式 DATA LV_COUNT_ROW TYPE I."当前行 DATA LV_LABST TYPE C LENGTH 18. FIELD-SYMBOLS:<FS_DATA_FILED>, <FS_CONTENT_FIELD>. SELECT MARD~WERKS, MARD~LGORT, MARD~MATNR, MAKT~MAKTX, MARD~LABST, MARA~MEINS INTO TABLE @GT_DATA UP TO 200 ROWS FROM MARD INNER JOIN MARA ON MARD~MATNR = MARA~MATNR LEFT OUTER JOIN MAKT ON MARD~MATNR = MAKT~MATNR WHERE MAKT~SPRAS = @SY-LANGU. DESCRIBE TABLE GT_DATA LINES LV_ROW."填充数据行数 DATA A1 TYPE I. CALL METHOD LCL_DOCUMENT->HAS_SPREADSHEET_INTERFACE EXPORTING NO_FLUSH = 'X' IMPORTING * ERROR = IS_AVAILABLE = A1 * RETCODE = . "实例化SHEET对象 CALL METHOD LCL_DOCUMENT->GET_SPREADSHEET_INTERFACE EXPORTING NO_FLUSH = 'X' IMPORTING * ERROR = SHEET_INTERFACE = LCL_SHEET * RETCODE = . "选中SHEET1 CALL METHOD LCL_SHEET->SELECT_SHEET EXPORTING NAME = 'Sheet1' NO_FLUSH = 'X' * IMPORTING * ERROR = * RETCODE = . *CALL METHOD LCL_SHEET->GET_ACTIVE_SHEET * EXPORTING * NO_FLUSH = 'X' ** IMPORTING ** SHEETNAME = ** ERROR = ** RETCODE = * . "创建一个左上角为第一行第一列,共计6列200行,名叫RANGE1的范围对象 CALL METHOD LCL_SHEET->INSERT_RANGE_DIM EXPORTING NO_FLUSH = 'X' NAME = 'RANGE1' LEFT = 1 TOP = 1 ROWS = LV_ROW COLUMNS = 6 * UPDATING = -1 * SHEETNAME = '' * IMPORTING * ERROR = * RETCODE = . LT_RANGE = VALUE #( ( NAME = 'RANGE1' ROWS = LV_ROW COLUMNS = '6' ) ). LOOP AT GT_DATA INTO GS_DATA. LV_COUNT_ROW = SY-TABIX. DO 6 TIMES. ASSIGN COMPONENT SY-INDEX OF STRUCTURE GS_DATA TO <FS_DATA_FILED>. LS_CONTENT-ROW = LV_COUNT_ROW. LS_CONTENT-COLUMN = SY-INDEX. IF SY-INDEX = 5. LV_LABST = <FS_DATA_FILED>. CONDENSE LV_LABST NO-GAPS. LS_CONTENT-VALUE = LV_LABST. ELSE. LS_CONTENT-VALUE = <FS_DATA_FILED>. ENDIF. APPEND LS_CONTENT TO LT_CONTENT. CLEAR LS_CONTENT. ENDDO. CLEAR GS_DATA. ENDLOOP. "填充数据 CALL METHOD LCL_SHEET->SET_RANGES_DATA EXPORTING NO_FLUSH = 'X' RANGES = LT_RANGE CONTENTS = LT_CONTENT * UPDATING = -1 * RANGESDEF = * IMPORTING * ERROR = * RETCODE = . "设置范围字体格式 LT_FORMATTABLE = VALUE #( ( NAME = 'RANGE1' SIZE = 11 BOLD = 1 ALIGN = 1 ) )."RANGE1字体大小11 加粗 水平居中 CALL METHOD LCL_SHEET->SET_RANGES_FORMAT EXPORTING FORMATTABLE = LT_FORMATTABLE NO_FLUSH = 'X' * UPDATING = -1 * IMPORTING * ERROR = * RETCODE = . "设置范围边框格式 CALL METHOD LCL_SHEET->SET_FRAME EXPORTING RANGENAME = 'RANGE1' TYP = '127' COLOR = 1 * NO_FLUSH = ' ' * IMPORTING * ERROR = * RETCODE = . "设置列自动优化 CALL METHOD LCL_SHEET->FIT_WIDEST EXPORTING NO_FLUSH = 'X' NAME = 'RANGE1' * IMPORTING * ERROR = * RETCODE = . "更改SHEET名称 CALL METHOD LCL_SHEET->SET_SHEET_NAME EXPORTING NEWNAME = '可用库存清单' OLDNAME = 'Sheet1' NO_FLUSH = 'X' * IMPORTING * ERROR = * RETCODE = . "保存文件(该方法会自动默认保存到c盘用户文件下的文档文件夹中) CALL METHOD LCL_DOCUMENT->SAVE_AS EXPORTING FILE_NAME = '可用库存清单' NO_FLUSH = 'X' * PROMPT_USER = ' ' * IMPORTING * ERROR = * RETCODE = . ENDFORM. *&---------------------------------------------------------------------* *& Module STATUS_0100 OUTPUT *&---------------------------------------------------------------------* *& *&---------------------------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET PF-STATUS 'STANDARD'. SET TITLEBAR 'DOI TEST'. "实例化容器 PERFORM FRM_CONTAINER. "创建容器控制器 PERFORM FRM_CONTAINER_CONTROL. "创建EXCEL文档 PERFORM FRM_CREATE_EXCEL. "填充数据 PERFORM FRM_SET_DATA. ENDMODULE. *&---------------------------------------------------------------------* *& Module USER_COMMAND_0100 INPUT *&---------------------------------------------------------------------* * text *----------------------------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. "退出时释放实例。 IF LCL_DOCUMENT IS NOT INITIAL. CALL METHOD LCL_DOCUMENT->CLOSE_DOCUMENT. ENDIF. IF LCL_CONTAINER IS NOT INITIAL. CALL METHOD LCL_CONTAINER->FREE. ENDIF. IF LCL_CONTROL IS NOT INITIAL. CALL METHOD LCL_CONTROL->DESTROY_CONTROL. FREE LCL_CONTROL. ENDIF. LEAVE PROGRAM. ENDMODULE.