文章目录
- 前言
- 一、案例介绍/笔者需求
- 二、SE24 查看类
- `a.`基本属性 Properties
- `b.`接口 Interfaces
- `c.`友元 Friends
- `d.`属性 Attributes
- `e.`方法 Methods
- `f.`事件 Events
- `g.`局部类型 Types
- `h.`别名 Aliases
- `i.`其他 Other
- 三、OOALV 创建的步骤
- `a.`调用OOALV的方法
- `b.`实例化OOALV对象
- `c.`实例化 ooalv对象 构造方法 需要的对象 (容器 )
- `d.`调用OOALV显示的方法
- 四、优化 以及 增加扩展 功能
- `a.`表单的刷新
- `b.`设置alv样式布局 Layout
- `c.`可修改属性设置
- `d.`布局 排序 筛选 设置
- `e.`按钮的隐藏
- 五、OOALV的 事件 交互
- `a.`代码的重构
- `b.`自定义按钮的增加
- `c.`按钮功能交互
- 六、其他常用 事件 和 方法
- `a.`获取选中行的方法
- `b.`单击事件 和 获取选中单元格属性值的 方法
- `c.`双击事件
- `d.`数据 刷新 到 内表 中 的事件
- 七、容器的更换 以及 分割容器
- END、总结
前言
本文3w字+,先 点赞 关注 收藏
制作不易 谢谢🤞
这篇文章给大家介绍一下SAP 中的 OOALV,如果ABAP的对面向对象OO 没有基础的可以先去看笔者的另外一篇文章 SAP ABAP 之面向对象OO ,OOALV 必须先会 ABAP面向对象 不然是看不懂的,之前我那片文章主要讲的是本地类 ,这篇文章会讲到 SE24 全局类 和 如何使用 OOALV的类。
虽然 OOALV 比 FUNALV 难理解刚开始上手可能不习惯,但是 OOALV 的优点还是毋庸置疑的使用多了也就习惯了,虽然它的代码量看起来比较臃肿但实际还是比较模块化易于维护的。OOALV 比 FUNALV要强大很多,尤其是 灵活的事件处理、分屏显示多个ALV、定制化更高、性能更好、OOALV 提供了许多传统函数式 ALV 无法比拟的优势,通过面向对象的设计,提高了代码的可维护性、灵活性和性能,是 ABAP 开发中非常重要的技能。
一、案例介绍/笔者需求
OOALV 主要依靠全局类 CL_GUI_ALV_GRID 来使用实现的 ,这个类里面呢包含了 OOALV 基本调用的功能 基本属性 ,下面的案例主要围绕 使用 SE24 如何查看了解一个类的使用 还有 OOALV 的案例 来展开讲解,SE24 如何创建一个类不会过多的介绍,如果对本地类熟练了 这个 SE24 如何创建也就很轻松了,SE24 呢主要还是更多使用我们系统中现有的这些类 。
二、SE24 查看类
我们就拿 CL_GUI_ALV_GRID 这个创建 OOALV 的类 来做参考介绍,这样也就在后面 OOALV 案例的创建使用打下了基础。
a.
基本属性 Properties
这个属性可不是 我们类中的属性不是成员组件那些,而是这个 类的一些基本信息吧。就和SE38查看程序的属性一个意思吧。
这个分页签主要看两个东西,就是这个类的超类也就是基类/父类,我们这个CL_GUI_ALV_GRID是CL_GUI_ALV_GRID_BASE的 子类/派生类。反过来后者就是前者的 基类/父类。还有就是这个向前声明这里提一嘴。后面的案例我们也会 用到 向前声明。
1.超类
看此文的 标题二 中的 d
2.向前声明
看此文的 标题十 中的 d
b.
接口 Interfaces
接口是什么有什么用 看此文的 标题七
c.
友元 Friends
友元是什么有什么用 看此文的 标题九
d.
属性 Attributes
这里的属性,跟我们本地类对应起来 就是用 class-data 、data、constant 声明的那些东西。
1.属性 Attribute
第一列是属性的名字
2.级别 Level
Static Attribute 就是静态属性就是 class-data 声明的 ,Instance Attribute 就是实例属性就是 data 声明的,Constant就是声明的常量。
3.访问区域 Visbility
这里我不多讲解了直接把之前的一张表搬运过来。 详情 请看此文的 标题二中的b
. | 公有部分 PUBLIC | 保护部分 PROTECT | 私有部分 PRIVATE |
---|---|---|---|
这个类的方法 (类本身) | √ | √ | √ |
类继承的方法 (继承类) | √ | √ | X |
对外的数据接口 (外 部) | √ | X | X |
4.参照类型 Associated Type
这些 参照类型我们都可以 双击 进去查看 ,一般根据参考名就能大致判断出来参考的类型是个结构还是 变量还是表类型。中间是S的一般都是 结构 ,中间是T的一般都是 表类型。
5.描述 Description
描述这个没啥说的,有时候找对应属性或者这个属性不清楚的时候就把这个描述翻译一下 结合起来看。
6.初始值 Initial value
初始值一般也就常量 会有。
7.其他 Other
pass
e.
方法 Methods
这里的方法,跟我们本地类对应起来 就是用 class-methods 、methods 声明的那些东西。
1.方法 Method
第一列是属性的名字
2.级别 Level
Static Method 就是静态方法就是 class-methods 声明的 ,Instance Method 就是实例方法就是 Methods 声明的。
3.访问区域 Visbility
这里我不多讲解了直接把之前的一张表搬运过来。 详情 请看此文的 标题二中的b
. | 公有部分 PUBLIC | 保护部分 PROTECT | 私有部分 PRIVATE |
---|---|---|---|
这个类的方法 (类本身) | √ | √ | √ |
类继承的方法 (继承类) | √ | √ | X |
对外的数据接口 (外 部) | √ | X | X |
4.描述 Description
描述这个没啥说的,有时候找对应方法或者这个方法不清楚的时候就把这个描述翻译一下 结合起来看。
5.带波浪线的
带波浪线的其实就是接口中的方法,波浪线 前面的接口名肯定在接口的那个分页签中是有的,不过这些接口中的方法在我们这个ALV的类中 没写实现因为用不到 这些方法 在其他的类中是应该有写实现部分的。详情看此文的 标题七
6. 方法的查看
a、 我们双击这些方法名都可以出现具体的代码,这些代码都和我们之前在 IMPLEMENTATION 中写的方法的实现都是差不多的。不过 这些方法 只能一个一个 看 ,不能像本地类一样 整体查看所有的。
b、 注意上图我们查看 SET_GRID_STEP 方法发现代码中有个RAISE 这是 异常 不要和事件搞混了,查看异常是先点击方法名,再点击异常按钮 如下图所示 。异常是什么 ?详情看此文的 标题四中的C
c、 方法的参数在方法中也是很重要的,后面的案例中会详细说到。方法参数的使用和不同的传入传出方式 详情看此文的 标题三
f.
事件 Events
事件是ABAP面向对象很重要的一点 ,也是我们OOALV的重中之重。
1.事件
这个分页签的事件都是声明也就是我们 DEFINITION 声明的事件。但是具体这些事件在哪里被 RAISE 了也就是在哪个方法中被触发抛出了这个得我们自己去查。
1、 触发抛出事件对应方法的查找。
2、 使用位置列表可以查看我们哪些类和程序都去捕获类这个事件。注意是捕获不是抛出。也就是这个事件被抛出后位置列表展现的这些类和程序是捕获此事件并执行相应的方法。
2.参数
同样 的事件也有 参数的 传递,我们在这个分页签中也可以先点击事件再点击参数查看这个事件 有哪些参数的传递。
我还找了一个参数是不可选的,也就是你必须在捕获方法那边需要接收的意思吧。
g.
局部类型 Types
这里定义的类型都是一些这个类使用的局部类型。可见性都是私有的 。
1.查看代码
h.
别名 Aliases
别名就是给接口中的 方法 起别名,因为接口中的 方法 调用写起来还挺麻烦的 又要写接口名 又要写波浪线 又要写方法名,所以起别名就会使得调用方便许多。但是我们这个类中的这些接口方法都是没起别名的,可能因为这些方法都没用上也没写实现。别名详情看此文的 标题 七 中的 b 中的 3 。
i.
其他 Other
1.查看 源代码
查看源代码 其实上面 我们提过了 这边 再说一遍。方法的源代码好像不能这样整体的查看,只能一个一个的双击查看。
三、OOALV 创建的步骤
之前那片文章主要涉及到 类的创建 现在上面也介绍 了SE24对类的查看,下面呢主要介绍类的使用,重点就是如何使用我们的 CL_GUI_ALV_GRID 类中的哪些属性、哪些方法、哪些事件、等等,来创建一个OOALV。
我们就从如何调用显示ALV的方法 SET_TABLE_FOR_FIRST_DISPLAY 延续着串联下去。
a.
调用OOALV的方法
首先我们研究一下这个方法正确的调用方式,这个方法呢其实就是相当我们之前 FUNALV 调用的函数 REUSE_ALV_GRID_DISPLAY ,其实使用一个类和使用一个方法都是差不多的,主要 区别 就是类中的方法需要通过类或者实例对象来调用,然后我们只需要研究它需要哪些参数,最后制造它需要的参数直接传入就行了 ,我们 并不需要关心它内部 是如何实现的,我们只关心调用的 结果 。
1.这个方法通过什么调用
这个方法肯定是通过 对象 调用的,因为级别标明了是 实例方法。所以我们得先实例化一个这个类的对象 ,通过这个对象再去调用这个方法 。
b.
实例化OOALV对象
注意 我们上面1步骤只是对象的声明,还没有实例化,要调用方法肯定得先实例化对象吧。所以 这一步我们来看这个 对象如何进行实例化。
1.一般情况
一般我们直接像下图这样就可以实例化成功吧,但是这里报错了说有一个强制参数,意思就是必输参数吧,这证明我们这个类是有构造方法的,所以我们得去SE24表单中进行查看这个构造方法 需要传入哪些参数 。
2.查看构造方法
构造方法是 CONSTRUCTOR 我们直接在SE24方法中的页签搜就行,或者找方法类型那列有锤子标志的就是构造方法。对构造方法不清楚的可以看此文的 标题二 中的 C
a.
构造方法的参数
我们其实不用在乎构造方法具体做了什么但是我们很在乎构造方法需要传入哪些参数吧,不然对象就没法实例化,我们点击参数之后发现有一个参数是必输的,我们先 不管这个 参数是什么先把这个参数声明出来给我们实例化go_alv对象的时候传入先激活 成功再说。
b.
激活代码
如下图所示这样就可以激活成功,I_PARENT参数参考的也是一个类所以它也是一个对象。现在虽然 能 激活但其实我们实例化 go_alv对象的时候等于传了一个空的东西过去,也就是类型能对应上但是 是个空的,就好像很你传内表一样虽然类型对上了但是内表没有数据,目前是这样的情况。那么我们肯定是 不能给它传一个空的对象 过去的,肯定得实例化这个对象,那么在实例化之前我们肯定得 弄清楚这玩意到底是个什么东西?下面我们进行实例化的时候就明白了。
c.
实例化 ooalv对象 构造方法 需要的对象 (容器 )
实例化这个对象之前还是跟上面实例化ooalv对象 的时候一样,先看它 有没有构造 方法,看它构造方法 需要传什么。
1.CL_GUI_CONTAINER 的 构造方法
如下图所示我们又找到了 这个类的构造方法,也就是说 这个 类实例化对象 的时候必须传入 CLSID 可以看到这个参数的翻译是 此容器的类ID,那么我们先对这个类和这个类的对象有个大致了解吧,这个对象其实创造好之后就是一个容器,容器 是什么呢 ?容器就是放东西的,我们ooalv展示的时候总要有地方展示 吧,哎!它就是在这个容器里面展示,我一个屏幕可以有多个容器然后这些容器我都放置ooalv,当然容器这个东西还是挺强大的 它不仅可以放ooalv还可以放html页面,你也可以在里面显示浏览器内容显示某个url内容都可以。
这个就是容器 ,但是我们不会用所提及的这个容器类了 ,我们会直接用它的子类,CL_GUI_CUSTOM_CONTAINER。CL_GUI_CONTAINER 其实是一个抽象基类,定义了通用的 GUI 容器接口和功能,容器也是分为多种的 , 下面我们将使用 CL_GUI_CUSTOM_CONTAINER 创建一个容器对象,用这个类要创建一个容器是先要在屏幕中画一个控件的,我们先把代码中的参考类替换一下。
2.CL_GUI_CUSTOM_CONTAINER 构造方法
我们还是同样的 操作,找到这个类的构造方法之后发现有一个 CONTAINER_NAME,是必输参数,这个CONTAINER_NAME翻译过来是:要链接到的屏幕名称,原文是 Name of the Screen CustCtrl Name to Link Container To,这里面有个 CustCtrl,这个就是屏幕控件它是Dialog程序中画屏幕的时候的一种控件,我们把这个控件画好之后把控件名称传给这个参数就行了。对 Dialog程序 不清楚的可以看笔者之前SAP屏幕开发的文章。SAP屏幕开发
3.代码的调整
我们先把代码调整一下,将代码做如下调整然后激活 。现在运行肯定是什么效果都没有的,没有屏幕的显示也没有alv的展示。
4.控件的绘制 命名
首先 1、 要创建一个屏幕,2、 然后打开 屏幕绘制器 3、 选中容器控件 画一个 最大的 容器,你在 屏幕画多大这个alv最终 就是多大 。这3个步骤的过程我简单 说一下,详细操作 还请看之前屏幕开发的文章 。
5.屏幕的显示
既然我ooalv是要在容器中 显示,而容器又在屏幕1000中,那么我是不是得显示1000屏幕才能显示容器才能显示ooalv吧。既然涉及到屏幕的调用那么相应的代码逻辑应该是在屏幕逻辑流中调用吧,你把取数设置表头这些逻辑肯定是要在界面显示前就要设置好吧所以这些应该都去PBO下面执行吧。
现在我们程序执行之后是如下图这样的,中间是有一个我们画的控件的,这个控件显示的样式是有一点alv的雏形了,其实这个控件会显示什么 由我们给它放入的东西决定,我们给它放的是ooalv它就是alv,给它放浏览器内容它就是其他样式了。
这是给这个控件放了url内容它显示了浏览器内容就长这样,就和alv没关系喽!!!
d.
调用OOALV显示的方法
调用的方法我们上面已经提过了是 SET_TABLE_FOR_FIRST_DISPLAY,现在只需要把参数给这个方法造好传入就行了。
1.查看这个方法的参数
这个方法中的参数其实和我们 FUNALV 的参数都是差不多的,可以打开SE37去查看REUSE_ALV_GRID_DISPLAY对比一下的。
首先肯定是和 FUNALV 传的参数是差不多的 有的甚至类型也都一样,传入的肯定有表头 fieldcat、还有要展示的 数据内表 吧。这两样都是最基本必须的。还有一些其他参数像ALV的样式 layout 等等 这些都不急。。。。
2.重构代码
在制造这些数据之前我们先将代码重构一下,我这个案例划分的比较细致,后期代码量多了完全可以在不影响执顺序的情况下合并合并代码。现在这些MODULE都创建了但是里面的内容都是空的接下来我们将这些MODULE的逻辑都补充一下。
a.
status_1000
这里直接把标准程序的复制到们程序中去。
代码也给上 1000 运行后 按钮都亮了,但是点击没有反应,我们还对这些按钮的功能没写逻辑。而且这些按钮其实多了,工具栏哪些按钮都用不上,ooalv显示出来之后会有自己的一套工具栏按钮,我们先把返回 退出这几个按钮设置一下功能吧。简单操作一下
这样搞完之后返回就可以正常用了
b.
create_alv
这个简单 就是实例化ooalv的对象 之前已经实现了 直接把代码搬运到指定MODULE中即可。
c.
get_data
这里我先写展示的数据内表吧不然 不知道我们表头要展示哪些字段。但是 执行顺序还是先走的 set_fieldcat设置表头 。这两个顺序不重要,顺序重要的 是实例化完ooalv对象之后再调用方法就行了。
d.
set_fieldcat
设置表头的这个内表 我们参照方法中参数参考的就行,类中对应的传入参数是 IT_FIELDCATALOG 参考的类型是LVC_T_FCAT。
代码完善表头赋值,这里我们简单一点,后期想要什么再加吧。需要什么自己去搜吧。
e.
call_alv
终于来到我们方法的调用了,拭目以待吧。我 们采用 模式 调用这样不容易出错参数也不用自己 写 。方法调用之后 把数据内表和表头都传给对应参数执行程序即可看到ooalv哦,牛逼吧兄弟们简单吧兄弟们,看到这里了给个一键三连呗 谢谢。
3.运行结果
可以看到数据以alv的形式展现了出来,并且ooalv是 自带工具栏按钮的,功能也都正常。
4.Copy code
到这里我们OOALV最核心 的部分已经说完了,后面我们会对功能进行逐渐的扩展,例如 事件 、ALV刷新 、去除增加按钮 等等。这里先留一版当前的代码。记得 创建屏幕 、画控件、创建按钮status。
a.
屏幕逻辑流
PROCESS BEFORE OUTPUT.
MODULE status_1000 ."设置按钮
MODULE create_alv ."实例化ooalv和容器
MODULE set_fieldcat."设置表头
MODULE get_data ."取数
MODULE call_alv ."调用展示ooalv的方法
PROCESS AFTER INPUT.
MODULE USER_COMMAND_1000.
b.
报表源码
REPORT zglyn005.
DATA go_alv TYPE REF TO cl_gui_alv_grid.
DATA go_div TYPE REF TO cl_gui_custom_container.
TYPES: BEGIN OF ty_student,
name TYPE c LENGTH 40,"姓名
class TYPE c LENGTH 10,"班级
age TYPE i ,"年龄
sex TYPE c LENGTH 1 ,"性别
origin TYPE c LENGTH 40,"籍贯
END OF ty_student.
DATA: gt_students TYPE TABLE OF ty_student.
DATA: gt_fieldcat TYPE lvc_t_fcat.
DATA: gs_fieldcat TYPE lvc_s_fcat.
DEFINE appendfield. "设置alv表头 宏
clear gs_fieldcat.
gs_fieldcat-fieldname = &1. "对应字段名
gs_fieldcat-coltext = &2. "描述
append gs_fieldcat to gt_fieldcat.
END-OF-DEFINITION.
CALL SCREEN '1000'.
*&---------------------------------------------------------------------*
*& Module STATUS_1000 OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE status_1000 OUTPUT.
SET PF-STATUS '1000'.
* SET TITLEBAR 'xxx'.
ENDMODULE. " STATUS_1000 OUTPUT
*&---------------------------------------------------------------------*
*& Module CREATE_ALV OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE create_alv OUTPUT.
CREATE OBJECT go_div
EXPORTING
container_name = 'DIV1'.
CREATE OBJECT go_alv
EXPORTING
i_parent = go_div.
ENDMODULE. " CREATE_ALV OUTPUT
*&---------------------------------------------------------------------*
*& Module SET_FIELDCAT OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE set_fieldcat OUTPUT.
appendfield 'NAME' '姓名'.
appendfield 'CLASS' '班级'.
appendfield 'AGE' '年龄'.
appendfield 'SEX' '性别'.
appendfield 'ORIGIN' '籍贯'.
ENDMODULE. " SET_FIELDCAT OUTPUT
*&---------------------------------------------------------------------*
*& Module GET_DATA OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE get_data OUTPUT.
gt_students = VALUE #( ( name = '美国队长' class = '一班' age = '99' sex = '男' origin = '芝加哥')
( name = '钢铁侠' class = '二班' age = '54' sex = '男' origin = '华盛顿')
( name = '黑寡妇' class = '一班' age = '36' sex = '女' origin = '旧金山')
( name = '蜘蛛侠' class = '六班' age = '20' sex = '男' origin = '皇后区')
( name = '小贱贱' class = '三班' age = '37' sex = '男' origin = '柏林') ).
ENDMODULE. " GET_DATA OUTPUT
*&---------------------------------------------------------------------*
*& Module CALL_ALV OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE call_alv OUTPUT.
CALL METHOD go_alv->set_table_for_first_display
* EXPORTING
* i_buffer_active =
* i_bypassing_buffer =
* i_consistency_check =
* i_structure_name =
* is_variant =
* i_save =
* i_default = 'X'
* is_layout =
* is_print =
* it_special_groups =
* it_toolbar_excluding =
* it_hyperlink =
* it_alv_graphics =
* it_except_qinfo =
* ir_salv_adapter =
CHANGING
it_outtab = gt_students
it_fieldcatalog = gt_fieldcat
* it_sort =
* it_filter =
* EXCEPTIONS
* invalid_parameter_combination = 1
* program_error = 2
* too_many_lines = 3
* others = 4
.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
ENDMODULE. " CALL_ALV OUTPUT
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_1000 INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE user_command_1000 INPUT.
CASE sy-ucomm.
WHEN '&F03'.
LEAVE PROGRAM.
WHEN '&F15'.
LEAVE TO SCREEN 0.
WHEN '&F12'.
ENDCASE.
ENDMODULE. " USER_COMMAND_1000 INPUT
四、优化 以及 增加扩展 功能
这里我们对我们刚才的案例来进行优化和功能的扩展
a.
表单的刷新
我们上面的案例现在存在这么一个问题,每当我点击工具栏按钮,或者双击行项目数据之后都会触发PAI吧,那么触发PAI之后又会走PBO,那么此时我们PBO下面的代码又会走一遍,但其实这些代码没必要重复调用吧,我们等于又实例化对象又设置status又设置表头取数等等。这些都没必要,我们可以判断当 go_alv 为空的时候才走这些代码否则我刷新一下ALV画面就行了。
1.代码重构
我们在加入刷新操作逻辑之前先对代码再优化重构一下,因为屏幕逻辑流中最好不要写判断(好像也不能写)。我们将之前的那些MODULE都集中在一起叫 ini_ooalv。然后把之前的那些MODULE都改为PERFORM再到这个ini_ooalv里面调用即可。顺便也加上了刷新的逻辑但是没写实现。
2.刷新alv的方法
刷新ALV的方法是 REFRESH_TABLE_DISPLAY,还有一个方法是用来刷新表头的 如果我们表头有更改则需要刷新表头 SET_FRONTEND_FIELDCATALOG,我们这里只演示刷表单内容的。调用的时候依然通过系统调用模式来调用。调用成功了但是 这里面的两个参数是要研究一下的。
3.参数的研究
这个 IS_STABLE 好理解这里不多说了, I_SOFT_REFRESH 如果给了X,那么合计的数据或者是排序筛选的数据不受影响,举例:我年龄这一列合计完是300,表单刷新之后有一个人的年龄增加5岁,那么按道理我合计完结果应该是305 了,但是由于我I_SOFT_REFRESH给了X所以依然保持之前的300。一般不传这个字段虽然相对来说消耗性能但是可以忽略不计。
4.刷新前后对比
为了把我们 刷新等等效果明显的展示出来我们做如下图的操作。然后当我们点击这个按钮之后就会看到 alv增加了一行。当我们把 alv_refresh 这个 PERFORM 注释掉再运行点击此按钮就发现不会刷新alv表单了,虽然数据已经添加 进去了,大家 /h 打断点再点击按钮可以详细 看一下程序 的执行过程的。
b.
设置alv样式布局 Layout
这里我们把Layout也加进去,其实表头 fieldcat 和 样式布局layout,这两个东西的属性字段都很多 大家需要什么功能需要怎么样自己去搜就行了。这里我 就添加一些最基本的 就行了。类型的参考就参考方法中的参数类型就行了。
1.Layout
这里设置表单左侧选择框的时候要注意和 FUNALV的有点不一样,FUNALV是 在内表 中加一个字段使用 layout中的box_fname 来 控制的,ooalv的不用加字段直接给sel_mode字段赋值就行,但是赋值 什么是有讲究的。
gs_layout-sel_mode = 'A'."行多选、列多选、单元格能单选、能显示复选框
gs_layout-sel_mode = 'B'."行单选、列多选、单元格不能选、不显示复选框
gs_layout-sel_mode = 'C'."行多选、列多选、单元格不能选、不显示复选框
gs_layout-sel_mode = 'D'."行多选、列多选、单元格能单选、能显示复选框
gs_layout-sel_mode = ' '."行单选、列多选、单元格不能选、不显示复选框
gs_layout-sel_mode = '' ."行单选、列多选、单元格不能选、不显示复选框
*最后两行 给空值或者给空格和 给B是 一样的
c.
可修改属性设置
当我们不管是 以列 还是 以行 以单元格 为单位进行修改内容的时候ooalv的工具栏一些 增加 删除 按钮 和 最左侧的 选择框 这些都会显示出来。
1.整个表单可修改
设置 layout-edi = ‘X’.即可
2.以列为单位可修改
设置对应列的 fieldcatt-edi = ‘X’.即可
3.以单元格为单位可修改
这个稍微有点复杂,要用到逆向思维,我们会将 SEX字段为空的单元格设置为可修改状态 ,我们一步一步来即可,首先我们大概说一下都要做什么:
1、 在数据展示的内表新增一个字,这个字段名一般叫CELLSTL你也可以自己取一个无所谓,这个字段类型参考LVC_T_STYL 是一个表类型,这也就意味着我们这个字段是一个内表。
2、 在需要设置修改属性的位置 通过结构给内表CELLSTL赋值添加数据,CELLSTL就是我新增的那个字段这个字段是一个内表。我来分步详细介绍一下第二步是什么意思吧:首先我们要锁定一个单元格肯定是通过一行再加一列吧,比如第二行第二列就锁定了一个单元格吧,锁定了就能给这个单元格单独设置属性了吧。
a、 那么如何锁定行呢 ?就是上面说的那句话 “在需要设置修改属性的位置” 要修改第二行其中一个单元格就给第二行数据的CELLSTL内表添加数据。比如我们要给性别为空的单元格设置可修改那么我通过循环展示的数据内表判断此时的性别字段是否为空如果为空那么就要给CELLSTL内表赋值添加数据了,这就是锁定行了。
b、 那么如何锁定列呢?CELLSTL内表有一个字段FIELDNAME就是列字段名,例如我们性别字段是SEX那么就给FIELDNAME字段赋值SEX就可以了。
c、 那么如何控制单元格是否可修改属性呢?CELLSTL内表有一个字段STYLE就是控制单元格属性的。有 STYLE1234四个字段应该不仅仅是控制可修改属性还有一些例如搜索帮助什么的吧
3、 第2步的c我们说过了给STYLE赋值来控制单元格的状态属性,那么这个STYLE赋什么值呢?从下图 可以看到 它的参考组件和类型 是LVC_STYLE RAW4类型的 ,我们可不能随便给X什么的,这个STYLE的属性值其实在我们ooalv的类中是有定义的是一些常量。
4、 在类中找STYLE的属性值 ,首先这 属性值肯定类型 是RAW4类型的,并且肯定是成对存在的,一个控制可修改一个控制不可修改都是这样 成对存在的。
5、 最后一步把我们添加的这个内表字段 在Layout赋值一下。Layout有一个STYLEFNAME字段,这个字段要赋值成我们新增的那个字段名(内表),这也就是 为什么 这个 字段名可以随便取的原因了。
a.
新增内表字段
参考类型是LVC_T_STYL字段名可以随便取但是一般取CELLSTL,cell就是 计算机屏幕上的单元格的意思,STL就是 style的缩写意思是样式,合起来就是 计算机屏幕上的单元格样式。当然你也可以随便取无所谓,只要到时候给Layout的 STYLEFNAME字段赋值的时候别写错就行
再顺手给Layout的STYLEFNAME字段赋值 ,防止后面忘了。最好大写我这里忘改了。
b.
正常思维情况
先进行数据的调整: 把其中两行数据的SEX的字段搞成空的。方便效果的演示
定义一个perform: 记得放在取数的后面。
set_cell的逻辑:这里的逻辑详情看图中的注解 ,我们每行数据都有一个cellstl的内表,我们只要给这行的cellstl的内表的style赋值了就证明是要改这一行的单元格的属性至于是哪一列的由fieldname来控制。按道理我们像下面这样写了之后应该是有效果的,但其实是出不来效果的,具体原因: 这个原因是由于一般属性和表单属性优先级或者是冲突的关系,当我们这个alv出来之后其实这些单元格默认是不可修改的状态 ,当我们更改了它的属性的时候其实还是会保持默认的状态,这就和Tablecontrol控件一样,当我们根据向导创建的是不可修改的Tablecontrol控件的时候完了又把它调整为可修改状态是没用的,因为它创建的时候某些属性就是缺失没法用的。
c.
实际反向思维
这种控制到某个单元格的属性效果我们一般是先将整列设置为可修改,然后再将不需要修改的单元格设置为不可修改状态,如下图所示。
先将SEX整列设置为可修改状态。
再将SEX不为空的设置为不可修改状态
4.以行为单位可修改
这个就简单了,我们都能控制到某个 单元格了那么控制整个行不是轻而易举吗?只要给当前行的cellstl内表增加所有列名添加多行数据就行了。
5.其他
像其他F4之类的都是正常思维正常逻辑操作就行。唯独可修改属性 是反向思维。
d.
布局 排序 筛选 设置
这些都比较简单 而且感觉 排序筛选不怎么常用 ,我就不做示例了直接总结整理了一下内容。
1.布局设置
在进行布局设置时,需要对以下参数进行传值:EXPORTING 参数中的 I_SAVE(保存布局) 和 IS_VARIANT(筛选布局) 。
2.I_SAVE参数详解
I_SAVE 是一个字符类型的参数,用于定义布局保存的行为,其值可以是一下值:
1、 - : 不能保存布局
2、 X : 布局只能被保存为标准布局,不能指定用户
3、 U : 只能指定用户布局
4、 A : 既能选择标准布局,也可选择指定用户布局
3.IS_VARIANT参数详解
要进一步管理布局,需要使用 IS_VARIANT 参数。这个参数参考 DISVARIANT 结构,其关键字段包括:REPORT = SY-REPID (程序名称)、VARIANT = 布局保存格式。
为了管理布局,有三个常用函数:
1、 REUSE_ALV_VARIANT_DEFAULT_GET:读取默认的布局
2、 REUSE_ALV_VARIANT_EXISTENCE:检测指定布局是否存在
3、 REUSE_ALV_VARIANT_F4:显示布局格式选择对话框
4.优先级管理
在以下情况下,布局管理参数设置优先级最高:1、 排序、筛选等设置时,以布局管理参数设置为优先 2、 用户设置布局参数默认值时,以布局参数传值优先
5.排序 (Sorting)
传值:对 CHANGING 参数 IT_SORT 进行传值,内表参考 LVC_T_SORT 结构参考 LVC_S_SORT
6.筛选 (Filtering)
传值:对 CHANGING 参数 IT_FILTER 进行传值,内表参考 LVC_T_FILT 结构参考 LVC_S_FILT
e.
按钮的隐藏
ooalv的按钮和funalv的按钮是有很大区别的虽然长得都差不多,但其实操作设置完全不一样,funalv的按钮都是通过 SET PF-STATUS <status名称>. 语句设置带出来的在应用工具栏哪一行。ooalv是自己就带了这些按钮根本不用你去用这个语句设置这些按钮,它这些按钮其实是存在于我们画的控件容器当中的。我们上面案例用了SET PF-STATUS语句是为了设置 标准工具条那些返回退出的按钮的。
1.隐藏按钮的参数查找
既然这些按钮是通过调用ooalv的方法带出来的那么我们就去方法中找有没有相应的参数,而且以SAP的ABAP程序的一般思路当我们想要添加某些东西的时候我不是 进行添加,而是把所有的显示出来然后再把 不需要的隐藏掉,所以我们在调用ooalv的方法中找一找有没有EXCLUDING这样的关键字之类的。
2.赋什么值?
这个内表是有一点特殊的,它是没有字段的,当我们声明好这个内表打断点查看它只有一列,并且没有字段名,这种内表是可以直接赋值的不需要指定具体字段。那么这个内表能添加哪些值?可以赋的值应该是那些按钮的功能代码,但是我们也不知道那些按钮的功能代码是啥,所以我们又得去属性当中找了。
3.按钮功能代码的查找
通过上面我们知道肯定是要添加 UI_FUNC类型的值,因为这个内表行类型参考的是UI_FUNC,所以我们在属性当中找UI_FUNC类型的。我们就将当表单可修改状态下的 插入、删除、新增行、复制行、这些按钮隐藏掉吧,因为一般数据是取的数据库表的话不允许用户有这样操作。
4.给内表添加需要隐藏的按钮
定义好数据之后先给调用ooalv方法传值,防止后面忘掉。
代码逻辑的编写
前后效果对比
五、OOALV的 事件 交互
这是一个重点也算是ooalv的优势亮点精髓吧。事件 交互的基本原理就是我们在当前程序中创建一个捕获类,这个类中声明捕获ooalv事件的方法。例如当我们用户执行了双击事件那么就会触发ooalv的某个方法,然后这个方法中会抛出双击事件,这个双击事件会被我们在程序中定义的捕获方法所捕获到并执行相应的代码逻辑。具体步骤如下。
1、 在程序中定义本地类 (捕获类)
2、 在这个类中声明方法并用for event捕获ooalv中的事件
3、 定义捕获方法的实现至于捕获之后你想要干什么由你自己决定。可以灵活使用事件传递过来的参数做出各种操作。
4、 注册事件 注册事件 注册事件 重要的事情说3遍,要将这种事件关系落实到我们具体的对象之间。
a.
代码的重构
现在程序又比较乱了,而且要写本地类所以我们先将程序分块重新架构一下。
1.全局数据定义TOP
*&---------------------------------------------------------------------*
*& 包含 ZGLYN005_TOP
*&---------------------------------------------------------------------*
DATA go_alv TYPE REF TO cl_gui_alv_grid.
DATA go_div TYPE REF TO cl_gui_custom_container.
DATA gs_stable TYPE lvc_s_stbl.
TYPES: BEGIN OF ty_student,
name TYPE c LENGTH 40,"姓名
class TYPE c LENGTH 10,"班级
age TYPE i ,"年龄
sex TYPE c LENGTH 1 ,"性别
origin TYPE c LENGTH 40,"籍贯
cellstl TYPE lvc_t_styl ,"控制单元格属性
END OF ty_student.
DATA: gt_students TYPE TABLE OF ty_student.
DATA: gs_layout TYPE lvc_s_layo.
DATA: gt_fieldcat TYPE lvc_t_fcat.
DATA: gs_fieldcat TYPE lvc_s_fcat.
DATA: gt_exclude TYPE ui_functions."按钮的隐藏
DATA: gs_exclude TYPE ui_func ."按钮的隐藏
CLASS lcl_app_compt DEFINITION DEFERRED.
DATA: event_handler TYPE REF TO lcl_app_compt."捕获事件的对象
DEFINE appendfield. "设置alv表头 宏
clear gs_fieldcat.
gs_fieldcat-fieldname = &1. "对应字段名
gs_fieldcat-coltext = &2. "描述
IF &1 = 'SEX'.
gs_fieldcat-edit = 'X'.
ENDIF.
append gs_fieldcat to gt_fieldcat.
END-OF-DEFINITION.
2.本地类CLS
*下面事件交互的案例中会解释这些代码为什么这样写
*&---------------------------------------------------------------------*
*& 包含 ZGLYN005_CLS
*&---------------------------------------------------------------------*
CLASS lcl_app_compt DEFINITION.
PUBLIC SECTION.
METHODS handle_toolbar FOR EVENT toolbar OF cl_gui_alv_grid
IMPORTING e_object
e_interactive.
ENDCLASS.
CLASS lcl_app_compt IMPLEMENTATION.
METHOD handle_toolbar.
DATA ls_button TYPE stb_button.
CLEAR:ls_button."清空添加数据的结构体
ls_button-butn_type = '3' .
APPEND ls_button TO e_object->mt_toolbar.
CLEAR:ls_button.
ls_button-function = 'but01' ."随便取 判断的时候写对就行了
ls_button-function = '我是but01' .
ls_button-icon = icon_history."输入事务码ICON随便找一个图标
APPEND ls_button TO e_object->mt_toolbar.
ENDMETHOD.
ENDCLASS.
3.PBO事件O01
*&---------------------------------------------------------------------*
*& 包含 ZGLYN005_O01
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Module INI_OOALV OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE ini_ooalv OUTPUT.
IF go_alv IS INITIAL.
PERFORM status_1000 ."设置按钮
PERFORM create_alv ."实例化ooalv和容器
PERFORM set_fieldcat."设置表头
PERFORM set_layout ."设置alv样式布局
PERFORM get_data ."取数
PERFORM set_cell ."设置单元格属性
PERFORM excl_but ."隐藏按钮
PERFORM call_alv ."调用展示ooalv的方法
ELSE.
PERFORM alv_refresh ."刷新alv
ENDIF.
ENDMODULE. " INI_OOALV OUTPUT
4.PAI事件I01
*&---------------------------------------------------------------------*
*& 包含 ZGLYN005_I01
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_1000 INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE user_command_1000 INPUT.
CASE sy-ucomm.
WHEN '&F03'.
LEAVE PROGRAM.
WHEN '&F15'.
LEAVE TO SCREEN 0.
WHEN '&F12'.
APPEND VALUE #( name = '战争机器 ' class = '七班' age = '42' sex = '男' origin = '内华达') TO gt_students.
ENDCASE.
ENDMODULE. " USER_COMMAND_1000 INPUT
5.Perform子程序F01
*&---------------------------------------------------------------------*
*& 包含 ZGLYN005_F01
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form STATUS_1000
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM status_1000 .
SET PF-STATUS '1000'.
* SET TITLEBAR 'xxx'.
ENDFORM. " STATUS_1000
*&---------------------------------------------------------------------*
*& Form CREATE_ALV
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM create_alv .
CREATE OBJECT go_div
EXPORTING
container_name = 'DIV1'.
CREATE OBJECT go_alv
EXPORTING
i_parent = go_div.
ENDFORM. " CREATE_ALV
*&---------------------------------------------------------------------*
*& Form SET_FIELDCAT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM set_fieldcat .
appendfield 'NAME ' '姓名'.
appendfield 'CLASS ' '班级'.
appendfield 'AGE ' '年龄'.
appendfield 'SEX ' '性别'.
appendfield 'ORIGIN' '籍贯'.
ENDFORM. " SET_FIELDCAT
*&---------------------------------------------------------------------*
*& Form GET_DATA
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM get_data .
gt_students = VALUE #( ( name = '美国队长' class = '一班' age = '99' sex = '男' origin = '芝加哥')
( name = '钢铁侠' class = '二班' age = '54' sex = '男' origin = '华盛顿')
( name = '黑寡妇' class = '一班' age = '36' sex = '女' origin = '旧金山')
( name = '蜘蛛侠' class = '六班' age = '20' origin = '皇后区')
( name = '小贱贱' class = '三班' age = '37' origin = '柏林') ).
ENDFORM. " GET_DATA
*&---------------------------------------------------------------------*
*& Form CALL_ALV
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM call_alv .
CALL METHOD go_alv->set_table_for_first_display
EXPORTING
* i_buffer_active =
* i_bypassing_buffer =
* i_consistency_check =
* i_structure_name =
* is_variant =
* i_save =
* i_default = 'X'
is_layout = gs_layout
* is_print =
* it_special_groups =
it_toolbar_excluding = gt_exclude
* it_hyperlink =
* it_alv_graphics =
* it_except_qinfo =
* ir_salv_adapter =
CHANGING
it_outtab = gt_students
it_fieldcatalog = gt_fieldcat
* it_sort =
* it_filter =
* EXCEPTIONS
* invalid_parameter_combination = 1
* program_error = 2
* too_many_lines = 3
* others = 4
.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
ENDFORM. " CALL_ALV
*&---------------------------------------------------------------------*
*& Form ALV_REFRESH
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM alv_refresh .
gs_stable-row = 'X'.
gs_stable-col = 'X'.
CALL METHOD go_alv->refresh_table_display
EXPORTING
is_stable = gs_stable
* i_soft_refresh =
EXCEPTIONS
finished = 1
OTHERS = 2.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
ENDFORM. " ALV_REFRESH
*&---------------------------------------------------------------------*
*& Form SET_LAYOUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM set_layout .
gs_layout-cwidth_opt = 'X' ."自动优化列宽
gs_layout-zebra = 'X' ."斑马纹 隔行变色
gs_layout-sel_mode = 'D' ."最左侧的选择框
gs_layout-stylefname = 'cellstl' ."控制单元格属性的内表名
* gs_layout-edit = 'X' ."整个表单可修改
ENDFORM. " SET_LAYOUT
*&---------------------------------------------------------------------*
*& Form SET_CELL
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM set_cell .
DATA ls_styl TYPE lvc_s_styl.
LOOP AT gt_students INTO DATA(gs_students).
CLEAR ls_styl.
IF gs_students-sex IS INITIAL.
* ls_styl-style = cl_gui_alv_grid=>mc_style_enabled.
ls_styl-style = cl_gui_alv_grid=>mc_style_f4.
ls_styl-fieldname = 'SEX'.
INSERT ls_styl INTO TABLE gs_students-cellstl.
* ls_styl-fieldname = 'NAME'.
* INSERT ls_styl INTO TABLE gs_students-cellstl.
* ls_styl-fieldname = 'CLASS'.
* INSERT ls_styl INTO TABLE gs_students-cellstl.
* ls_styl-fieldname = 'AGE'.
* INSERT ls_styl INTO TABLE gs_students-cellstl.
* ls_styl-fieldname = 'SEX'.
* INSERT ls_styl INTO TABLE gs_students-cellstl.
* ls_styl-fieldname = 'ORIGIN'.
* INSERT ls_styl INTO TABLE gs_students-cellstl.
ENDIF.
MODIFY gt_students FROM gs_students.
ENDLOOP.
ENDFORM. " SET_CELL
*&---------------------------------------------------------------------*
*& Form EXCL_BUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM excl_but .
* gs_exclude = cl_gui_alv_grid=>mc_fc_loc_insert_row.
* APPEND gs_exclude TO gt_exclude.
* gs_exclude = cl_gui_alv_grid=>mc_fc_loc_delete_row.
* APPEND cl_gui_alv_grid=>mc_fc_loc_delete_row TO gt_exclude.
ENDFORM. " EXCL_BUT
*&---------------------------------------------------------------------*
*& Form SET_EVENT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM set_event .
CREATE OBJECT event_handler.
SET HANDLER event_handler->handle_toolbar FOR go_alv.
ENDFORM. " SET_EVENT
b.
自定义按钮的增加
首先明确一点 增加 按钮 是通过ooalv的事件 去增加的所以我们应该去找增加按钮的事件,根据 事件 中的参数来研究如何增加按钮。至于这个事件在什么时候被抛出了那么我们不用关心。反正ooalv显示完毕之前肯定是被抛出了。
1.增加按钮的事件
增加按钮的事件是 TOOLBAR
2.TOOLBAR的传递参数
它有两个传递参数都是可选的但是我们在 捕获它的时候还是都接收一下。E_OBJECT 这个参数就是工具栏对象,就指的是我ooalv的应用工具栏, E_INTERACTIVE 这个参数一般用不到,当你 给这个参数设置为X的话,表示工具栏按钮是交互式的,用户可以点击工具栏按钮,并且按钮会触发相应的事件或动作。当给你给空的时候,表示工具栏按钮是非交互式的,按钮是灰色的或不可点击的,即用户不能与该按钮进行交互。
3.类的声明事件的捕获
类名 方法名 随便取。这里 大家可以打断点查看一下E_OBJECT这个参数的。对后面的理解会有帮助。
4.E_OBJECT参数详解
这个参数 参考 的是一个类,证明这个 参数是 一个对象,那么这一个对象包含什么内容?我们就去对象参考的 CL_ALV_EVENT_TOOLBAR_SET 类中去查看,可以看到这个类没有方法只有两个属性,MT_TOOLBAR 属性是工具栏按钮它是一个内表,MT_BTNMNU 属性是工具栏按钮到上下文菜单的分配也是一个内表,这两个属性都是内表并且都是实例属性,这就证明我们接收到的 E_OBJECT对象参数它里面包含两个内表,而这两个内表有什么值决定了我们工具栏有什么按钮。所以我们在捕获到这个事件之后给E_OBJECT对象中的MT_TOOLBAR内表添加值进去就行了。
1、 MT_TOOLBAR 内表字段详解
字段 | 作用 |
---|---|
FUNCTION | 功能代码Funcode |
ICON | 图标 |
QUICKINFO | 鼠标悬停显示的信息 |
BUTN_TYPE | 按钮类型: 0 正常按钮(默认值 ) 1 菜单和缺省按钮 2 菜单 3 分隔符 4 单选按钮 5 复选框 |
DISABLED | 按钮状态为不可用 |
TEXT | 显示文本 |
CHECKED | 设置为选中时的状态 |
5.捕获方法的实现代码完善
这一步我们也说了就是给E_OBJECT中的内表添加数据就能增加按钮。
6.声明捕获对象
我们习惯的把数据定义写 在 top中对象的声明也在top中,但是通过观察我们包含程序的前后顺序发现类的定义是在声明对象之后的所以会报错的 ,而这里我们就能用到向前声明这个东西了 ,向前声明我们上面也详细解释过了。
向前声明,这样就会不报错了,这句话的意思也可以理解为我告诉程序我有一个类声明还在后面。
7.实例化捕获对象 注册事件
我们在创建一个Perform用来专门实例化对象 和 事件的注册。
8.运行效果
可以看到我们只剩一个按钮了,这是因为我们给这个内表添加数据之前把这个内表清空了,而那些标准的按钮也在这个对象的内表中。所以现在等于应用工具栏按钮的内表只剩一行数据了。
9.增加分割线
分割线有助于我们按钮的分类和美观。挤在一起不好看。分割线在上面的参数详解中已经提到了,我们只需要给内表对应位置添加值就行了,添加值的时候只用给butn_type给值就行了。看得出来下面的添加数据代码比较臃肿了 你们自己写个 perform优化一下就行。
c.
按钮功能交互
按钮功能很简单用事件 USER_COMMAND,当我们用户点击了工具栏按钮之后就会抛出这个事件至于这个事件是在哪个方法中抛出的这个方法是怎么 被调用的这些我们可以不用关心,反正 用户点击了按钮就会抛出这个事件。感兴趣的可以按照本文标题 二 中的 f 查找在什么方法抛出了事件,这个方法又在哪里被调用了。
1.USER_COMMAND传递的参数
USER_COMMAND传递的参数很简单就一个,也很好理解,E_UCOMM这玩意就是按钮的功能代码嘛,就是我们按钮的Funcode。
写案例的时候发现了一个bug你们也调整一下
2.按钮功能实现
上面已经有了基础,这里我就简单说一下就行了。其实为了更模块化更易于维护我们方法的的实现都可以再创建一个perform。不然这个类的实现都会写一大堆方法的逻辑。看个人习惯吧无所谓。
3.注意事项
一般容器里面的这些按钮也就是ooalv的TOOLBAR事件带出来的这些按钮要设置功能的话都是通过USER_COMMAND这个事件来设置按钮功能,如果是针对整个界面的按钮就是菜单工具栏哪些退出返回按钮那些都是SET PF-STATUS设置的,这块按钮的功能是在屏幕逻辑流的PAI实现的,不要把这几套按钮搞混了,菜单工具栏哪些按钮是不会触发我oolav的事件的。
六、其他常用 事件 和 方法
这里不会介绍的很详细,相信你们看完上面的内容已经自己可以找对应事件对应方法来扩展ooalv的功能了。
a.
获取选中行的方法
我们可以把之前的功能事件都结合起来做一个小功能,当我们用户点击一个修改按钮的时候就把当前行的SEX字段的单元格变更为可修改状态。做这个功能要用到我们上面的 toolbar、user_command 事件来增加按钮和设置按钮功能,还需要通过展示数据内表中的 cellstl 内表来控制每一行当中的每一个字段的单元格的属性。
1.按钮的增加
按钮在之前的方法里面增加即可,图标自己用icon事务码去找 。
2.按钮功能实现
按钮功能在之前的CASE语句下面增加一个perform。功能都写在这个perform中。
3.准备事项
上面说过我们单独控制单元格属性的话都是逆向思维,所以先把SEX列都设置为可修改状态,然后展示之前再把每行数据的SEX字段的单元格变为不可修改状态。最后我们点击按钮的时候再把对应行的单元格变为可修改。
1、 先设置为可修改
2、 再设置为不可修改
3、 此时DEBUG查看cellstl内表
4.modify_sex逻辑完善
这个小案例我们主要还是学会使用 get_selected_rows 获取选中行的这个方法。下图中modify_sex逻辑我也有写注释 不过意外情况我可能会考虑不周到大家主要还是对程序逻辑的理解即可。调用 get_selected_rows 方法有两个回参 大家SE24里面自己去看就行了,要是对回参内容不了解就看SE24里面的字段描述再结合 DEBUG查看回参内表数据就懂了,我就不多解释了。
FORM modify_sex .
DATA et_index_rows TYPE lvc_t_row .
DATA et_row_no TYPE lvc_t_roid.
DATA ls_styl TYPE lvc_s_styl.
CALL METHOD go_alv->get_selected_rows
IMPORTING
et_index_rows = et_index_rows
et_row_no = et_row_no.
IF et_index_rows IS NOT INITIAL.
LOOP AT et_index_rows INTO DATA(ls_index_rows).
READ TABLE gt_students INTO DATA(gs_students) INDEX ls_index_rows-index.
ls_styl-fieldname = 'SEX'.
ls_styl-style = cl_gui_alv_grid=>mc_style_enabled."可修改
* INSERT ls_styl INTO TABLE gs_students-cellstl."会插入失败,SEX其实已经存在这个内表中了
READ TABLE gs_students-cellstl WITH KEY fieldname = 'SEX' TRANSPORTING NO FIELDS.
"修改必须指定显式index,不然用的是loop循环的隐式会对应不上,上面读取成功之后sy-tabix就是对应行的索引
MODIFY gs_students-cellstl FROM ls_styl INDEX sy-tabix.
MODIFY gt_students FROM gs_students INDEX ls_index_rows-index."把结构中的数据更新到内表
CLEAR: ls_styl,gs_students.
ENDLOOP.
"修改完展示的内表数据必须刷新因为ooalv的按钮并不会触发PAI不会调用ini_ooalv走到alv_refresh
PERFORM alv_refresh.
ELSE.
MESSAGE '请至少选择一行' TYPE 'S' DISPLAY LIKE 'E'.
ENDIF.
ENDFORM. " MODIFY_SEX
5.运行效果
单行多行都可以,不选择的话会提示消息。ooalv的选中行并不需要左侧必须有选择框,如果Layou的 sel_mode设置为B或者C没有左侧选择框的话并不影响获取选中行。
b.
单击事件 和 获取选中单元格属性值的 方法
单击事件是 HOTSPOT_CLICK。要使用这个事件之前先在表头 FIELDCAT 通过 HOTSPOT 字段给指定列设置热点。然后定义捕获方法,再写方法实现,最后注册事件。 HOTSPOT_CLICK 有三个传递参数 一般常用的就是 E_ROW_ID(行信息)、E_COLUMN_ID(列信息),还有一个是ES_ROW_NO这可能是有翻页功能的那种表单才会用得到。这个事件我们可以配合一个获取单元格值的方法,get_current_cell 可以获取选中单元格的一些属性值 比如 第几列 第几行 单元格的值 等等一些值。前提这个单元格被选中了也就是得让这个单元格获得焦点。我们点击事件等于和这个方法比较连贯这两个配合起来挺好的,当然你也可以选中单元格之后点击按钮触发事件再调用这个方法也可以获取到值的。
1.设置热点
我们给name这个字段设置热点。
2.捕获事件
事件传递过来的这些参数我们用不上,这些参数具体是什么自己DUBUG去看。
3.方法具体内容实现
参数就不详细介绍了,我一般喜欢在SE24类的声明部分找到方法的定义把参数都复制过来再调整定义成变量这样类型也不会错,这样比较快一点。至于方法的调用 可以用 模式也可以复制SE24的声明部分然后代码稍微调整一下就行。
4.事件注册
c.
双击事件
双击事件是 DOUBLE_CLICK。双击事件就不用设置热点了,这里我们和单击事件做同样的事情 ,简单做一下示例。
d.
数据 刷新 到 内表 中 的事件
上面我们做了好多关于单元格可修改属性操作,虽然表面上看起来是可以修改了但是当我们改完之后 这些值并不会刷新到我们的内表,修改单元格数据这块要分两种情况,一种是你修改完触发了oolav的事件比如点击了ooalv的按钮或者是单击双击事件。这种情况 其实数据是可以刷新到内表的,但是如果是触发了我们整个屏幕的PAI这个数据就刷新不到我们的内表因为你触发屏幕的PAI我们现在的程序逻辑就等于是刷新了一下整个表单而已。
数据刷新到内表中的事件是 DATA_CHANGED。SAP给的描述是 Data was Changed,我的理解就是根据界面中的修改把值反馈到内表中。因为我们一般保存按钮就 点击的是屏幕菜单工具栏那个按钮不会单独给ooalv再加一个保存按钮来达到保存数据的效果。
这个事件还有一点比较特别,在注册的时候还要指明在何时触发这个事件,我是回车时抛出这个事件 还是 单元格值变化时触发。
1.触发屏幕PAI
给屏幕PAI的 user_command_1000 打断点。
2.触发ooalv事件
触ooalv按钮功能事件,给捕获按钮功能的handle_user_comm的方法打断点。数据刷新到内表中去了。
3.事件的参数
这个事件的参数要详细解释 一下,有5个传递参数 ,我们主要用 er_data_changed,其他 4个参数感觉不常用传递过来也没什么值。er_data_changed参数参考的是一个 类,证明 这个参数是一个对象,然后这个 对象传递过来之后对象中有好多属性打断点可以进去详细看一下。我们主要用这个对象中的MT_MOD_CELLS这个属性是一个内表,事件被触发后这个内表会记录所有被更改单元格的一些信息,第几行是哪个字段更新为了什么值都存于这个内表当中。
如果我们要根据修改的值做一些操作 比如数据更新到数据库表中就可以循环这个内表进行更新数据库表的操作,总不能触发了这个事件之后我把表单中的所有数据都在数据库更新一遍,这样操作是不合理的。
4.捕获方法与方法实现
下面我就模拟修改数据库信息了,如果出来展示数据的弹框就证明数据修改成功 如果没出来弹框就证明没修改。
5.事件注册
这个事件的注册比较特殊 ,要调方法 register_edit_event 来指定事件的触发方式,这个方法只有一个传入参数 I_EVENT_ID 我们传入类中的静态属性就行。这里我们用回车触发,因为当单元格值变化触发这个太频繁了没必要。单元格值变化触发是当变化之后还必须失去焦点才会触发。
6.效果演示
效果是很明显,但是还有个问题用户其实更新完数据之后习惯点菜单栏中的保存按钮,如果是这样的情况那么我们数据库表并不能更新成功吧,因为点击菜单栏中的保存按钮没有触发事件。
7.采用方法触发DATA_CHANGED事件
DATA_CHANGED是一个事件我们如果想用非事件的方式触发的话还有一个方法可以使用,我们可以当用户点击了保存按钮之后调用这个方法来触发DATA_CHANGED事件达到我们功能的实现。这个方法叫 CHECK_CHANGED_DATA SAP给的描述是 Verification of Changes and Triggering of Event DATA_CHANGED 意思是:变更验证和触发事件DATA_CHANGED,调用这个方法会校验表单的数据是否有更改如果有更改才会抛出DATA_CHANGED事件。
1、 参数详解:当我们数据更改是无效的E_VALID回参就是空,当更改是有效的就是X。这方法中的两个参数都可以不用不接收。EXPORTING类型的参数永远是可选的虽然可选列没打勾。
2、 方法调用,记得是写在屏幕的PAI下面。
七、容器的更换 以及 分割容器
详情 请看此文
其实我们创建一个容器对象的方式有多种,上面我们是通过创建屏幕在屏幕中画了一个控件,然后依据这个控件名创建了容器对象,如果我们想要一个屏幕多显示几个alv的话就在这个屏幕中多画几个控件,再依据这些控件实例化几个容器,然后实例化ooalv对象的时候将这些容器对象相应传入就得到了几个ooalv对象,然后ooalv对象调用各自显示alv的方法这些alv就会展现在各自的容器中。这种容器我们可以叫做 自定义容器
还有一种创建容器的方法是纯代码编写。不用画控件,叫做 自适应Docking容器 这种容器有个优点就是可以灵活的充满整个屏幕, 官方解释叫做 可以停靠的容器,意思就是它可以停靠在 SAP 窗口的四个边(上、下、左、右)。停靠的意思是这个容器可以固定在这些边缘,并且在窗口大小变化时会自动调整大小以适应窗口。使界面布局更灵活和有条理。
还有一种容器叫做 对话框容器,就是以弹框的形式展现出来。它是完全和主窗口分开脱离的 ,也可以灵活的设置它的大小。
容器其实也是可以分割的我们上面提到的三种容器都可以分割,我们可以通过另外一个类将这个容器分割为多个容器。然后拿着分割的这些容器又可以去实例化ooalv对象了,或者 是显示图片 html 等等都可以 。
END、总结
以上就是今天要讲的内容,本文仅仅简单介绍了 OOALV,感觉笔者讲的好对自己有帮助的还麻烦点个免费的赞赞制作不易谢谢谢谢!!!如果有说错或者不好的地方还望大家提出来见谅。感觉笔者写的好的别忘了关注点赞加评论哦,也欢迎大家一起来讨论。谢谢!