Lazarus中文社区

 找回密码
 立即注册(注册审核可向QQ群索取)

QQ登录

只需一步,快速开始

Lazarus IDE and 组件 下载地址版权申明
查看: 5171|回复: 13

lazrepot报表memo中的中文换行乱码?

[复制链接]

该用户从未签到

发表于 2015-4-28 21:42:22 | 显示全部楼层 |阅读模式
报表上放一个memo,然后里面放一段中文,结果换行后所有行首的第一个中文都成了?

请教这个有无办法解决?
没有的话,有啥子报表是linux下能用的?
回复

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-4-28 22:47:18 | 显示全部楼层
参考下fastreport的乱码

主要改fr_class.pas中的wrapline过程,其中有一段:
else if s[last] = then
OutLine(Copy(s, beg, last - beg)) else
OutLine(Copy(s, beg, last - beg + 1));//造成乱码的根本原因
改为
else if s[last] = then
OutLine(Copy(s, beg, last - beg)) else
if ByteType(s,last) = mbLeadByte then //判断是否是汉字字节
OutLine(Copy(s, beg, last - beg ))
else
OutLine(Copy(s, beg, last - beg + 1));
后面的
LoopPos := cur;
beg := last + 1; last := beg;
要改为:
LoopPos := cur;
if ByteType(s,last) = mbLeadByte then
begin
beg := last ; last := beg;
end
else
begin
beg := last + 1; last := beg;
end;
参照http://tian.yeah.net的 fastreport2.41c
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-4-28 22:48:00 | 显示全部楼层
lr_class.pas 3608行应该是问题关键。
今晚太困了,明天再搞
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-4-29 11:27:51 | 显示全部楼层
  1. procedure WrapLine(const s: String);
  2. var
  3.     i, cur, beg, last, LoopPos: Integer;
  4.     WasBreak, CRLF: Boolean;
  5.   begin
  6.     CRLF := False;
  7.     LoopPos := 0;
  8.     for i := 1 to Length(s) do
  9.       if s[i] in [#10, #13] then
  10.       begin
  11.         CRLF := True;
  12.         break;
  13.       end;
  14.     last := 1; beg := 1;
  15.     if not CRLF and ((Length(s) <= 1) or (WCanvas.TextWidth(s) <= maxwidth)) then
  16.       OutLine(s + #1)
  17.     else
  18.     begin
  19.       cur := 1;
  20.       while cur <= Length(s) do
  21.       begin
  22.         if s[cur] in [#10, #13] then
  23.         begin
  24.           OutLine(Copy(s, beg, cur - beg) + #1);
  25.           while (cur < Length(s)) and (s[cur] in [#10, #13]) do Inc(cur);
  26.           beg := cur; last := beg;
  27.           if s[cur] in [#13, #10] then
  28.             Exit else
  29.             continue;
  30.         end;
  31.         if s[cur] <> ' ' then
  32.         if WCanvas.TextWidth(Copy(s, beg, cur - beg + 1)) > maxwidth then
  33.         begin
  34.           WasBreak := False;
  35.           if (Flags and flWordBreak) <> 0 then
  36.           begin
  37.             i := cur;
  38.             while (i <= Length(s)) and not (s[i] in spaces) do
  39.               Inc(i);
  40.             b := BreakWord(Copy(s, last + 1, i - last - 1));
  41.             if Length(b) > 0 then
  42.             begin
  43.               i := 1;
  44.               cur := last;
  45.               while (i <= Length(b)) and (WCanvas.TextWidth(Copy(s, beg, last - beg + 1 + Ord(b[i])) ) <= maxwidth) do
  46.               begin
  47.                 WasBreak := True;
  48.                 cur := last + Ord(b[i]);
  49.                 Inc(i);
  50.               end;
  51.               last := cur;
  52.             end;
  53.           end
  54.           else
  55.             if last = beg then last := cur;
  56.           if WasBreak then
  57.            begin
  58.              if ByteType(s,last) =  mbLeadByte then     //Tian 2001.03
  59.              begin
  60.                OutLine(Copy(s, beg, last - beg ));
  61.              end
  62.              else If ByteType(s,last) =  mbSingleByte then
  63.                     begin
  64.                       OutLine(Copy(s, beg, last - beg + 1));
  65.                     end
  66.                    else If ByteType(s,last) =mbTrailByte then
  67.                           begin
  68.                             OutLine(Copy(s, beg, last - beg +1));
  69.                           end;
  70.            end
  71.           else if s[last] = ' ' then
  72.             OutLine(Copy(s, beg, last - beg))
  73.             else
  74.               OutLine(Copy(s, beg, last - beg + 1));
  75.           if ((Flags and flWordBreak) <> 0) and not WasBreak and (last = cur) then
  76.             if LoopPos = cur then
  77.             begin
  78.               beg := cur + 1;
  79.               cur := Length(s);
  80.               break;
  81.             end
  82.             else
  83.               LoopPos := cur;
  84.           if ByteType(s,last) =  mbLeadByte then  //Tian 2001.03
  85.             begin
  86.              beg := last ; last := beg;
  87.             end
  88.           else If ByteType(s,last) =  mbSingleByte then
  89.             begin
  90.               beg := last + 1; last := beg;
  91.             end
  92.           else If ByteType(s,last) =mbTrailByte then
  93.             begin
  94.               beg := last+1 ; last := beg;
  95.             end;
  96.         end;
  97.         if s[cur] = ' ' then last := cur;
  98.         Inc(cur);
  99.       end;
  100.       if beg <> cur then OutLine(Copy(s, beg, cur - beg + 1) + #1);
  101.     end;
  102.   end;
复制代码
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-4-29 11:29:04 | 显示全部楼层
将以上的代码替换掉lr_class.pas 里的同名函数,记得在lr_class.pas行首
const段添加 spaces: set of Char = [' ', '.', ',', '-'];
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-4-29 11:30:05 | 显示全部楼层
现在看还是有点问题的,每行为偶数汉字时候没有什么问题,奇数时最后一个字不会显示或者只显示一半
回复 支持 反对

使用道具 举报

  • TA的每日心情
    开心
    2017-3-1 22:40
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2015-4-29 15:45:47 | 显示全部楼层
    用1.2.6没有这个问题
    回复 支持 反对

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2015-4-29 15:56:14 | 显示全部楼层
    clxer 发表于 2015-4-29 15:45
    用1.2.6没有这个问题

    是的,上午有人在群里提醒我了,然后下午装了1.2.6,发现正常,1.2.6下的代码如下:
    1. procedure TfrMemoView.WrapMemo;
    2. var
    3.   size, size1, maxwidth: Integer;
    4.   b: TWordBreaks;
    5.   WCanvas: TCanvas;
    6.   desc, aword: string;

    7.   procedure OutLine(const str: String);
    8.   var
    9.     n, w: Word;
    10.   begin
    11.     n := Length(str);
    12.     if (n > 0) and (str[n] = #1) then
    13.       w := WCanvas.TextWidth(Copy(str, 1, n - 1)) else
    14.       w := WCanvas.TextWidth(str);
    15.     {$IFDEF DebugLR_detail}
    16.     debugLn('Outline: str="%s" w/=%d w%%=%d',[copy(str,1,12),w div 256, w mod 256]);
    17.     {$ENDIF}
    18.     SMemo.Add(str + Chr(w div 256) + Chr(w mod 256));
    19.     Inc(size, size1);
    20.   end;

    21.   procedure WrapLine(const s: String);
    22.   var
    23.     i, cur, beg, last, len: Integer;
    24.     WasBreak, CRLF, IsCR: Boolean;
    25.     ch: TUTF8char;
    26.   begin

    27.     CRLF := False;
    28.     for i := 1 to Length(s) do
    29.     begin
    30.       if s[i] in [#10, #13] then
    31.       begin
    32.         CRLF := True;
    33.         break;
    34.       end;
    35.     end;

    36.     last := 1; beg := 1;
    37.     if not CRLF and ((Length(s) <= 1) or (WCanvas.TextWidth(s) <= maxwidth)) then
    38.     begin
    39.       OutLine(s + #1)
    40.     end else
    41.     begin

    42.       cur := 1;
    43.       Len := UTF8Desc(S, Desc);

    44.       while cur <= Len do
    45.       begin
    46.         Ch := UTF8Char(s, cur, Desc);

    47.         // check for items with soft-breaks
    48.         IsCR := Ch=#13;
    49.         if IsCR then
    50.         begin
    51.           //handle composite newline
    52.           ch := UTF8Char(s, cur+1, desc);
    53.           //dont increase char index if next char is LF (#10)
    54.           if ch<>#10 then
    55.             Inc(Cur);
    56.         end;
    57.         if Ch=#10 then
    58.         begin
    59.           OutLine(UTF8Range(s, beg, cur - beg, Desc) + #1);
    60.           //increase the char index since it's pointing to CR (#13)
    61.           if IsCR then
    62.             Inc(cur);
    63.           Inc(cur);
    64.           beg := cur;
    65.           last := beg;
    66.           Continue;
    67.         end;

    68.         if ch <> ' ' then
    69.         if WCanvas.TextWidth(UTF8Range(s, beg, cur - beg + 1, Desc)) > maxwidth then
    70.         begin

    71.           WasBreak := False;
    72.           if (Flags and flWordBreak) <> 0 then
    73.           begin

    74.             // in case of breaking in the middle, get the full word
    75.             i := cur;
    76.             while (i <= Len) and not UTF8CharIn(ch, [' ', '.', ',', '-']) do
    77.             begin
    78.               Inc(i);
    79.               if i<=len then
    80.                 ch := UTF8Char(s, i, Desc);
    81.             end;

    82.             // find word's break points using some simple hyphenator algorithm
    83.             // TODO: implement interface so users can use their own hyphenator
    84.             //       algorithm
    85.             aWord := UTF8Range(s, last, i - last, Desc);
    86.             if (FHyp<>nil) and (FHyp.Loaded) then
    87.             begin
    88.               try
    89.                 b := FHyp.BreakWord(UTF8Lowercase(aWord));
    90.               except
    91.                 b := '';
    92.               end;
    93.             end else
    94.               b := BreakWord(aWord);

    95.             // if word can be broken in many segments, find the last segment that
    96.             // fits within maxwidth
    97.             if Length(b) > 0 then
    98.             begin
    99.               i := 1;
    100.               while (i <= Length(b)) and
    101.                 (WCanvas.TextWidth(UTF8Range(s, beg, last - beg + Ord(b[i]), Desc) + '-') <= maxwidth) do
    102.               begin
    103.                 WasBreak := True;
    104.                 cur := last + Ord(b[i]);  // cur now points to next char after breaking word
    105.                 Inc(i);
    106.               end;
    107.             end;

    108.             if (not WasBreak) and (FHyp<>nil) and FHyp.Loaded then
    109.               // if hyphenator was specified and is valid don't break
    110.               // words which hyphenator didn't break
    111.             else
    112.               // last now points to nex char to be processed
    113.               last := cur;
    114.           end
    115.           else
    116.           begin
    117.             if last = beg then
    118.               last := cur;
    119.           end;

    120.           if WasBreak then
    121.           begin
    122.             // if word has been broken, output the partial word plus an hyphen
    123.             OutLine(UTF8Range(s, beg, last - beg, Desc) + '-');
    124.           end else
    125.           begin
    126.             // output the portion of word that fits maxwidth
    127.             OutLine(UTF8Range(s, beg, last - beg, Desc));
    128.             // if space was found, advance to next no space char
    129.             while (UTF8Char(s, last, Desc) = ' ') and (last < Length(s)) do
    130.               Inc(last);
    131.           end;

    132.           beg := last;
    133.         end;

    134.         if UTF8CharIn(Ch, [' ', '.', ',', '-']) then
    135.           last := cur;
    136.         Inc(cur);
    137.       end;

    138.       if beg <> cur then
    139.         OutLine(UTF8Range(s, beg, cur - beg + 1, Desc) + #1);
    140.     end;
    141.   end;
    复制代码
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2018-10-15 08:29:06 | 显示全部楼层

    RE: lazrepot报表memo中的中文换行乱码?

    {2018.10.15  Lazarus1.8.4}
    {LR_Class}
    {3784 procedure WrapLine(const s: String); var 加入定义}
        utf8Charlen:integer;
    {3838 if ch <> ' ' then   行后插入}
        begin
              if ord(ch)>=192 then {如果是多字节 UTF8,则第一字节大于192,UTF8CharacterLengthFast根据第一字节,返回UTF8字符字节数}
                 utf8Charlen:= UTF8CharacterLengthFast(@ch)
                 else
                 utf8Charlen:=1;
    {UTF8多字节字符,第一字节高位开始1的个数为字符占用字节数,>=192为多字节}
    {函数UTF8CharacterLength要检测整个UTF8字符所占字节,ch为char,这里使用返回字节数总为1,}
    {3839 if WCanvas.TextWidth(copy(s, beg, cur - beg + utf8Charlen{1})) > maxwidth then 改为 }
        if WCanvas.TextWidth(copy(s, beg, cur - beg + utf8Charlen{1})) > maxwidth then
    {bug出现在cur-beg+1这里。}
    {如果是cur遇到3字节汉字刚好要换行时,当cur指向前2字节不可显示,WCanvas.TextWideth=0,}
    {cur指向第3字节时,显示宽度不够,换行,第二行则从cur指向的第三字节打头,丢失了前2字节,字符不完整,被显示成?号}
    {更改后的算法:遇到多字节UTF8字符第一字节时,copy将整个utf8字符截入 测试宽度}
    {3912 if Ch in [' ', '.', ',', '-'] then  行前插入   }
        end;
    {2018.10.15-------------------------------}
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2018-10-16 08:32:13 | 显示全部楼层

    RE: lazrepot报表memo中的中文换行乱码?

    cp8001 发表于 2018-10-15 08:29
    {2018.10.15  Lazarus1.8.4}
    {LR_Class}
    {3784 procedure WrapLine(const s: String); var 加入定义}

    {20181016  Lazarus1.8.2}
    //UTF8CharacterLengthFast非多字节字符首字节,返回值为1
    //只需将LR_Class 3839行改为如下:
    if WCanvas.TextWidth(copy(s, beg, cur - beg + UTF8CharacterLengthFast(ch))) > maxwidth then
    {20181016--------------}
    回复 支持 反对

    使用道具 举报

    *滑块验证:

    本版积分规则

    QQ|手机版|小黑屋|Lazarus中国|Lazarus中文社区 ( 鄂ICP备16006501号-1 )

    GMT+8, 2025-1-21 15:55 , Processed in 0.040504 second(s), 12 queries , Redis On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表