现在做的一个项目,需要涉及到打印,所以选择了FASTREPORT。网上下的FOR DELPHI2009是有源代码的,用起来还是不错,我前面的BLOG中已经写了几个封装的功能,用了下还是比较爽的。
但是发现几个问题。
项目需要打印一个很大篇幅的文章,文章内容放在一个数据库的TEXT字段中,内容大小又不一样,大的可能需要用好几十页纸才能打完,小的可能只有几个字,并且每行打印的时候都要求要下划先,如果一行文字中间折行的,整行需要加下划线。
效果如下:
用 FASTREPORT设计还是比较简单的,直接把这个字段拖进来就好了,然后设置这个MemoView的StretchMode为 smActualHeight,这样就可以打印多行了,然后设置UnderLines为True就可以打印的时候有下划线了。然后设置一下字体和 LineSpacing就可以了。
但是运行后发现两个问题:
1.设置UnderLines属性后,最后一行的下划线有时候会打印出来,有时候又不打印。
2.文章内容,如果超过一页,文章的最后一行也是有时候会打出来,有时候又打不出来。
网上下了几个版本,都存在这个问题,并且官方网站也没有提起,没办法,只能自己去研究FASTREPORT的代码了。
最开始认为这两个问题是同一个问题,经过分析发现是不同的两个BUG。
先研究下划线问题。
这个问题比较简单,先找到frxClass单元中的TfrxCustomMemoView的Draw方法,专门有一个函数DrawUnderlines;是用于划下划线的,中间有一段循环:
dy := FY + h + (GapY - LineSpacing + 1) * ScaleY;
while dy < FY1 do
begin
Canvas.MoveTo(FX, Round(dy));
Canvas.LineTo(FX1, Round(dy));
。。。。
这个代码中循环的判断while dy < FY1 do是有问题的。他并没有考虑最后一行的情况,修改如下:
h := FDrawText.LineHeight * ScaleY;
dy := FY + h + (GapY - LineSpacing + 1) * ScaleY;
//hl changed 20090602
while dy < (FY1 + Trunc(LineSpacing/2) ) do
// while dy < FY1 do
begin
Canvas.MoveTo(FX, Round(dy));
Canvas.LineTo(FX1, Round(dy));
OK,问题解决。
最后一行有可能不打印的问题就麻烦了。要去研究整个FASTREPORT的运行机制。折腾到凌晨一点多,基本有点眉目了。
原因在于计算行高的时候,没考虑到最后一行是不需要计算LineSpacing的情况。
错误代码如下:
function TfrxDrawText.GetOutBoundsText(var ParaBreak: Boolean): WideString;
var
PrnSz: Integer;
n, vl, Ln: Integer;
ratio: Extended;
Tag: TfrxHTMLTags;
cl: LongInt;
begin
ParaBreak := False;
Result := '';
n := FText.Count;
if n = 0 then Exit;
FCanvas.Lock;
try
PrnSz := -FCanvas.Font.Height;
ratio := FDefPPI / FScrPPI;
// number of lines that will fit in the bounds
vl := Trunc((FOriginalRect.Bottom - FOriginalRect.Top + 1) / (PrnSz / ratio + FLineSpacing));--这里是有问题的
修改为:
function TfrxDrawText.GetOutBoundsText(var ParaBreak: Boolean): WideString;
var
PrnSz: Integer;
n, vl, Ln: Integer;
ratio: Extended;
Tag: TfrxHTMLTags;
cl: LongInt;
begin
ParaBreak := False;
Result := '';
n := FText.Count;
if n = 0 then Exit;
FCanvas.Lock;
try
PrnSz := -FCanvas.Font.Height;
ratio := FDefPPI / FScrPPI;
// number of lines that will fit in the bounds
vl := Trunc((FOriginalRect.Bottom - FOriginalRect.Top + 1) / (PrnSz / ratio + FLineSpacing));
//hl changed 20090603
if ((FOriginalRect.Bottom - FOriginalRect.Top + 1) - vl * (PrnSz / ratio + FLineSpacing)) >= (PrnSz / ratio) then
Inc(vl);
然后再修改计算剩余高度的代码。修改方法同上。
OK,问题解决。
本文来自博客园,作者:del88,转载请注明原文链接:https://www.cnblogs.com/del88/archive/2012/02/26/2369217.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人