对话屏幕Dynpro(SE51)
屏幕元素
屏幕属性
l 屏幕序号(Screen number)。四个数字组成的序列号,用于在程序中确定屏幕,该序号在同一个ABAP程序内部是唯一的。
l 屏幕类型(Screen type)。ABAP中的屏幕类型包括普通屏幕、模式对话框、选择屏幕和子屏幕等。普通屏幕一般占据整个用户窗口,而模态对话框只占据用户窗口的一部分;选择屏幕是根据程序中定义的select-option和parameters自动生成的,一般不用于对话程序设计中;子屏幕则可以显示在不同屏幕的某个区域之中。
l 后续屏幕(Next screen)。定义当前屏幕的后续屏幕序号,即系统的对话处理器结束当前屏幕的处理之后,应前往的下一个屏幕。通过后续屏幕,可以把事务中的一系统屏幕连接起来,形成一个屏幕序列,如果某个屏幕的或没有设置,则表明该屏幕是一个屏幕序列的结束。该属性可以在程序中动态控制。
l 光标位置(Cursor position)。屏幕初始状态的光标位置,一般默认状态下,光标位于屏幕中的第一个输出字段。在程序设计中,可以动态地替换属性中定义的初始光标位置。
l 屏幕组(Screen group)。可以将一系列的屏幕组合在一个4字符的屏幕组中,屏幕组ID运行期间存储于系统字段sy-dyngr中,用于程序对多个屏幕整体操作。
l 行列范围(Lines/columns)。用于设定屏幕所占据的空间,如果屏幕较大,系统将自动生成滚动条。
l 上下文菜单(Context memu),用于设定属于整个屏幕的上下文菜单(右键菜单)。
每一个屏幕都有一个OK_CODE字段,但不显示在屏幕上。用户触发PAI事件的操作所对应的Function Code就会存储到这个字段中,然后再传递到ABAP程序中相同名称的全局变量中,必须为每个屏幕分配这个名叫OK_CODE的屏幕元素,否则虽然可以触发事件,但Function Code不能在屏幕与ABAP程序之间进行传递了
在屏幕中也可以像ABAP程序那样读写系统预置的系统变量,但是,在屏幕中系统变量是通过结构SYST来管里的,而不是SY,所以,你必须使用SYST-<name>来定位它们
PAI事件的触发、屏幕元素Function Code设置
1. 如果复选框与单选按钮没有设置Function Code,则它们就会像普通的输入框一样,即使状态发生了改变,也不会触发PAI事件。但是对于按钮,即使没有设置Function Code,也会触发PAI事件,此时的Function Code 为空。
2. 如果复选框与单选按钮设置Function Code,则复选框与单选按钮不只是简单的输入元素,而且还会触发PAI事件。
3. 以下屏幕元素可以触发PAI事件
? 点击屏幕上的某个按钮
? 点击了某个已分配了Function Code的单选按钮或复选框
? 点击了某个菜单或标准工具条、应用工具条件上的按钮
? 快捷键
? 从下拉框中选择条目
4. 不同的屏幕元素的Function Code的设置方式如下:
? 屏幕中的按钮、复选框、单选按钮、下拉框的Function Code都是通过屏幕元素 attributes来设置的(注:如果是选择屏幕,则通过USER-COMMAND选项来设置)
? 而菜单、standard toolbar、application toolbar中的Function Code是通过GUI status来设置的
? 快捷键所对应的Function Code也是通过GUI status来设置的
屏幕流逻辑Screen Flow Logic
屏幕流逻辑包括四种事件块:
PROCESS BEFORE OUTPUT.
...
PROCESS AFTER INPUT.
...
PROCESS ON HELP-REQUEST.
...
PROCESS ON VALUE-REQUEST.
...
前两个一定要有,当都出现时请按上面顺序写
当你创建一个新屏幕时,头两个事件块会自动的创建。运行时触发时间点如下:
? PROCESS BEFORE OUTPUT (PBO)
在前一屏幕的PAI事件后或当前屏幕显示之前自动触发,你可以在这个块中对数据进行初始化赋值。在PBO结束时,屏幕将会显示出来。
? PROCESS AFTER INPUT (PAI)
当用户操作(如F8,点击按钮,回车、或点击带Function Code的单选/复选按钮,可选择带Function Code下拉框中的某选项时)了屏幕上某个功能元素时就会触发,你可以在这个块中如对输入值的检查。PAI事件结束后,系统将会调用一下屏幕或者返回到屏幕调用处(ABAP程序)继续执行
? PROCESS ON HELP-REQUEST (POH) and PROCESS ON VALUE-REQUEST (POV)
当用户按F1与F4时触发,处理完之后返回到当前屏幕
对话屏幕中的字段命名大小写问题
在对话屏幕中为输入字段命名时,名字一定要大小,否则在屏幕逻辑流中用到该字段时则会出错:
原因就是在屏幕设计界面中,命名时写成了小写了:
所以屏幕字段命名时一定要大写(好像小写时,如果不在屏幕逻辑流中使用时也是可行的,但一旦用在屏幕逻辑流中进,就会出问题),正确的做法是在输入名称之后,回车一下,则名称会自动转换为大小:
即Element list中的命名为大小即可:
示例:屏幕元素自动参考数据词典(或程序)中的表或结构字段
如果屏幕上的元素字段参考的是数据词典的字段(屏幕元素的名称为表名-字段名的形式)时,必须在ABAP程序里使用TABLES语句来定义这个表接口,这样就可以通过这个表接口在屏幕与ABAP程序之间自动的进行数据传递:
另外,也可以是只引用一个或几个数据词典中某个表中一个或几个字段,不一定要引用整张表。再次,这些参照词典中的字段需要将以下钩上:
当给某个屏幕字段命名时,如果这个字段的名称为“表名(或结构)-字段名”形式时,回车时系统会提示:
当点击Yes后,该字段的Parameter ID会自动的设置为 MARA-MATNR字段所对应Data Element所设置的Parameter ID,另外,From dict.也会自动被钩上,但时,SET Parameter与GET Parameter 没有自动钩上,如果需要通过SAP Memory传递值,则需要将这两个手动钩上:
Data Element中的Parameter ID对选择屏幕是没有任何作用的,如下面的语句不能用来在SAP Memory中传递值:
PARAMETERS: m TYPE mara-matnr.
除非使用MEMORY ID 选项才起作用:
PARAMETERS: m TYPE mara-matnr MEMORY ID mat.”注,这里的MEMORY ID不一定要设置成与MATNR所对应的Data Element设置的Parameter ID一样,这里可以随便设置,如XXX
所以选择屏幕中的参数选项 MEMORY ID的作用就等同于对话屏幕中的SET/GET Parameter,它们是作用是相同的(都是针对SAP Memory),只不过一个用于选择屏幕中,一个用于对话屏幕。
ABAP程序如下:
.
MODULE get_data INPUT.
SELECT SINGLE countryfr cityfrom airpfrom INTO CORRESPONDING FIELDS OF spfli
FROM spfli WHERE carrid = spfli-carrid AND connid = spfli-connid.
ENDMODULE.
运行程序,输入条件后回车,结果屏幕如下:
注:由于Airline配置了Check Table,如果输入的Airline不合法,则不会执行PAI事件,所以在执行PAI事件前,数据词典中所设置的数据有效性会先进行检查。
Function Codes的读写机制
当用户在对话屏幕上触发一个命令时,会将命令所对应的Function Code复制到对话屏幕上一个特殊的隐藏字段OK_CODE中,如果在ABAP中具有一个与对话屏幕这个隐藏字段同名的OK_CODE时,则在屏幕字段向内存字段进行同名拷贝时,屏幕上的这个隐藏字段OK_CODE的值也将会被自动拷贝到程序中的这个字段中,然后就可以在PAI事件块里调用ABAP中的Module中使用此隐藏字段
如果触发PAI时的Function Code为空,则不会放入到对话屏幕中定义的OK_CODE 字段中(SYST- UCOMM与SY-UCOMM也不会发生改变:还是保留上次PAI的Function Code),
注意,此图还有点问题,如果是针对回车键(命令行中未输入内容时回车)是对的,但如果按的是屏幕中的未分配Function Code的按钮时,虽然不会重置OK_CODE,但还是会重置SYST- UCOMM 与 SY-UCOMM。
ok_code的定义
为什么要将ok_code拷贝一次?
在程序中你应该使用OK_CODE来代替SY-UCOMM,这有两种原因:第一,ABAP程序可以完全控制在它里面定义的变量,第二,你不应该修改ABAP系统变量的值。然而,你必须在ABAP程序中清空OK_CODE,因为以下几个原因:如果一个屏幕中的某个按钮未设置Function Code时也是可以触发PAI事件时,并且由于其Function Code此时为空而不会去设置OK_CODE(但此时SYST- UCOMM 或 SY-UCOMM会被重新设置为空),这样的话OK_CODE中的值还为上一次触发PAI时所设置的Function Code。所以一般情况下在使用OK_CODE之前,先将OK_CODE拷贝到SAVE_OK变量中,并随后将OK_CODE清空,以便为下一次PAI事件所使用做准备(比如下一屏幕直接在屏幕上按回车时,Function Code为空,因为在回车时命令框里没有输入任何命令,则此时OK_CODE字段不会被设置,所以还回沿用上次所设置的OK_CODE,所以就会出现问题),并在MODULE 中针对SAVE_OK来进行编程:
DATA: ok_code LIKE sy-ucomm,
save_ok LIKE ok_code.
在第一个PAI module中,需要将ok_code放在save_ok中,并清空ok_code,其他PAI module中就直接使用save_ok即可
MODULE user_command_0100 INPUT.
save_ok = ok_code.
CLEAR ok_code.
CASE save_ok.
WHEN 'BACK' OR 'EXIT' OR 'CANCEL'.
LEAVE PROGRAM.
WHEN OTHERS.
ENDCASE.
ENDMODULE.
其实还有一种方案可能替换这种使用前拷贝方案:就是还是针对OK_CODE编程,不另外定义save_ok,而是在每个屏幕的 PBO 里将ABAP中的OK_CODE清空。
另外如果在Command Line未输入内容时就按回车(其实光标在屏幕上输入框里按回库也是这样,只要命令行没有输入内容时),此时的Function Code也是空,此时除OK_CODE还是不会被重置, 并且SYST- UCOMM 与 SY-UCOMM也不会被重新设置为空。
每个屏幕的OK字段都可以用不同的名字,但是,最好的做法是每个屏幕中的OK字段都叫OK_CODE,这样的话ABAP程序中只需要定义一个名称为OK_CODE的变量即可以接受所屏幕中的OK字段值(即Function Code)
图形化用户接口 GUI
GUI主要有:
1、 标题栏:当前屏幕的标题,GUI Title
2、 菜单条:包含了可扩展的菜单,其中每个子菜单项都指向一个应用程序的功能,其中“System”、“Help”两个菜单项不能被应用程序更改和扩展,因此这类菜单荋以及其中的子菜单项将出现在每一个应用的屏幕中。
每个屏幕都会有系统标准工具条(Standard Toolbar),包含的按钮代表了所有屏幕中都会用到的系统功能,如保存、回退、取消等。可以为菜单项和工具条项分配功能键(FunctionKeys),这样当用户在屏幕按下相应的功能键时,相当于执行了已经分配了这个功能的菜单项。
应用工具条(ApplicationToolbar)是与特定应用相关的工具条,集成了当前屏幕常用的功能。
将菜单条、标准工具条、功能键的设置以及应用工具条统称为“GUI Status”,使用SETPF-STATUS xxx来设置的。使用SET TITLEBAR xxx设置标题。
若为ABAP屏幕分配一个GUI Status、GUI Title,则该屏幕的所有后续屏幕缺省都有了该Status、Title,如果想在后续的子屏幕中更换成另外一个不同的Title,则需要重新设置
ABAP中维护GUI Status的工具叫Menu Painter。
除开“System”与“Help”菜单,最多还可以创建6个菜单项
GUI Status(Menu Painter)
GUI status为用户提供了屏幕范围内的功能,每一种功能都有一个Function Code,并且当用户选择这个功能时,就会触发PAI事件,在每PAI事件里,这些Function Code将会放到系统变量SYST-UCOMM(SY-UCOMM)中,并且分配给OK_CODE隐藏字段。在Screen中使用OK_CODE之前,必须在Screen Painter中给它分配一个名字。
(注:这里讲的是对话屏幕上的Status,如果是List Status,则不会有什么PAI事件,也不会将Function Code存储到什么OK_CODE,而是直接触发ABAP报表程序中的 AT USER-COMMAND 事件,可以在此事件中通过ABAP系统全局变量SY-UCOMM来接收传递过来的Function Code)
ABAP程序中的所有Function Code,除了按钮(还有复选框、单选按钮)的Function Code是在Screen Painter中分配的,其他都是在Menu Painter中进行定义与管理的:
GUI Status可以是让用户很方便的操作屏幕,它代替了命令行中的输入。当然我们可以不点击Menu bars、Standard toolbars、Application toolbars或者屏幕中的按钮,直接在Command Line中输入这些菜单、工具条与按钮所对应的Function Code,回车后也可以触发PAI事件。
Normal Status(Menu Painter详解)
此种类型的Status用在如下类型的普通屏幕中:
通过Menu Bar可以创建新的菜单,在创建时不需要分配键盘快捷键,但可以在Function Keys设置部分中的Freely Assigned Function Keys(此类型的Function Key——快捷键,可由用户自己*分配)中为菜单设置一个键盘快捷键,这样不需要通过鼠标点击菜单而是通过所设置的快捷键来代替鼠标;
通过Application Toolbar创建应用工具条件上的按钮的过程中,会弹出一个设置快捷键的对话框要求设置快捷键,所以创建自定义应用工具条时一定要分配一个键盘快捷键;
Function Keys中的Standard Toolbar不需要设置快捷键(正是因为这些为标准工具条,已经为这些固有的图标绑定了快捷键,并且这些快捷键被系统所保留使用),因为这些是预设的标准工具条(因为标准工具条上有哪些功能图标是不能再由我们自己定义了,只能使用上面预设的那几个,如果要使用,只需要输入相应的Function code就代表开启此按钮了),并且已经固定分配了相应的快捷键,系统预设的快捷键如下:
Functionkey |
Icon |
Purpose |
Ctrl+Sor F11 |
Save |
|
F3 |
Back |
|
Shift+F3 |
Exit |
|
Esc or F12 |
Cancel |
|
Ctrl+P |
|
|
Ctrl+F |
Find |
|
Ctrl+G |
Find next |
|
Ctrl+PgUp |
Firstpage |
|
PgUp |
Previous page |
|
PgDn |
Nextpage |
|
Ctrl+PgDn |
Lastpage |
具体的内置快捷键可以通过以下方式来查看:
另外,也可以设置一个与菜单或工具条按钮无关的纯粹的快捷键,如上面的Function Code为 SHORTCUT 的快捷键。
不管是菜单、工具条按钮、还是快捷键最终都会触发PAI事件,并且会将所对应的Function Code会存储到SY-UCOMM系统变量中。
上面的Recommended Function Key Setting(此类型的Function Key——快键捷,已经被系统推荐使用,所以最好不要另作其它用途,如F2为查看详情,相当于鼠标双击)部分的为推荐部分,当不输入FunctionCode时,相应的功能不会被激活,只要输入了Function code则会激活相应功能,Function Code可以任意,相应功能不需要我们写代码去实现了,因为系统已具备这样的功能。
Standard Toolbar栏中预设的图标按钮在默认情况是不会被激活的,只有当输入相应Function Code才会被激活,但此时在Standard Toolbar中只能点击它,具体的功能还是需要在ABAP程序中写代码来实现相应功能,这与Recommended Function Key Setting部分是不一样的。
一般情况下,需至少激活Standard Toolbar中的Back (F3), Exit (shift+F3), and Cancel (F12)中的一个功能,并实现相应代码,以便用户能够离开屏幕(如果将的Funcode设为BACK、设置为EXIT、设置为BREAK时(具体什么值与屏幕的类型有关系:选择屏幕、List列表输出屏幕、对话屏幕都是不一样,如要使用系统提供的默认实现,则一定要按要求值给出,具体值请参考后面),会自动的leave program.对话屏幕好像就不行???,选择屏幕好像已自动实现)
下面这些Function Keys不会触发PAI事件,它们被保留下来用作其他的功能:
? F1 calls the field help调用字段的帮助
? F4 calls the input help调用输入帮助
? F10 places the cursor in the menu bar将光标定位到菜单条上
回车:standard toolbar中的回车键 默认就是被激活的,即使根本没有给屏幕设置过GUI status。只要用户在命令行中按回车键后(不管是否输入了内容),都会触发相应屏幕的PAI事件,并且输入的内容会被当作Function Code传递给SY-UCOMM或OK_CODE(在Screen中)字段(如果未输入,则不会输入到SY-UCOMM或OK_CODE中,但会触发PAI事件)
F2(鼠标双击):在预设中,F2已经与鼠标的双击关联起来了,F2已具有了鼠标双击的功能。当用户按了F2或在屏幕上双击了鼠标都会触发PAI事件,所以F2是一个很特别的键,一般不要拿来作其他功能使用。
Shift + F10(鼠标右键):该组合键已经被分配给了鼠标右击功能,不能再用于其他用途。注意:有时鼠标右键弹不出右键菜单,这是因为选中了快捷剪切和粘贴功能了,去掉即可,否则只能使用Shift + F10快捷键或者使用Shift+鼠标右击才能弹出右键菜单:
选择屏幕与List列表输入屏幕上的标准工具按钮FunctionCode需要如下输入才能使用系统提供的默认的功能(不需要我们再实现):
选择屏幕:
List列表:
Dialog BoxStatus
此种类型的Status用在如下类型模态屏幕中:
(注意:Dialog Box类型的Status没有Menu Bar与Standard Toolbar两项)
Reserved Function Keys部分为保留快捷键,如果要相应对应功能,只需要输入Function Code,但要注意的是Function code一定要为上面图中输入的,否则功能将不会被触发(这些功能也已经由系统实现了,我们不需要实现)。另外,如果将Reserved Function Keys部分所配置的Function Code又在Application Toolbar部分进行了分配,这些功能图标将会在对话框屏幕下方出现,如:
(但不知为什么上面红色字体的 ENTER 没有显示??后来找到原因了:是因为Function Code被去激活了:
)
Context Menu Status
该类型的Status用作右键菜单
可以将右键菜单链接到某些屏幕元素,包括输入输出字段、文本字段、表格控件以及屏幕区域等。
具体使用请参考Context Menus for Screen中的示例代码
Dialog Status for Lists
快速创建(Status模板)
可以将系统标准GUI Status作为模板导入到当前程序中,在Menu Painter中选择系统菜单“ExtrasàAdjusttemplate”。
将系统标准的GUI STATUS导入到当前的GUI STATUS中作为编辑的模板:
标准Status拷贝
当需要为ALV报表或普通程序绘制Status时,我们先可以拷贝标准的Status,则在此基础上修改即可:
上面的ALV工具条是先拷贝自标准条,再在标准条上加一按钮,通过SE41,拷贝程序SAPLSLVC_FULLSCREEN的状态STANDARD_FULLSCREEN过来:
如果不是ALV,是Write输入时,拷贝:
两种方式创建屏幕字段
从词典中获取
要想在对话屏幕与ABAP程序中进行数据传递,则还得要在ABAP定义中作如下定义才可:
TABLES: sdyn_conn.
或者是:
DATA: sdyn_conn TYPE sdyn_conn.(注:此种方式可能会有问题,数据不能传输??)
从程序中获取
对话屏幕与程序之间的数据传输
在ABAP对话屏幕编程中,对话屏幕与程序之间的数据自动传输发生在:屏幕字段名与程序中定义的同名的全局变量之间,此变量一般可以是普通的类型的单变量,但更多是定义成结构体变量。下面以结构体变量为传输体来了解数据传输过程。
使用TABLE语句来定义一个内存结构体变量,该结构中的字段与对话屏幕上的各输入字段是一一对应的,即名称与类型都相同。TABLE后面的数据类型可以是词典中的结构类型或透明表类型,具定义出来的结构体变量名与后面指定的词典结构类型及透明表类型一致,例如:
TABLES sdyn_conn.:利用结构体类型sdyn_conn定义了一个结构体变量sdyn_conn
TABLES sflight.:利用透明表类型sflight定义了一个结构体变量sflight
因为结构体变量中的各字段与对话屏幕上的各输入字段具有对应关系,因此,该结构体变量被用作屏幕与程序之间的数据传输通道:
上图中,使用了词典中的结构体类型sdyn_conn定义了一个内存变量sdyn_conn,而对话屏幕100上的各个字段的定义也是来自于结构体类型sdyn_conn,因此,内存变量sdyn_conn将作为屏幕100与调用它的程序之间的数据传输通道:即在屏幕100的PBO事件完成后,内存变量sdyn_conn中的各字段值将自动传输给对应的屏幕字段;当用户在屏幕上点击确认结束输入后,在触发PAI事件之前,各屏幕的字段的值将自动传输给内存变量sdyn_conn相应各同名字段中,因此,可以在PAI事件块中对结构体变量sdyn_conn进行处理。
工具栏中按键之间的分隔符
其中“分隔符”的插入方法为:在需要插入分隔符的方框内选择菜单“Edit—>Insert——>Separator line”即可插入分隔符
Calling ABAP Dialog Modules
在PBO事件块里,你可以使用MODULE语句来调用在ABAP program里如下定义的dialog module:
MODULE <mod> OUTPUT.
...
ENDMODULE.
在PAI, POH, 与 POV事件块里,你可以使用MODULE语句来调用在ABAP program里如下定义的dialog module:
MODULE <mod> [INPUT].
...
ENDMODULE.
从技术角度来说,在同一个ABAP Program里,两个不同类型的module(OUTPUT、INPUT)可以使用相同的名称,但这不推荐使用。不同的屏幕可以调用ABAP程序里同一个dialog module,所以可以将多个屏幕共同的代码写在一个dialog module里(如将OK_CODE拷贝到SAVE_CODE里,将将OK_CODE清空这一过程),然后在所有的屏幕的PAI事件开头调用这个dialog module。
MODULE位于ABAP主程序中,相当于该主程序中声明的的不带参数的子程序,因此在ABAP主程序中声明的所有全局变量在MODULE块的程序中都可以进行调用,而且MODULE块内部定义的变量在其他MODULE来说也是全局的,但MODULE外面程序代码中不可引用,而且声明变量的MODULE要在引用变量所在MODULE的前面:
MODULE status_0100 OUTPUT.
DATA texttable TYPE tt_text.
...
ENDMODULE.
MODULE user_command_0100 INPUT.
CALL METHOD editor->get_text_as_stream
IMPORTING
text = texttable. 这里的texttable实质上引用是的上面module中声明的变量
ENDMODULE.
SY-DYNNR系统变量里存储了当前屏幕的屏幕号。
在flow logic里,有各种不同的调用dialog modules的方法,flow logic的语法允许你在调用dialog modules时附加一些条件,并且通过控制数据在screen与ABAP program之间的传输入:
通过Module 对屏幕字段进行检验
ABAP中的Module经常是用来对屏幕字段输入的值进行检验的,具体请参考这里
Module的简单调用(所有屏幕字段都会被传输到ABAP程序中)
可以使用如下的flow logic语句来调用module:
MODULE <mod>.
(如果前面未指定FIELD选项,则表示此Module对所有字段都有效,而不是针对某个屏幕字段校验的,相当于选择屏幕的AT SELECTION-SCREEN事件)
如果你使用这种简单的流逻辑语句来调用module,则数据在屏幕与ABAP程序之间是这样传输的:
? 在PAI事件中,所有屏幕字段会在第一个PAI module调用之前(前提是自动输入检查需要通过),就已传递到ABAP程序中相同名的字段中(数据从“对话屏幕”传递到“ABAP程序”中进行处理)。
? 在最后一个PBO module调用之后与屏幕显示之前,所有ABAP程序中的同名(与屏幕字段)字段将会传回到屏幕相应字段中(数据从“ABAP程序”传递到“对话屏幕”中进行显示)。
屏幕字段传输时间点控件(FIELD)
如果使用前一节的介绍的简单调用Module的方式来调用dialog module时,所有的屏幕字段在PAI事件块处理开始之前都会传递到ABAP程序。
screen flow logic 中的FIELD语句可以用来控制在什么时候将屏幕字段传递到ABAP程序中相应的字段中。
FIELD <f>.
使用FIELD语句后,屏幕字段<f>需要在该语句处理完后才传递到ABAP程序相应的字段中,在后没有带module选项时,仅仅只是控制屏幕字段传输到ABAP程序中的时间点,如需对屏幕字段进行检验,需要在屏幕字段值传递到ABAP程序之前,通过以下语句来实现检验:
FIELD <field_name> MODULE <module_name>:可以用来对屏幕字段field_name进行检验使用,检验的代码写在module_name中。这相当于选择屏幕的 AT SELECTION-SCREEN ON < field_name>的作用,即Module只对<field_name>字段起作用,因此Module是专门用来校验此屏幕字段的
仅只有未出现在FIELD语句中的屏幕字段才会在PAI事件块处理前传输到ABAP程序中去。所以当某个屏幕字段出现在FIELD语句中,并且在该 FIELD语句未执行完之前,不要在PAI dialog modules中使用该屏幕字段(该屏幕字段相关的FIELD语句执行完成之后才可以在后续的PAI dialog modules调用中使用),否则,ABAP程序同名字段中的值使用的是前一次对话屏幕中所设置的值。
FIELD可以被使用在PAI、POH、POV事件中,但在PBO中不起作用。
PROCESS BEFORE OUTPUT.
MODULE init_screen_100.
PROCESS AFTER INPUT.
MODULE user_command_0100.
MODULE module_1.
"box2屏幕字段在该语句执行完后,且在module_2调用之前,才会传递ABAP程序中,所以
"在该语句执行完之前ABAP程序中相应字段是不会有值
FIELD box2.
MODULE module_2.
"box1、box3屏幕字段在该语句执行完后,且在module_3调用之前,才会传递ABAP程序中,所以
"在该语句执行完之前ABAP程序中相应字段是不会有值
FIELD: box1, box3.
MODULE module_3.
.
MODULE init_screen_100 OUTPUT.
SET PF-STATUS 'SDSS'.
CLEAR: box1, box2, box3, box4.
ENDMODULE.
MODULE user_command_0100 INPUT.
save_ok = ok_code.
CLEAR ok_code.
IF save_ok = 'CANCEL'.
LEAVE PROGRAM.
ENDIF.
ENDMODULE.
MODULE module_1 INPUT.
mod1_result1 = box1.
mod1_result2 = box2.
mod1_result3 = box3.
mod1_result4 = box4.
ENDMODULE.
MODULE module_2 INPUT.
mod2_result1 = box1.
mod2_result2 = box2.
mod2_result3 = box3.
mod2_result4 = box4.
ENDMODULE.
MODULE module_3 INPUT.
mod3_result1 = box1.
mod3_result2 = box2.
mod3_result3 = box3.
mod3_result4 = box4.
ENDMODULE.
? 由于BOX4未在FIELD语句出现过,所以在PAI事件之前就已经传递到ABAP程序中,所以在module_1、module_2、module_3三个PAI dialog modules里BOX4字段都是有值的。
? BOX2屏幕字段要在FIELD BOX2.语句之后才能传递取ABAP相应的BOX2字段中去,所以在module_1中是BOX2字段是没有值的,但在module_2、module_3中会有值。
? 而BOX1、BOX3需要在FIELD: box1, box3.语句后才能传递取ABAP相应的BOX1、BOX3字段中去,所以在module_1、module_2中不会有值,只有在module_3中才有值。
AT EXIT-COMMAND
如果某个屏幕字段有一些约束检查(如参照的是某个数据表中的字段),则需要先通过这些字段的检测,才会触发PAI事件。如果某个屏幕字段为必须,但没有输入时,点击工具条中的退出按钮或屏幕中的按钮时是不会起作用的,这就意味着在输入检测通不过的情况下,PAI事件块里的正常MODULE语句是不会被执行的,如屏幕中的文本框为必输入,点击工具条中的Cancel按钮或者是屏幕中的Cancel按钮时无法退出程序:
为了避免这个问题:在输入不合法的情况下也可以退出程序,可以使用以下几步:
1. 设置成E类型的Function Codes
可以将屏幕中的按钮与GUIstatus上的按钮的Function Code的类型设置为E类型。
将屏幕中的按钮的Function Code设置为E类型:
同样,在GUI status的Standard Toolbar栏中,我们一般需要将Back (F3), Exit (shift+F3), and Cancel (F12)所对应的Function Code类型设置为E类型(因为这三个按钮一般是用来退出程序来使用的):
2. EXIT-COMMAND
对于E类型的Function Code,可以使用如下语句在PAI事件块中来触发:
MODULE <mod> AT EXIT-COMMAND.
不管该语句在screen flow logic的PAI事件块里的什么地方,都会在字段的约束自动检测之前执行,因此,此时其他的屏幕字段的值不会被传递到ABAP程序中去,当该MODULE执行完后,如果未退出该屏幕,则会进行正常PAI(即PAI事件块里没有带EXIT-COMMAND选项的MODULE语句)事件块。
该语句在字段约束自动检测之前会被执行,一般用来正常退屏幕来使用,如果未使用LEAVE语句退出屏幕,则会在这之后还会继续进行字段的自动检测,检测完后还会继续PAI的处理(即执行PAI事件块中不带EXIT-COMMAND选项的MODULE语句)
注意:PAI事件块里只有第一个附加EXIT-COMMAND选项的MODULE语句者会被执行(只要有一类型为E的Function Code按钮被点击就会执行),其他附加EXIT-COMMAND选项的MODULE语句不会被执行,如:
PROCESS AFTER INPUT.
MODULE execute1.
"只要是E类的Function Code都会执行
MODULE cancel AT EXIT-COMMAND.
"永远都不会执行
MODULE back AT EXIT-COMMAND.
MODULE execute2.
上面的 MODULE execute1.与MODULE execute2.两个语句会在字段约束自动检测通过之后才会被执行,而MODULE cancel AT EXIT-COMMAND语句则会在字段约束自动检测之前就会被执行,由于MODULE back AT EXIT-COMMAND语句是第二个事EXIT-COMMAND选项的MODULE语句,所以永远都不会被执行了。
带执行条件的MODULE
这里的FIELD与前面的数据传输控制(FIELD)的使用是一样的:只有当FIELD <f>执行完成后,后面ABAP中<mod>中才能读到字段<f>的值,在这之前的module中是没有数据的。
FIELD dynp_field MODULE mod [ {ON INPUT}
| {ON REQUEST}
| {ON *-INPUT}
| {ON {CHAIN-INPUT|CHAIN-REQUEST}}
| {AT CURSOR-SELECTION}.
1、单个字段检查(即调用module) |
FIELD <FLD1> MODULE <MDL1>. |
2、单个字段被多个MODULE检查 |
FIELD <FLD1> MODULE <MDL1>,MODULE <MDL2>. |
3、检查多个字段,使用CHAIN |
CHAIN. |
4、不是初始值(即不为空时、非初始值)才检查,该事件适合于对屏幕新增数据的检查 |
FIELD <FLD1> MODULE <MDL1> ON INPUT. |
5、屏幕字段输入框中的值发生变化时检查(如在原本为空值的字段中输入数据,或修改某字段的值),该事件适合于屏幕中字段的值变更时的检查 |
FIELD <FLD1> MODULE <MDL1> ON REQUEST. |
6、CHAIN中不是初始值检查 |
CHAIN. |
FIELD… MODULE…(单个屏幕字段)
FIELD <f> MODULE <mod> ON INPUT|REQUEST|*-INPUT.
在编辑屏幕的PAI的时候,对字段的检查一般用field xxx module xxx或者用chain。有两种操作可供选择,一种是on input,另一种是on request。
? ON INPUT:只要该字段不为初始值就会触发module。不同类型字段的初始值是不一样的:如果是字符类型其初始值为Space;数字类型的为zero(不同类型的具体初始值请参考《ABAP BC Programming.docx》)。即使用户在输入框输入了值,但这个值为初始值时也不会触发
? ON REQUEST:该字段发生变化后触发module
例如,有两个字段,a、b,两个module,check_a check_b:
field a module check_a on input.
field b module chec_b on request.
无论a发生任何变化,只要a不为空,则每一次回车都会触发check_a;
反之,只有b发生变化后才会触发check_b,如果两次回车中间b没有发生变化,则不会触发check_b。
注:此方式与CHAIN不同,不能如下写法:
FIELDa. " FIELD与MODULE只能写在同一语句中
MODULE check_a ON INPUT.
FIELD a,b. "非Chain中时,FIELD后面不能跟多个字段
MODULEcheck_a ON INPUT.
FIELD a.
MODULE check_a ON CHAIN-INPUT. "但可以使用CHAIN-?是否有意思没有测试
? ON *-INPUT
如果屏幕字段<f>的输入内容第一个字符为“*”,并且该屏幕字段<f>设置了“* Entry”属性,且没有ON INPUT时,则会调用<mod>module ,并且首字符星号不会被传递到ABAP程序中去。
CHAIN…ENDCHAIN(多个屏幕字段)
不能嵌套。可以将多个屏幕字段组织在一块进行验证。此语句的作用就是相当于选择屏幕的AT SELECTION-SCREEN ON BLOCK block事件,用来对一个逻辑块的屏幕字段进行校验,这里的逻辑块是按Module前FIELD选项指定的屏幕字段来划分的,如下的
CHAIN.
FIELD: <f1>, <f2>,<fi...>.
MODULE <mod1> ON CHAIN-INPUT|CHAIN-REQUEST.
FIELD: <g1>, <g2>,<gi...>.
MODULE <mod2> ON CHAIN-INPUT|CHAIN-REQUEST.
...
ENDCHAIN.
只要<fi>中某个字段满足条件(<mod1>后面的CHAIN-INPUT与CHAIN-REQUEST条件),<mod1>就会被调用,而只要<fi>或<gi>中的某个字段满足条件,则<mod2>就会被调用。如果在module中检测不通过(如MESSAGE… E类消息时),则CHAIN…ENDCHAIN之外的所有其他屏幕字段将会被锁定且置灰,这与选择屏幕的AT SELECTION-SCREEN ON BLOCK校验是一样的
CHAIN.
FIELD: <f1>, <f2>,<fi...>.
FIELD <f> MODULE <mod1> ON INPUT|REQUEST|*-INPUT|CHAIN-INPUT|CHAIN-REQUEST.
MODULE <mod2> ON CHAIN-INPUT|CHAIN-REQUEST.
ENDCHAIN.
<mod1>被调用的条件是所对应字段<f>满足ON后面指定的条件即可执行。<mod2>被调用的条件是只要<fi>或<f>中的某个字段满足条件即可执行。
ON INPUT与ON CHAIN-INPUT区别
CHAIN.
FIELD:f1,f2.
FIELD: f3 MODULE mod1 ON INPUT.
ENDCHAIN.
只有f3包含非初始值时才调用mod1
CHAIN.
FIELD:f1,f2.
FIELD:f3 MODULE mod1 ON CHAIN-INPUT.
ENDCHAIN
f1,f2,f3中任一字段包含非初始值時都調用mod1.
注意on input 与on chain-input的不同
AT CURSOR-SELECTION鼠标双击时调用
在AT CURSOR-SELECTION语句调用之前,先也要通过字段有效性检测这一过程,这与AT EXIT-COMMAND是不一样的(它会绕过字段输入有效检测过程),屏幕字段的值会按照FIELD语句的出现的顺序传递到ABAP程序中,但此时Function Code不会传递到ABAP程序中去,所以此时SY-UCOMM与OK_CODE不受影响,存放的值还是上一次的值。
MODULE <mod> AT CURSOR-SELECTION.
当鼠标双击(或F2)输入/输出( I/O)类型的屏幕字段时(比如下图中屏幕字段类型为 I/O 的屏幕字段)才会调用<mod>:
注意:要使鼠标双击屏幕输入元素时AT CURSOR-SELECTION生效,还必须在GUI Status里设置:将F2(一般使用F2,不要使用别的快捷键,因为F2本来就是系统预设的鼠标功能)所对应的Function Code为CS,并且Function Type为S,此时才能激活鼠标双击功能:
还可以与FIELD一起使用:
FIELD <f> MODULE <mod> AT CURSOR-SELECTION.
或者,针对多个屏幕字段时:
CHAIN.
FIELD: <f1>, <f2>,...
MODULE <mod> AT CURSOR-SELECTION.
ENDCHAIN.
上面这两种方式下,只有当鼠标双击(或F2)I/O 类型字段<f>或<fi>屏幕字段时,<mod>才会被调用(注意:<f>或<fi>只能是I/O 类型的屏幕字段)。
AT CURSOR-SELECTION语句调用优先顺序:
? 如果有某个屏幕字段可能有以下三种语句:MODULE <mod> AT CURSOR-SELECTION(包括在CHAIN…ENDCHAIN里的语句)、FIELD <f> MODULE <mod> AT CURSOR-SELECTION有关,则带FIELD的语句会先执行(不管FIELD语句这三者前还是后),其他的语句不再被执行。
? 对于同一个屏幕字段<f>,如果有多条FIELD <f> MODULE <mod> AT CURSOR-SELECTION语句,则只有第一条会被执行
? 如果有多条MODULE <mod> AT CURSOR-SELECTION 的语句,则只有最后一条语句会被执行
示例:
) WITH 'c2: ' fld.
ENDMODULE.
在GUI status STATUS_100中,图标被激活,且Function Code为CANCEL,类型为E。快捷键F2也被激活,Function Code为 CS类型为S。
? 只要1或2输入框不为空时,MODULE_1将被调用
? 只要3个框任何一个输入内容发生了改变,则MODULE_2就会被用调用
? 只要输入框3输入的内容以*开头,则会调用MODULE_*(注意:屏幕字段INPUT3需要设置“* Entry”属性才能触发)
? 当在INPUT1上按F2或双击时,c1会被调用(因为带FIELD的要比不带FIELD的语句调用优先级要高);如果将第20行注掉,则此时cursor会被调用(因为有多条不带FIELD的语句时,最后一条才会被执行,所以要想在INPUT1上双击时调用c2,则需要将19、20都注掉)
? 当在INPUT2或INPUT3上按F2或双击时,cursor会被调用,而c2不会被调用,因为有多条不带FIELD的语句时,最后一条才会被执行
ABAP Statements for Screens
SET PF-STATUS
SET PF-STATUS <stat> [OF PROGRAM <prog>] [EXCLUDING <f>|<itab>].
给屏幕设置STATUS(屏幕菜单、工具条)
DATA fcode TYPE TABLE OF sy-ucomm.
...
MODULE status_0100 OUTPUT.
"去激活Function code为CHANGE、SAVE的功能
APPEND 'CHANGE' TO fcode.
APPEND 'SAVE' TO fcode.
SET PF-STATUS 'STATUS_0100' EXCLUDING fcode.
ENDMODULE.
SET TITLEBAR、激活Title Bar
SET TITLEBAR title [OF PROGRAM prog][WITH text1 ... text9].
除非另外有一个SET TITLEBAR重新设置了Title,否则当前屏幕及后继屏幕的Tile一样。占位符placeholders &1 ... &9可以被相应的text1 ... text9所替换,如果要显示一个&,则要在Title中使用&&来代替
.
...
MODULE status_0100 OUTPUT.
...
title = 'TITLE_0100'.
prog = '...'.
p1 = '...'.
p2 = '...'.
SET TITLEBAR title OF PROGRAM prog WITH p1 p2.
...
ENDMODULE.
GET CURSORFIELD
GET CURSOR FIELD<f>[OFFSET<off>][LINE<lin>][VALUE<val>] [LENGTH<len>] [AREA area]..
当用户在屏幕上进行操作后,我们需要知道光标操作所在哪个屏幕元素上,这个典型应用是F2(或鼠标双击)。该语句就是找出光标所在屏幕元素,它会将光标所在屏幕是元素的名称写入<f>变量中,如果光标在屏幕字段里,则SY-SUBRC为0,否则为4。
? OFFSET将光标所在屏幕元素内容中的位置写到变量off中
? LINE如果光标落在了table control表格控件中的某行,则将光标所在的行号写到lin变量中。如果光标不在table control表格控件中,则lin的值为0.
? VALUE将屏幕字段的内容(指显示模式下的内容,也就是说还包括格式字符)写到val变量中
? LENGTH将屏幕字段的显示长度写入到len变量中
? AREA
LIST屏幕的光标读取与定位请参考GET CURSOR FIELD、GET CURSOR LINE
.
MODULE user_command_0100 INPUT.
save_ok = ok_code.
CLEAR ok_code.
CASE save_ok.
WHEN 'CANCEL'.
LEAVE PROGRAM.
WHEN 'SELE'.
GET CURSOR FIELD fld OFFSET off VALUE val LENGTH len.
ENDCASE.
ENDMODULE.
MODULE init_screen_0100 OUTPUT.
SET PF-STATUS 'SDSS'.
ENDMODULE.
SET CURSOR FIELD
光标定位一是可以通过屏幕属性静态的设置
二是在PBO中动态的指定光标位置:
SET CURSOR FIELD <f> [OFFSET <off>].
输入检测
自动输入检测
屏幕的自动检测在所有屏幕字段内容传递到ABAP程序中之前,也在screen flow logic处理之前发生。如果想绕过自动检测之前就要调用module,则需要在调用时使用 AT EXIT-COMMAND选项
如果自动检测出现了错误,消息将显示在屏幕的状态条上显示,相应字段继续等待正确的输入,只有当所有输入都通过了自动检测后才会触发PAI正常处理(AT EXIT-COMMAND选项的调用除外)。自动检查以如下顺序来运行:
1. 必输字段检测
2. 数据格式检测
3. ABAP Dictionary检测
? 如果参照的字段为foreign key,则会进行Check Table检测
? fixed values检测
发现在一个自动联动现象:当SDYN_CONN-CARRID、SDYN_CONN-CONNID同时出现时,自动就具有联动功能,如果输入了SDYN_CONN-CARRID的值,则SDYN_CONN-CONNID的值会受它影响,如果不输入就选择SDYN_CONN-CONNID的值,则SDYN_CONN–CARRID框中的值会自动填上。
屏幕逻辑流中进行检测FIELD…VALUES
已过时
在ABAP Dialog Modules进行检测
当检测不通过时,可以在相应的module中发送warning (type W) 或者 error (type E)类型的消息,PAI处理就会暂停,直到输入通过检测后才会继续向后执行。
FIELD <f> MODULE <mod>.
当<mod>中发送出警告或错误类型的信息时,相应字段<f>将会要求重新输入,一旦输入检测通过后,将继续后面的PAI语句的处理,以前的module不会再次调用。
CHAIN.
FIELD: <f1>, <f2>,...
MODULE <mod1>.
FIELD: <g1>, <g2>,...
MODULE <mod2>.
...
ENDCHAIN.
当<mod1>或者<mod2>中发送出警告或错误类型的信息时,所以出现在CHAIN…ENDCHAIN块FIELD语句中的屏幕字段将会要求重新输入,其他屏幕字段被锁定且置灰不能输入。一旦输入检测通过后,将继续进后面的PAI语句的处理,以前的module不会再次调用
PROCESS BEFORE OUTPUT.
MODULE init_screen_0100.
PROCESS AFTER INPUT.
MODULE cancel AT EXIT-COMMAND.
FIELD input1 MODULE module_1.
FIELD input2 MODULE module_2.
FIELD input3 MODULE module_3.
CHAIN.
FIELD input4.
MODULE chain_module_1.
FIELD input5.
FIELD input6 MODULE chain_module_2.
ENDCHAIN.
MODULE execution.
.
MESSAGE 'chain_module_2: (input4 + input5 + input6) <= 100' TYPE 'E'.
ENDIF.
ENDMODULE.
MODULE execution INPUT.
MESSAGE 'execution:' TYPE 'I'.
ENDMODULE.
Search help (F4)
F4 Help也叫“Input Help”,而Search help又是Input Help的一种
对话屏幕字段绑定搜索帮助
F4IF_FIELD_VALUE_REQUEST:通过函数绑定搜索帮助
Domain固定值fixed values
检查表Check Table --- Value Table
也可以在Domain中指定一个值表(Value Table)作为字段取值范围的限制,但是与指定固定值的方式不同的是,为一个Domain简单地指定一个取值表不会导致用户的输入被自动校验,也不会自动出现F4 Help。只有通过表外键按钮将该Value Table指定为主表之后,一个值表才能真正成为Check Table。所以要想成为真正有效的Check Table,必须要做两个操作:
一是要为字段对应的Domain设置Value Table(即主表,其实这一步不是必须的,在通过按钮指定主表时,可以不用指定为字段所参照的元素所对应Domain所设置的Value Table,而是指定其他的主表也是可以的—— 但最好不要这样做,Value Check时会出其他问题),
二是要为表字段通过为它设置外键。
检查表(主表:SCOUNTER)的主键字段与外键表(从表:SBOOK)中的外键字段一一对应进行校验。
外键的检验也只能用于屏幕用户的输入检查,如果用ABAP程序直接向表中插入记录,则此处定义的外键检查不起作用
PARAMETERS p_carid TYPE sbook-carrid VALUE CHECK.
PARAMETERS p_cuter TYPE sbook-counter VALUE CHECK.
F4命中清单中的所有数据都来自于主表:
注:命中清单中的ID列即CARRID背景色不是蓝色,所以选择一条时,不会自动填充屏幕字段P_CARID,原因是对应的Search Help中的CARRID参数对应的EXP没有打上钩:
如果将这个钩打上,则会相应列背景色会为蓝色,且会自动填充,达到联动效果。
一般当某个外键所参照主表的主键上如果设置了搜索帮助(如上面COUNTER外键所引用的主表主键字段SCOUNTER-COUNTNUM已分配搜索“SCOUNTER_CARRIER_AIRPORT”:),则这个主表主键上的搜帮助会带到从表中相应外键上来,请看上面的SBOOK-COUNTER外键字段的搜索帮助也为“SCOUNTER_CARRIER_AIRPORT”,该搜索帮助决定了整个F4 Help处理及显示过程(如联动查询及自动填充效果)。另外,虽然主表主键上的搜索帮助会带到相应外键上来,但带过来后还可以修改,比如上面示例中带过来的搜索帮助中,CARRID参数所对应的EXP没有钩上,所以示例中的屏幕字段P_CARID不能使用命中清单中的ID列来自动填中,所以我们可以新建一个搜索帮助,并将CARRID搜索参数所对应的EXP钩上,则可达到自动上屏幕的效果;
另外,有些外键所参照的主表主键没有指定搜索帮助,此时参考的从表(或主表)屏幕字段的F4 Help就只有一个简单的字段了,如上面SBOOK-LOCCURKEY字段:
PARAMETERSp_cur TYPE sbook-LOCCURKEY VALUE CHECK.
SE11创建基本搜索帮助(Elementary Search Help),及参数说明
创建搜索帮助时,搜索帮助的数据源可以来于:表/视图(通过“选择方法”指定)、ABAP程序(通过“搜索帮助出口”指定)。下面以视图为源来创建搜索帮助。
SE11中,SAP提供了一种“帮助视图”,专门为维护搜索帮助设立的,该类视图提供表的关联信息,不会在数据库服务器上占用实际的物理空间。
创建交货订单信息相关视图:
l LIKP:交货单的表头
l VBUK:交货单状态
l KNA1:客户主数据
需要在帮助视图中显示的字段有:LIKP-VBELN交货单号;LIKP-KUNNR货物送达方的编码;KNA1-NAME1送达方的名称;VBUK-WBSTK交货单状态,“C”表示已交货
基本索引帮助:最基本也是“集合搜索帮助”组成部分的帮助,如果按F4后显示条件限制对话框,则只会有一个限制条件页面;
集合搜索帮助(collective search help):是由多个基本索引帮助组成的,中可以包含多个search help,这个也就是我们看到的选择界面有多个tab的那种情况。如果按F4后显示条件限制对话框,则会有多个条件限制页面TAB标签,即可以选择不同的“基本索引帮助”来筛选数据
l 简短描述:设置的简短描述不是限制对话框中的标题。限制对话框中的标题如何设置???
l 选择方法(selecttion method):可以是选数据表,或者是视图。当所选择的表有text table时,会自动填充下面的“文本表”标签,并且search help会根据用户登录语言自动选择相应的text。
l 限制对话框行为:按F4后是否弹出条件过滤对话框,有以下三种选择:
2 立即显示值:在按F4后立即显示命中清单,不会弹出限制对话框,通常如果命中清单记录很少时则建议使用该选项。
2 具有值限制的对话:立即显示限制值的对话框。如果正常情况下可能条目的清单非常大,则选择该选项。
2 根据值集合的对话:如果命中清单包含的条目小于100个,那么立即显示该命中清单。如果其包含的条目多余100个,那么显示限制值用的对话框。
l 快捷键:此键只在该基本搜索帮助包括到某个集合搜索帮助里时,才可使用(有意义)??作用是在集合搜索帮助的限制对话框中,出现了多个限制TAB标签页面,所以可以使用此处设置的键快速切换到相应的TAB标签页面????
HOT KEY是用来做多个search help合并时用到的,决定出现的顺序。
l 搜索帮助出口(search help exit):可以用作此搜索帮助的增强函数,对搜索出来的数据进一步进行处理。如下面出口中,在命中清单显示之前,对数据进行过滤处理:
(代码中STRING+3(4)取的是搜索帮助的第一个参数,但如果是在 CALLCONTROL-STEP = RETURN时间点时,STRING+0(4)才是第一个搜索帮助参数,因RECORD_TAB在不同时间点可能是变化着的,具体请参照后面IMP、EXP参数详细说明)
l 搜索帮助参数:来自于数据库表或视图中的字段
定义search help的parameter时,你需要定义它是IMPORT还是EXPORT。同fm一样IMPORT和EXPORT PARAMETER构成了search help的interface。
2 IMP:输入参数。表示屏幕上相应字段是否作为搜索帮助的过滤条件(即报表选择屏幕上的字段的值是否从报表选择屏幕上传递到搜索帮助中去)
如果是F4字段时,屏幕字段中的值包含“*”时,才会将F4字段传递到Search Help中。除开F4屏幕字段外,而其他只要是Link到了相应的Search Help参数的屏幕字段,则不管IMP是否钩选上,只要相应屏幕字段中有值,则会传入到搜索中作为过滤条件。所以IMP是否钩选上,只会影响该参数所Link到的F4屏幕字段值是否传入到搜索帮助,而其他非F4屏幕字段,只要与搜索帮助相应参数Link过,不管IMP参数是否钩先,则屏幕字段值都会传入到搜索帮助中。
另外,如果要对已传入的屏幕字段值进行再次修改,则可以将搜索帮助的“对话框性为—对话类型”设为“C 具有值限制的对话”,传入的屏幕字段值会在弹出限制对话框中相应字段中显示,此时就可以对这些值做进一步修改;如果没有弹出限制对话框,则屏幕上传入的值不会再次被修改的可能,会直接传入到搜索帮助作为过滤条件
注:上图中只有屏幕字段是参照表或结构字段而非通过编程来绑定Help时,在搜索帮助查询时,除了可以将F4屏幕字段传入到搜索帮助中(前提是值中有“*”,且IMP被钩选过了)作为搜索帮助的过滤条件,其他非F4屏幕字段(与搜索参数有Link关系的屏幕字段)的值也会传入到搜索帮助中作为搜索条件;在返回时,会将相应的命中清单中的列(这些列与屏幕字段是有映射关系)自动填充到相应的屏幕字段中。另外,如果是通过程序方式 MATCHCODE绑定(或其通过Data Element绑定)时,则在查询时不会将其他非F4屏幕字段传入到搜索帮助时,也不会在返回时填充其他非F4屏幕字段,在返回时,会默认返回 EXP中第一个钩选列到F4屏幕字段中。
注:IMP与EXP一定要至少一个被钩选,在将此搜索帮助分配给表字段时,IMP或EXP被钩选的列才会出现在分配界面,否则在绑定过程的分配界面是不会出现这些参数的
TABLES:zsflight.
SELECT-OPTIONS:so_carr FOR zsflight-carrid," MATCHCODE OBJECT ZH_SCARR,"航线代码
so_conn FOR zsflight-connid," MATCHCODE OBJECT ZH_SPFLI."航班代码
so_from for zsflight-CITYFROM.
2 EXP:输出参数,表示搜索帮助的此列会从搜索帮助中传递到报表选择屏幕上(表示F4选中一条记录后显示到屏幕上文本框中的值——背景字段为浅蓝色的列的数据会被输出,输出的数据可能是多列。注:只有当EXP钩上且相应字段出现在了屏幕上,才会自动填充到相应屏幕字段,如果没有钩上——没钩上的字段背景色为白色,即使出现在了屏幕上,选择命中清单时也不会自动填充),且F4字段一定要将EXP钩上(否则选择后F4字段不能上屏)。可以通过return_tab(具体可以参考自定义对话屏幕字段F4中相应代码解释)参数接收用户所选择的数据。
是否显示为浅蓝色,是由SHLP-FIELDPROP内表参数中SHLPOUTPUT字段的值来决定的;但如果是通过“Attaching to Data Elements”或直接通过编程方式使用Search Help时,即使EXP有多列被钩选,也只有最前面被钩选的列的背景色为浅蓝色,如果此时也要使被钩选的所有EXP列背景色为浅蓝色,则可以通过修改内表中SHLPOUTPUT字段的值来达此目的,因为调试发现在CALLCONTROL-STEP= DISP 时间点之前时,如果此时SHLPOUTPUT的值为X,则显示出来的命中清单相应列背景色就是浅蓝色的:
(注:此内表实质上就是用来存储“搜索帮助参数”属性列表的。刚进入F4IF_SHLP_EXIT_EXAMPLE时,搜索帮助参数EXP列中只要是被钩选的列,它所对应此内表的 SHLPOUTPUT列都会是 X ——上图就是首次进入出口函数时SHLP-FIELDPROP内表的内存状态,但运行到CALLCONTROL-STEP= DISP 时间点时,只有EXP列中第一个被钩选的列所对应的SHLPOUTPUT字段的值为X,其他都会清空,所以需要在CALLCONTROL-STEP= DISP 时间点修改此内表值,下面为CALLCONTROL-STEP= DISP 时间点时内表 SHLPOUTPUT的内存状态:)。
另外,不管时搜索帮助参数的EXP列钩选了多少个,返回时,命中清单中所选记录的所有列都会返回,这可以通过观察F4IF_SHLP_EXIT_EXAMPLE的RECORD_TAB内表参数获知,因为RECORD_TAB在不同的时间点存储了不同的数据——如果刚好是在CALLCONTROL-STEP= DISP时间点之后,存储的是搜索帮助所有命中的记录(如从数据库中搜索出来的所有数据);如果是在CALLCONTROL-STEP= RETURN时间点时,存储的则是用户选中的记录。下面就来在这两个时间点来看看RECORD_TAB内表数据:
2 CALLCONTROL-STEP= DISP时:
2 当从命中清单中选中第一条记录进入到F4IF_SHLP_EXIT_EXAMPLE函数后,此时是CALLCONTROL-STEP=RETURN时间点:
上面两个时间点来看,RECORD_TAB内表中STRING字段存储的就是命中清单与用户选中记录的数据,并且是将这些数据的多列拼接起来之后存储在此字段中的(注:或留空时,所有搜索帮助的参数还是都会被拼接起来存储在此字段中,与LPOS设置无关),这些拼接在一起的数据是通过F4IF_SHLP_EXIT_EXAMPLE的SHLP-FIELDDESCR内表参数中的OFFSET(按字节来计算的)及INTLEN(内部长度,按字节来计算的)来划分的,并且在不同的CALLCONTROL-STEP时间点时,OFFSET的取值是变化的,且时间与上面两种是相对应的:
2 CALLCONTROL-STEP= DISP时:
2 当从命中清单中选中第一条记录进入到F4IF_SHLP_EXIT_EXAMPLE函数后,此时是CALLCONTROL-STEP= RETURN时间点:
l LPOS(列表):命中清单中各列的显示顺序,如果为0或留空的列则不会显示。位置编号不能在列中出现多次,但是允许有间隔。另外,在基本搜索帮助中,至少在命中清单中出现一个参数
l SPOS:搜索帮助的过滤条件,对搜索结果进行过滤。如果在命中清单显示之前,弹出限制对话框,则还可以进一步修改那些从选择屏幕上带过来的条件值。此数字就是限制搜索帮助选择条件屏幕字段摆放顺序,如果为0或留空的列则不会出在限制条件页中
l SDis:如果勾选了,则在弹出的限制对话框中对应的字段用户不可输入,是只读的。下面是前面创建的Search Help,其中搜索参数WBSTK的SDis钩上了,所以弹出的限制对话框中所对应的屏幕字段不能进行修改:
l Modified:如果这个勾打上的话,数据元素(Data Element)列,变成可修改状态,也就是说可以为这个字段指定其它数据元素
l 缺省值:此处设置的默认值是被相应的SPos列所使用的。可以有三种值设置方式:a ‘literal’(in quotes), a parameter ID(ZRD), or a system field (SY-UNAME).
F4IF_SHLP_EXIT_EXAMPLE出口函数参数说明及实例
u 出口函数参数
下面以ZH_SPFLI搜索帮助来理解F4IF_SHLP_EXIT_EXAMPLE出口函数各参数:
TABLES: zsflight.
SELECT-OPTIONS:s_carrid FOR zsflight-carrid, "航线代码
s_connid FOR zsflight-connid, "航班代码
s_ctyfrm FOR zsflight-cityfrom. "起飞城市
以上面搜索帮助为例,运行报表程序,并在出口函数中设置断点,来理解一下F4IF_SHLP_EXIT_EXAMPLE出口函数各参数:
l SHLP参数
2 SHLPNAME 搜索帮助名
2 SHLPTYPE 搜索帮助的类型,取值如下:
SH Search help 搜索帮助
CH Check table 表检查
CT Check table with text table 有文本表的检查表
FV Fixed values for domains 域的固定值
DV Fixed values from flow logic 流逻辑的固定值
CA Calendar help 日历帮助
CL Time help 时间帮助
SR Search help for data element (temporary) 数据元素的搜索帮助(临时)
MC Matchcode 匹配代码
MI Matchcode ID 匹配代码标识
IN Internal Table 内表
2 INTDESCR搜索帮助的内部信息,一般程序使用不到
2 INTERFACE 包含了Help中的所有参数,当前使用哪个参数为F4屏幕字段,屏幕字段与Help参数映射信息(映射关系是通过SHLPFIELD与VALFIELD两列来映射),以及传入的F4屏幕字段的值(其他非F4屏幕字段的值不会在这里存储,而是在SHLP-SELOPT存储的)
2 FIELDDESCR注要描述了Help各参数在命中清单RECORD_TAB-STRING中的偏移量与长度,便于各字段值的读取:
2 FIELDPROP实质上存储的就是Help参数属性,与Search Help SE11维护界面里的相同
2 SELOPT存储了选择屏幕与限制对话框屏幕上所有与此Help Link过的字段值,即这些会作为搜索帮助的过滤条件
l CALLCONTROL参数
Callcontrol-step: 该字段的值是由系统设置,并且你可以在程序中进行修改它。出口函数会在处理的每一步(时间点)都会调用一次This field is set by the system and can be changed by your code. The function module will be called once for each step of the process, with some conditional exceptions noted below.
1. SELONE
Call before selecting an elementary search help. The possible elementary search helps are already in SHLP_TAB. This timepoint can be used in a search help exit of a collective search help to restrict the selection possibilities for the elementary search helps.
在选择基本元素搜索帮助之前调用。所有基本搜索帮助都已经放在了SHLP_TAB中了。该时间点是用来在集合搜索帮助中限制某些基本搜索帮助是否可选(应该就是在该时间点用来控制某个基本搜索帮助在弹出限制对话框中是否显示出来)
Entries that are deleted from SHLP_TAB in this step are not offered in the elementary search help selection. If there is only one entry remaining in SHLP_TAB, the dialog box for selecting elementary search helps is skipped. You may not change the next timepoint.
The timepoint is not accessed again if another elementary search help is to be selected during the dialog.
2. PRESEL1
After selecting an elementary search help. Table INTERFACE has not yet been copied to table SELOPT at this timepoint in the definition of the search help (type SHLP_DESCR_T). This means that you can still influence the attachment of the search help to the screen here. (Table INTERFACE contains the information about how the search help parameters are related to the screen fields).
在选择一个基本搜索帮助后调用。在该时间点上,SHLP/SHLP_TAB中的表INTERFACE不再复制到表SELOPT,这就意味着你仍然可以在这里影响搜索帮助到屏幕的映射关系(表INTERFACE包含了关于搜索帮助参数到屏幕字段的映射信息)
3. PRESEL
Before sending the dialog box for restricting values. This timepoint is suitable for predefining the value restriction or for completely suppressing or copying the dialog.
在限制对话框中的条件值发送之前调用。该时间点适合于对预定义值进行控制
4. SELECT
Before selecting the values. If you do not want the default selection, you should copy this timepoint with a search help exit. DISP should be set as the next timepoint.
选值之前调用(如果有弹出限制对话框,则会在弹出限制对话框中点击确认按钮后调用)。如果你不想使用默认选择,那就应该使搜索帮助退出该时间点,将DISP设置成下一个时间点
5. DISP
Before displaying the hit list. This timepoint is suitable for restricting the values to be displayed, e.g. depending on authorizations.
在命中清单显示之前调用。该时间用于控制搜索帮助的输出结果。例如,在输出搜索结果时对用户检查权限,删除未授权的数据
5. RETURN (usually as return value for the next timepoint一般作为下一个时间点的返回值)
set by your code if one hit was found during selection
The RETURN timepoint should be returned as the next step if a single hit was selected in a search help exit.
如果在一个搜索帮助退出中选择了一个单独命中,那么就将RETURN时间点作为下一步返回
It can make sense to change the F4 flow at this timepoint if control of the process sequence of the Transaction should depend on the selected value (typical example: setting SET/GET parameters). However, you should note that the process will then depend on whether a value was entered manually or with an input help.
如果对事务处理序列的控制取决于已选中的值(典型例子:设置SET/GET参量),那么在该时间点上改变F4的流程就是有意义的。然而,应该注意到,该处理将取决于一个值是手工输入的还是用输入帮助输入的。
7. RETTOP
follows RETURN if called from a collective search help
You only go to this timepoint if the input help is controlled by a collective search help. It directly follows the timepoint RETURN. The search help exit of the collective search help, however, is called at timepoint RETTOP.
只有当输入帮助由集合搜索帮助控制时,才转到该时间点。它直接跟着时间点RETURN。然而,集合搜索帮助的搜索帮助退出是在时间点RETTOP上调用的。
8. EXIT (only for return as next timepoint仅为了下一个时间点的返回)
set by your code. Terminates the search help process
The EXIT timepoint should be returned as the next step if the user had the opportunity to terminate the dialog within the search help exit.
如果用户有机会在一个搜索帮助退出中终止对话,那么EXIT时间点应作为下一步返回
9. CREATE
The CREATE timepoint is only accessed if the user selects the function "Create new values". This function is only available if field CUSTTAB of the control string CALLCONTROL was given a value not equal to SPACE earlier on.
仅当用户选择函数“创建新值”时,才访问CREATE时间点。且当赋予控制参数CALLCONTROL所对应的结构体中的字段CUSTTAB为非空值时,该时间点才是有效的。
The name of the (customizing) table to be maintained is normally entered there. The next step returned after CREATE should be SELECT so that the newly entered value can be selected and then displayed.
正常的情况下,在那里输入将要维护的表(定制)的名字。CREATE之后,返回的下一步应该是SELECT,这样才能选择新输入的值,并且随后显示。
10. APP1, APP2, APP3
If further pushbuttons are introduced in the hit list with function module F4UT_LIST_EXIT, these timepoints are introduced. They are accessed when the user presses the corresponding pushbutton.
如果带有函数模块F4UT_LIST_EXIT的命中列表包含了更深一层的按钮,那么也会介入这些时间点。当用户单击相应的按钮时,就能访问这些时间点。
注:如果F4帮助是一个集合搜索帮助,那么就在时间点SELONE和RETTOP上调用集合搜索帮助的出口。(RETTOP仅当用户选择一个值)。在所有的其也时间点上,调用选择的元素搜索帮助的出口。
如果F4帮助是一个基本搜索帮助,不执行RETTOP时间点。在时间点SELONE(当时)调用元素搜索帮助的出口,其他准备工作都在时间点PRESEL1上执行
Table中的接口定义:
l SHLP_TAB
Table of elementary search helps
存储所有的基本搜索帮助,行结构与Changing接口中的SHL结构类似
l RECORD_TAB
用来存储命中清单上将要显示的所有记录数据。另外,在选择命中清单上某条件数据返回时,该内表也会存储被选中记录
u 出口函数实例1
下面创建一个与F4IF_SHLP_EXIT_EXAMPLE函数一样的出口函数ZFVBELN_FIND_EXIT:
,
wbstk TYPE wbstk,
lfdat TYPE lfdat_v,
vbeln TYPE vbeln_vl,
END OF lt_tab.
"用于存储从选择屏幕上传进的屏幕字段的选择条件值
DATA: r_vbeln TYPE RANGE OF vbeln_vl WITH HEADER LINE,
r_lfdat TYPE RANGE OF lfdat_v WITH HEADER LINE,
r_wbstk TYPE RANGE OF wbstk WITH HEADER LINE,
wa_selopt LIKE LINE OF shlp-selopt."
"callcontrol-step该字段的值是由系统设置,并且你可以在程序中进行修改它。出口函数会在处理的每一步(时间点)都会调用一次
IFcallcontrol-step = 'SELECT'."如果有弹出限制对话框,则会在弹出限制对话框中点击确认按钮后step值才为SELECT
"shlp-selopt存储的是经过映射转换后选择屏幕上字段的值,而不是直接为
"选择屏幕字段名,而是转映射为Help参数名后再存储到 selopt 内表中,
"屏幕字段到Help参数映射是通过 shlp-interface 来映射的
LOOP AT shlp-selopt INTO wa_selopt.
CASE wa_selopt-shlpfield.
WHEN 'VBELN'."由于屏幕字段已映射为了Help相应参数,所以这里不是S_VBELN
MOVE-CORRESPONDING wa_selopt TO r_vbeln.
APPEND r_vbeln.
WHEN 'LFDAT'.
MOVE-CORRESPONDING wa_selopt TO r_lfdat.
APPEND r_lfdat.
WHEN 'WBSTK'.
MOVE-CORRESPONDING wa_selopt TO r_wbstk.
APPEND r_wbstk.
ENDCASE.
ENDLOOP.
"根据屏幕上传进的条件查询数据
SELECT likp~vbeln likp~lfdat vbuk~wbstk INTO CORRESPONDING FIELDS OF TABLE lt_tab
FROM likp INNER JOIN vbuk ON likp~vbeln = vbuk~vbeln
WHERE likp~vbeln IN r_vbeln AND
likp~lfdat IN r_lfdat AND
vbuk~wbstk IN r_wbstk.
"该函数的作用是将内表 lt_tab 中的数据转换成record_tab,即将某内表中的数据显示在命中清单中
CALL FUNCTION 'F4UT_RESULTS_MAP'
TABLES
shlp_tab = shlp_tab
record_tab = record_tab
source_tab = lt_tab
CHANGING
shlp = shlp
callcontrol = callcontrol.
"注:下一个时间点一定要直接设置为 DISP,否则命中清单不会有值,也不显示出来
"从表面上看,SELECT时间点下一个就是 DISP时间点,按理是不需要设置为DISP,
"但如果不设置为DISP,出口函数在执行完后,系统会转入DISP时间点执行(即再次调用此出口函数)
",但再次进入此出口函数时,record_tab内表已经被清空了(是否可以通过判断callcontrol-step的值来决定走什么新的逻辑代码来解决此问题?)。如果这里直接设置为DISP,就好比欺骗
"了系统一样,告诉系统当前执行的正是DISP时间点,而不是SELECT,系统就不会再转到 DISP时间点了
"而是直接显示。还有一个主要的时间点就是:CALLCONTROL-STEP= RETURN
callcontrol-step = 'DISP'.
ENDIF.
ENDFUNCTION.
选择屏幕代码:
DATA: ZSTRUCT TYPE ZSTRUCT.
SELECT-OPTIONS:s_vbeln FOR ZSTRUCT-vbeln,
s_lfdat FOR ZSTRUCT-lfdat,
s_wbstk FOR ZSTRUCT-wbstk.
u 实例2:非主键搜索帮助创建删除重复项的方法
通过se11创建非主键字段的搜索帮助,在命中清单中会出现重复项。这需要在搜索帮助的search help exit里面建一个自建的搜索帮助出口函数在函数中将重复项去掉。具体代码增加地方如下:
FUNCTIONzeh_lxsecond.
IF callcontrol-step = 'DISP'.
SORT RECORD_TAB.
DELETE ADJACENT DUPLICATES FROM RECORD_TAB COMPARING ALL FIELDS."zsecond.
EXIT.
ENDIF.
ENDFUNCTION.
创建集合搜索帮助(Collective Search Help)
集合搜索帮助可以包含多个基本搜索帮助,但是最好保证所包含的搜索帮助中至少存在一个相同的参数,如前面两节“SE11创建搜索帮助(以视图为数据源),及参数说明”中的ZH_VBELN搜索帮助、“出口函数参数及实例——出口函数实例”中的ZH_VBELN_01搜索帮助,都包含了系统参数VBELN,可以分别参照交货单的送达方查找单号,或者通过交货日期来查找交货单号:
下面创建一个名为 ZH_VBELN_02 的集合搜索帮助:
在搜索帮助参数中,这里输入搜索参数一般都来源于包含的所有基本搜索帮助的参数(注:包含进来的这些参数要在基本搜索帮助里要么是IMP参数,要么是EXP参数,否则加进来激活时会报错,比如这里的WBSTK,由于在两个基本搜索帮助中都没有钩选IMP与EXP,所以这里不能加进来),这里的 IMP(导入)、EXP(导出)与基本搜索帮助里的IMP EXP作用是一样的,但这里的IMP EXP会覆盖基本搜索中的IMP EXP,输入输出参数以此集合帮助中设置的为准,除开IMP、EXP以集合搜索帮助中的为准外,其他的LPos、SPos、SDis则以各自的基本元素搜索帮助中的设置为准:
然后再将ZH_VBELN与ZH_VBELN_01两个基本搜索帮助包含进来,并分配参数:
然后再将集合搜索帮助绑定到自定的结构上面:
最后在报表程序中Link这个结构:
DATA: zstruct TYPE zstruct.
SELECT-OPTIONS:s_vbeln FOR zstruct-vbeln,
s_lfdat FOR zstruct-lfdat,
s_kunnr FOR zstruct-kunnr,
s_name1 FOR zstruct-name1,
s_wbstk FOR zstruct-wbstk.
注:发现集合搜索帮助在屏幕字段中输入“*”后,发现如果本应该是输出字段的,最后在命中清单中却不是输出字段(背景色不是浅蓝色的了),如果含有“*”还是正常,这是系统的一个bug吗??
表/结构字段绑定搜索帮助的两种方式
首先必须要创建一个Search Help,然后将表字段链接到这SH也有两种方法
1. 直接在SE11的表字段上(这种方式按F4键可能会带出多个值,具体要看SH的参数而定),如图:
2. 通过数据元素实现Search help,如图:
Search help绑定方式
注:绑定的搜索参数MSEHI一定要是输出参数,但可以不是输入参数,所以IMP不必选中,但EXP一定要选中。所以Data Element中绑定的搜索参数可能是搜索帮助的输入参数(屏蔽字段可以传入到搜索帮助),但一定是输出参数
Check Table即主表,引用此Check Table的表即从表,为某个表字段设置Check Table的过程实质上就是为某个表字段设置外键的过程,所以Check Table与外键是同一概念
CheckTable(主表)的所有关键字键都会自动的成为搜索帮助的输入输出参数。如果CheckTable有 text Table,则这个text Table的第一个text field 根据用户登录语言也会显示出来
3. Attaching to a Table Field or Structure Field
如果搜索帮助的EXP参数被分配到了表字段,则当用户在命中清单上选择一条数据时,此参数的内容会返回到相应屏幕字段;如果搜索帮助的IMP分配到了表字段,则F4屏幕字段的值会传入到搜索帮助中
搜索帮助可以直接绑定到屏幕字段上,在这种情况下,这个搜索帮助只能用在此屏幕中。如果同一个字段在不同的屏幕上使用,则最好将搜索帮助绑定到参照表或结构字段上会共用一些
可以通过以下几种方式将搜索帮助直接绑定到屏幕字段上:
l 在屏幕设计界面Screen Painter中的字段属性Search help中设置搜索帮助名称
l The name of the search help can be defined for selection screens in ABAP reports in the PARAMETERS or SELECT-OPTIONS statement directly following the supplement AS SEARCH PATTERN.
l …MATCHCODE OBJECT search_help… ???
以上方式都只会将搜索帮助的第一个EXP参数分配到绑定的字段,结果就是命中清单中只有一列值返回到屏幕中
Search Help Hierarchy(优先级)
When you call the input help for a screen field, there is first a check if an input help is defined for the field on the screen. There are three cases here. If there is a programmed help with PROCESS ON VALUE-REQUEST, it is executed. If there is no programmed help, the system tries to call the search help assigned to the field on the screen. If no search help is assigned to the field on the screen, the help defined with FIELD SELECT or FIELD VALUESis offered.
先PROCESS ON VALUE-REQUEST,再MATCHCODE OBJECT,最后FIELD SELECT or FIELD VALUES
If no input help is defined for the field on the screen, the system tries to call the search help attached to the table field(表字段). If there is no search help here, it tries to display the check table help(检查表). There are two cases here. If a search help is attached to the check table, it is displayed. Otherwise only the key values of the check table are displayed. If there is a text table for the check table, the text for the key value is added in the user’s logon language.
先看是否绑定了检查表Check Table,再看表字段是否绑定了搜索帮助。如果这两种同时出现,则会优先使用Check Table
If there is no check table for the field, the system tries to call the search help from the data element. If there is no search help for the data element either, existing domain fixed values are displayed. The calendar help and time help are automatically provided for fields with data type DATS and TIMS.
如果以上都不存在搜索帮助时,则看data element是否绑定了帮助,如果没有,再看domain是否存在fixed values。最后是系统提供的DATS and TIMS类型Help
SE11测试Search Help
此种测试方式是在没有写报表程序的情况下,也可以对Help进行测试,不同的是这里的选择屏幕是动态生成的,且模拟的是那种通过表或结构字段绑定的Search Help(非程序绑定),所以通过此种方式模拟具有联动效果(屏幕字段可以传入到搜索帮助中作为过滤条件,从命中清单返回的结果可以自动填充到相应的屏幕字段中)
通过程序绑定表字段中的搜索帮助、动态生成搜索帮助(绑定到某个内表)并联动
本实例中,屏幕字段 CARRIER 的Search help是程序在运行时,通过F4IF_FIELD_VALUE_REQUEST(另一个与此函数相似的函数为:F4_FIELD_ON_VALUE_REQUEST——描述:该功能模块完成对于屏幕上的字段,增加F4帮助功能,通过输入的表名、字段名、检索帮助名来绑定,从而获取输入值)函数绑定到一个表字段上(该表字段上已绑定过搜索帮助);下面实例中CONNECT的Search help是通过函数F4IF_INT_TABLE_VALUE_REQUEST绑定到一个内表上实现的。
在本实例中,CARRIER与 CONNECT具有联带效果,即CONNECT 的命中清单的数据受到 CARRIER 屏幕字段值的约束,二是从CONNECT 的命中清单返回时,会将CONNCT对应的 CARRIER自动填充:
对话屏幕代码:
PROCESS BEFORE OUTPUT.
MODULE init.
PROCESS AFTER INPUT.
MODULE cancel AT EXIT-COMMAND.
PROCESS ON VALUE-REQUEST.
FIELD carrier MODULE value_carrier.
FIELD connect MODULE value_connection.
ABAP程序代码:
命中清单数据
.
MODULE init OUTPUT.
progname = sy-repid.
dynnum = sy-dynnr.
ENDMODULE. "init OUTPUT
"对话屏幕中CARRIER屏幕字段的Search Help实现
MODULE value_carrier INPUT.
DATA:return_tab TYPE TABLE OF ddshretval WITH HEADER LINE.
"F4IF_FIELD_VALUE_REQUEST函数的作用是在运行时,可以动态的为某个屏幕字段
"设置Search Help,这个被引用的Help来自某个表(或结构)字段上绑定的Help。
"该函数实质上就是在运行时调用某个Search Help,直到用户从命中清单上选中某
"条件记录(之前一直会阻塞),才会去执行后面的代码
CALL FUNCTION 'F4IF_FIELD_VALUE_REQUEST'
EXPORTING "将对话屏幕中的CARRIER字段的Search Help设置成 DEMOF4HELP 表中的CARRIER1
"字段上所绑定的Search Help
tabname = 'DEMOF4HELP'"搜索帮助来自于哪个表
fieldname = 'CARRIER1'"搜索帮助来自于哪个表的哪表字段
SEARCHHELP='DEMO_F4_DE'"明确帮助具体来自于表字段DEMOF4HELP-CARRIER1上的DEMO_F4_DE帮助(可省略此参数)
SHLPPARAM = 'CARRID'"指定搜索帮助(DEMO_F4_DE)中的哪个参数(CARRID)绑定到屏幕字段(CARRIER)上如果不指定,则默认将搜索帮助中的第一个参数(CARRID)绑定到屏幕字段(CARRIER)上
"将 DEMOF4HELP-CARRIER1上绑定的搜索帮助DEMO_F4_DE的CARRID参数绑定到CARRIER 屏幕字段上
dynpprog = progname
dynpnr = dynnum
dynprofield = 'CARRIER'
VALUE=''"用来指定F4屏幕字段(CARRID)的值,如果该值包含了通配符* 将会传入到搜索帮助里作为搜索帮助的过滤条件,一般情况下,不用设置此值,因为如果 DYNPPROG, DYNPNR, STEPL 这些参数可用的情况,会自动去获取相应屏幕字段的值
MULTIPLE_CHOICE = 'X'"命中清单中的记录是否可以多选,即命中清单中记录前是否有复选框
SELECTION_SCREEN =''"是否使用屏幕字段CARRIER所参照的Domain中设置的 value table
TABLES
return_tab = return_tab."用来接收从命中清单上选中并返回的记录
""""将用户从命中清单中选中的记录填充到对话屏幕相应的字段中(注:下面更新屏幕字段的代码应该也可以由F4IF_FIELD_VALUE_REQUEST函数的回调接口CALLBACK_FORM来代替,当然没有连带效果,所以不需要采用此方式)
CLEAR: field_value, dynpro_values[].
"填充对话屏幕中的CARRIER屏幕字段
"field_value-fieldname = 'CARRIER'.
"field_value-fieldvalue = return_tab-fieldval.
"APPEND field_value TO dynpro_values.
"由于carrier屏幕字段本身此时为F4字段,所以可以直接赋值就可以更新屏幕中的值,所以可以不用使用 DYNP_VALUES_UPDATE 函数的方式来更新,但下面的CONNECT屏幕字段就不可以采用这种直接赋值方式来更新屏幕中的值,因为它是非F4字段
carrier = return_tab-fieldval.
.
"F001 F002为动态生成的Search help的参数,且F002已经映射到了屏幕字段CONNECT
"(在调用F4IF_INT_TABLE_VALUE_REQUEST过程通过参数已指明),除了CONNECT本身
"F4字段回填到屏幕中,屏幕字段CARRIER也要需要能够自动从命中清单中自动填充,这
"就需要屏幕字段CARRIER与Search help的F001参数作一个映射关系,这个映射关系就是
"在这里指明的
interface-shlpfield = 'F0001'.
interface-valfield = 'CARRIER'.
interface-value = carrier."从CARRIER屏幕字段中传过来的值,
interface-f4field = ''."CARRIER屏幕字段不是F4字段
APPEND interface TO shlp-interface.
ENDFORM.
通过TR_F4_HELP实现简单Search Help(数据来源于内表)
P_LGOR屏幕字段的F4搜索帮助的最后整体效果如下:
在该实例中,屏幕字段P_WERKS参照的Data Elementwerks_d绑定了一个搜索帮助:H_T001W_C,但这个帮助是Collective srch hlp类型的帮助:
并且H_T001W_T还是一个Append search help,它又包含H_T001W:
H_T001W才是最终的基本元素搜索帮助:
在P_WERKS屏幕字段上按F4键,弹出的搜索帮助效果如下(可以看出弹出的限制对话框中的屏幕字段都是由H_T001W基本元素帮助的SPos一起决定的):
iv_no_of_key_columns
iv_width_of_titles
no_line_picked .
READ TABLE gt_itab INDEX l_index."读取用户选中的命中清单中的记录
"由于P_LGORT本身就是F4字段,所以可用不用DYNP_VALUES_UPDATE函数
"就可以直接更新屏幕就的字段,但 P_WERKS 必须使用此函数来更新
",而不能像P_LGORT屏幕字段那样直接赋值进行更新
"dynpfields-fieldname = 'P_LGORT'.
"dynpfields-fieldvalue = gt_itab-lgort.
"APPEND dynpfields .
"由于P_LGORT是F4字段,所以可以直接采用赋值方式就可以更新
p_lgort = gt_itab-lgort.
"但P_WERKS非F4字段,所以不能直接采用上面赋值方式来更新,要使用DYNP_VALUES_UPDATE函数
dynpfields-fieldname = 'P_WERKS'.
dynpfields-fieldvalue = gt_itab-werks.
APPEND dynpfields .
CALL FUNCTION 'DYNP_VALUES_UPDATE'
EXPORTING
dyname = sy-repid
dynumb = sy-dynnr
TABLES
dynpfields = dynpfields.
ENDIF.
Search Help三种不同绑定方(表字段、Check Table、Struct)式实现同样效果
1. 通过表字段绑定Help
此种方式需要使用SE11创建Search Help,然后将Search Help绑定到某表字段上,并将其他Search Help的参数也分配到其它表字段上
下图中将Search Help参数分配给表字段:
TABLES:zsflight.
SELECT-OPTIONS:so_carr FOR zsflight-carrid," MATCHCODE OBJECT ZH_SCARR,"航线代码
so_conn FOR zsflight-connid," MATCHCODE OBJECT ZH_SPFLI."航班代码
so_from for zsflight-CITYFROM." 起飞城市
只要在上图中的命中清单中选择一数据后,会将选中记录的相应列自动填充相应屏幕字段(Help参数里打上钩的EXP列——如果EXP列没有打钩,就不会自动填充到相应字段中?且这些列所分配的表字段在程序中被Link到屏幕字段),达到联动效果(搜索与返回都会产生联动:搜索SO_CONN时,会将SO_CARR与SO_FROM屏幕字段一起传入到搜索帮助里,并且从命中清单返回到屏幕时,SO_CARR与SO_FROM屏幕字段也会使用选中命中清单的相应列来自动填充)
2. 通过Check Table实现Search Help
此种方式不需要使用SE11来创建真正的Search Help,只需要为相应的表字段指定外键,则会自动为此表字段设置Check Table,一旦表字段有Check Table后,不需为该表字段绑定Search Help,所有Link具有Check Table约束的表字段屏幕字段时都会自动拥有Search Help。
Check Table实质上就是一种给从表字段设置外键的过程,Search Help的数据来源于主表。
还是以上面创建的表为例,来通过设置Check Table来达到实现Search Help的目的:ZSFLIGHT表中的主键有三个字段:MANDT、CARRID、CONNID,其中MANDT已经设置了Check Table T000,下面为CARRID、CONNID两个字段设置Check Table:
设置Check Table后,表的相关信息如下:
同样的屏幕代码,只不过此时屏幕字段的Search Help是由Check Table(主表)来实现的:
TABLES:zsflight.
SELECT-OPTIONS:so_carr FOR zsflight-carrid," MATCHCODE OBJECT ZH_SCARR,"航线代码
so_conn FOR zsflight-connid," MATCHCODE OBJECT ZH_SPFLI."航班代码
so_from for zsflight-CITYFROM." 起飞城市
但与上面第一种方式不同的是,由于ZSFLIGHT的CITYFROM不是外键(未设置Check Table),所以表字段ZSFLIGHT-CITYFROM Link选择屏幕字段SO_FROM的值不会传到Search Help中,从命中清单返回时也不会自动填充该屏幕字段:
另外,使用Check Table实现Search Table时,好像对限制框是否弹出来不能进行设置?
3. 绑定到结构字段
此种方式只是将第一种方式的表换成了结构,在程序中Link此结构就可以了,其绑定帮助的过程与表字段是一样的。
DATA: zstruct TYPE zstruct.
SELECT-OPTIONS:so_carr FOR zstruct-carrid," MATCHCODE OBJECT ZH_SCARR,"航线代码
so_conn FOR zstruct-connid," MATCHCODE OBJECT ZH_SPFLI,"航班代码
so_from FOR zstruct-cityfrom."起飞城市
此种设计方式与第一种效果完全一样,不会像第二种Check Table那样,屏幕字段SO_FROM也会传入。
其实,除了上面三种方式后,结构实质上也可以设置Check Table,所以与上面第二种方式一样,也可以实质Search Help。
动态修改屏幕
与选择屏幕一样,对话屏幕也有对应的SCREEN内表(下面这些属性是可以动态修改的):
Component |
Length |
Type |
Description |
Attribute(Screen Painter中对应的静态属性) |
NAME |
30 |
C |
如果参数是select-options类型参数,则参数名以LOW与HIGH后缀来区分。 TABLES: mara. |
Name |
3 |
C |
Modificationgroup1 |
Group1 |
|
GROUP2 |
3 |
C |
Modificationgroup2 |
Group2 |
GROUP3 |
3 |
C |
Modificationgroup3 |
Group3 |
GROUP4 |
3 |
C |
Modificationgroup4 |
Group4 |
REQUIRED |
1 |
C |
Fieldinputis mandatory必输入 ,去掉OBLIGATORY选项(不去掉也会被忽略),并在AT SELECTION-SCREEN ON field事件里时进行为空验证 取值为 0:不必输,框中前面也没有钩 1:必输,框中前面有钩 2:不必输,但框中前面有钩,此时需要手动检验 ). |
Mandatoryfield |
1 |
C |
Fieldis readyfor input可输入 通过此属性可以控制输入框的可输入性。 复选框是否可输入可以参考这里 DEMO_MESSAGES程序(SAP自带的各种情况下的Message测试) 如果是复选框(Check Box)与单选按钮(Radio Button),则当此属性设置为0时,则不可输入,并且会变灰(前提是要静态属性INVisible没有设置),这与输入框不太一样(输入在不能输入的情况下也不会变灰) 选中not possible时,表示只显示,不能输入: possible与recommended都是可选,但不区别是什么?? required选项:表示必输入字段 |
Input |
|
OUTPUT |
1 |
C |
Fieldis for displayonly仅显示,不输入输入。当选中此静态属性后,Input Field清除选中且置灰不能再选择 |
Output |
INTENSIFIED |
1 |
C |
Fieldis highlighted高亮度显示字段 input类型的fields(可输入字段)中的内容会从黑色变为红色, output类型的fields(不可输入字段)中的内容会从黑色变为蓝色 |
bright |
INVISIBLE |
1 |
C |
Fieldis suppresse字段内容不可见,不单指隐藏整个输入字段(如screen-Input=0,screen-Invisible=1时,整个字段会被隐藏,但如果只有screen-Invisible=1,只输入字段本身不会被隐藏,而只是输入框中的内容被显示为******) |
Invisible |
LENGTH |
1 |
X |
Fieldlength 可以对input/outputfields或者是 Outputonlyfields进行设置,其值不能大于Screen Painter里静态设置的显示长度的值 |
VisLg |
ACTIVE |
1 |
C |
Fieldis active激(字段可见并用于输入) |
Input/Output/Invisible(三个静态属性都设置时才相当于ACTIVE) |
DISPLAY_3D |
1 |
C |
Three-dimensional box 输入框四周会有线框,否则没有 |
Two-dimensional |
VALUE_HELP |
1 |
C |
Inputhelpbuttondisplay激活输入帮助 |
Inputhelp |
REQUEST |
1 |
C |
Inputexists 默认为0,如果设置为1,则作用好比修改了屏幕字段内容,这时会执行PAI块里的ON REQUEST或者ONCHAIN-REQUEST的模块调用,而不管是屏幕字段的内容是否真正的改变了 |
- |
最后一列(Attribute)表示屏幕字段在Screen Painter中所对应的各自静态属性。上面动态属性除了LENGTH属性之外,设置为1表示激活该动态属性,0表示去激活该动态属性
Screen Painter里的静态属性Output Only在上表SCREEN内表中没有对应的动态属性,所以该属性不能动态的修改
Output Only:表示屏幕字段只能显示,不能被修改
你可以在PBO中通过如下代码进行属性修改:
AT SELECTION-SCREEN OUTPUT.
LOOP AT SCREEN.
...
MODIFY SCREEN.
...
ENDLOOP.
若已经在Screen Painter 中静态地将一个屏幕字段设置为不可见的,则要想在程序中将其修改成可见,不能使用语句SCREEN-ACTIVE = 1,而应该使用SCREEN-INVISIBLE = 0;但如一个屏幕字段在Screen Painter中被静态地设置为可见的,则可以通过语句SCREEN-ACTIVE = 0将其设置为不可见,此语句相当于下面三个语句的组合使用:
SCREEN-INVISIBLE = 1、SCREEN-INPUT = 0、SCREEN-OUTPUT = 0
在PBO开始时ACTIVE通常为1,除非设置了这样的静态属性:INPUT = 0, OUTPUT = 0, and INVISIBLE = 1,则ACTIVE会自动设为0。另外,如果设置动态属性INPUT = 0, OUTPUT = 0, and INVISIBLE = 1,则此时ACTIVE 相当于 0(其实则此时ACTIVE设置任何值都会被忽略,即使设置为1也不会有效果)。ACTIVE属性的唯一目的是,让你能够通过一个单独的属性就能将屏幕字段inactive掉。
在ACTIVE, INPUT, OUTPUT, 与INVISIBLE动态属性之间存在着一种特定优先规则,它们还有受屏幕字段的静态属性所影响,但ACTIVE动态属性在Screen Painter中没有与之对应的静态属性。不同组合设置效果如下:
ACTIVE |
INPUT |
OUTPUT |
INVISIBLE |
Effect |
1 |
1 |
1 |
0 |
屏幕字段会显示,即使静态属性Invisible被设置 屏幕字段的内容会显示 屏幕字段可以输入,即使静态属性Input未被设置。但是,如果静态属性Outputonly被设置后,屏幕字段将不能输入。 |
1 |
1 |
0 |
0 |
屏幕字段会显示,即使静态属性Invisible被设置,但不能设置静态属性Outputonly。 屏幕字段的内容不显示 屏幕字段可以输入,即使静态属性Input未被设置。 |
1 |
0 |
1 |
0 |
屏幕字段会显示,即使静态属性Invisible被设置 屏幕字段的内容会显示 屏幕字段不能输入,即使设置了Input静态属性 |
1 |
0 |
0 |
0 |
屏幕字段会显示,即使静态属性Invisible被设置,但不能设置静态属性Outputonly。 屏幕字段的内容不显示 屏幕字段不能输入,即使设置了静态属性Input |
1 |
1 |
1 |
1 |
屏幕字段会显示,即使静态属性Invisible被设置,但不能设置静态属性Outputonly。 屏幕字段的内容显示为*星号 屏幕字段可以输入,即使静态属性Input未被设置。但输入的内容会替换为*星号 |
1 |
1 |
0 |
1 |
屏幕字段会显示,即使静态属性Invisible被设置,但不能设置静态属性Outputonly。 屏幕字段的内容显示为*星号 屏幕字段可以输入,即使静态属性Input未被设置。但输入的内容会替换为*星号 |
1 |
0 |
1 |
1 |
屏幕字段去激活 屏幕字段不显示,不管你设置何种静态属性 |
0 |
0 |
0 |
1 |
屏幕字段去激活 屏幕字段不显示,不管你设置何种静态属性 |
如果设置了静态属性 Output only,则会忽略动态属性INPUT、OUTPUT的设置。
具体实例请参考:DEMO_DYNPRO_MODIFY_SCREEN,下面是这个示例程序0100屏幕中6个输入框在Screen Painter中INPUT、OUTPUT 、OUTPUT ONLY、INVISIBLE静态属性的初始值:
屏幕字段的属性对应于上面表格后面10动态属性
能正确显示出当前属性状态,需要将内部状态(0、1只适于
屏幕,这里可以省略,
屏幕的下一屏幕静态属性设置的就是100
屏幕)不弹出来。该语句作用是:如果该语句用在PBO中,当前屏幕不会显示,
,则可以使用此语句来过路此屏幕,当然这可以使用LEAVE SCREEN.语句来代替此语句,但LEAVE SCREEN需要放在PBO的最后面(因为LEAVE SCREEN后面的语句是不会再执行的),但SUPPRESS DIALOG可以放在PBO中的任何位置
屏幕)并到达(TO)列表处理,并且(AND)设置其nextscreen 为0,即关闭List时,会结束输出列表屏幕并返回到该屏幕序列最开始调用处主屏幕100(如果未使用RETUN选项,则点击List标准工具栏上的Back按钮时,会返回到当前屏200所设置的下一屏幕——静态属性设定与动态指定都可)
) itab-name,
11 itab-active,
15 itab-input,
19 itab-output,
23 itab-invisible,
27 itab-required,
31 itab-intensified,
35 itab-display_3d,
39 itab-value_help,
43 itab-request,
47 length.
ENDLOOP.
ENDMODULE.
FORM change_input CHANGING val TYPE any.
IF val = 'X'.
val = '1'.
ELSEIF val = ' '.
val = '0'.
ELSEIF val = '1'.
val = 'X'.
ELSEIF val = '0'.
val = ' '.
ENDIF.
ENDFORM.
module USER_COMMAND_0200 input.
save_ok = ok_code.
CLEAR ok_code.
endmodule.
复合屏幕元素
图标Status Icons(ICON_CREATE)
可以使用ICON_CREATE函数来为Status Field 生成符合某种格式的Icon信息串(选择屏幕上带图标按钮实例请参考这里):
REPORT DEMO_DYNPRO_STATUS_ICONS.
.
ENDCASE.
ENDMODULE.
右键菜单Context Menus for Screen
Context menu是右键点击的时候在鼠标的位置弹出的。在定义screen object的时候可以定义是否提供context menu(screen,input fields,table controls和box等),当选择context menu的一个object时,事件处理就会执行应用程序的一个subroutine,这种机制传递了一个指向subroutine的reference,程序通过这个menu reference来显示menu。可以通过menu painter来创建menu或者动态创建menu。当执行一个menu function时,application program得到control并响应用户输入。Context menu被分配给output fields,当你给box,table control或screen分配context menu时,所有没有分配context menu从属于它的output fields都会继承这个context menu。可以通过object navigator来创建context menu,也可以通过menu painter来创建。Context menu是一种特殊的GUI STATUS,它有name,descripative text和status type:context menu
可以通过CL_CTMENU类的静态方法load_gui_status来load通过Menu painter预先定义好的context menu。通过其他方法可以重新创建和动态修改context menu。如果用户通过context menu激活了一个function(菜单项),这个function的function code就会填到command field中并根据function type触发相应的PAI。Cl_ctmen除了静态方法load_gui_status外还有一系列的方法用来动态修改context menu,这些方法在ON_CTMENU_<context>中调用。
在Screen Painter中可以通过元素的来设置context menu(不是具体某个菜单项,它是一个菜单上下文,相当于一个菜单容器,它里面有什么样的菜单项)的构造处理。如果没有给某个元素设置context menu,则该元素会继承上一级的元素的菜单(如某个Frame中某个元素未设置,则它会继续直Frame所设置的上下文菜单,如果Frame未设置,则会继续屏幕所设置的)
如果某元素绑定context menu后,当在元素上鼠标右键(不会触发PAI事件,只有当选择某个具体菜单项时才会触发PAI)时,会自动调用ON_CTMENU_<context>(<context>为context menu的ID)这样的一个Form,所以可以在回调该From时动态的定义context menu的构造过程
对于每一个分配给元素的context menu,在运行时会自动创建一个CL_CTMENU对象,当用户右击请求这个context menu时,会将这个context menu的引用传递给下面所示的这个Form:
FORM ON_CTMENU_<context> USING <l_menu> TYPE REF TO cl_ctmenu.
...
ENDFORM.
对象传递给这个Form时,context menu中是没有菜单项的,这时可以在这个Form中使用CL_CTMENU对象相关方法来动态的构造context menu
右键菜单示例:
利用“CL_CTMENU”类中的各种方法可以实现许多功能,如方法“load_gui_status”允许使用系统预定义的上下文菜单;可通过方法“add_menu”或者“add_submenu”来添加其他的同级菜单对象或者子菜单,以及添加分隔线、激活或者禁止选择(菜单项呈灰色)等。
通过Menu Painter创建context menu时,类型要选择Context Menu:
这里创建CONTEXT_MENU_1、CONTEXT_MENU_2、CONTEXT_MENU_3三个context menu:
以及普通类型的SCREEN_101:
REPORT demo_dynpro_context_menu.
.
WHEN 'SQUAREROOT'.
field2 = field1 ** ( 1 / 2 ).
WHEN 'CUBICROOT'.
field2 = field1 ** ( 1 / 3 ).
ENDCASE.
ENDMODULE.
FORM on_ctmenu_text USING l_menu TYPE REF TO cl_ctmenu.
"加载已定义好的静态上下文菜单
CALL METHOD l_menu->load_gui_status
EXPORTING
program = prog
status = 'CONTEXT_MENU_1'"CANCEL
menu = l_menu.
ENDFORM.
FORM on_ctmenu_frame USING l_menu TYPE REF TO cl_ctmenu.
CALL METHOD cl_ctmenu=>load_gui_status
EXPORTING
program = prog
status = 'CONTEXT_MENU_2'"HIDE
menu = l_menu.
CALL METHOD cl_ctmenu=>load_gui_status
EXPORTING
program = prog
status = 'CONTEXT_MENU_1'"CANCEL
menu = l_menu.
IF flag = ' '."如果已点击过 HIDE ,则此时HIDE菜单设置为不可用
DATA: fcodes TYPE ui_functions .
APPEND 'HIDE' TO fcodes .
CALL METHOD l_menu->disable_functions
EXPORTING
fcodes = fcodes.
ENDIF.
ENDFORM.
FORM on_ctmenu_reveal USING l_menu TYPE REF TO cl_ctmenu.
CALL METHOD cl_ctmenu=>load_gui_status
EXPORTING
program = prog
status = 'CONTEXT_MENU_3'"REVEAL
menu = l_menu.
CALL METHOD cl_ctmenu=>load_gui_status
EXPORTING
program = prog
status = 'CONTEXT_MENU_1'"CANCEL
menu = l_menu.
IF flag = 'X'."如果已点击过 REVEAL ,则此时REVEAL菜单设置为不可用
DATA: fcodes TYPE ui_functions .
APPEND 'REVEAL' TO fcodes .
CALL METHOD l_menu->disable_functions
EXPORTING
fcodes = fcodes.
ENDIF.
ENDFORM.
FORM on_ctmenu_input USING l_menu TYPE REF TO cl_ctmenu.
DATA calculate_menu TYPE REF TO cl_ctmenu.
CREATE OBJECT calculate_menu."下面通过程序动态创建上下文菜单
"======给上下文菜单添加菜单项
CALL METHOD calculate_menu->add_function
EXPORTING
fcode = 'SQUARE'
text = '平方'.
CALL METHOD calculate_menu->add_function
EXPORTING
fcode = 'CUBE'
text = '立方'.
CALL METHOD calculate_menu->add_function
EXPORTING
fcode = 'SQUAREROOT'
text = '开平方'.
CALL METHOD calculate_menu->add_function
EXPORTING
fcode = 'CUBICROOT'
text = '开立方'.
"=======将上面动态创建的上下文菜单挂到当前(计算)菜单下面,成为子菜单
CALL METHOD l_menu->add_submenu
EXPORTING
menu = calculate_menu
text = '计算'.
ENDFORM.
运行效果如下:
由于Field2已经隐藏,所Hide Result右键不可用
Field2上没有设置Menu,所以继承自FRAME
在FRAME之外,显示屏幕的标准Context Menus
子屏幕Subscreens
如果是通过屏幕编辑器创建的子屏幕是,则在创建子屏幕时,需要指定屏幕的类型为子屏幕类型:
并且Next Screen一定要设置成自己。子屏幕需要放在子屏幕区域,且不能超过区域大小。
另外,除了像上面那样通过屏幕编辑器来创建子屏幕外,还可以通过通过SELECTION-SCREEN BEGIN OF SCREEN dynnr AS SUBSCREEN语句在ABAP程序代码中来定义子屏幕,定义后也可能通过下面的CALL SUBSCREEN语句来调用,而不一定要使用屏幕绘制器绘制的屏幕
子屏幕限制:
? 个子屏幕共用同一ABAP程序中全局变量field,而且这4个子屏幕上都有一个名为field的输入框)
? 子屏幕中没有OK_CODE字段,使用的是主屏幕中的OK_CODE field;
? 子屏幕的flowlogic不能包括MODULE... AT EXIT- COMMAND的语句,类型为E的Function Code仅只能在主屏幕中处理;
? 子屏幕flowlogic中不能包含SET TITLEBAR,SET PF-STATUS,SETSCREEN,LEAVE SCREEN,or LEAVE TO SCREEN这些语句,任何这些语句都会引起运行错误,不能在子屏幕中改变主屏幕的GUI Status
在主屏幕的flow logic中使用CALL SUBSCREEN将子屏幕include进行来,语句如下:
PROCESS BEFORE OUTPUT.
...
CALL SUBSCREEN <area> INCLUDING [<prog>] <dynp>.
...
子屏幕都需要放在主屏幕中的某个指定的<area>区域元素中。
为了调用子屏幕的PAI事件,需要在主屏幕的PAI flow logic里如下调用:
PROCESS AFTER INPUT.
...
CALL SUBSCREEN <area>.
...
该语句的作用等效于调用(触发)了子屏幕中的PAI事件块
不能够将CALL SUBSCREEN语句放在CHAIN and ENDCHAIN 或者 LOOP and ENDLOOP之间调用。SY-DYNNR会在CALL SUBSCREEN开始到结束之前发生修改,且为子屏幕的屏幕号,并在返回到主屏幕时修改成主屏幕的屏幕号
示例:DEMO_DYNPRO_SUBSCREENS
先要画两个可以存储子屏幕的区域控件:
效果:
报表主程序:
) ) ) ) ) 个子屏幕共有的输入框
.).).
ENDMODULE.
MODULE fill_0140 OUTPUT.
field = field2.
ENDMODULE.
MODULE cancel INPUT."如果点击了标准工具栏上的“取消”按钮后退出整个程序
LEAVEPROGRAM.
ENDMODULE.
MODULE save_ok INPUT.
save_ok = ok_code.
CLEAR ok_code.
ENDMODULE.
MODULE user_command_0110 INPUT.
IF save_ok = 'OK1'.
number1 = '0120'.
field1 = field.
CLEARfield.
ENDIF.
ENDMODULE.
MODULE user_command_0130 INPUT.
IF save_ok = 'OK2'.
number2 = '0140'.
field2 = field.
CLEARfield.
ENDIF.
ENDMODULE.
MODULE user_command_100 INPUT.
CASE save_ok.
WHEN'SUB1'.
number1 = '0110'.
WHEN'SUB2'.
number1 = '0120'.
CLEAR field1.
WHEN'SUB3'.
number2 = '0130'.
WHEN'SUB4'.
number2 = '0140'.
CLEAR field2.
ENDCASE.
ENDMODULE.
100主对话屏幕:
子屏幕:
Tabstrip(Tab条)
从技术角度来看,Tab条中的每一个Tab page是由子屏幕与Table Title按钮组成的:
所以,每一个Tab page是由一个Tab Title(实质上就是一个按钮,Tab title与按钮具有一样的属性)、一个子屏幕区域(用来Include子屏幕)组成的:
功能代码类型设置为“P”表示当用户按下这个TAB页按钮时,不触发主屏幕后台的PAI事件,如果FctType留空,则会触发
Ref.Field表示该TAB页按钮与其对应的要显示的子屏幕的连接,在PBO流逻辑中将使用这个“Ref.Field”调用对应的子屏幕
静态的Tabstrip(多个子屏幕区域)
必须为每一个Tab title分配一个单独的子屏幕区域,并且tabe title的Funcode的类型为P,还需在主屏幕的PBO块中加载所有的subscreens,以及在主屏幕的PAI块中调用每个subscreens的PAI事件。
当切换Tab page时,主屏幕的PAI事件不会触发(但子屏幕事件是否触PAI发看是否满足以下两个条件:一是在主屏幕的PAI块中调用了子屏幕的PAI事件了,即调用了CALL SUBSCREEN: <area>这样的语句;二是子屏幕中的元素确是触发了PAI事件,如点击了子屏幕中的某个按钮),所以在切换期间是不会对子屏幕中进行input checks数据检测动作,input checks数据检测动作需要等到点击主屏幕上的某个具有Function Code的元素时才触发(如F8)。所以静态的Tabstrip适用于显示数据,而不适合于输入数据。
对于静态的Tabstrip,需要在主屏幕的PBO与PAI中一次性(仅需一次)加载所有的子屏幕:
PROCESS BEFORE OUTPUT.
...
CALL SUBSCREEN: <area1> INCLUDING [<prog1>] <dynp1>,
<area2> INCLUDING [<prog2>] <dynp2>,
<area3> INCLUDING [<prog3>] <dynp3>,
...
PROCESS AFTER INPUT.
...
CALL SUBSCREEN: <area1>,
<area2>,
<area3>,
...
动态的Tabstrip(共用一个子屏幕区域)
所有的table title共用一个子屏幕区域,这是通过Screen Painter中Table Title元素的属性来设定共享的。此时Table Title的Function code类型不指定,因此当每次进行切换时,会触发主屏幕的PAI事件,这样如果主屏幕的PAI块中调用了子屏幕的PAI事件,则子屏幕的PAI事件也会被调用。另外,在切换到其他Tab page之前会进行当前子屏幕的input checks数据检测动作,只有通过了input checks数据检测动作后才能切换到其他Tab page。另外,不像静态Tabstrip那样一次性全部将子屏幕加载到Tabstrip控件中,而是每次切换时include相应的子屏。
对于动态的Tabstrip,需要在主屏幕的PBO与PAI中多次(但每次只加载一个子屏幕)动态加载某个子屏幕:
PROCESS BEFORE OUTPUT.
...
CALL SUBSCREEN <area> INCLUDING [<prog>] <dynp>.
...
PROCESS AFTER INPUT.
...
CALL SUBSCREEN <area>.
...
静态Tabstrip示例
.
MODULE status_0100 OUTPUT.
SET PF-STATUS 'SCREEN_100'.
ENDMODULE.
MODULE cancel INPUT.
LEAVE PROGRAM.
ENDMODULE.
MODULE user_command INPUT.
save_ok = ok_code.
CLEAR ok_code.
IF save_ok = 'OK'.
MESSAGE i888(sabapdocu) WITH 'MYTABSTRIP-ACTIVETAB ='
mytabstrip-activetab.
ENDIF.
ENDMODULE.
动态Tabstrip示例
这个示例是将上面静态的改成了动态的,基本上一样
报表程序:
.
MODULE status_0100 OUTPUT.
SET PF-STATUS 'SCREEN_100'.
ENDMODULE.
MODULE cancel INPUT.
LEAVE PROGRAM.
ENDMODULE.
MODULE user_command INPUT.
save_ok = ok_code.
CLEAR ok_code.
IF save_ok = 'OK'.
MESSAGE i888(sabapdocu) WITH 'MYTABSTRIP-ACTIVETAB =' mytabstrip-activetab.
ELSE.
mytabstrip-activetab = save_ok.
CASE save_ok."点击Tab Title时需要手动切换Tab
WHEN 'PUSH1'.
number = '0110'.
WHEN 'PUSH2'.
number = '0120'.
WHEN 'PUSH3'.
number = '0130'.
ENDCASE.
ENDIF.
ENDMODULE.
选择屏幕中的 Tabstrip
选择屏幕中的 Tabstrip 示例请参考这里
通过向导创建Tabstrip
选择工具栏中的,绘制控件时,会弹出向导界面:
输入Tabstrip对象名:
输入每个Tab标签的标题,输入的个数也决定了Tab标签的个数:
每个Tab标签页面需要单独分配一个子屏幕,定义好页面后,系统将自动分配功能代码并为每个页面自动分配一个子屏幕:
输入生成的代码所存放的Include文件名:
完成后屏幕绘制上会生成名为TAB01的Tab标签控件:
根据生成的代码来看,向导所采用的是动态Tabstrip方式生成的:
PROCESS BEFORE OUTPUT.
*&SPWIZARD: PBO FLOW LOGIC FOR TABSTRIP 'TAB01'
MODULE TAB01_ACTIVE_TAB_SET.
CALL SUBSCREEN TAB01_SCA
INCLUDING G_TAB01-PROG G_TAB01-SUBSCREEN.
* MODULE STATUS_1001.
*
PROCESS AFTER INPUT.
*&SPWIZARD: PAI FLOW LOGIC FOR TABSTRIP 'TAB01'
CALL SUBSCREEN TAB01_SCA.
MODULE TAB01_ACTIVE_TAB_GET.
* MODULE USER_COMMAND_1001.
.
*&SPWIZARD: FUNCTION CODES FOR TABSTRIP 'TAB01'
CONSTANTS: BEGIN OF C_TAB01,
TAB1 LIKE SY-UCOMM VALUE 'TAB01_FC1',
TAB2 LIKE SY-UCOMM VALUE 'TAB01_FC2',
END OF C_TAB01.
*&SPWIZARD: DATA FOR TABSTRIP 'TAB01'
CONTROLS: TAB01 TYPE TABSTRIP.
DATA: BEGIN OF G_TAB01,
SUBSCREEN LIKE SY-DYNNR,
PROG LIKE SY-REPID VALUE 'ZJZJ_TABSTRIPWIZARD',
PRESSED_TAB LIKE SY-UCOMM VALUE C_TAB01-TAB1,
END OF G_TAB01.
DATA: OK_CODE LIKE SY-UCOMM.
*&SPWIZARD: OUTPUT MODULE FOR TS 'TAB01'. DO NOT CHANGE THIS LINE!
*&SPWIZARD: SETS ACTIVE TAB
MODULE TAB01_ACTIVE_TAB_SET OUTPUT.
TAB01-ACTIVETAB = G_TAB01-PRESSED_TAB.
CASE G_TAB01-PRESSED_TAB.
WHEN C_TAB01-TAB1.
G_TAB01-SUBSCREEN = '1002'.
WHEN C_TAB01-TAB2.
G_TAB01-SUBSCREEN = '1003'.
WHEN OTHERS.
*&SPWIZARD: DO NOTHING
ENDCASE.
ENDMODULE.
*&SPWIZARD: INPUT MODULE FOR TS 'TAB01'. DO NOT CHANGE THIS LINE!
*&SPWIZARD: GETS ACTIVE TAB
MODULE TAB01_ACTIVE_TAB_GET INPUT.
OK_CODE = SY-UCOMM.
CASE OK_CODE.
WHEN C_TAB01-TAB1.
G_TAB01-PRESSED_TAB = C_TAB01-TAB1.
WHEN C_TAB01-TAB2.
G_TAB01-PRESSED_TAB = C_TAB01-TAB2.
WHEN OTHERS.
*&SPWIZARD: DO NOTHING
ENDCASE.
ENDMODULE.
结论:通过上面的实例的实现,发现向导Tab控件比手动写的Tab控件要简单得多,所以尽量采用向导生成的方式来生成Tab控件。
Custom Controls(自定义控件)
自定义控件是通过Screen Painter的来创建的区域与放在该区域中的应用控件组成的。通过只是创建了用来存放具体应用组件的一个区域(即容器),需要放什么则是通过一系列相应类来编程实现的。
SAP Control Framework的事件类型
System events:
该事件发生时,不会触发PBO和PAI事件(所以也不会自动发生数据传输)。这类事件的优点是:事件处理方法会第一时间自动调用,不管input checks检测是否通过,因为事件处理方法总是在PAI触发之前执行,而PAI事件触前才进行input checks检测,所以input checks检测是在事件处理方法调用之后才进行;这类事件的缺点是:有可能屏幕字段的内容不会传递到ABAP程序中,这就会造成下一屏幕显示的数据为过时数据,但我们可以在事件处理方法中通过cl_gui_cfw=>set_new_ok_code手动设置Function code ,让PAI事件触发,则屏幕字段内容肯定会被传递到ABAP程序中去,所以这样可以避免这个问题。
Application events:
该事件在PAI处理完后会自动触发(这种情况下屏幕字段已经传输到程序变量),你也可以在PAI事件当中使用CL_GUI_CFW=>DISPATCH来人为触发Application events事件的处理,当事件处理方法调用完后,控制权又会返回到DISPATCH的调用点继续执行PAI事件。
此种类型的事件的优点如下:可以控制事件处理方法在何时调用,并且在调用前数据已经传递到ABAP程序中了;缺点是:如果input checks检测不通过时,事件处理方法是不会被执行的。
(注意:此图有点问题,因为在没有使用DISPATCH的情况下,当PAI事件执行完后,也会自动的调用事件处理方法)
CL_GUI_SPLITTER_CONTAINER
主要功能就是container的拆分。
CONSTRUCTOR:构造方法,主要参数:
PARENT -- Parent Container,待拆分的cl_gui_container的引用
ROWS –需要显示多少行,举例,你想把container分成上下两个部分,那么rows = 2
COLUMNS – 需要分成多少列
接下来主要是一些setter和getter方法
SET_BORDER 设置边框的格式,space:不设置 ‘X’:设置
SET_ROW_HEIGHT — GET_ROW_HEIGHT 用来设置行的高度
SET_COLUMN_WIDTH - GET_COLUMN_WIDTH 设置列的宽度
SET_ROW_MODE - GET_ROW_MODE 设置行的模式
SET_COLUMN_MODE - GET_COLUMN_MODE 设置列的模式
下面这四个方法原理一样,主要设置splitter的属性,例如能不能移动等等
SET_ROW_SASH - GET_ROW_SASH
SET_COLUMN_SASH - GET_COLUMN_SASH
get_container方法用来获取指定的拆分格子,参数:
row: 第几行
column: 第几列
container:获取到的格子引用,其类型还是一cl_gui_container类型的Container
SAP的GUI的类列表
CLASS NAME |
Super CLASS NAME |
DESCRIPTIO |
CL_GUI_OBJECT |
|
Proxy Class for a GUI Object |
CL_FORMPAINTER_BASEWINDOW |
CL_GUI_OBJECT |
SAP Form Painter Window Base Class |
CL_FORMPAINTER_BITMAPWINDOW |
CL_FORMPAINTER_BASEWINDOW |
SAP Form Painter Bitmap Window Class |
CL_FORMPAINTER_TEXTWINDOW |
CL_FORMPAINTER_BASEWINDOW |
SAP Form Painter Text Window Class |
CL_GUI_CONTROL |
CL_GUI_OBJECT |
Proxy Class for Control in GUI |
CL_DSVAS_GUI_BUSIGRAPH |
CL_GUI_CONTROL |
DSVAS: Proxy for Business Graphic |
CL_GFW_GP_PRES_CHART |
CL_GUI_CONTROL |
GFW: Product-specific section of CL_GUI_GP_PRES (Chart) |
CL_GFW_GP_PRES_PIG |
CL_GUI_CONTROL |
GFW: product specific section for web view |
CL_GFW_GP_PRES_SAP |
CL_GUI_CONTROL |
GFW: product-specific section of CL_GUI_GP_PRES (SAP BUSG) |
CL_GUI_ALV_GRID_BASE |
CL_GUI_CONTROL |
Basis Class for ALV Grid |
CL_CALENDAR_CONTROL_SCHEDULE |
CL_GUI_ALV_GRID_BASE |
Calendar View (Day, Week, Month) |
CL_GUI_ALV_GRID |
CL_GUI_ALV_GRID_BASE |
ALV List Viewer |
CL_ALV_DD_LISTBOX |
CL_GUI_ALV_GRID |
D&D List Box |
CL_BUKF_CAT_GRID |
CL_GUI_ALV_GRID |
Key Figures - Grid of categories |
CL_BUKF_DSRC_GRID |
CL_GUI_ALV_GRID |
Key Figures - Grid for Data sources |
CL_BUKF_FILTER_GRID |
CL_GUI_ALV_GRID |
Key Figures - Filter for Key Figure |
CL_BUKF_KF_GRID |
CL_GUI_ALV_GRID |
Key Figures - Grid for Key Figures |
CL_BUKF_TERMS_GRID |
CL_GUI_ALV_GRID |
Key Figures - Grid for terms |
CL_FTR_GUI_ENTRY_ALV |
CL_GUI_ALV_GRID |
Class: ALV Grid Control for Initial Screen (Without Toolbar) |
CL_GFW_GP_GRID_ALV |
CL_GUI_ALV_GRID |
ALV grid proxy |
CL_GUI_AQQGRAPHIC_ADAPT |
CL_GUI_CONTROL |
Network Adapter |
CL_GUI_AQQGRAPHIC_CONTROL |
CL_GUI_CONTROL |
BW Basis Class Network Control |
CL_GUI_AQQGRAPHIC_NETPLAN |
CL_GUI_AQQGRAPHIC_CONTROL |
Network Control |
CL_GUI_BARCHART |
CL_GUI_CONTROL |
Bar chart wrapper |
CL_GUI_BORDERPAINTER |
CL_GUI_CONTROL |
SAP Border Painter Control Proxy Class |
CL_GUI_BTFEDITOR |
CL_GUI_CONTROL |
SAP BTF Editor Control Proxy Class |
CL_GUI_CALENDAR |
CL_GUI_CONTROL |
Calendar Control Proxy Class |
CL_GUI_CHART_ENGINE_WIN |
CL_GUI_CONTROL |
Graphics: Presentation Graphics (SAP GUI for Windows) |
CL_GUI_CONTAINER |
CL_GUI_CONTROL |
Abstract Container for GUI Controls |
CL_GUI_CONTAINER_INFO |
CL_GUI_CONTAINER |
Information on Container Controls |
CL_GUI_CUSTOM_CONTAINER |
CL_GUI_CONTAINER |
Container for Custom Controls in the Screen Area |
CL_GUI_DIALOGBOX_CONTAINER |
CL_GUI_CONTAINER |
Container for Custom Controls in the Screen Area |
CL_ECL_VIEWER_FRAME |
CL_GUI_DIALOGBOX_CONTAINER |
Manage EAI Control in Own Window |
CL_GUI_ECL_VIEWERBOX |
CL_GUI_DIALOGBOX_CONTAINER |
ECL Viewer as Dialog Box |
CL_GUI_DOCKING_CONTAINER |
CL_GUI_CONTAINER |
Docking Control Container |
CL_GUI_EASY_SPLITTER_CONTAINER |
CL_GUI_CONTAINER |
Reduced Version of Splitter Container Control |
CL_EU_EASY_SPLITTER_CONTAINER |
CL_GUI_EASY_SPLITTER_CONTAINER |
Internal Test; Do Not Use |
CL_GUI_GOS_CONTAINER |
CL_GUI_CONTAINER |
Generic Object Services Container |
CL_GUI_SIMPLE_CONTAINER |
CL_GUI_CONTAINER |
Anonymous Container |
CL_GUI_SPLITTER_CONTAINER |
CL_GUI_CONTAINER |
Splitter Control |
CL_GUI_ECL_2DCOMPARE |
CL_GUI_CONTROL |
Compare Module for 2D Viewer |
CL_GUI_ECL_3DCOMPARE |
CL_GUI_CONTROL |
Compare Module for 3D Viewer |
CL_GUI_ECL_3DMEASUREMENT |
CL_GUI_CONTROL |
Measurement Module for 3D Viewer |
CL_GUI_ECL_3DSECTIONING |
CL_GUI_CONTROL |
Sectioning Module for 3D Viewer |
CL_GUI_ECL_MARKUP |
CL_GUI_CONTROL |
Markup (Redlining) Component |
CL_GUI_ECL_PMI |
CL_GUI_CONTROL |
PMI Module for the 3D Viewer |
CL_GUI_ECL_PRIMARYVIEWER |
CL_GUI_CONTROL |
Basis Class for ECL Viewers (2D und 3D) |
CL_GUI_ECL_2DVIEWER |
CL_GUI_ECL_PRIMARYVIEWER |
Engineering Client 2D Viewer |
CL_GUI_ECL_3DVIEWER |
CL_GUI_ECL_PRIMARYVIEWER |
Engineering Client 3D Viewer |
CL_GUI_ECL_VIEWER |
CL_GUI_CONTROL |
Proxy Class for Engineering Client Viewer |
CL_GUI_FORMPAINTER |
CL_GUI_CONTROL |
SAP Form Painter Control Proxy Class |
CL_GUI_GLT |
CL_GUI_CONTROL |
Internal; Do Not Use! |
CL_GUI_GP |
CL_GUI_CONTROL |
GFW: Superclass of all graphics proxies |
CL_GUI_GP_GRID |
CL_GUI_GP |
GFW: Grid proxy |
CL_GUI_GP_HIER |
CL_GUI_GP |
GFW: Structure graphics |
CL_GUI_GP_PRES |
CL_GUI_GP |
GFW: Business graphic |
CL_GUI_GRLT |
CL_GUI_CONTROL |
Internal; Do Not Use !! ( restricted license - see docu) |
CL_GUI_HTML_EDITOR |
CL_GUI_CONTROL |
HTML Editor |
CL_GUI_ILIDRAGNDROP_CONTROL |
CL_GUI_CONTROL |
Interactive List: Drag & Drop |
CL_GUI_MOVIE |
CL_GUI_CONTROL |
SAP Movie Control |
CL_GUI_NETCHART |
CL_GUI_CONTROL |
Network wrapper |
CL_GFW_GP_HIER_SAP |
CL_GUI_NETCHART |
GFW: Product-specific section of CL_GUI_GP_HIER (NETZ) |
CL_GUI_PDFVIEWER |
CL_GUI_CONTROL |
PDF Viewer |
CL_GUI_PICTURE |
CL_GUI_CONTROL |
SAP Picture Control |
CL_GFW_GP_PRES_WEB |
CL_GUI_PICTURE |
GFW: product specific section for web view |
CL_GUI_RTF_EDITOR |
CL_GUI_CONTROL |
SAP SAPscript Editor Control |
CL_GUI_SAPSCRIPT_EDITOR |
CL_GUI_RTF_EDITOR |
SAP SAPscript Editor Control |
CL_GUI_SELECTOR |
CL_GUI_CONTROL |
SAPSelector: Control for selecting colors or bitmaps |
CL_GUI_SPH_STATUS_CONTROL |
CL_GUI_CONTROL |
SAPphone: Status Event Control |
CL_GUI_TABLEPAINTER |
CL_GUI_CONTROL |
SAP Table Painter Control Proxy Class |
CL_GUI_TIMER |
CL_GUI_CONTROL |
SAP Timer Control |
CL_GUI_TOOLBAR |
CL_GUI_CONTROL |
Toolbar Control |
CL_CCMS_AL_GUI_TOOLBAR |
CL_GUI_TOOLBAR |
Alerts: GUI Toolbar Used in the Visual Framework |
CL_GUI_WCF_WWP |
CL_GUI_CONTROL |
Internal Tool - DO NOT USE |
CL_KW_AUTOMATION_CONTROL |
CL_GUI_CONTROL |
Helper Class for General Automation Objects |
CL_LC_EDITOR_CONTROL |
CL_GUI_CONTROL |
Lifecycle Editor Control |
CL_GCM_LCEDITOR_CONTROL |
CL_LC_EDITOR_CONTROL |
Control for the display of definition life cycles |
CL_SOTR_SPELLCHECKER |
CL_GUI_CONTROL |
Interface with OTR Spellchecker |
CL_SRM_BASE_CONTROL |
CL_GUI_CONTROL |
SRM Control |
CL_SRM_STACKED_CONTROL |
CL_SRM_BASE_CONTROL |
RM Control with Stack |
CL_TREE_CONTROL_BASE |
CL_GUI_CONTROL |
Internal Tree Control Class |
CL_GUI_SIMPLE_TREE |
CL_TREE_CONTROL_BASE |
Simple Tree Control |
CL_ITEM_TREE_CONTROL |
CL_TREE_CONTROL_BASE |
Internal Tree Control Class |
CL_GUI_COLUMN_TREE |
CL_ITEM_TREE_CONTROL |
Column Tree Control |
BDMT_CONTROL |
CL_GUI_COLUMN_TREE |
Administers Tree Control for Monitoring |
CL_BUCC_TREE |
CL_GUI_COLUMN_TREE |
Consistency Checks - Library Tree |
CL_GFW_COLUMN_TREE |
CL_GUI_COLUMN_TREE |
Do not use!!!!!!!! |
CL_GFW_GP_HIER_SAPTREE |
CL_GFW_COLUMN_TREE |
GFW: Product-specific section of CL_GUI_GP_HIER |
CL_HU_COLUMN_TREE |
CL_GUI_COLUMN_TREE |
Tree that Displays Handling Units |
CL_GUI_LIST_TREE |
CL_ITEM_TREE_CONTROL |
List Tree Control |
C_OI_CONTAINER_CONTROL_PROXY |
CL_GUI_CONTROL |
For Internal Use |
SCE_HTML_CONTROL_EVENT_HANDLER |
CL_GUI_CONTROL |
Event Handler for SCE HTML Control |
CL_ALV_TREE_BASE |
CL_GUI_CONTROL |
Basis Class ALV Tree Control |
CL_GUI_ALV_TREE |
CL_ALV_TREE_BASE |
ALV Tree Control |
CL_GCM_WORKLIST_TREE |
CL_GUI_ALV_TREE |
CM: Worklist |
CL_PT_GUI_TMW_ALV_TREE |
CL_GUI_ALV_TREE |
Small Modification to CL_GUI_ALV_TREE |
CL_GUI_ALV_TREE_SIMPLE |
CL_ALV_TREE_BASE |
Simple ALV Tree |
CL_SIMPLE_TREE_VIEW_MM |
CL_GUI_ALV_TREE_SIMPLE |
Simplest Kind of Tree |
CL_GUI_ECATT_RECORDER |
CL_GUI_CONTROL |
SAP eCATT Recorder Control - To be used by eCATT only! |
CL_GUI_TEXTEDIT |
CL_GUI_CONTROL |
SAP TextEdit Control |
CL_GCM_TEXTEDIT |
CL_GUI_TEXTEDIT |
CM: Long text control |
CL_SOTR_TEXTEDIT |
CL_GUI_TEXTEDIT |
Edit Control for the OTR |
CL_GUI_HTML_VIEWER |
CL_GUI_CONTROL |
HTML Control Proxy Class |
CL_BFW_HTML_VIEWER_POC |
CL_GUI_HTML_VIEWER |
Browser Framework: Proxy for HTML Control |
CL_CCMS_BSP_VIEWER |
CL_GUI_HTML_VIEWER |
HTML Control Proxy Class |
CL_CCMS_AL_OBJ_DET_HTML_VIEWER |
CL_CCMS_BSP_VIEWER |
Alerts: Component That Displays Object Properties with HTML |
CL_CCMS_FROG_HTML_VIEWER |
CL_GUI_HTML_VIEWER |
CL_GUI_FROG_HTML_VIEWER |
CL_SSF_HTML_VIEWER |
CL_GUI_HTML_VIEWER |
Smart Forms: Enhanced HTML Viewer |
CL_GUI_ECL_MATRIX |
CL_GUI_OBJECT |
Represents a Complete Data Type with 13 Floats |
CL_GUI_RESOURCES |
CL_GUI_OBJECT |
GUI Resources (Fonts, Colors, ...) |
CL_WF_GUI_RESOURCES |
CL_GUI_RESOURCES |
Getting Front Settings |
CL_WF_GUI_RESOURCES_4_HTML |
CL_GUI_RESOURCES |
Get Front Settings for HTML Generation |
CL_KW_AUTOMATION_OBJECT |
CL_GUI_OBJECT |
For Internal Use |
CL_TABLEPAINTER_BASETABLE |
CL_GUI_OBJECT |
SAP Table Painter Table Base Class |
CL_TABLEPAINTER_TABLE |
CL_TABLEPAINTER_BASETABLE |
SAP Table Painter Table Class |
CL_TABLEPAINTER_TEMPLATE |
CL_TABLEPAINTER_BASETABLE |
SAP Table Painter Template Class |
C_OI_AUTOMATION_OBJECT |
CL_GUI_OBJECT |
For Internal Use |
CL_GUI_FRONTEND_SERVICES |
CL_GUI_OBJECT |
Frontend services |
自定义类事件处理示例:
.
ENDIF.
ENDMETHOD.
METHOD static_meth."静态方法触发事件
"静态方法不能确发实例事件
"RAISE EVENT too_fast EXPORTING p1 = speed .
"触发静态事件
RAISE EVENT too_fast_static EXPORTING p1 = 1 .
ENDMETHOD.
METHOD show_speed.
WRITE: / 'show_speed: ' ,msg.
ENDMETHOD.
ENDCLASS.
"监听器
CLASS handler DEFINITION.
PUBLIC SECTION.
METHODS:"实例处理方法
"事件处理方法的定义,参数一定要与事件定义时的参数名一致,sender为事件源
handle_1 FOR EVENT too_fast OF vehicle IMPORTING p1 sender,
"如果省略了sender,则 handle_2 不能访问sender对象
handle_2 FOR EVENT too_fast OF vehicle IMPORTING p1 ,
"注意:静态事件不会传递 sender 参数
handle_11 FOR EVENT too_fast_static OF vehicle IMPORTING p1.
CLASS-METHODS:"静态处理方法
handle_3 FOR EVENT too_fast OF vehicle IMPORTING p1 sender,
handle_4 FOR EVENT too_fast OF vehicle IMPORTING p1,
handle_33 FOR EVENT too_fast_static OF vehicle IMPORTING p1.
ENDCLASS.
CLASS handler IMPLEMENTATION.
METHOD handle_1.
sender->show_speed( msg = 'handle_1' ).
WRITE: / 'handle_1:' , p1.
ENDMETHOD.
METHOD handle_2.
"不能访问sender对象
"sender->show_speed( ).
WRITE: / 'handle_2:' , p1.
ENDMETHOD.
METHOD handle_11.
WRITE: / 'handle_11:' , p1.
ENDMETHOD.
METHOD handle_3.
sender->show_speed( msg = 'handle_3' ).
WRITE: / 'handle_3:' , p1.
ENDMETHOD.
METHOD handle_4.
WRITE: / 'handle_4:' , p1.
ENDMETHOD.
METHOD handle_33.
WRITE: / 'handle_33:' , p1.
ENDMETHOD.
ENDCLASS.
DATA: o_vehicle TYPE REF TO vehicle,
o_handler TYPE REF TO handler.
START-OF-SELECTION.
CREATE OBJECT: o_vehicle,o_handler.
"实例事件处理方法 注册
SET HANDLER o_handler->handle_1 FOR o_vehicle.
SET HANDLER o_handler->handle_2 FOR ALL INSTANCES.
SET HANDLER handler=>handle_3 FOR ALL INSTANCES.
SET HANDLER handler=>handle_4 FOR ALL INSTANCES.
"静态事件处理方法注册:对事件处理方法所对应的类的所有实例都有效
SET HANDLER o_handler->handle_11.
SET HANDLER handler=>handle_33.
DO 6 TIMES.
CALL METHOD o_vehicle->accelerate.
ENDDO.
自定义控件事件处理示例:
.
* Dialog Modules *****************************************************
MODULE status_0100 OUTPUT.
SET PF-STATUS 'SCREEN_100'.
IF init IS INITIAL."只做一次
init = 'X'.
"TEXTEDIT为Screen Painter中自定义容器名
CREATE OBJECT container
EXPORTING
container_name = 'TEXTEDIT'.
CREATE OBJECT editor
EXPORTING
parent = container."将文件编辑器控件放入自定义容器中
CREATE OBJECT handle.
"文本编辑器需要触发(使用RAISE EVENT语句触发)的事件列表,即你要告诉文本编辑控件
"需要使用 RAISE EVENT 语句触发哪些事件(因为只在类中进行定义了的事件是不会自动触
"发的,需要我们使用 RAISE EVENT 这个的语句来进行触发,然后监听这些事件的事件处理
"方法就会被回调),这与自己定义普通类事件原理是一样的(请参见vehicle类中的accelerate
"方法,此方法触发了too_fast与too_fast_static两个事件,只不过文本编辑器中触发事件的
"语句不需要我们写了,我们只需要告诉文本编辑器控件需要触发哪些事件,它就会使用RAISE EVENT
"语句自动帮我们去触发了)
event-eventid = cl_gui_textedit=>event_f1.
event-appl_event = ' '. "system event
APPEND event TO event_tab.
event-eventid = cl_gui_textedit=>event_f4.
event-appl_event = 'X'. "application event
APPEND event TO event_tab.
.
ENDMODULE.
* Class Implementations **********************************************
CLASS event_handler IMPLEMENTATION.
METHOD handle_f1.
DATA row TYPE i.
MESSAGE 'F1 event handling' TYPE 'I'.
"获取光标在文本编辑中的位置
CALL METHOD sender->get_selection_pos
IMPORTING
from_line = row.
"取文本编辑中光标所在行的文本,并放到文本框中
CALL METHOD sender->get_line_text
EXPORTING
line_number = row
IMPORTING
text = field.
"set_new_ok_code:设置一个新的Function code.该方法只能用于处理system event的
"handler方法中,以此手动触发PAI处理
"系统事件默认是不会触发PAI的,如果需要触发,则需要在事件处理方法中手动触发。注意:当事件处理方法执行完后才触发PAI
CALL METHOD cl_gui_cfw=>set_new_ok_code "raise PAI for system events
EXPORTING new_code = 'F1'.
"清空缓冲,让服务器端与屏幕终端同步
CALL METHOD cl_gui_cfw=>flush.
ENDMETHOD.
METHOD handle_f4.
DATA row TYPE i.
MESSAGE 'F4 event handling' TYPE 'I'.
CALL METHOD sender->get_selection_pos
IMPORTING
from_line = row.
CALL METHOD sender->get_line_text
EXPORTING
line_number = row
IMPORTING
text = field.
CALL METHOD cl_gui_cfw=>flush.
ENDMETHOD.
ENDCLASS.
Table Controls表格控件
程序创建
在Screen Painter中,Table的每一列都是一个文本框控件,也需要为每一个列统一命名:
在设计时,如果要给表格增加列头或列体时,在表格控件所在的以外区域先将文本框与标签创建好,再托入到表格控件相应位置。
另外,如果表格中的列都是来自于词典中的透明表时或结构时,可以这样来做:首先画一个表格控件,并将透明表或词典结构作为表格控件的命:
然后从词典中引用字段:
并将选择的字段拖入到表格控件中:
如果需要让表格中的项可以选择的话,需要在设计表格控件时,指定透明表或词典结构中的某个字段作为选择列:
),
rowspage TYPE i,"表格控件可以显示的最大行数,用来实现翻页功能(一屏中可显示的最大行数)
lastrowdisp TYPE i ,"表格控件中显示的最后一行数据的索引
line_count TYPE i."表格中实际显示的行数(一屏可能没有显示满)
==============================
在运行时,flights是一个结构,里面的cols字段是一个包含所有有列信息的内表,可以对这个内表进行处理:如隐藏某列:
data :ls_col like line of flights-cols.
ls_col.
modify flights-cols index sy-tabix from ls_colWHERE screen-name = 'TZODA_WARNING-BUN'.
==============================
rowspage 行
flights)
)后,系统会自动转换到一下屏幕(100)
,即当前屏幕结束后,整个屏幕序列会结束
,如果跳转的下一屏幕为0,则
.
ENDIF.
ENDIF.
ENDCASE.
ENDFORM.
Screen 200 Flow logic:
(即flights-top_line记录了当前循环到了内表中
(这里的
"flights-top_line与PAI中的作用是一样的,但退出循环时会恢复到当前表格显示
"的第一行记录索引)
"3、可循环次数为系统变量sy-loopc的值
"4、在PAI中,此类循环不能像上面PBO那样附加选项
LOOP AT int_flights .
MODULE modi_flights.
ENDLOOP.
MODULE user_command_0200.
通过向导创建
通过向导创建出来的表格可以同时实现数据的批量输入、输出及维护
本例通过表SPFLI为数据源来演示
由于数据表格可能实现批量维护操作,在ABAP报表主程序中定义两个内表:XSPFLI与YSPFLI,XSPFLI用于保存更新前的数据,YSPFLI用于保存修改后的数据,参照内表YSPFLI对物理表SPFLI进行修改操作,便能将中新增或修改的数据更新到数据库中;而对于在表格中被删除的数据,可以在数据更新前通过两张对比来获取:
.
双击程序中的 1001,创建1001对话屏幕,并且为该屏幕创建名为T001的GUI:
绘制1001屏幕:
选择工具条中的Table Control(with Wizard),并在屏幕上拖动,系统将会弹出表控件向导初始页面:
为表格控制命名:
表格控件的数据源可以是物理表,也可以是程序中的内表(但只能为标准内表),这里我们引用程序中的标准内表YSPFLI作为数据源:
选择表格控件中需要展示的表字段:
表格控制属性设置:
表格控件附带按钮:
指定用来存放表格向导产生的代码的INCLUDE文件名:
双击表格控件,在表格控件属性框中还可以进一步设置表格属性(从弹出的表格控件属性框可以看到,与非向导的表格控件是一样的)
完成后可以看到生成的代码,代码与上面程序创建表格控件:
但向导创建完后,但运行是没有数据的:
下面将数据从SPFLI表中查出来,并将所获取的数据存放到YSPFLI中,且查询代码需要放在CALL SCREEN之前:
再次运行,结果如下:
从上图可以看出,“保存”与“退出”按钮都还未激活,原因就是还没有给对话屏幕程序加上GUI,下面给设置:
运行结果:
下面来实现这两个按钮的点击触发功能代码:
在1001屏幕逻辑流的PAI块里,加上如下调用Module代码:MODULE USER_COMMAND_1001.,然后再在ZSCREEN04_TAB Include文件里加上与数据库表同步的代码:
.
ELSEIF ok_code = 'SAVE'.
LOOP AT yspfli."未被删除的数据就是要被从数据库中删除的数据
DELETE TABLE xspfli FROM yspfli.
ENDLOOP.
DELETE spfli FROM TABLE xspfli.
MODIFY spfli FROM TABLE yspfli.
COMMIT WORK.
ENDIF.
CLEAR:ok_code.
ENDMODULE.
结论:通过上面的实例的实现,发现向导表格比手动写的表格控件要简单得多,而且还具有很好的维护功能与翻页功能,所以尽量采用向导生成的方式来生成表格控件。
Tree Control 树
),nodedisp()..
MODULE status_0100 OUTPUT.
IF container_r ISINITIAL.
PERFORM create_tree.
ENDIF.
ENDMODULE.
MODULE user_command_0100 INPUT.
save_code = ok_code.
CLEAR ok_code.
CASE save_code.
WHEN'BACK'.
LEAVEPROGRAM.
ENDCASE.
ENDMODULE.
FORM create_tree.
"创建树所在父容器对象
CREATE OBJECT container_r EXPORTING container_name = container_name1.
"创建树对象.创建时需要传入父容器
CREATE OBJECT tree_r EXPORTING parent = container_r
"节点选择模式:单选
node_selection_mode = cl_gui_simple_tree=>node_sel_mode_single.
"子程序 make_data 负责从数据库中获取数据到树内表中
PERFORM get_data.
"将子程序 make_data 构造好的内表传递给树对象的 add_nodes 方式,构造节点
CALLMETHOD tree_r->add_nodes
EXPORTING
table_structure_name = 'MTREESNODE'
node_table = node_table.
PERFORM register_event."注册节点双击事件
ENDFORM.
FORM make_node USINGvalue(nkey) TYPE string"节点名
value(nname) TYPE string"节点文本
value(pnode) TYPE string"父节点名,如果为空则为根节点
value(is_leaf) TYPE string."是否叶节点
CLEAR node1.
node1-node_key = nkey.
node1-text = nname.
node1-relatkey = pnode.
IF is_leaf = 'X'.
node1-relatship = cl_gui_simple_tree=>relat_last_child.
node1-isfolder = ''.
ELSE.
CLEAR node1-relatship.
node1-isfolder = 'X'.
ENDIF.
node1-hidden = ''.
node1-disabled = ''.
CLEAR: node1-exp_image,node1-expander,node1-n_image.
APPEND node1 TO node_table.
ENDFORM.
FORM register_event.
DATA: double_event TYPE cntl_simple_event,
eventlist TYPE cntl_simple_events.
double_event-eventid = cl_gui_simple_tree=>eventid_node_double_click.
double_event-appl_event = 'X'.
APPEND double_event TO eventlist.
"树所需要监听的事件列表
CALLMETHOD tree_r->set_registered_events
EXPORTING
events = eventlist.
"指定tree_r的事件处理方式为event_handler的handle_dbclick方法
SETHANDLER event_handler->handle_dbclick FOR tree_r.
ENDFORM.
FORM get_data.
DATA: s1 TYPE string,s2 TYPE string,s3 TYPE string.
DATA:wa1 TYPE scarr,wa2 TYPE spfli,wa3 TYPE sflight.
SELECT * FROM scarr INTO wa1 WHERE carrid = carrid.
s1 = wa1-carrname.
PERFORM make_node USING s1 s1 ''''.
SELECT * FROM spfli INTO wa2 WHERE carrid = carrid.
CHECK wa2-cityfrom ISNOTINITIAL.
CHECK wa2-cityto ISNOTINITIAL.
CONCATENATE wa2-cityfrom '------' wa2-cityto INTO s2.
PERFORM make_node USING s2 s2 s1 ''.
SELECT * FROM sflight INTO wa3 WHERE carrid = carrid AND connid = wa2-connid.
s3 = wa3-fldate.
PERFORM make_node USING s3 s3 s2 'X'.
ENDSELECT.
ENDSELECT.
ENDSELECT.
ENDFORM.
ALV Grid Control
请参考《ALV.docx》文档中的“OO ALV->创建ALV”章节
多行文本编辑器
先创屏幕100,然后放一个名为EDITOR的自定义控件容器,用来存放多行文本编辑器:
工具栏中新增保存按钮:
在开发前,先讲讲长文本:
在以前,使用过READ_TEXT函数读取过各种各样的长文本,比如物料长文本、销售长文本等,在读取里时,一般需要传递长文本对象名、长文本ID、及长文本名称,READ_TEXT函数参数如下:
与读取函数READ_TEXT对应的是写函数SAVE_TEXT,它是将长文本以固有的格式存储到相应的物理表中,其中有一个重要的入参HEADER,其类型参照了THEAD结构(实质上为STXH表结构),用于存储长文本相关的各种属性:
长文本最后都存储到了STXH、STXL两个物理表中。在使用READ_TEXT与SAVE_TEXT时,都需要指定长文本对象以及文本ID,这些是通过SE75来维护的:
上面看到的物料长文本对象及文本ID,在物料维护时可以看到:
SAP中的长文本都是以文本对象和文本ID分类别类存储到STXH、STXL两个物理表中,所以想将长字符串,比如这里编辑器中的文本以长文本形式存储到表中,则需要先定义对应的文本对象及文本ID,并且在定义文本对象时,可以指定长文本的格式:如每行的字符个数,这里我们创建需要在下面程序使用的文本对象Z001:
当运行后面程序后,文本编辑器中的文本会以长文本的形式存储到STXH与STXL两个物理表中,STXH表存储的为长文本相关头信息,STXL存储的是真正的数据,但长文本是以LRAW类型存储的,在屏幕上不能直接显示出来:
最后程序运行结果如下:
max_number_chars
name
not_found
object
reference_check
wrong_access_to_archive .
MESSAGE '无此文本' TYPE 'I'.
ENDIF.
MESSAGE ls_header TYPE 'I'."将长文本相关属性信息打印到状态栏
"将从表中读取到的长文本转换为能在文本编辑器显示的文本
CALL FUNCTION 'CONVERT_ITF_TO_STREAM_TEXT'
EXPORTING
language = sy-langu
TABLES
itf_text = it_lines
text_stream = texttable.
"将内表数据赋值给文本编辑器
CALL METHOD editor->set_text_as_stream
EXPORTING
text = texttable.
ENDMODULE.
MODULE user_command_0100 INPUT.
CASE sy-ucomm.
WHEN 'SAVE'.
"从文本编辑器中读取文本到内表中
CALL METHOD editor->get_text_as_stream
IMPORTING
text = texttable.
"将文本编辑器中的长文本数据转换为附带信息的可存储到表中的标准格式的长文本
CALL FUNCTION 'CONVERT_STREAM_TO_ITF_TEXT'
EXPORTING
language = sy-langu
TABLES
text_stream = texttable
itf_text = it_lines.
"将内表数据通过函数转换为 LRAW 类型并存放到指定的物理表中
CALL FUNCTION 'SAVE_TEXT'
EXPORTING
client = sy-mandt
header = wa_thead
savemode_direct = 'X'
TABLES
lines = it_lines.
ENDCASE.
ENDMODULE.
Call屏幕
call screen 200 starting at 37 5
ending at 87 22.
在Menu Painter中设计200屏幕时,Screen Type选择的是Modal dialog box,但此选项不是导致屏幕200本身以弹出对话框的形式显示,其意思与Call 选择屏幕时的选项AS WINDOW的使用相同。
屏幕是否以对话框的形式显示,是由starting at选项决定的,这与Calling选择屏幕中的选项是一样的
弹出确认对话框
.
CHECK l_answer = '1'.