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

  • 来源: 互联网 作者: rocket   2008-03-20/14:04
  • 打印中一些问题的解决方法 (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是否在想我呢???:)


    评论 {{userinfo.comments}}

    {{money}}

    {{question.question}}

    A {{question.A}}
    B {{question.B}}
    C {{question.C}}
    D {{question.D}}
    提交

    驱动号 更多