前言
本文1w字+,先 点赞 关注 收藏
制作不易 谢谢🤞
这篇文章给大家介绍一下SAP ABAP 中常用的容器,容器是一个很强大的东西,也是很重要必会的技能,它可以显示多种多样的内容,例如ALV、图片、html、等等,其实就一个html就能显示好多好多东西了 ,html能显示base64编码格式的各种数据如 图片、PDF、等等。所以利用好容器可以开发创建出更丰富的用户界面。并且容器是可以拆分的,可以调整大小的,这就铸就了它灵活的界面设计和布局管理方式。通过容器,开发者可以轻松地创建结构化和互动性强的用户界面。
一、案例介绍/笔者需求
这个案例我们会介绍 3 种常用的容器 ,会说明这些容器的特点以及优缺点,还有如何分割我们的容器。这篇文章主要还是针对容器的讲解,在涉及到容器的创建操作我都会详细注解,像这个容器如何显示ooalv如何显示html何显显示指定url这些都不会过多讲解的。主要是3种容器的区别和如何分割容器。
二、自定义容器
自定义容器使用类 CL_GUI_CUSTOM_CONTAINER 来实例化创建,这个容器比较好理解 创建起来步骤多一点,得手动在屏幕上把控件画出来,个人感觉比较适用于固定大小的显示,这种不太灵活,适用于那种固定布局显示的需求吧。但是一般需求显示个alv啥的也感觉都够用。
a.
实例化对象
这个类实例化对象的时候构造方法有一个必传参数如下图所示,CONTAINER_NAME 这个参数就是我们在屏幕中画的控件的名字。所以实例化这个容器对象之前我们先创建一个屏幕然后画控件才能实例化。
1.创建程序
事务码SE38创建程序,跟着编号 12345 走就行了,不多解释。
2.创建屏幕
跟着编号 123456789 10 走就行
3.实例化对象
如下图 所示我们就成功创建了一个容器对象,并且它在屏幕1000中 ,我们现在就算 CALL SCREEN ‘1000’. 也没效果的,因为这个容器什么都没放 什么都没注入。其实构造方法的参数还有一些后面我们都会介绍到的。
b.
自定义容器效果演示
这里我们用这个容器来显示url的内容,就显示作者的CSDN博客首页吧。这里我们也就不用屏幕逻辑流了因为程序比较简单也不涉及到用户交互,就靠程序逻辑流按顺序执行完相应代码然后显示屏幕1000就行了 。当然你也可以显示oolav或者研究显示其他内容 我只是感觉这个显示url比较简单,做案例程序比较方便。
1.显示html的类
CL_GUI_HTML_VIEWER 这个类用于在容器中显示 HTML 内容。这个类非常有用,它允许在 SAP GUI 环境中嵌入和展示 HTML 页面或内容。
2.显示指定的 URL 页面
CL_GUI_HTML_VIEWER类有一个实例方法 SHOW_URL 可以显示指定的url页面。
3.实例化HTML对象
首先我们得实例化一个CL_GUI_HTML_VIEWER类的对象,这个对象实例化的时候构造方法是和ooalv一样都要传入一个容器对象也可以叫做父容器,只是参数名有点区别ooalv是 I_PARENT 这个是PARENT。
4.调用显示方法
我们这个显示方法肯定是要在CALL屏幕之前就调用吧,你不能屏幕都显示了才调用,如果方法调用在CALL屏幕之后那么就得来个刷新才能显示当前容器的内容,顺序不要搞乱了。
5.运行效果
可以看到我们这个控件大小是不灵活的,我控件画了那么大它就只能显示这么大,这样用户体验不是很好。明明屏幕还有那么多的空间。
c.
Copy Code
记得 创建屏幕 和 画控件,控件名 传入的时候要写对。
REPORT /sc1/glyntest05.
DATA cust_cont TYPE REF TO cl_gui_custom_container.
CREATE OBJECT cust_cont EXPORTING container_name = 'DIV'.
DATA lo_html_viewer TYPE REF TO cl_gui_html_viewer.
CREATE OBJECT lo_html_viewer
EXPORTING
parent = cust_cont.
lo_html_viewer->show_url( url = 'https://www.baidu.com/').
CALL SCREEN '1000'.
实例化对象或者调用方法的时候我们都可以用ABAP对象模式,自动带出所有参数。
*******************以下是实例化自定义容器对象的完整参数********************
***********************后面的案例会详细介绍这些参数***********************
CREATE OBJECT cust_cont
EXPORTING
parent = 父容器
container_name = 控件名
style = 容器样式
lifetime = 容器生命周期
repid = 当前程序
dynnr = 屏幕编号
no_autodef_progid_dynnr = 是否自动定义程序ID和屏幕编号
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
create_error = 3
lifetime_error = 4
lifetime_dynpro_dynpro_link = 5
others = 6.
三、自适应容器
自适应容器 使用类 CL_GUI_DOCKING_CONTAINER 来实例化创建,这个不用画控件但是必须得有一个屏幕,这种容器有个优点就是可以灵活的充满整个屏幕, 官方解释叫做 可以停靠的容器,意思就是它可以停靠在 SAP 窗口的四个边(上、下、左、右)。停靠的意思是这个容器可以固定在这些边缘,并且在窗口大小变化时会自动调整大小以适应窗口。
下面直接就给效果演示就行了,主要是理解实例化这个容器的时候这些参数的作用就可以了。
a.
常用 必须 参数理解
首先来看几个常用的,好理解的。
1、REPID 这个参数给当前 程序名就行了,它和dynnr参数能确保容器与特定屏幕和报告程序关联。
2、DYNNR 这个参数给要在哪个屏幕编号嵌入显示该容器,也可以使用系统变量sy-dynnr来更灵活的嵌入到相应屏幕。
3、SIDE 设置容器的停靠位置 ,它和EXTENSION参数决定了容器显示位置布局。可以传 1、2、4、8。 但是一般取类的静态属性尽量别写硬编码。这个参数默认值如下图。
4、EXTENSION 这个是 设置容器的尺寸 不传的话是有默认值50的,如果想要容器上下左右撑满直接给9999,如果你容器是停靠在左侧那么这个这个尺寸就是从左往右延申,如果停靠在顶部就是从上往下延申,以此类推,容器停靠位置的尺寸永远都是100%的,比如停靠在左侧 那上下尺寸就是100%停靠在顶部左右尺寸就是100%,下面的案例看了就懂了。
1.停靠左侧 尺寸100
可以看到这个容器停靠在了屏幕左侧,然后尺寸也很小 ,我们也可以手动拖动容器右侧的5个点改变容器的大小。
2.停靠左侧 尺寸9999
参数自己改我不给代码示例了,可以看到容器撑满了我们整个屏幕并且可以随着我们GUI窗口的大小变化而变化,给9999没什么特殊的含义,尺寸9999能撑满我们整个屏幕 是因为你电脑屏幕就那么大 ,这世界上应该没有尺寸9999 的屏幕吧 哈哈哈哈哈,所以不管哪个用户用这个界面始终都是撑满的。效果很不错
3.停靠顶部 尺寸200
如下图所示,效果很明显,看到这里相信你已经理解这几个常用的参数了。
b.
METRIC 度量单位
METRIC 不怎么常用,它可以指定我们extension参数以什么单位设置尺寸,可以传的值有0、2、1在下图中我也标注了。传的话最好取类的属性。
1.像素 毫米 比较
从下面两个图片对比,单位为 像素 尺寸为 200 的时候才和单位是 毫米 尺寸是 20 的设置大小差不多。效果还是明显的
c.
RATIO 百分比尺寸
RATIO其实也是控制尺寸大小的,只不过它是以百分比控制并且优先级高于extension,它这个百分比只是相对于当先GUI窗口的百分比,并不会随着GUI窗口的变化还继续保持百分比尺寸。这个参数不能小于5不能大于95不然会报错。
1.效果演示
可以看到我extension参数已经设置了9999的尺寸,但是运行后依然是相对当前GUI以50%的尺寸大小显示。
d.
STYLE 容器样式
STYLE 是定义容器的窗口样式,例如是否具有边框、是否可调整大小等,可以传的参数如下图。有些样式很奇怪。。。。。有些样式有看不出来效果。大家自己去试。
e.
其他 参数理解
这些参数感觉不常用而且我也没试出来效果。
1、CAPTION 这个参数是设置标题的, 按照文档来说会显示在容器的顶部可是我传入之后并没有显示。
2、LIFETIME 定义容器的生命周期。lifetime_default是默认值,指明容器在其父容器存在期间保持活动状态。一般用不上
3、PARENT 指定当前容器的父容器。父容器是CL_GUI_CONTAINER类的实例,用于将当前容器嵌入到父容器中。但是我自己尝试容器好像里面不能再嵌套一个容器,而且这种嵌套需求感觉也不合理,嵌入感觉不就是跟分割容器一样吗?还有一种解释是说我们创建的这些容器本身就是不需要父容器的,因为他自己本身就是父容器,你看我们之前实例化ooalv,显示url内容,都是需要我们传入一个父容器将这些内容嵌入显示在这个父容器里面,而现在这个自适应容器自己本身就是父容器了,对于它来说父容器应该就是GUI这个窗口了。应该是隐式的把GUI窗口作为父容器了,而对于我们GUI窗口而言 它的父容器应该就是我们电脑桌面了。好像是这样的意思。如果哪位大佬看见了可以帮忙解释一下这个参数在这个对象中到底是什么意思。最后我也找了源码应该就是如我想的那样这个参数不传的话程序就会获取当前对话框作为父容器了。如下图所示当我们 实例化一个自适应容器的时候它的构造方法里面调用了GET_FRAM_CONTAINER把父容器这个参数又传到了这个方法里面去,然后 在这个方法里面 做了是不是空的判断。
4、NAME 指定容器的名称。感觉没啥用啊!
5、NO_AUTODEF_PROGID_DYNNR 决定是否自动定义程序ID和屏幕编号。如果你给这个参数给了X,那么你会发现你不用指定 REPID (程序ID) 和 DYNNR(屏幕编号) 这两个参数。程序会为你自动给上系统变量 sy-repid、sy-dynnr。一般都是我们手动指定这两参数。这个参数可能就是更简单方便的实例化容器吧。
REPORT /sc1/glyntest05.
DATA auto_cont TYPE REF TO cl_gui_docking_container.
CREATE OBJECT auto_cont
EXPORTING
repid = sy-repid "当前程序
dynnr = '2000' "屏幕编号
side = cl_gui_docking_container=>dock_at_top "停靠位置
extension = 300 "设置容器的尺寸
ratio = 5
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
create_error = 3
lifetime_error = 4
lifetime_dynpro_dynpro_link = 5
OTHERS = 6.
DATA lo_html_viewer TYPE REF TO cl_gui_html_viewer.
CREATE OBJECT lo_html_viewer
EXPORTING
parent = auto_cont.
lo_html_viewer->show_url( url = 'https://www.baidu.com/').
CALL SCREEN '2000'.
***********************以下是完整参数***********************
CREATE OBJECT auto_cont
EXPORTING
parent = 父容器
repid = 当前程序
dynnr = 屏幕编号
side = 停靠位置
extension = 容器尺寸
style = 容器样式
lifetime = 容器生命周期
caption = 容器标题
metric = 度量单位
ratio = 以百分比设置尺寸
no_autodef_progid_dynnr = 是否自动定义程序ID和屏幕编号
name = 容器名称
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
create_error = 3
lifetime_error = 4
lifetime_dynpro_dynpro_link = 5
others = 6.
四、对话框容器
对话框容器 使用类 CL_GUI_DIALOGBOX_CONTAINER 来实例化创建,有了上面两个容器的案例相信大家已经对容器理解的差不多了,不同容器的相同参数也都是差不多的意思。这个对话框容器还是有点特别的,它必须要有个父容器,而且它的父容器可以是我们的电脑桌面,其实GUI窗口的父容器也应该是电脑桌面吧 ,如果以电脑桌面作为对话框容器的父容器那么这个对话框容器是和GUI窗口是平级的互不影响的。如果我们以GUI窗口作为对话框容器的父容器那么它就是与我们GUI窗口紧密结合的。
如下图所示我找到了GUI中的典型案例。
参数都是使用容器父类的静态属性屏幕。可传参数如下图。
对话框容器还有一个特殊的地方需要我们需要自己设置退出关闭容器的逻辑,是通过事件设置,并且按钮的增加好像也是通过事件吧我 没研究。
a.
独立于GUI窗口
独立于GUI窗口适合查阅文档或者是。。。。。哈哈想不出来了,反正就是和GUI窗口没有关联性了就是弹出来了一个独立的窗口。
1.代码实现
参数你们自己看注释吧。
2.运行效果
我们会发现当我们点击GUI窗口之后 这个弹框容器就会被置于后面去。证明它是独立于GUI窗口的两个互不影响的。这就是因为它父容器不是GUI窗口而是和GUI窗口的父容器是同一个。
b.
紧密结合于GUI窗口
其实这个弹框容器的这个父容器参数是不好演示的。因为我们实际用的这些软件的窗口都是有嵌套的,就拿GUI来说它一个界面当中可能有容器的嵌套,然后这些容器是有层级的,那么这个弹框容器到底要紧密结合于哪层容器这都是不好做演示的,我这里就是直接演示和GUI窗口紧密结合起来。其实我自己也没太搞明白这个参数具体到底如何使用,但是大概意思就是这样的。
1.代码实现
参数已经介绍过了,这里的屏幕编号我们得写死一下,因为没CALL 2000屏幕之前系统变量 sy-dynnr 还是默认是 1000。所以这个弹框容器就没被设置到显示的屏幕2000上。或者把这段代码包成 PBO 的 MODULE也可以。
2.运行效果
我们会发现当我们点击GUI窗后这个弹框始终显示在GUI窗的前面。这就是弹框容器和GUI窗有着紧密结合,其实日常中好多应用都有这种弹窗吧,你必须关闭这个窗口才能操作父容器,但是我们这里要实现这样的效果应该还是要借助一些事件方法代码逻辑的。
c.
CLOSE关闭事件
这个类中的事件都很奇怪居然都没有传递参数。但是我看了其他文章资料他们就直接接收了一个参数,这个参数好像就是这个对象本身。最后经过自己了解原来每个事件其实都是有这个参数的,每个事件都会把自己本身传递过来的。这个参数是在整个面向对象的源码中写死的。sender 这个参数名是固定的,它是隐式传递的不用在事件声明的时候定义。这是 SAP 控制事件处理的一种惯例,sender 参数用于标识引发事件的对象。
下面我还用ooalv的 user_command事件尝试了一下,确实每个事件都有这个 sender 参数,这些 事件把对象本身传递过来之后我们就可以用对象调用方法或者是获取对象的一些属性了。
1.关闭弹窗容器的方法
关闭弹窗只需要用对象本身调用方法 set_visible 并给 visible 参数传空格即可。像下图所示我在PAI下面写了一个MODULE,现在我们只要触发了PAI这个方法就会被调用弹窗就会被关闭。
2.CLOSE关闭事件
现在我们将上面这个方法和我们的关闭事件结合起来。完了别忘了实例化对象和注册事件。
实例化对象 注册事件
3.效果演示
点击下图中的关闭按钮就可以触发 COLSE事件并调用方法关闭弹窗。
4.其他事项
这个弹窗容器类还是有蛮多事件和方法的,大家可以SE24去看慢慢研究。
d.
Copy Code
REPORT /sc1/glyntest05.
CLASS class_event DEFINITION.
PUBLIC SECTION.
METHODS close FOR EVENT close OF cl_gui_dialogbox_container IMPORTING sender.
ENDCLASS.
CLASS class_event IMPLEMENTATION.
METHOD close.
CALL METHOD sender->set_visible
EXPORTING
visible = ' '
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
OTHERS = 3.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
DATA dialogbox_cont TYPE REF TO cl_gui_dialogbox_container.
CREATE OBJECT dialogbox_cont
EXPORTING
parent = cl_gui_container=>screen0 " 容器父类的屏幕静态属性 层级的级别为0
* parent = cl_gui_container=>desktop " 一个独立于屏幕的弹框适合通知或工具窗口
width = 350 "对话框 宽
height = 350 "对话框 高
* style = "样式
repid = sy-repid "当前程序名
dynnr = '2000' "当前屏幕编号 也可以写死
* lifetime = "容器生命周期
top = 50 "距离 顶部 距离
left = 500 "距离 左侧 距离
caption = '我是标题' "标题
* no_autodef_progid_dynnr = "是否自动定义程序ID和屏幕编号
* metric = "度量单位
* name = "容器名称
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
create_error = 3
lifetime_error = 4
lifetime_dynpro_dynpro_link = 5
event_already_registered = 6
error_regist_event = 7
OTHERS = 8.
DATA lo_html_viewer TYPE REF TO cl_gui_html_viewer.
CREATE OBJECT lo_html_viewer
EXPORTING
parent = dialogbox_cont.
lo_html_viewer->show_url( url = 'https://www.baidu.com/').
DATA event TYPE REF TO class_event.
CREATE OBJECT event.
SET HANDLER event->close FOR dialogbox_cont.
CALL SCREEN '2000'.
五、容器的拆分
我们上面所提及到的容器都是可以进行分割的,如果要拆分步骤拆分逻辑也都是一样的。
a.
选择合适的类
容器的拆分有两个类可以用,如果你只是简单的拆分就用带有EASY的这个类就是 步骤六,如果你是复杂灵活的拆分那么就用没带EASY的那个类就是 步骤七。
这两个拆分容器的类主要区别是:带EASY的最多就是一分为二 分割为上下或者左右,没带EASY的就是可以一次性分割多个容器出来,一般感觉EASY就够用了。容器拆分完之后都还可以用这两个类继续拆分的。
六、容器的简单拆分
容器的简单拆分使用类 CL_GUI_EASY_SPLITTER_CONTAINER,这个类使用起来比较简单方便,实例化这个拆分对象传入对应参数后从拆分对象就可以获得拆分得到的两个容器。
a.
实例化对象 并 拆分容器
实例化这个拆分对象之前我们必须要有一个存在的容器 。这个容器我就用自适应容器了就简单创建一下。
1.代码实现
参数是什么看代码注释即可。
b.
获取分割到的容器
这个类网上没有文章详细的介绍过,也没指明如何获取拆分得到的容器。笔者也是仔细在类中的属性找到了。都看到这里了给个三连吧。制作不易
1.拆分得到的容器对应的属性
从这下图的两个的属性名称就能判断出来这两个属性就是拆分得到的两个容器。
如果垂直拆分那么 TOP_LEFT_CONTAINER 就代表的是拆分后左边的容器, BOTTOM_RIGHT_CONTAINER 就是右边的。
如果水平拆分那么 TOP_LEFT_CONTAINER 就代表的是拆分后顶部的容器, BOTTOM_RIGHT_CONTAINER 就是底部的。
2.容器嵌入url
我是水平拆分 我给顶部的显示百度 底部的显示必应。
3.效果演示
效果还可以吧。
c.
继续拆分
可以看到我们还能对拆分的容器再次进行拆分。实现逻辑还是一样的。只要把对象别搞乱就行了。
d.
Copy Code
记得 创建屏幕 2000
REPORT zglyn006.
DATA container TYPE REF TO cl_gui_docking_container."被拆分的容器
CREATE OBJECT container
EXPORTING
repid = sy-repid
dynnr = '2000'
ratio = 95.
DATA splitter TYPE REF TO cl_gui_easy_splitter_container."拆分容器的对象
CREATE OBJECT splitter
EXPORTING
link_dynnr = sy-dynnr "当前屏幕
link_repid = sy-repid "当前程序
* metric = "度量单位 默认 毫米制
parent = container"被拆分的容器
orientation = 0 "0水平分割 1垂直分割
sash_position = 50 "拆分条位置 百分比
with_border = 1 "有边界1 无边界0 没试出来效果
* name = "拆分对象的名称
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
OTHERS = 3.
DATA lo_html_viewer1 TYPE REF TO cl_gui_html_viewer.
CREATE OBJECT lo_html_viewer1
EXPORTING
parent = splitter->top_left_container.
lo_html_viewer1->show_url( url = 'https://www.baidu.com/').
DATA lo_html_viewer2 TYPE REF TO cl_gui_html_viewer.
CREATE OBJECT lo_html_viewer2
EXPORTING
parent = splitter->bottom_right_container.
lo_html_viewer2->show_url( url = 'https://www.bing.com/').
CALL SCREEN '2000'.
七、容器的灵活拆分
容器的灵活拆分使用类 CL_GUI_SPLITTER_CONTAINER ,这个类和带EASY的那个拆分类使用起来有以下几个主要区别。
1、 它拆分完之后不是去属性中获取对应的容器,因为它是灵活多变的,它也不知道你一口气能分割出来几个容器 可能是两个也可能是9个所以它不能写死让你去属性中直接拿到拆分后的容器,拆分完之后需要用对应位置的容器指定一个容器对象,这个容器对象就是你最终拆分得到的容器。所以你最终分割了几个容器你就先要定义几个容器对象。
2、
3、
a.
实例化对象拆分容器
同样的实例化这个对象之前我们必须要有一个存在的容器 。
1.代码实现
参数是什么看代码注释即可,好多参数我没试出来效果这些参数也不常用,会用以下这些参数绝对够你用了 。
b.
获取分割的容器
获取分割的容器要用到实例方法 GET_CONTAINER 其实 实例化之后我们可以运行程序看一下容器是已经被分割了,但是这两个容器我们还不知道名字,这一步我们会把这两个容器指定给我们定义的容器对象,然后就可以拿着这两个容器对象进行操作了。
1.获取第1行第1例
分割为2行1列之后 顶部的等于是第1行第1列
2.获取第2行第1例
分割为2行1列之后 底部的等于是第2行第1列
3.嵌入url
4.效果演示
c.
继续拆分
这次我们把底部的再分割以一下。
d.
一次性拆分多个容器
可以看到这个类很强大,我们如下图一次性分割了6个,那么获取的时候就要定义6个容器对象,然后按照这些容器的几行几列指定到我们定义的容器对象。
e.
设置 行高 列宽
设置 行高 列宽 用如下图所示的方法,其实每个类的方法都有很多大家自己下去多看看。
这两个方法都有两个参数 ID 和 设置的尺寸 。这个 ID 是灵活多变的,取决于你将容器分割成了几行 几列,如果分割 成了2行3列,那么设置行高的时候ID只能传1和2,传1代表设置第一行的,传2代表设置第2行的。设置列宽的时候 ID可以是1、2、3。分别代表 设置第一列、设置第二列、设置第三列。如果将容器分割成了3行3列那么以此类推。如果你将ID传错超过了 行数 列数 那么不会报错也没啥效果。
下面的案例我将容器拆分为3行3列,做点简单的演示。
1.设置第2行的行高
效果很明显
2.设置第3列的列宽
效果很明显
八、总结
下图是一张SAP中类继承的关系,可以感觉到设计的人很牛逼啊!这里面ooalv、容器、拆分容器、显示html,继承关系都很明了。设计出来的这些的类的内部都是大有内涵呐!!!加油大家。别忘了3连。谢谢
以上就是今天要讲的内容,本文仅仅简单介绍了 SAP中的几种容器和对容器的拆分方法,感觉笔者讲的好对自己有帮助的还麻烦点个免费的赞赞制作不易谢谢谢谢!!!如果有说错或者不好的地方还望大家提出来见谅。感觉笔者写的好的别忘了关注点赞加评论哦,也欢迎大家一起来讨论。谢谢!