工作生活与爱好

工作中的记录; 生活中的记忆; 业余爱好的记载。

2007-01-15

 

ABAP:SmartForms 之二--设计

报表要求:(见下表)


要求:
1、不是套打,表格线也需要输出
2、每张报表打印8行记录,不足的空白行也需要输出
3、按凭证号打印单据,可以连续打印多张报表。

、创建样式:
在创建Form之前,需要创建多种段落和字体样式,供Form中的文字使用。需要设置多种“段落格式”,并且必须在“表头数据”中设定“标准段落”

1.创建段落格式,一般有RH(Report Header),PD(Page Header), PB(Page Bottom),LD(Line Header and Details),字体:CNSONG,9pt。注意最好在各段落的“首行缩”中设定1mm的缩进,否则,在Form中表格线和文字之间会没有任何间隙。
2.设置“表头数据”中“标准段落”
3、保存并激活样式文件。

二、创建SmartForm

1、在“全局设置”-〉“表格属性”-〉“输出选项”中
设定“页格式”:即纸张的大小
“样式”:设定本Form使用的默认样式文件,这里指定为第一步创建的样式文件。

2、在“全局设置”-〉“表格接口”-〉“导入”
设置两个参数:
ptr_header type c
ptr_items type c
这两个参数用来传入我们在Report中Export内表数据的句柄(ID key)。

3、在“全局设置”-〉“全局定义”中进行多项设定
a、“类型”设定,在这里需要定义4个类型,一个用来保存表头数据的工作区和内表,一个用来保存明细数据的工作区和内表,它们的结构必须与Report中Export到数据库中的内表的结构完全对应一致,否则,我们将不能从传入的句柄(ID key)中恢复内表数据。

* 领料单抬头信息
TYPES:
BEGIN OF TYP_header_ROW ,
mblnr LIKE mseg
-mblnr, " 凭证号
bldat LIKE rkpf-rsdat, " 凭证日期
c_so(16) TYPE c, " 销售订单号
c_issdt LIKE sy-datum, " 发货日期
werks LIKE mseg-werks, " 地点
PLNAT_NAME LIKE t001w-name1, " 出货单位名称
kokrs LIKE mseg-kokrs, " 控制范围
kostl LIKE mseg-kostl, " 成本中心
cc_name LIKE cskt-ktext, " 成本中心名称名称
c_depart(45) TYPE c, " 领料部门
bwart LIKE mseg-bwart, " 移动类型代码
btext_mt LIKE t156t-btext, " 移动类型描述
c_btext_mt(60) TYPE c, " 移动类型次数
C_TOTAL(17) TYPE C, "合计输出时由用户手工填写
END OF TYP_header_ROW .

TYPES: TYP_HEADER_TABLE TYPE TYP_HEADER_ROW OCCURS
0.

* 领料单明细信息
TYPES:
BEGIN OF TYP_ITEMS_ROW ,
mblnr LIKE mseg
-mblnr, " 物料凭证编号 : 物料凭证
rsnum LIKE rkpf-rsnum, " 凭证号 : 预留单
mjahr LIKE mseg-mjahr, " 物料凭证年度
zeile LIKE mseg-zeile, " 序号
bwart LIKE mseg-bwart, " 移动类型代码
werks LIKE mseg-werks, " 地点
kokrs LIKE mseg-kokrs, " 控制范围
kostl LIKE mseg-kostl, " 成本中心
matnr LIKE mseg-matnr, " 物料号码
maktx LIKE makt-maktx, " 物料描述
erfme LIKE mseg-erfme, " 计量单位
c_planc LIKE resb-bdmng, " 计划数量(手工填写)
c_outc LIKE mseg-erfmg, " 实发数量
c_count(6) TYPE c, " 件数(手工填写)
lgort LIKE mseg-lgort, " 仓储地点
charg LIKE mseg-charg, " 备注
END OF TYP_ITEMS_ROW.

TYPES: TYP_ITEMS_TABLE TYPE TYP_ITEMS_ROW OCCURS
0.


b、在“全局数据”中,定义全局的变量,我们需要定义如下几个变量
wa_header type typ_header_row "表头数据工作区,由于SmartForms中的内表不能有HeaderLine,因此必须定义一个与内表结构一样的工作区

ig_header type typ_header_table "表头数据内表
wa_items type typ_items_row "表单明细工作区
ig_items type typ_items_table "表单明细内表
wa_blanks type typ_items_row "空白行工作区
ig_blanks type typ_items_table "空白行内表
g_count type i "记录一张报表的明细的记录数量
G_CURRLINE type i "记录所有报表共计打印了多少行,用于判断最后一页
G_TOTALLINES type i "记录内表ig_items总行数,用于判断最后一页
G_CURRPAGE type i "一个凭证的当前页码
G_TOTALPAGE type i "一个凭证的总页码



c、在“初始化”中,将数据句柄中的内表恢复到刚设定的全局变量中
输入参数:ptr_header,ptr_items,ig_header,ig_items,g_totallines

perform Restor_buffer using ptr_header changing ig_header.
perform Restor_buffer using ptr_items changing ig_items.

DESCRIBE TABLE IG_ITEMS LINES G_TOTALLINES.

d、在Freecode"格式化程序"中,定义Form Restor_buffer函数

form Restor_buffer using typeid type c changing t type table.
import t from database indx(hk) id typeid.
endform.



至此,我们已经得到了表头和明细这2个内表的数据,下面准备画报表并输出数据。

4、在“页和窗口”中,在“%Page1”页下,添加3个窗口
"MAIN主窗口": 在SmartForm中,只有窗口类型为“主窗口”的窗口,才能被循环。例如,在最前面的样表中,明细数据有20条,不能在一页中打印输出完毕,需要输出 4页才能打印完一张单据的数据,在这4张单据中,表头和表尾是不变的,但是表中间部分数据却是变化的,中间这个窗口需要被循环输出4次。因此需要将这个窗 口类型设定为“主窗口”。在本例中为现实明细数据的这部分。
“窗口1”:从表最上面到明细栏的标题栏(包括标题栏)
“窗口2”:最底下2行。
注意:窗口的宽度加上遍距不能大于纸张宽度。

创建好这三个窗口,设定好窗口的宽度,高度,以及位置信息。下图是整个SmartForm的结构

注意,我将输出表头的窗口“%windows1 页头”放在了输出明细数据的窗口“主窗口”的下面,这是必须的,因为表头中的数据需要从表头内表ig_header中来。loop1是循环内表 ig_header,将数据放到表头工作区wa_header中。因此,%windows1 页头窗口就可以直接使用工作区wa_header中的数据。如果该窗口放在了主窗口的前面,那么至少第一页中表头会没有数据,而且后面每一页的表头显示的 都是下一个表头的内容。
注:虽然打印机输出时,现打印%WINDOWS1 页头,再打印MAIN主窗口,最后打印%WINDOW2页尾窗口,但是程序执行时,却是按照上图中树结构从上到下进行处理的,是先处理MAIN主窗口,其 次%WINDOWS1 页头,最后%WINDOW2页尾窗口的逻辑顺序,可以从跟踪SMARTFORMS程序得知。

下面详细介绍整个逻辑流程和代码:

1、%LOOP1表头循环
设置:数据-〉loop循环-〉操作数:ig_header into wa_header
作用:循环表头内表中的数据,每次打印一个凭证的行项目数据。由于内表在这里不能有工作区,因此将每个表头数据放置到另外的工作区。

2、%LOOP4计算单个凭证总页码
设置:数据-〉loop循环-〉操作数:IG_ITEMS INTO WA_ITEMS
WHERE条件:IBLNR = WA_HEADER-IBLNR
作用:由于在打印每张凭证及行项目之前,需要知道该凭证的总页数,因此需要首先计算IG_ITEMS内表中有多少条当前凭证的行记录数。

3、%CODE4累计单个凭证的行项目数
输入参数:G_COUNT
代码:

G_COUNT = G_COUNT + 1.

作用:累计当前凭证的行项目数。

4、%CODE1计算当前凭证总页码
输入参数:G_TOTALPAGE,G_COUNT
代码:

G_TOTALPAGE = 0.

*计算单个凭证的总页码
G_TOTALPAGE
= G_COUNT MOD 8.

IF G_TOTALPAGE = 0.
G_TOTALPAGE
= G_COUNT DIV 8.
ELSE.
G_TOTALPAGE
= G_COUNT DIV 8 + 1.
ENDIF.

G_COUNT
= 0.

作用:根据第三步累计的单个凭证的总行项目数,以及每页打印的行记录数(8),计算该凭证需要打印的总页数。计算完毕以后,G_COUNT重新置0。

6、%LOOP2循环输出明细
设置:数据-〉loop循环-〉操作数:IG_ITEMS INTO WA_ITEMS
WHERE条件:IBLNR = WA_HEADER-IBLNR
作用:这里的循环条件与第2步的条件完全一致,准备循环打印当前凭证的所有行项目。

7、%CODE2记录行数加1
输入参数:G_COUNT,G_CURRLINE
代码:

* 每打印一行行记录,记录数量加1
G_COUNT
= G_COUNT + 1.

G_CURRLINE
= G_CURRLINE + 1.

作用:每循环一次,当前凭证打印的行记录数加1,所有凭证打印的总行记录数加1。

8、%TEMPLATE4数据明细
作用:模板,行记录的表格,以及相关文本内容。LOOP2每循环一次,就打印输出一行该模板以及文本内容。行高一般为5mm(根据实际调整),注意模板的宽度不能超过窗口的宽度。在“细节”中可以调整模板的每个单元格的宽度,以及每行的高度。

9、%TEXT22 - %TEXT30文本内容
%TEXT22 序号:&G_COUNT(CZT4R)& 输出选项-〉输出结构:第1行第1列
%TEXT23物料号码:&WA_ITEMS-MATNR& 输出选项-〉输出结构:第1行第2列
依此类推。

10、%CODE5计算当前页码
输入参数:G_COUNT,G_CURRPAGE
代码:

DATA: L_LINE TYPE I.
L_LINE
= G_COUNT MOD 8.

IF L_LINE = 0.
G_CURRPAGE
= G_COUNT / 8.
ELSE.
G_CURRPAGE
= G_COUNT DIV 8 + 1.
ENDIF.

作用:每输出一行,计算当前行所在的页码,即为当前页

11、%CODE3计算空行
输入参数:G_COUNT,IG_BLANKS,WA_BLANKS
代码:

G_COUNT = G_COUNT MOD 8.

* 需要的空记录行数
IF G_COUNT <> 0.
G_COUNT
= 8 - G_COUNT.
ENDIF.

CLEAR IG_BLANKS[].
DO G_COUNT TIMES.
APPEND wa_blanks
to ig_blanks.
ENDDO.

G_COUNT
= 0.

作用:在当前凭证的所有有效数据行打印完毕以后,还需要计算需要打印多少空行,才能刚好打印满一张纸。用计算的数量,填充内表IG_BLANKS,计算完毕以后,G_COUNT必须清0。

12、%LOOP3 补充打印空行
设置:数据-〉loop循环-〉操作数:IG_BLANKSS INTO WA_BLANKS
WHERE条件:无
作用:循环内表IG_BLANKS,次数为内表中的记录数,即空行数,打印输出空行。

13、%TEMPLATE5空数据明细
作用:该模板与第8步的TEMPLATE4完全一样,只是该模板下不需要有文本TEXT,只序号输出模板的表格线即可。
到 此步骤,已经打印完毕了当前凭证的所有有效数据行和补充的空行,如果当前凭证需要打印多页,例如有30条行记录,需要打印3个满页,第4页数出6行数据, 补充2个空行,这3次分页是系统自动分页的,分也之前,自动处理页头和页尾窗口,输出这两个窗口的内容。自动分页的条件是“MAIN主窗口”的高度被打印 满了,因此一定要注意,主窗口的高度必须等于你需要的高度,不要多,也不要少,在本例中,高度为8行 x 5mm = 40mm


14、%CONDITION1分页
设置:一般属性-〉节点条件:G_CURRLINE <> G_TOTALLINES
作用:在一个凭证打印完毕以后,将要进入打印下一个凭证之前,需要分页,但是在打印完最后一个凭证的最后一页以后,却不能有分页,否则最后会多一个空行。

15、%COMMAND1强制分页
设置:一般属性-〉转到新页:%PAGE1
作用:在G_CURRLINE <> G_TOTALLINES 条件成立(不是最后一行)的情况下,强制分页。
你 也许会说,这里不强制分页,系统也会自动分页,因为前面输出的高度正好都满足的各窗口的高度,会自动进行分页,确实如此,系统会自动进行分页,但是在这里 强调:强制分页是必须的,不能使用自动分页,原因是:自动分页发生的时间不是我们预想的,我们需要在第13步执行完毕以后,马上进行分页,这时, WA_HEADER中的内容还是当前凭证的数据,这样,在处理页头和页尾窗口时,数据是正确的。而自动分页却不在此时发生,而是在第1步LOOP1循环再 次执行以后,也就是WA_HEADER之中的内容变成下一条以后才发生,这样我们就不能输出正确的表头和表尾数据,因此必须使用强制的分页命令。

16、表头和表尾窗口
由于这两个窗口非常简单,仅输出文字描述和WA_HEADER中的内容,因此不详细说明。


Q&A
1.打印预览表格线都正常,但是用针式打印机输出出现部分表格线无法输出。
答:这个可能是由于针式打印机的分辨率较小的缘故,使用激光或者喷墨打印机可以正常输出,或者在SmartForms中加粗表格线,使用30TW。

2.在使用穿孔纸连续打印时,后面的纸张出现错位现象。
答:原因不是很清楚,需要设置打印机中的纸张格式,将纸张高度根据错位的距离进行加或者减,多次调整以后可以达到没有错位。


Comments: 发表评论



<< Home

Archives

1990年1月15日   2007年1月14日   2007年1月15日   2007年1月16日   2007年1月17日   2007年1月18日   2007年1月19日   2007年1月20日   2007年1月22日   2007年1月23日   2007年1月24日   2007年1月25日   2007年1月26日   2007年1月27日   2007年1月29日   2007年1月30日   2007年1月31日   2007年2月1日   2007年2月2日   2007年2月3日   2007年3月13日   2007年5月15日   2007年5月16日   2007年6月2日  

This page is powered by Blogger. Isn't yours?