WEB开发网
开发学院软件开发Delphi 关于中文折行及相关问题的解决方法 阅读

关于中文折行及相关问题的解决方法

 2006-02-04 13:38:18 来源:WEB开发网   
核心提示: 打印中一些问题的解决方法 (taogou)以下quickrpt版本都为3.6关于自动折行 需求:将超过长度的文本自动折行解决方法:根据DELPHI的判断函数来控制超过长度文本的取舍,其实它本身有判断并截取中文字符的功能,关于中文折行及相关问题的解决方法,但是只取了第一行,所以就没有折行的效果,1、不知道格式该怎么定
 

打印中一些问题的解决方法 (taogou)
以下quickrpt版本都为3.6


关于自动折行 
需求:将超过长度的文本自动折行
解决方法:根据DELPHI的判断函数来控制超过长度文本的取舍,其实它本身有判断并截取中文字符的功能,
但是只取了第一行,所以就没有折行的效果。
源码:文件 QRCtrls;函数 FormatLines;子函数AddWord

PRocedure AddWord(aWord : string);
{$ifdef ver100}
  var
   S: string;
{$endif}
  begin
   while aLineWidth(NewLine + aWord) > Width do  //字符长度超过指定长度
   begin
    if NewLine = '' then
    begin
{$ifdef ver100}  //版本控制 似乎只分了{$ifdef VER36} 和这个。
     if SysLocale.FarEast then
     begin
      while true do
      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)) < Width do
      begin
       NewLine := NewLine + copy(aWord, 1, 1);
       Delete(aWord, 1, 1);
      end;
{$else}
     while aLineWidth(NewLine + copy(aWord, 1, 1)) <= Width do
     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) > Width do
{$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 CanPrint do 
  if (FCurrentLine <= FFormattedLines.Count - 1) and CanPrint  then
  begin
   PrintLine(FCurrentLine);
   inc(FCurrentLine);
  end;
  修改为
  while (FCurrentLine <= FFormattedLines.Count - 1) and CanPrint do  //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 MoreData do
    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-1 do
       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;


注:第一次写这样的东东和大家共享,感觉有点力不从心。原因?太明显了,1、不知道格式该怎么定义
2、不知道怎么写注解  3、我的文笔又很懒  4、不知道MM是否在想我呢???:)

OK,本次东东就东到这里,同志们,好东西拿出来共享吧

Tags:关于 相关

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接