需求分析:
1、具体需求
本《设计界面管理订单》有如下需求:
- 程序执行后,显示初始界面,在界面中可以输入订单号后,点击按钮进行新建、修改、查看和删除的操作;
- 在点击“新建订单”时,如果输入的订单编号在订单表中已存在,则发出错误提示且停止创建操作;否则在订单维护界面中维护订单的具体信息,包括订单相关的员工、雇员、物料等信息;
- 在点击“修改订单”时,如果输入的订单编号在订单表中不存在,或输入的订单编号在10000~60000范围,则发出错误提示且停止修改操作;否则打开订单维护界面以进行更改;
- 在点击“查看订单”时,如果输入的订单编号在订单表中不存在,则发出错误提示且停止查看操作;否则打开显示订单的详细;
- 在点击“删除订单”时,如果输入的订单编号在订单表中不存在,或输入的订单编号在10000~60000范围,则发出错误提示且停止删除操作;否则将删除此订单编号的记录及返回提示;
- 在“新建订单”和“修改订单”操作的订单维护界面中,如果输入了数据后,还没点击“保存”前点击了“返回”,则弹出窗口给用户进行确认是否保存。
2、开发分析
要达成本实践目标,将需要使用ABAP的数据处理和界面设计技术,程序流程分析如下。
图9- 34 程序流程
实践步骤:
本实践可以在ABAP工作台(SE80)完成所有工作,也可以通过不同的工具完成不同部分。
No | 部分 | 说明 | 事务代码 |
---|---|---|---|
1 | 建立程序 | 建立本实践的程序,设置程序基本信息。 | SE38 |
2 | GUI状态标题设计 | 设计GUI状态,增加相应的功能以接受用户的指令;设计GUI标题,以在程序运行时显示在界面的标题上。 | SE41 |
3 | 屏幕设计 | 根据实践需求设计屏幕,并将相关元素添加到屏幕上。 | SE51 |
4 | 代码编写 | 编写代码以进行变量定义、数据获取、输出数据到界面等。 | SE38 |
4.1 | 对象定义 | 定义要使用的变量,以在程序执行过程中计算和存储临时值。 | |
4.2 | 程序初始事件 | 通过START-OF-SELECTION执行程序初始事件。 | |
4.3 | 屏幕100事件 | 对于屏幕100,数据输出到屏幕前的处理(PBO事件);以及在用户点击按钮后触发相应操作(PAI事件)。 | |
4.4 | 屏幕150事件 | 对于屏幕150,数据输出到屏幕前的处理(PBO事件);以及在用户点击按钮后触发相应操作(PAI事件)。 | |
4.5 | 子程序 | 根据程序执行的过程将部分代码封装为主程序,以实现代码重用、提高效率和提高代码可读性。 |
1、建立程序
与一般程序的建立过程一样,在程序编辑器初始界面输入程序名称后点击创建,设置类型和状态后,将进入程序编辑器界面,默认代码如下,不改动内容,保存后退出。
REPORT zu0902_order_trans.
2、GUI状态标题设计
使用菜单设计器(SE41),完成GUI状态和GUI标题的设计。
2.1、建立状态
在本实践中,在程序执行初始界面和订单维护的界面都会有相应的工具栏,因此需要建立2个相应的GUI状态,本步骤可参考实践9A1完成。
1)GUI状态STAT1
GUI状态STAT1的模拟结果如图9-35所示,编辑维护的界面如图9-36。
各功能按钮的定义可参考下表完成。
2)GUI状态STAT2
GUI状态STAT1的模拟结果如图9-37所示,编辑维护的界面如图9-38。
各功能按钮的定义可参考下表完成。
2.2、建立标题
重新执行“菜单设计器”,在初始界面中选择“标题列表”后点击创建,参考图9-39所示建立2个标题。
3、屏幕设计
在本实践中,有程序执行初始界面,还有订单维护的界面,因此需要建立2个屏幕,本步骤可参考实践9A1,使用屏幕设计器(SE51),完成各个屏幕的设计。
3.1、初始屏幕100
1)屏幕属性
2)屏幕格式设计
点击工具栏的“格式”后,在显示“屏幕绘制器”界面中添加屏幕元素,结果如图9-41。
3)屏幕元素清单
点击工具栏的“元素列表”按钮,将返回到屏幕定义的“元素清单”中,此处将列出界面中所包含的元素,以及各元素的具体属性,如图9-42。
4)屏幕逻辑流
点击“逻辑流”页签,逻辑流的代码如下。
PROCESS BEFORE OUTPUT.
MODULE status_0100.
*
PROCESS AFTER INPUT.
* MODULE user_command_0100.
MODULE over_and_out_0100 AT EXIT-COMMAND.
CHAIN.
FIELD:ztorders_h-orderid
MODULE validate_input_0100.
ENDCHAIN.
MODULE main_pai_0100.
在如上屏幕100的“逻辑流”PBO事件中,包含一个MODULE:status_0100,此MODULE在屏幕输出前执行,包括设置GUI、标题栏、变量初始值等,具体代码将在后续屏幕100的PBO事件代码中实现。
PAI事件中,则包含了3个MODULE:
over_and_out_0100,此MODULE是在屏幕100中点击“退出”时的响应,并加上AT EXIT-COMMAND关键字,以在自动字段检查之前调用模块(对应按钮需将类型设置为E);如果PAI中没有此MODULE,则会点击“退出”按钮时还会执行后面的语句,如检查输入的订单编号,而这是多余的。
validate_input,此MODULE是继续响应点击按钮,以对输入的订单编号进行检查;如点击“新建”时,输入的订单编号在数据表中已存在,则返回相应提示。
main_pai_0100,此MODULE是继续对点击不同的按钮进行响应,如点击新建或修改、显示,则进入屏幕150,如点击删除,则对指定的订单进行删除。
CHAIN……ENDCHAIN,通过CHAIN语句,当输入的编号发生变化时,则调用MODULE:validate_input进行检查。
3.2、订单明细屏幕150
1)屏幕属性
2)屏幕格式设计
通过“屏幕绘制器”对屏幕150添加的屏幕元素结果,如图9-44所示。
3)屏幕元素清单
点击工具栏的“元素列表”按钮,将返回到屏幕定义的“元素清单”中,此处将列出界面中所包含的元素,以及各元素的具体属性,如图9-45。
4)屏幕逻辑流
点击“逻辑流”页签,逻辑流的代码如下。
PROCESS BEFORE OUTPUT.
MODULE status_0150.
LOOP AT ordersi_tab INTO ztorders_i WITH CONTROL items.
MODULE items_0150_change_field_attr.
ENDLOOP.
*
PROCESS AFTER INPUT.
CHAIN.
FIELD:ztorders_h-orderid, ztorders_h-customerid,
ztorders_h-employeeid,ztorders_h-orderdate, ztorders_h-shipdate.
MODULE set_change_0150 ON CHAIN-REQUEST.
ENDCHAIN.
LOOP AT ordersi_tab.
MODULE items_0150_modify.
ENDLOOP.
MODULE user_command_0150.
在如上屏幕150的“逻辑流”PBO事件中,包含2个MODULE:
status_0150,此MODULE在屏幕150输出前执行,包括设置GUI、标题栏、元素显示属性等,具体代码将在后续屏幕150的PBO事件代码中实现。
items_0150_change_field_attr,此MODULE是设置字段的显示,通过LOOP AT语句读取和填充数据到屏幕150的界面元素后,根据不同的操作(新建、修改、显示)设置元素显示状态(可更改、只显示)
PAI事件中,则包含了3个MODULE:
CHAIN……ENDCHAIN,通过CHAIN语句,当订单编号、客户编号、雇员编号、订单日期、交货日期值发生变化时,则调用MODULE:set_change_0150设置界面元素的显示状态。
set_change_0150,此MODULE是通过对变量“data_chg_150”的赋值,设置界面元素的显示状态(X则为可更改)。
items_0150_modify,此MODULE结合LOOP AT语句,调用子程序在维护订单明细数据后,更新内表数据。
user_command_0150,此MODULE是对点击不同的按钮进行响应。
4、代码编写
完成如上步骤后,接下来通过程序编辑器(SE38)对代码的各部分进行编写。
4.1、对象定义
根据程序功能需求,定义的变量、内表、控件等对象如代码所列。
*****对象定义*****
CONTROLS: items TYPE TABLEVIEW USING SCREEN 0150."子屏幕150中的列表元素
TABLES:ztorders_h, ztorders_i. "根据表格定义的内表
DATA:ordersi_tab TYPE STANDARD TABLE OF ztorders_i
WITH HEADER LINE, "含工作区内表,存储读取的订单明细数据
ok_code TYPE sy-ucomm, "用户指令
save_ok_code TYPE sy-ucomm, "保存用户指令,用以设置界面元素状态
strng TYPE string, "在不同操作时显示的界面标题不同
data_chg_150(1) TYPE c, "记录子屏幕150是否为修改状态
answer(1) TYPE c, "记录数据更改退出时用户的确认
prv_orderid TYPE ztorders_h-orderid. "用以记录已操作过的订单
4.2、程序初始事件
在程序执行后,通过START-OF-SELECTION语句,调用屏幕100以进行后续处理。
*&----------------------------------------------------------------------*
*& START-OF-SELECTION
*&----------------------------------------------------------------------*
START-OF-SELECTION.
CALL SCREEN 0100. "调用主屏幕100
4.3、屏幕100事件
1)PBO事件的MODULE
当屏幕100被调用的时候,首先触发屏幕的PBO事件,此事件包含的MODULE status_0100的代码如下。
*&---------------------------------------------------------------------*
*& Module STATUS_0100 OUTPUT
*&---------------------------------------------------------------------*
* 主屏幕100的初始GUI状态标题栏及变量设置
*----------------------------------------------------------------------*
MODULE status_0100 OUTPUT.
SET PF-STATUS 'STAT1'. "设置屏幕GUI状态为STAT1
SET TITLEBAR 'TITLE01'. "设置屏幕GUI标题栏为TITLE01
prv_orderid = ztorders_h-orderid. "清空内表前将操作过的订单号记录起来
FREE: ztorders_h, "清空变量数据以对新的订单进行操作
ordersi_tab.
ok_code = ' '.
data_chg_150 = ' '.
items-lines = 0.
ztorders_h-orderid = prv_orderid. "设置屏幕中的订单编号为之前操作的
ENDMODULE.
此代码首先设置GUI状态为STAT1,标题为TITLE01;然后使用prv_orderid变量,记录上一次操作的订单编号;随后对存储订单抬头信息和订单明细数据的内表、包括点击的操作、字段状态、行数量进行重置;最后将前面保存的prv_orderid值赋值给字段ztorders_h-orderid。这样在操作完成一个订单后返回初始屏幕时,各个变量被重置,同时上一次订单编号显示在输入框。
2)PAI事件的MODULE
当点击GUI状态对应图标时,将触发屏幕的PAI事件。
over_and_out_0100是PAI后的第一个MODULE,此MODULE是对按钮“退出”点击后的响应:退出程序。
*&---------------------------------------------------------------------*
*& Module OVER_AND_OUT_0100 INPUT
*&---------------------------------------------------------------------*
* 订单编号输入及订单操作前如果点击退出按钮,则退出程序
*----------------------------------------------------------------------*
MODULE over_and_out_0100 INPUT.
IF ok_code = 'EXIT'.
LEAVE PROGRAM.
ENDIF.
ENDMODULE.
validate_input_0100通过CHAIN语句,在输入的订单编号更改时触发。此MODULE首先根据输入的订单编号从订单表ztorders_h中读取记录;然后根据点击的按钮和读取记录的结果,给出不同的处理:如果点击的按钮为“新建”且读取到记录(sy-subrc为0)则输出错误提示,如果点击的按钮不是“新建”且没有读取到记录也一样输出错误提示。
*&---------------------------------------------------------------------*
*& Module VALIDATE_INPUT_0100 INPUT
*&---------------------------------------------------------------------*
* 输入订单编号后,
* 如果此编号已存在且点击了新建,则发出错误提示
* 如果此编号不存在而点击的不是新建,同样发出错误提示
*----------------------------------------------------------------------*
MODULE validate_input_0100 INPUT.
SELECT SINGLE * FROM ztorders_h INTO ztorders_h WHERE
orderid = ztorders_h-orderid. "根据输入的订单编号从表中读取记录
"点击新建且记录存在则输出错误提示
IF ok_code = 'NEW' AND sy-subrc = 0.
MESSAGE e091(zu03_mclass01) WITH ztorders_h-orderid.
"点击的不是新建且记录不存在则输出错误提示
ELSEIF ok_code <> 'NEW' AND sy-subrc <> 0.
MESSAGE e092(zu03_mclass01) WITH ztorders_h-orderid.
ENDIF.
ENDMODULE.
main_pai_0100则根据点击的按钮进行不同的处理。
*&---------------------------------------------------------------------*
*& Module MAIN_PAI_0100 INPUT
*&---------------------------------------------------------------------*
* 主屏幕100的不同按钮点击后触发事件
*----------------------------------------------------------------------*
MODULE main_pai_0100 INPUT.
save_ok_code = ok_code.
CASE ok_code.
WHEN 'NEW'.
strng = '新建'.
LEAVE TO SCREEN 150.
WHEN 'MODIFY'.
IF ztorders_h-orderid NOT BETWEEN 10000 AND 60000.
PERFORM read_table.
strng = '修改'.
LEAVE TO SCREEN 150.
ELSE. "不能修改编号范围在10000~60000的订单
MESSAGE s096(zu03_mclass01) WITH ztorders_h-orderid
DISPLAY LIKE 'E'.
ENDIF.
WHEN 'DISPLAY'.
PERFORM read_table.
strng = '显示'.
LEAVE TO SCREEN 150.
WHEN 'DELETE'.
IF ztorders_h-orderid NOT BETWEEN 10000 AND 60000.
PERFORM delete_sr USING answer ztorders_h.
IF answer = 1.
DELETE ztorders_h.
DELETE FROM ztorders_i WHERE orderid = ztorders_h-orderid.
MESSAGE s094(zu03_mclass01) WITH ztorders_h-orderid
DISPLAY LIKE 'W'.
ELSE.
MESSAGE s095(zu03_mclass01).
ENDIF.
ELSE. "不能删除编号范围在10000~60000的订单
MESSAGE s096(zu03_mclass01) WITH ztorders_h-orderid
DISPLAY LIKE 'E'.
ENDIF.
WHEN 'EXIT'.
LEAVE PROGRAM.
ENDCASE.
ENDMODULE.
4.4、屏幕150事件
1)PBO事件的MODULE
当屏幕150被调用的时候,首先触发屏幕的PBO事件。
MODULE status_0150中,首先设置GUI状态为STAT2,标题为TITLE02;然后调用子程序change_scr_150_prop设置屏幕元素的显示属性。
*&---------------------------------------------------------------------*
*& Module STATUS_0150 OUTPUT
*&---------------------------------------------------------------------*
* 子屏幕150的初始GUI状态标题栏及界面元素属性设置
*----------------------------------------------------------------------*
MODULE status_0150 OUTPUT.
SET PF-STATUS 'STAT2'. SET TITLEBAR 'TITLE02' WITH ztorders_h-orderid strng.
PERFORM change_scr_150_prop.
ENDMODULE.
MODULE items_0150_change_field_attr是结合PAI中的LOOP AT语句,逐行对表格控件的各个单元格设置显示属性。
*&---------------------------------------------------------------------*
*& Module items_0150_change_field_attr OUTPUT
*&---------------------------------------------------------------------*
* 子屏幕150设置界面表格控件的显示。
*----------------------------------------------------------------------*
MODULE items_0150_change_field_attr OUTPUT.
PERFORM change_scr_150_prop.
ENDMODULE.
2)PAI事件的MODULE
当点击GUI状态对应图标时,将触发屏幕的PAI事件。
set_change_0150模块,将变量data_chg_150赋值为“X”,由此表示为界面元素为可更改状态。
*&---------------------------------------------------------------------*
*& Module SET_CHANGE_0150 INPUT
*&---------------------------------------------------------------------*
* 子屏幕150设置界面元素为修改状态
*----------------------------------------------------------------------*
MODULE set_change_0150 INPUT.
data_chg_150 = 'X'.
ENDMODULE.
Items_0150_modify模块,则通过调用子程序,在表格控件中的数据更改后,更新内表的数据。
*&---------------------------------------------------------------------*
*& Module ITEMS_0150_MODIFY INPUT
*&---------------------------------------------------------------------*
* 子屏幕150将修改后的表格数据填充到表格控件对应内表
*----------------------------------------------------------------------*
MODULE items_0150_modify INPUT.
PERFORM modify_ordersitem.
ENDMODULE.
user_command_0150模块则是响应不同按钮点击后的处理。
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_0150 INPUT
*&---------------------------------------------------------------------*
* 子屏幕150的不同按钮点击后触发的事件
*----------------------------------------------------------------------*
MODULE user_command_0150 INPUT.
CASE ok_code.
WHEN 'BACK'.
IF data_chg_150 = 'X'.
PERFORM abort_sr USING answer ztorders_h.
IF answer = 1.
LEAVE TO SCREEN 0100.
ENDIF.
ELSE.
LEAVE TO SCREEN 0100.
ENDIF.
WHEN 'SAVE'.
data_chg_150 = ' '.
MODIFY ztorders_h.
MODIFY ztorders_i FROM TABLE ordersi_tab.
IF sy-subrc <> 0.
ENDIF.
MESSAGE s093(zu03_mclass01) WITH ztorders_h-orderid.
ENDCASE.
ENDMODULE.
4.5、子程序
在屏幕事件(包括PBO和PAI)中,多处用到了不同的子程序。
其中子程序read_table,是用以根据屏幕100中输入的订单编号,获得订单抬头和订单行项目的数据并分别存储到内表ztorders_h和ordersi_tab中,同时设置表格控件的行数量(items-lines)。
*&---------------------------------------------------------------------*
*& FORM read_table
*&---------------------------------------------------------------------*
* 从订单和订单明细表中获得数据填充内表以备输出
*----------------------------------------------------------------------*
FORM read_table.
SELECT SINGLE * FROM ztorders_h INTO ztorders_h WHERE
orderid = ztorders_h-orderid.
ztorders_h-oamount = 0.
SELECT * FROM ztorders_i INTO ordersi_tab WHERE
orderid = ztorders_h-orderid.
ztorders_h-oamount = ztorders_h-oamount + ordersi_tab-oquantity *
ordersi_tab-nprice * ( 1 - ordersi_tab-discount ).
APPEND ordersi_tab TO ordersi_tab.
ENDSELECT.
items-lines = sy-dbcnt.
ENDFORM.
子程序delete_sr,是在点击“删除”按钮后的响应,此子程序通过CALL FUNCTION调用功能函数“POPUP_TO_CONFIRM”以弹出对话框,以让用户确认。
*&---------------------------------------------------------------------*
*& Form DELETE_SR
*&---------------------------------------------------------------------*
* 确定是否对订单进行删除
*----------------------------------------------------------------------*
* -->P_ANSWER 返回是否删除,1则删除
* -->P_ZTORDERS_H 订单结构体,根据订单编号进行判断
*----------------------------------------------------------------------*
FORM delete_sr USING p_answer
p_ztorders_h TYPE ztorders_h.
DATA: txt TYPE string.
CONCATENATE '是否对编号为' p_ztorders_h-orderid '的订单进行删除?'
INTO txt.
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
titlebar = '确定是否删除订单'
* DIAGNOSE_OBJECT = ' '
text_question = txt
text_button_1 = '删除'(001)
* ICON_BUTTON_1 = ' '
text_button_2 = '不删除'(002)
* ICON_BUTTON_2 = ' '
* DEFAULT_BUTTON = '1'
* DISPLAY_CANCEL_BUTTON = 'X'
* USERDEFINED_F1_HELP = ' '
* START_COLUMN = 25
* START_ROW = 6
* POPUP_TYPE =
* IV_QUICKINFO_BUTTON_1 = ' '
* IV_QUICKINFO_BUTTON_2 = ' '
IMPORTING
answer = p_answer
* TABLES
* PARAMETER =
* EXCEPTIONS
* TEXT_NOT_FOUND = 1
* OTHERS = 2
.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
ENDFORM.
子程序change_scr_150_prop,则是根据不同的按钮操作,设置屏幕元素的显示属性。
*&---------------------------------------------------------------------*
*& Form CHANGE_SCR_150_PROP
*&---------------------------------------------------------------------*
* 子屏幕150设置界面元素的属性
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM change_scr_150_prop .
LOOP AT SCREEN.
CASE save_ok_code.
WHEN 'DISPLAY'.
screen-input = 0.
WHEN 'MODIFY'.
screen-input = 1.
WHEN 'NEW'.
screen-input = 1.
ENDCASE.
CASE screen-name.
WHEN 'ZTORDERS_H-ORDERID'.
screen-input = 0.
ENDCASE.
MODIFY SCREEN.
ENDLOOP.
ENDFORM.
子程序modify_ordersitem,则是将表格控件的数据更新到内表ordersi_tab中。
*&---------------------------------------------------------------------*
*& Form MODIFY_ORDESITEM
*&---------------------------------------------------------------------*
* 将表格控件包含的数据更改后更新到内表
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM modify_ordersitem .
ztorders_i-orderid = ztorders_h-orderid.
IF items-current_line <= lines( ordersi_tab ).
MODIFY ordersi_tab FROM ztorders_i INDEX items-current_line.
ELSE.
APPEND ztorders_i TO ordersi_tab.
ENDIF.
ENDFORM.
子程序abort_sr,跟子程序delete_sr类似,在点击退出时进行确认。
*&---------------------------------------------------------------------*
*& Form ABORT_SR
*&---------------------------------------------------------------------*
* 确定是否退出订单修改
*----------------------------------------------------------------------*
* -->answr 返回是否退出更改,1则退出
* -->stru 订单结构体,根据订单编号进行判断
*----------------------------------------------------------------------*
FORM abort_sr USING answr stru TYPE ztorders_h.
DATA txt TYPE string .
CONCATENATE '退出订单' ztorders_h-orderid '的修改?' INTO txt.
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
titlebar = '退出修改'
* DIAGNOSE_OBJECT = ' '
text_question = txt
text_button_1 = '退出'(001)
* ICON_BUTTON_1 = ' '
text_button_2 = '不退出'(002)
* ICON_BUTTON_2 = ' '
default_button = '2'
display_cancel_button = ' '
* USERDEFINED_F1_HELP = ' '
start_column = 40
start_row = 2
* POPUP_TYPE =
* IV_QUICKINFO_BUTTON_1 = ' '
* IV_QUICKINFO_BUTTON_2 = ' '
IMPORTING
answer = answr
* TABLES
* PARAMETER =
* EXCEPTIONS
* TEXT_NOT_FOUND = 1
* OTHERS = 2
.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
ENDFORM.
将如上各部分代码合并,则组成了整个实践的程序,完成后对所有内容进行激活。