在 Delphi XE8 和 Delphi 7 之间显示 RTF 文本时出现问题
Trouble with displaying RTF-Text between Delphi XE8 and Delphi 7
我无法在两个 delphi 版本之间显示 RTF 格式的文本。
TDBRichEdit-Control 和 TRichEdit-Control 似乎无法解析提供的 RTF 文本。
有时似乎要让它在 XE8 中工作,您只需将 TDBRichEdit 连接到数据集中的适当字段,但相同的方法会弄乱 Delphi 7 版本。
所以我们认为我们可以通过代码来处理这个问题。
基本上我们用普通的 TRichEdits 替换了 TDBRichEdits 和
通过流提供 RTF。
textstream:=TStringStream.Create(CDS.FieldByName('TEXT').AsString);
try
RichEditFAPLAN.Lines.Clear();
RichEditFAPLAN.Lines.LoadFromStream(textStream);
finally
textstream.Free();
end;
直到大约 1 小时前,当我决定将上面的代码移到它自己的全局可用函数中时,它一直运行良好。
procedure StreamRichTextTo(ARichEdit:TCustomRichEdit; ADataSet:TDataSet; AFieldName:String);
var
ws:WideString;
Stream:TStringStream;
begin
ARichEdit.Lines.Clear();
if (ADataSet=nil) or (ADataSet.FindField(AFieldName)=nil) or (ADataSet.FieldByName(AFieldName).IsNull) then exit;
ws:=UTF8Decode(ADataSet.FieldByName(AFieldName).AsString);
Stream:=TStringStream.Create(ws);
try
Stream.Position:=0;
ARichEdit.Lines.LoadFromStream(Stream);
finally
Stream.Free();
end;
end;
我尝试了这段代码的不同变体。使用 MemoryStream、Widestring、UTF8 编码、AnsiString 等等。
procedure StreamRichTextTo(ARichEdit:TCustomRichEdit; ADataSet:TDataSet; AFieldName:String);
var
{$IFDEF VER150}
ws:WideString;
Stream:TStringStream;
{$ELSE}
s:AnsiString;
//Stream:TMemoryStream;
Stream:TStringStream;
{$ENDIF}
begin
ARichEdit.Lines.Clear();
if (ADataSet=nil) or (ADataSet.FindField(AFieldName)=nil) or (ADataSet.FieldByName(AFieldName).IsNull) then exit;
{$IFDEF VER150}
ws:=UTF8Decode(ADataSet.FieldByName(AFieldName).AsString);
Stream:=TStringStream.Create(ws);
{$ELSE}
{
s:=ADataSet.FieldByName(AFieldName).AsAnsiString;
Stream:=TMemoryStream.Create();
Stream.Clear();
Stream.Write(PAnsiChar(s)^,length(s));
}
s:=ADataSet.FieldByName(AFieldName).AsAnsiString;
Stream:=TStringStream.Create(s,TEncoding.UTF8);
//Stream.WriteString(s);
Stream.Position:=0;
{$ENDIF}
try
ARichEdit.Lines.LoadFromStream(Stream);
finally
Stream.Free();
end;
end;
一切都无济于事,XE-RTF-Text 总是看起来像这样或简单的 '':
{\rtf1\fbidis\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 arial;}{\f1\fswiss\fprq2\fcharset0 Arial;}{\f2\fnil arial;}}
\viewkind4\uc1\pard\ltrpar\lang1031\f0\fs20 Gie\'dftemp.: \tab 1350 - 1370 \'b0C
\par \ul\f1 Form fest verklammern und belasten
\par \ulnone\f0
\par \tab\tab\f2
\par }
此外,我在评论中回复的带有 "textstream" 的原始代码也不再有效。
我正在寻找的是一种代码解决方案,可以正确处理不同 IDE 版本之间的 RTF 文本。
编辑:
这是一个示例项目代码。
问题是,在这个项目中一切正常。
我不知道为什么相同的代码在我们的软件中不再有效,我无法复制它。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Data.DB,
Datasnap.DBClient;
type
TForm1 = class(TForm)
REGoal: TRichEdit;
Button1: TButton;
CDS: TClientDataSet;
RESource: TRichEdit;
procedure Button1Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure StreamRichTextTo(ARichEdit:TRichEdit; ADataSet:TDataSet; AFieldName:String);
var
Stream:TStringStream;
//{$IFDEF VER150}
ws:WideString;
//{$ELSE}
//{$ENDIF}
begin
ARichEdit.Lines.Clear();
if (ADataSet=nil) or (ADataSet.FindField(AFieldName)=nil) or (ADataSet.FieldByName(AFieldName).IsNull) then exit;
try
//{$IFDEF VER150}
ws:=UTF8Decode(ADataSet.FieldByName(AFieldName).AsString);
Stream:=TStringStream.Create(ws);
//{$ELSE}
// Stream:=TStringStream.Create(ADataSet.FieldByName(AFieldName).AsString);
//{$ENDIF}
ARichEdit.Lines.LoadFromStream(Stream);
finally
Stream.Free();
end;
end;
(* Copy this to RESource
{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 arial;}{\f1\fnil arial;}}
\viewkind4\uc1\pard\lang1031\f0\fs20 Erste Form ist eine Zulegekontrolle durchzuf\fchren.
\par
\par
\par \f1
\par }
*)
procedure TForm1.Button1Click(Sender: TObject);
var
Stream:TStringStream;
begin
if CDS.FindField('TEXT')=nil then
begin
CDS.FieldDefs.Add('TEXT',ftWideString,4096);
CDS.CreateDataSet();
end;
CDS.Edit();
CDS.FieldByName('TEXT').AsString:=RESource.text;
CDS.Post();
StreamRichTextTo(REGoal,CDS,'TEXT');
end;
- 只需创建一个新的 Form1
- 添加2个TRichEdits,一个叫RESource,一个叫REGoal
- 添加一个 TClientDataSet 并将其命名为 CDS
- 添加按钮
- 将 OnClick 过程分配给按钮
我会尝试在D7中创建项目,然后将其移植到XE8,也许这样可以重现效果。
编辑 2:
在 Delphi 7 中创建项目,然后在 XE8 中打开它产生相同的结果。
我的猜测是,当数据库值分配给字符串变量(或直接传递到流中)时发生了一些事情,这就是我无法重现错误的原因。
也可能数据库有问题。
这是一个带有 VarChar-Field
的 Firebird 3.0 数据库
这是代码的工作版本。
显然由于我们的编辑器
中的错误,RTF 代码本身存在问题
procedure StreamRichTextTo(ARichEdit:TRichEdit; ADataSet:TDataSet; AFieldName:String);
var
{$IFDEF VER150}
ws:WideString;
{$ELSE}
ws:String;
{$ENDIF}
Stream:TStringStream;
begin
ARichEdit.Lines.Clear();
if (ADataSet=nil) or (ADataSet.FindField(AFieldName)=nil) or (ADataSet.FieldByName(AFieldName).IsNull) then exit;
{$IFDEF VER150}
ws:=UTF8Decode(ADataSet.FieldByName(AFieldName).AsString);
{$ELSE}
ws:=ADataSet.FieldByName(AFieldName).AsString;
{$ENDIF}
Stream:=TStringStream.Create(ws);
try
ARichEdit.Lines.LoadFromStream(Stream);
finally
Stream.Free();
end;
end;
我无法在两个 delphi 版本之间显示 RTF 格式的文本。
TDBRichEdit-Control 和 TRichEdit-Control 似乎无法解析提供的 RTF 文本。
有时似乎要让它在 XE8 中工作,您只需将 TDBRichEdit 连接到数据集中的适当字段,但相同的方法会弄乱 Delphi 7 版本。
所以我们认为我们可以通过代码来处理这个问题。 基本上我们用普通的 TRichEdits 替换了 TDBRichEdits 和 通过流提供 RTF。
textstream:=TStringStream.Create(CDS.FieldByName('TEXT').AsString);
try
RichEditFAPLAN.Lines.Clear();
RichEditFAPLAN.Lines.LoadFromStream(textStream);
finally
textstream.Free();
end;
直到大约 1 小时前,当我决定将上面的代码移到它自己的全局可用函数中时,它一直运行良好。
procedure StreamRichTextTo(ARichEdit:TCustomRichEdit; ADataSet:TDataSet; AFieldName:String);
var
ws:WideString;
Stream:TStringStream;
begin
ARichEdit.Lines.Clear();
if (ADataSet=nil) or (ADataSet.FindField(AFieldName)=nil) or (ADataSet.FieldByName(AFieldName).IsNull) then exit;
ws:=UTF8Decode(ADataSet.FieldByName(AFieldName).AsString);
Stream:=TStringStream.Create(ws);
try
Stream.Position:=0;
ARichEdit.Lines.LoadFromStream(Stream);
finally
Stream.Free();
end;
end;
我尝试了这段代码的不同变体。使用 MemoryStream、Widestring、UTF8 编码、AnsiString 等等。
procedure StreamRichTextTo(ARichEdit:TCustomRichEdit; ADataSet:TDataSet; AFieldName:String);
var
{$IFDEF VER150}
ws:WideString;
Stream:TStringStream;
{$ELSE}
s:AnsiString;
//Stream:TMemoryStream;
Stream:TStringStream;
{$ENDIF}
begin
ARichEdit.Lines.Clear();
if (ADataSet=nil) or (ADataSet.FindField(AFieldName)=nil) or (ADataSet.FieldByName(AFieldName).IsNull) then exit;
{$IFDEF VER150}
ws:=UTF8Decode(ADataSet.FieldByName(AFieldName).AsString);
Stream:=TStringStream.Create(ws);
{$ELSE}
{
s:=ADataSet.FieldByName(AFieldName).AsAnsiString;
Stream:=TMemoryStream.Create();
Stream.Clear();
Stream.Write(PAnsiChar(s)^,length(s));
}
s:=ADataSet.FieldByName(AFieldName).AsAnsiString;
Stream:=TStringStream.Create(s,TEncoding.UTF8);
//Stream.WriteString(s);
Stream.Position:=0;
{$ENDIF}
try
ARichEdit.Lines.LoadFromStream(Stream);
finally
Stream.Free();
end;
end;
一切都无济于事,XE-RTF-Text 总是看起来像这样或简单的 '':
{\rtf1\fbidis\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 arial;}{\f1\fswiss\fprq2\fcharset0 Arial;}{\f2\fnil arial;}}
\viewkind4\uc1\pard\ltrpar\lang1031\f0\fs20 Gie\'dftemp.: \tab 1350 - 1370 \'b0C
\par \ul\f1 Form fest verklammern und belasten
\par \ulnone\f0
\par \tab\tab\f2
\par }
此外,我在评论中回复的带有 "textstream" 的原始代码也不再有效。
我正在寻找的是一种代码解决方案,可以正确处理不同 IDE 版本之间的 RTF 文本。
编辑:
这是一个示例项目代码。 问题是,在这个项目中一切正常。 我不知道为什么相同的代码在我们的软件中不再有效,我无法复制它。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Data.DB,
Datasnap.DBClient;
type
TForm1 = class(TForm)
REGoal: TRichEdit;
Button1: TButton;
CDS: TClientDataSet;
RESource: TRichEdit;
procedure Button1Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure StreamRichTextTo(ARichEdit:TRichEdit; ADataSet:TDataSet; AFieldName:String);
var
Stream:TStringStream;
//{$IFDEF VER150}
ws:WideString;
//{$ELSE}
//{$ENDIF}
begin
ARichEdit.Lines.Clear();
if (ADataSet=nil) or (ADataSet.FindField(AFieldName)=nil) or (ADataSet.FieldByName(AFieldName).IsNull) then exit;
try
//{$IFDEF VER150}
ws:=UTF8Decode(ADataSet.FieldByName(AFieldName).AsString);
Stream:=TStringStream.Create(ws);
//{$ELSE}
// Stream:=TStringStream.Create(ADataSet.FieldByName(AFieldName).AsString);
//{$ENDIF}
ARichEdit.Lines.LoadFromStream(Stream);
finally
Stream.Free();
end;
end;
(* Copy this to RESource
{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 arial;}{\f1\fnil arial;}}
\viewkind4\uc1\pard\lang1031\f0\fs20 Erste Form ist eine Zulegekontrolle durchzuf\fchren.
\par
\par
\par \f1
\par }
*)
procedure TForm1.Button1Click(Sender: TObject);
var
Stream:TStringStream;
begin
if CDS.FindField('TEXT')=nil then
begin
CDS.FieldDefs.Add('TEXT',ftWideString,4096);
CDS.CreateDataSet();
end;
CDS.Edit();
CDS.FieldByName('TEXT').AsString:=RESource.text;
CDS.Post();
StreamRichTextTo(REGoal,CDS,'TEXT');
end;
- 只需创建一个新的 Form1
- 添加2个TRichEdits,一个叫RESource,一个叫REGoal
- 添加一个 TClientDataSet 并将其命名为 CDS
- 添加按钮
- 将 OnClick 过程分配给按钮
我会尝试在D7中创建项目,然后将其移植到XE8,也许这样可以重现效果。
编辑 2: 在 Delphi 7 中创建项目,然后在 XE8 中打开它产生相同的结果。
我的猜测是,当数据库值分配给字符串变量(或直接传递到流中)时发生了一些事情,这就是我无法重现错误的原因。
也可能数据库有问题。 这是一个带有 VarChar-Field
的 Firebird 3.0 数据库这是代码的工作版本。 显然由于我们的编辑器
中的错误,RTF 代码本身存在问题procedure StreamRichTextTo(ARichEdit:TRichEdit; ADataSet:TDataSet; AFieldName:String);
var
{$IFDEF VER150}
ws:WideString;
{$ELSE}
ws:String;
{$ENDIF}
Stream:TStringStream;
begin
ARichEdit.Lines.Clear();
if (ADataSet=nil) or (ADataSet.FindField(AFieldName)=nil) or (ADataSet.FieldByName(AFieldName).IsNull) then exit;
{$IFDEF VER150}
ws:=UTF8Decode(ADataSet.FieldByName(AFieldName).AsString);
{$ELSE}
ws:=ADataSet.FieldByName(AFieldName).AsString;
{$ENDIF}
Stream:=TStringStream.Create(ws);
try
ARichEdit.Lines.LoadFromStream(Stream);
finally
Stream.Free();
end;
end;