简介:这份资源面向使用 SAP Smart forms 进行报表开发与打印调试的 ABAP 顾问和开发人员,聚焦中文文本在英文登录环境中打印时出现字体重叠、错位等显示异常,给出可落地的排查与修正思路。压缩包共 1 个文件,为 doc 格式的实战记录文档,约 28KB,以文字说明配合代码片段呈现问题定位过程。目前已有 1087 人学习,适合正在处理中文打印乱码或重叠问题、又苦于 Notes 无效的中级开发者参考。文档从登录语言为 E 与 1 的环境差异切入,记录了通过调试 Smart forms 对应生成函数、追踪 SSFRT_SET_LANGUAGES 与 %header-langu 赋值逻辑来锁定根因的方法,并给出为 control_parameters-langu 赋值后再传参的修正方式。文中还整理了 Note 808326、908442 与 Note 1007575 关于 Unicode 预览重叠及亚洲字符超 31 字符被压缩的对应关系,便于读者按症状比对补丁状态,同时理解 SAPscript OPEN_FORM 中 language 参数的同类限制,形成较完整的排错路径。
1. 登录语言一切换,中文就叠成一坨
同一张 Smart Form、同一份测试数据、同一套 ECC 系统,用英文环境(login language = E)点打印预览,中文内容就叠在一起,字挤字、行压行;换到中文环境(login language = 1)再预览,排版立刻正常,超长内容还老老实实按预留宽度自动换行。这不是玄学,是很多做 SAP 表单打印的开发者都遇到过的坑:英文环境下 Smart Form 中文字体重叠。新手第一反应往往是“SAP 的 bug”,跑去翻 Note,发现该打的补丁一个不少,系统版本也不低,然后开始怀疑人生。这篇就按我当时的排查顺序,从 Note 对照、程序调试,到给control_parameters-langu赋值、把语言版本传进 Form,再把长中文被压缩的第二个坑一起拆开讲,适合被打印预览叠字卡住的 ABAP 开发者照着定位。
2. 根因不在 Note:语言版本在打印程序里就已经定错了
遇到叠字,先别急着改 Form 布局。Smart Form 的排版宽度是在运行时按“当前打印语言”的字符宽度算出来的,语言版本错了,后面怎么调样式都白搭。我当时的排查顺序是:先排除补丁问题,再进调试器看语言是从哪儿来的,最后才定位到调用程序没传参。
2.1 先把两个相似 Note 对一遍,排除“补丁没打”的可能
查到两条现象几乎一模一样的 Note:Note 808326 描述 Unicode 系统里打印预览文本格式不正确、字符可能重叠或间距过大;Note 908442 描述 Unicode 系统里亚洲文字在预览中重叠。症状描述跟眼前的问题高度吻合,很容易让人直接认定“打补丁就完事”。但我把 Corrections Instructions 里的代码逐段跟系统里的实现对比,发现 ECC6.4 上这两个 Note 早已生效。这一步很关键:如果停在“查 Note”阶段就收工,会误以为问题已解决,实际预览还是叠字。确认 Note 已打的方法是看 SNOTE 里该 Note 的实施状态,或者按 Correction Instructions 里的对象和代码行号进 SE37/SE38 比对当前实现,别只凭版本号猜。
2.2 调试生成的打印程序,找到 %header-langu 这一行
Smart Form 激活后会生成一个 Function Module,真正的打印调用逻辑就在这个 FM 里。进调试器,一般在 350 行之后能看到类似这样的调用:
* 生成的 Smart Form FM 内部:根据控制参数决定本次打印使用的语言版本 call function 'SSFRT_SET_LANGUAGES' exporting i_control_parameters = control_parameters " 调用方传入的控制结构 i_masterlanguage = '1' " 主语言,中文环境为 1 i_thrulang = ' ' i_install_lang = ' ' importing o_languages = %languages. * 取返回结构里的第一个语言作为表头语言,后续排版按它计算字符宽度 %header-langu = %languages-langu1.逻辑说明:SSFRT_SET_LANGUAGES的职责是从控制参数里解析出这次打印要用的语言集合,o_languages-langu1就是最终生效的语言版本,赋给%header-langu后,整个 Form 的字符宽度、换行策略都按它来算。参数说明:i_control_parameters是调用方传进来的控制结构,类型SSFCTRLOP;i_masterlanguage固定给'1',表示主语言按中文处理;i_thrulang和i_install_lang这里留空,表示不额外指定穿透语言和安装语言。问题就出在i_control_parameters上,往下看赋值逻辑就清楚了。
2.3 control_parameters 为空时,语言悄悄退回了 sy-langu
FM 内部对%header-langu的取值逻辑可以概括成一句:control_parameters is initial ? sy-langu : control_parameters-langu。也就是说,调用方如果没给control_parameters-langu赋值,系统就直接用当前登录语言sy-langu顶上。我在英文环境打印时sy-langu = 'E',于是%header-langu变成E;可系统里根本没有英文版的这个 Smart Form,于是中文版 Form 被当成英文版来排版——英文字符宽度按单字节算,中文双字节字符塞进按单字节预留的空间里,预览就叠成一坨,打到纸上重叠部分再展开,跟后面的内容交杂在一起。中文环境下sy-langu = '1',恰好和 Form 的实际语言版本对上,所以看起来一切正常。
注意:这个现象容易被误判成“字体问题”或“打印机驱动问题”,实际根因是排版语言和 Form 实际语言版本不一致。
2.4 为什么中文环境正常、英文环境翻车,值得单独想一遍
很多人会问:既然 Form 是中文的,英文环境下系统为什么不直接报错?因为 Smart Form 的运行时并不强校验“Form 语言 = 登录语言”,它只认%header-langu,然后按这个语言的字符宽度规则去量文本。中文环境登录时,%header-langu恰好等于 Form 的真实语言,排版规则匹配,自动换行也正常;英文环境登录时,语言被sy-langu顶成E,排版规则切到单字节逻辑,中文内容就成了“宽度算小了的文本”。所以这不是随机故障,而是可稳定复现的语言版本错配,复现条件就三条:登录语言为 E、Form 内容含中文、调用程序没给control_parameters-langu赋值。
3. 修复动作:把 control_parameters-langu 显式赋成 1 再传进去
根因确认后,修复并不复杂,但要改对位置。不是在 Smart Form 画布里改,也不是去改 SAP 标准 FM,而是在调用这个 Form 的打印程序里,把控制结构的语言字段显式赋成'1',再把整个结构传进 Form 的 FM。
3.1 在调用方程序里给控制结构补上语言字段
典型写法是在调用 Form 之前,先把control_parameters准备好:
data: lv_fm_name type rs38l_fnam, control_parameters type ssfctrlop, " Smart Form 控制结构 output_options type ssfcompop. " 输出/打印选项结构 * 关键一行:显式指定打印语言版本为 1(中文),不再依赖 sy-langu 兜底 control_parameters-langu = '1'. * 其余控制参数按业务需要设置,例如不弹出打印对话框 control_parameters-no_dialog = 'X'. control_parameters-preview = 'X'. * 取当前 Smart Form 对应的生成 FM 名称 call function 'SSF_FUNCTION_MODULE_NAME' exporting formname = 'ZSMART_FORM_DEMO' " 替换为实际的 Form 名称 importing fm_name = lv_fm_name.逻辑说明:control_parameters-langu = '1'是这次修复的核心,它保证SSFRT_SET_LANGUAGES拿到非空的i_control_parameters,从而走control_parameters-langu分支,而不是退回sy-langu。参数说明:langu字段类型是spras,'1'代表中文;no_dialog置X表示不弹打印参数对话框直接输出;preview置X表示走预览模式,方便测试时观察排版效果。如果你的场景需要弹对话框,可以不设no_dialog,但语言字段一定要在调用前赋好,不能指望对话框里临时选。
3.2 把控制结构完整传进 Form 的 FM
拿到 FM 名之后,调用时要确保control_parameters作为导出参数传进去,别只传业务数据:
* 调用生成的 Smart Form FM,控制结构必须整体传入 call function lv_fm_name exporting control_parameters = control_parameters " 含 langu = '1' output_options = output_options user_settings = ' ' importing job_output_info = data(ls_job_output) tables it_data = gt_data " 业务数据内表 exceptions formatting_error = 1 internal_error = 2 send_error = 3 user_canceled = 4 others = 5.逻辑说明:control_parameters是 Form FM 解析打印语言的唯一入口,只要这个结构里langu有值,生成的 FM 内部就会把%header-langu定成对应语言,排版宽度随之切换到双字节规则。参数说明:it_data是传给 Form 的业务数据内表,结构要和 Form 里定义的接口一致;output_options控制设备、份数等输出细节;异常处理至少要区分formatting_error和internal_error,前者多为接口数据不匹配,后者多为 FM 内部错误,跟语言无关。
3.3 改完之后的验证顺序,别跳过英文环境
改完代码不要只在中文环境下测,那等于没测。我当时的验证步骤是:第一步,把登录语言切成 E,跑同一张 Form,进调试器确认%header-langu的值已经是1而不是E;第二步,预览含长中文的测试数据,看是否还叠字、是否按预留宽度自动换行;第三步,真机打印一份到纸上,重点看超长中文换行后的行距和后续内容有没有交杂;第四步,再切回登录语言 1 回归一遍,确认原正常场景没被改坏。四步都过,语言版本这条线才算修完。
3.4 为什么在英文环境编辑 Form,后来会变成乱码
排查过程中还踩了一个坑:最初图省事,在英文环境里编辑 Smart Form,直接在画布上敲了中文字面量。后来在英文环境打印,这些中文描述全成了乱码。这个问题我至今没完全定位到具体成因,只能确认它跟编辑时的语言上下文有关。工程上的做法很朴素:要在 Form 里放中文字面量,就在中文环境里编辑和保存,别在英文环境里手敲中文。文本元素也走中文环境维护,避免字面量在传输或激活时被语言上下文改写。这条经验后来成了我的固定习惯——语言相关的编辑动作,一律在目标语言环境下完成。
4. 第二个坑:超过 31 个字符,中文被压成一团
语言版本修好后,叠字是没了,但多测几轮又发现新问题:取出来的中文字符串一旦比较长,预览里就压缩在一起,字间距变得极窄。去查 Note,找到 Note 1007575,症状写得明明白白:Unicode 系统里显示亚洲 Smart Form,表格行空间足够,但超过 31 个字符的文本会被压缩。
4.1 用边界数据把触发条件钉死
别凭感觉说“长文本会压缩”,要拿数据说话。我构造了三组测试数据:20 个中文字符、31 个中文字符、32 个及更长的中文字符,分别预览。结果是 31 个及以内排版正常,超过 31 个才开始压缩,且压缩程度随长度增加更明显。这一步的价值在于把问题从“偶发”变成“可复现的边界条件”——以后任何人报同样的问题,先问字符长度是否超过 31,能省掉一大半沟通成本。
4.2 这个 Note 修的是字符测量层,不是你的数据
Note 1007575 修正的是系统在 Unicode 环境下对亚洲字符的测量与压缩逻辑。换句话说,字符数超长时被压缩,不是你 Form 布局留白不够,也不是数据里混了全角空格之类的东西,而是运行时对长亚洲文本的宽度处理有缺陷。判断方法也简单:同一段文本,31 字符内正常、超出就压缩,且换行位置和行距都不对,基本可以锁定到这条 Note。如果你把字段拆短、强制在 31 字符处截断再拼接,客观上能绕过压缩,但那是把排版问题转嫁给数据,不推荐。
4.3 打 Note 前后的对比验证要做全
申请打上 Note 1007575 之后,验证不能只看“32 个字符那一组”。我的做法是把 20、31、32、50 字符四组数据全部重跑一遍预览,再各打印一份到纸上,确认压缩消失、换行位置正确、行距一致。同时回归第一章叠字场景,确认两个修复互不干扰。这里有个顺序经验:先修语言版本,再处理字符压缩。因为语言版本不对时,字符宽度本身就是错的,压缩问题会被叠字现象掩盖,先修压缩等于白测。
提示:补丁类修复要记录 Note 编号和实施日期,方便后续系统拷贝或升级后快速核对,避免在新建系统上重复踩同一个坑。
5. 避坑清单:这几处我真实翻过车
5.1 只查 Note 不改调用程序,修了个寂寞
现象:Note 808326、908442 在系统里显示已实施,预览依旧叠字。原因:这两条 Note 修的是标准层问题,而本次故障根因在调用程序没给control_parameters-langu赋值,标准层再正确也兜不住。解决:建立“补丁状态 + 调用传参”两条排查线,先确认 Note 已打,再进调试器看%header-langu的实际取值,两条线都过才算排除。
5.2 在英文环境编辑 Form,中文字面量变乱码
现象:英文环境编辑时敲入的中文描述,在英文环境打印全是乱码。原因:编辑时的语言上下文与打印语言不一致,字面量保存和读取环节出现偏差。解决:含中文字面量的 Form 一律在中文环境下编辑、保存、激活;文本元素同理。已经乱码的,回中文环境重新录入并传输,别在英文环境里试图“修字”。
5.3 只改了一个调用入口,其他入口继续叠字
现象:测试程序里改好了,生产上另一个事务码调同一张 Form 还是叠字。原因:同一张 Smart Form 可能被多个程序调用,只改了手头这一个。解决:改之前先用 SE11/SE84 反查该 FM 或 Form 的调用方,把所有调用点列出来逐个补control_parameters-langu = '1';改完在每个入口各跑一次英文环境预览。
5.4 SAPscript 场景漏了 OPEN_FORM 的 language 参数
现象:换成 SAPscript 打印,同样的中文叠字问题复现。原因:语言版本限制这条原则对 SAPscript 同样成立,只是入口从SSFRT_SET_LANGUAGES换成了OPEN_FORM的language参数。解决:调用OPEN_FORM时显式传language = '1',逻辑跟 Smart Form 完全一致——打印前先把语言版本钉死,不依赖登录语言兜底。
5.5 测试只测短中文,长文本问题上线才暴露
现象:测试阶段全是短字段,上线后长地址、长品名一打印就压缩。原因:测试数据没覆盖 31 字符边界。解决:打印类测试固定准备三档数据——短(10 字符内)、边界(31 字符)、超长(50 字符以上),三档都过预览和真机打印才算通过。这个习惯比任何补丁都省事。
6. 快速定位这类问题的顺序:先看语言,再看长度
被“中文叠字/压缩”卡住时,我现在的固定动作是三步。第一步,确认复现条件:切到登录语言 E,用含中文的数据预览,能稳定复现就进入下一步;如果中文环境也异常,那就不是语言版本问题,先查 Form 布局和字段长度。第二步,进调试器看生成的 Form FM,找到%header-langu的赋值处,看它是等于sy-langu还是等于调用方传入的control_parameters-langu;等于sy-langu且当前是 E 环境,基本可以判定调用程序漏传语言。第三步,语言修好后若仍异常,量字符长度,超过 31 个中文字符被压缩就对 Note 1007575。
| 现象 | 优先怀疑 | 确认方法 |
|---|---|---|
| 英文环境叠字、中文环境正常 | 调用程序未设control_parameters-langu | 调试看%header-langu是否等于sy-langu |
| 两种登录语言下都叠字 | Form 布局或字段宽度设置 | 检查画布窗口宽度与字段绑定 |
| 31 字符内正常、超出被压缩 | Note 1007575 未打 | 构造 31/32 字符边界数据复现 |
| SAPscript 场景叠字 | OPEN_FORM未传language | 检查调用处language参数是否为空 |
| 预览正常、打印到纸异常 | 输出设备或打印控制 | 换设备对比,检查output_options |
还有一个提速技巧:把%header-langu的值临时写进调试观察点,或者在外层程序里打印control_parameters-langu和sy-langu两个值,一眼就能看出语言从哪来。这比反复预览猜原因快得多。从那以后我每次做多语言打印,不管是 Smart Form 还是 SAPscript,都强制在调用前显式赋一次语言版本,测试数据必带 31 字符边界那一条——这两个动作花不了几分钟,但能挡掉后面一整轮的返工。希望帮到你。
本文还有配套的精品资源,点击获取