T
taogou
Unregistered / Unconfirmed
GUEST, unregistred user!
打印中一些问题的解决方法 (taogou)
以下quickrpt版本都为3.6
关于自动折行
需求:将超过长度的文本自动折行
解决方法:根据DELPHI的判断函数来控制超过长度文本的取舍,其实它本身有判断并截取中文字符的功能,
但是只取了第一行,所以就没有折行的效果。
源码:文件 QRCtrls;函数 FormatLines;子函数AddWord
procedure AddWord(aWord : string);
{$ifdef ver100}
var
S: string;
{$endif}
begin
while aLineWidth(NewLine + aWord) > Widthdo
//字符长度超过指定长度
begin
if NewLine = '' then
begin
{$ifdef ver100} //版本控制 似乎只分了{$ifdef VER36} 和这个。
if SysLocale.FarEast then
begin
while truedo
begin
if (aWord[1] in LeadBytes) and (Length(aWord) > 1) then
S := copy(aWord, 1, 2)
else
S := copy(aWord, 1, 1);
if aLineWidth(NewLine + S) < Width then
begin
NewLine := NewLine + S;
Delete(aWord, 1, Length(S));
end
else
Break;
end;
end
else
while aLineWidth(NewLine + copy(aWord, 1, 1)) < Widthdo
begin
NewLine := NewLine + copy(aWord, 1, 1);
Delete(aWord, 1, 1);
end;
{$else
}
while aLineWidth(NewLine + copy(aWord, 1, 1)) <= Widthdo
begin
if ByteType(aWord, Length(aWord)) = mbTrailByte then
//如果是是双字节字符,则截两位
//如果截的是双字节字符而长度恰好又超过了指定长度,
//系统默认将指定长度扩展一位。如果不愿意,当然这里也可以自己再加入控制
begin
NewLine:=NewLine +copy(aWord,1,2);
Delete(aWord, 1, 2);
end else
begin
NewLine := NewLine + copy(aWord, 1, 1);
Delete(aWord, 1, 1);
end;
end;
{$endif}
//taogou aWord := '';
//该句的赋值就将导致不能换行
end;
FlushLine;
//将截取的指定长度的字符加入到字符串列表中
{ if aLineWidth(aWord) > Width then
begin
if NewLine = '' then
begin
if Width = 0 then
aWord := ''
else
while aLineWidth(aWord) > Widthdo
{$ifdef ver100}
{ if ByteType(aWord, Length(aWord)) = mbTrailByte then
Delete(aWord, Length(aWord)-1, 2)
else
}
//{$endif}
{ begin
Delete(aWord, Length(aWord), 1);
end;
end;
NewLine := aWord;
FlushLine;
aWord := '';
end;
}
if not WordWrap then
begin
aWord := '';
LineFinished := true;
end;
end;
NewLine := NewLine + aWord;
end;
关于自动折行所引起的页行数可变控制
需求:文本折行后,是已设格式的行高自动变化,行数不容易控制,预览效果不堪入目。
解决方法:不允许已设行高自动变化,根据detail行高取舍文本的行数。例:不折行的情况下打印5行的固定
格式,会因为折行而打不了5行,程序自动将行高增大,在套打的情况下,情况非常糟糕。所以强制固定行高,
如果折行超过了固定高度,则超出部分不打印。
源码:文件 QRCtrls;主函数 PrintToCanvas;子函数CanPrint
找到下面着一行
TQRCustomBand(Parent).ExpandBand(LineHeight, AFExpanded, HasExpanded);
该行是根据你的CAPTION的行数来增加行数的,所以屏蔽掉
在主函数中找到下面这一行
ControlBottom := aTop + aHeight +1;
修改为
ControlBottom := aTop + TQRCustomBand(Parent).size.Length +1;
TQRCustomBand(Parent).size.Length 是当前DETAIL的行高
然后找到下面这个循环
while (FCurrentLine <= FFormattedLines.Count - 1) and CanPrintdo
if (FCurrentLine <= FFormattedLines.Count - 1) and CanPrint then
begin
PrintLine(FCurrentLine);
inc(FCurrentLine);
end;
修改为
while (FCurrentLine <= FFormattedLines.Count - 1) and CanPrintdo
//taogou
if (FCurrentLine <= FFormattedLines.Count - 1) and CanPrint then
begin
if Y + LineHeight < ControlBottom then
//taogou Y为当前开始打印的位置,lineHeight为字符行高
PrintLine(FCurrentLine); //controlbottom为detail的下限位置,仅当位置小于允许的位置才打印
inc(FCurrentLine);
end;
FCurrentLine:=FFormattedLines.Count;
//不管打了几行,都将当前行表示为该caption已经打印完毕
需求:控制多余行数,例:页打印行数为5行,当前打印记录数为12,带格式不套打,
则在最后页只有2行数据,从第3行到页脚为一片空白。这里需要将最后一页上3行打印上无数据的空格式.
解决方法:循环N次detail行的打印方法,并屏蔽掉记录
源码:文件 QuickRpt;主函数 TQRController.Execute
HasPrintedLines:=0;
//新增本函数局部变量 记录已经打印的行数
while MoreDatado
begin
inc(HasPrintedLines);
//增1
Application.ProcessMessages;
if ParentReport.QRPrinter.Cancelled then
Exit;
if ParentReport.PreparingDesignTime and (ParentReport.FPageCount > 1) then
Exit;
inc(FDetailNumber);
PrintGroupHeaders;
PrintBeforeControllers;
ParentReport.PrintBand(FDetail);
PrintAfterControllers;
if DSOK then
begin
DataSet.Next;
MoreData := not FDataSet.Eof;
if (FDataSet.Eof) then
//Add begin
begin
if FDetail<>nil then
//将detail中的TQRDBText and TQRLabel 全部不打
for j:=0 to FDetail.ControlCount-1do
begin
if FDetail.Controls[j] is TQRDBText then
TQRDBText(FDetail.Controls[j]).Enabled:=False;
if FDetail.Controls[j] is TQRLabel then
TQRLabel(FDetail.Controls[j]).Caption:='';
end;
for j:=1 to FPageMaxLines*ParentReport.PageNumber-HasPrintedLines do
// FPageMaxLines 页最大打印行数,外部传进来的变量
//ParentReport.PageNumber 总共打印的页数,因为只对最后一页进行控制,
//所以当前的打印页数已经确定,可以直接取
begin
Application.ProcessMessages;
//begin
1
if ParentReport.QRPrinter.Cancelled then
Exit;
PrintGroupHeaders;
PrintBeforeControllers;
if assigned(FDetail) then
FDetail.MakeSpace;
NotifyClients(qrMasterDataAdvance);
ParentReport.PrintBand(FDetail);
PrintAfterControllers;
//end 1
//从begin
1到这里的函数是直接COPY自2.0版本上的打印(此处应该有更加好的解决方法,
//偶只是懒了一下, ) 其实这段用在2.0中也是没有问题DI
end;
//Add end
end
end else
begin
MoreData := false;
if assigned(FOnNeedDataEvent) and not (csDesigning in ComponentState) then
OnNeedData(SelfCheck, MoreData);
end;
if CheckGroups then
begin
if DSOK then
DataSet.Prior;
PrintGroupFooters;
if DSOK then
DataSet.Next;
end;
if ParentReport is TQuickRep and
DSOK and (TQuickRep(ParentReport).DataSet = DataSet) and (RecCount <> 0) then
ParentReport.QRPrinter.Progress := (Longint(DetailNumber) * 100) div RecCount;
end;
以下quickrpt版本都为3.6
关于自动折行
需求:将超过长度的文本自动折行
解决方法:根据DELPHI的判断函数来控制超过长度文本的取舍,其实它本身有判断并截取中文字符的功能,
但是只取了第一行,所以就没有折行的效果。
源码:文件 QRCtrls;函数 FormatLines;子函数AddWord
procedure AddWord(aWord : string);
{$ifdef ver100}
var
S: string;
{$endif}
begin
while aLineWidth(NewLine + aWord) > Widthdo
//字符长度超过指定长度
begin
if NewLine = '' then
begin
{$ifdef ver100} //版本控制 似乎只分了{$ifdef VER36} 和这个。
if SysLocale.FarEast then
begin
while truedo
begin
if (aWord[1] in LeadBytes) and (Length(aWord) > 1) then
S := copy(aWord, 1, 2)
else
S := copy(aWord, 1, 1);
if aLineWidth(NewLine + S) < Width then
begin
NewLine := NewLine + S;
Delete(aWord, 1, Length(S));
end
else
Break;
end;
end
else
while aLineWidth(NewLine + copy(aWord, 1, 1)) < Widthdo
begin
NewLine := NewLine + copy(aWord, 1, 1);
Delete(aWord, 1, 1);
end;
{$else
}
while aLineWidth(NewLine + copy(aWord, 1, 1)) <= Widthdo
begin
if ByteType(aWord, Length(aWord)) = mbTrailByte then
//如果是是双字节字符,则截两位
//如果截的是双字节字符而长度恰好又超过了指定长度,
//系统默认将指定长度扩展一位。如果不愿意,当然这里也可以自己再加入控制
begin
NewLine:=NewLine +copy(aWord,1,2);
Delete(aWord, 1, 2);
end else
begin
NewLine := NewLine + copy(aWord, 1, 1);
Delete(aWord, 1, 1);
end;
end;
{$endif}
//taogou aWord := '';
//该句的赋值就将导致不能换行
end;
FlushLine;
//将截取的指定长度的字符加入到字符串列表中
{ if aLineWidth(aWord) > Width then
begin
if NewLine = '' then
begin
if Width = 0 then
aWord := ''
else
while aLineWidth(aWord) > Widthdo
{$ifdef ver100}
{ if ByteType(aWord, Length(aWord)) = mbTrailByte then
Delete(aWord, Length(aWord)-1, 2)
else
}
//{$endif}
{ begin
Delete(aWord, Length(aWord), 1);
end;
end;
NewLine := aWord;
FlushLine;
aWord := '';
end;
}
if not WordWrap then
begin
aWord := '';
LineFinished := true;
end;
end;
NewLine := NewLine + aWord;
end;
关于自动折行所引起的页行数可变控制
需求:文本折行后,是已设格式的行高自动变化,行数不容易控制,预览效果不堪入目。
解决方法:不允许已设行高自动变化,根据detail行高取舍文本的行数。例:不折行的情况下打印5行的固定
格式,会因为折行而打不了5行,程序自动将行高增大,在套打的情况下,情况非常糟糕。所以强制固定行高,
如果折行超过了固定高度,则超出部分不打印。
源码:文件 QRCtrls;主函数 PrintToCanvas;子函数CanPrint
找到下面着一行
TQRCustomBand(Parent).ExpandBand(LineHeight, AFExpanded, HasExpanded);
该行是根据你的CAPTION的行数来增加行数的,所以屏蔽掉
在主函数中找到下面这一行
ControlBottom := aTop + aHeight +1;
修改为
ControlBottom := aTop + TQRCustomBand(Parent).size.Length +1;
TQRCustomBand(Parent).size.Length 是当前DETAIL的行高
然后找到下面这个循环
while (FCurrentLine <= FFormattedLines.Count - 1) and CanPrintdo
if (FCurrentLine <= FFormattedLines.Count - 1) and CanPrint then
begin
PrintLine(FCurrentLine);
inc(FCurrentLine);
end;
修改为
while (FCurrentLine <= FFormattedLines.Count - 1) and CanPrintdo
//taogou
if (FCurrentLine <= FFormattedLines.Count - 1) and CanPrint then
begin
if Y + LineHeight < ControlBottom then
//taogou Y为当前开始打印的位置,lineHeight为字符行高
PrintLine(FCurrentLine); //controlbottom为detail的下限位置,仅当位置小于允许的位置才打印
inc(FCurrentLine);
end;
FCurrentLine:=FFormattedLines.Count;
//不管打了几行,都将当前行表示为该caption已经打印完毕
需求:控制多余行数,例:页打印行数为5行,当前打印记录数为12,带格式不套打,
则在最后页只有2行数据,从第3行到页脚为一片空白。这里需要将最后一页上3行打印上无数据的空格式.
解决方法:循环N次detail行的打印方法,并屏蔽掉记录
源码:文件 QuickRpt;主函数 TQRController.Execute
HasPrintedLines:=0;
//新增本函数局部变量 记录已经打印的行数
while MoreDatado
begin
inc(HasPrintedLines);
//增1
Application.ProcessMessages;
if ParentReport.QRPrinter.Cancelled then
Exit;
if ParentReport.PreparingDesignTime and (ParentReport.FPageCount > 1) then
Exit;
inc(FDetailNumber);
PrintGroupHeaders;
PrintBeforeControllers;
ParentReport.PrintBand(FDetail);
PrintAfterControllers;
if DSOK then
begin
DataSet.Next;
MoreData := not FDataSet.Eof;
if (FDataSet.Eof) then
//Add begin
begin
if FDetail<>nil then
//将detail中的TQRDBText and TQRLabel 全部不打
for j:=0 to FDetail.ControlCount-1do
begin
if FDetail.Controls[j] is TQRDBText then
TQRDBText(FDetail.Controls[j]).Enabled:=False;
if FDetail.Controls[j] is TQRLabel then
TQRLabel(FDetail.Controls[j]).Caption:='';
end;
for j:=1 to FPageMaxLines*ParentReport.PageNumber-HasPrintedLines do
// FPageMaxLines 页最大打印行数,外部传进来的变量
//ParentReport.PageNumber 总共打印的页数,因为只对最后一页进行控制,
//所以当前的打印页数已经确定,可以直接取
begin
Application.ProcessMessages;
//begin
1
if ParentReport.QRPrinter.Cancelled then
Exit;
PrintGroupHeaders;
PrintBeforeControllers;
if assigned(FDetail) then
FDetail.MakeSpace;
NotifyClients(qrMasterDataAdvance);
ParentReport.PrintBand(FDetail);
PrintAfterControllers;
//end 1
//从begin
1到这里的函数是直接COPY自2.0版本上的打印(此处应该有更加好的解决方法,
//偶只是懒了一下, ) 其实这段用在2.0中也是没有问题DI
end;
//Add end
end
end else
begin
MoreData := false;
if assigned(FOnNeedDataEvent) and not (csDesigning in ComponentState) then
OnNeedData(SelfCheck, MoreData);
end;
if CheckGroups then
begin
if DSOK then
DataSet.Prior;
PrintGroupFooters;
if DSOK then
DataSet.Next;
end;
if ParentReport is TQuickRep and
DSOK and (TQuickRep(ParentReport).DataSet = DataSet) and (RecCount <> 0) then
ParentReport.QRPrinter.Progress := (Longint(DetailNumber) * 100) div RecCount;
end;