打印和显示特殊需求
1. 问题概述 
客户的报表格式都是严格按照真实中电力部门的要求定制的,润乾打印操作票时,如果按行打印,不足补空时,不能控制当前行的字数。当单元格内容过多时,会造成下边的数据超出边距,自动换行而不带下边线的问题,无法保证页面的完整性。对于此问题我们技术以前给过解决办法:在数据行后,补一个可扩展的单元格,行高和数据行高度相当.首先用纸张高度,减去上下边距,再减去页眉和页脚的高度,再除以每个数据行的高度,即可得出每页上可容纳的数据行数.用COUNT()函数拿到数据的总条数,和每页可容纳的行数取余,即可得到最后一页余下的数据行数,再用每页的行数减去最后一页余下的数据行数,即可得到最后一页应该补多少个行高和数据行高度相当的空行,使用TO()函数对空白行作纵向扩展即可.配置为to函数:=to(1,int((297-6-6-20-8-8-25-8-8)/25)-ds1.count()%(int((297-6-6-20-8-8-25-8-8)/25))) 
297表示A4纸的高度,6、6为页边距 20:1(眉)8:2(眉)8:3(眉)25:6(脚)8:7(脚)8;8(脚)但是多少都是有些缺陷没能够达到希望实现的结果: 
1、空白行能够补充满全页 2、自动换行带下边线,动态扩展3、误差大
2. 案例 
南京朗坤软件
3. 解决办法 
1.用了自定义函数来处理当前行由于数据过多导致自动换行而不带下边线的问题,根据单元格宽度,每个字体的大小,计算java的字体规格, 
=warpWords( str(ds1.Add),fontFace =”宋体”,fontSize =11,cellWidth =220,pixel =1) 
4.0的API无法在自定义函数中获得报表定义或单元格集,所以单元格属性需要人工传进来。输入参数说明:待处理字符串,字体名称,字体大小,单元格宽度(像素值),像素差(支持小数) 
2.根据A4纸张高度推算一页数据大概25行 
3.补足空白行,根据动态扩展后的单元格来处理比较精确,补充的行,不显示序号:1、2、3等 
=to(1,25-count(B4{})%25) 
4. 程序说明
package apps; 
import java.awt.Font; 
import java.awt.FontMetrics; 
import java.awt.image.BufferedImage; 
import java.util.ArrayList; 
import com.runqian.base4.util.ReportError; 
import com.runqian.report4.model.expression.Expression; 
import com.runqian.report4.model.expression.Function; 
import com.runqian.report4.usermodel.Context; 
public class warpWords extends Function { 
// 输入参数:待处理字符串,字体名称,字体大小,单元格宽度(像素值),像素差(支持小数) 
public Object calculate(Context ctx, boolean isInput) { 
if(this.paramList.size()!=5) 
throw new ReportError(“warpword()函数需要五个参数!”); 
// 该参数不要传单元格,API文档有问题,暂时没法处理单元格 
String srcString = (String)((Expression)paramList.get(0)).calculate(ctx, isInput); 
// 4.0的API无法在自定义函数中获得报表定义或单元格集,所以单元格属性需要人工传进来 
String fontFace = (String)((Expression)paramList.get(1)).calculate(ctx, isInput); 
int fontSize = ((Integer)((Expression)paramList.get(2)).calculate(ctx, isInput)).intValue(); 
// 单元格宽度需要将单元格单位设置为像素才可看到,默认的宽度单位是毫米,不要传递该值 
float cellWidth = ((Number)((Expression)paramList.get(3)).calculate(ctx, isInput)).floatValue(); 
// 像素差值,Java和IE浏览器的处理字体会有些偏差,可通过此值微调字体宽度 
float pixel = ((Number)((Expression)paramList.get(4)).calculate(ctx, isInput)).floatValue(); 
// System.out.println(“–param1:”+str); 
// System.out.println(“–param2:”+fontFace); 
// System.out.println(“–param2:”+fontSize); 
// System.out.println(“–param2:”+cellWidth); 
// System.out.println(“–param2:”+pixel); 
// 计算java的字体规格 
Font font = new Font(fontFace,Font.PLAIN,fontSize); 
FontMetrics fm = new BufferedImage(10,10,BufferedImage.TYPE_4BYTE_ABGR).getGraphics().getFontMetrics(font); 
return this.warpString(srcString, fm, cellWidth, pixel); 
} 
private ArrayList warpString(String srcString, FontMetrics fontMetrics, float maxWidth, float offsetPixel){ 
String newString = “”
ArrayList al = new ArrayList(); 
float length = 0; 
for(int i=0;i<srcString.length();i++){ 
//System.out.println(“char = “+srcString.charAt(i)+”\tlength = “+length); 
// 发现换行符时,长度清零,计算下一个字符 
if(srcString.charAt(i)==‘\n’){ 
//newString += srcString.charAt(i); 
al.add(newString); 
newString = “”
length = 0; 
//i++; 
continue
} 
length += fontMetrics.charWidth(srcString.charAt(i)) + offsetPixel; 
// 字符串长度超过单元格长度时,回溯,加上换行符,长度清零 
if(length>maxWidth){ 
if(“,”.equals(srcString.charAt(i))){ 
newString += srcString.charAt(i); 
continue
} 
al.add(newString); 
i–; 
newString = “”
length = 0; 
} 
else 
newString += srcString.charAt(i); 
} 
if(length!=0) al.add(newString); 
return al; 
} 
public boolean isExtended() { 
return true
} 
}