Search code examples
delphi-7rtfdelphi-xe8richtext

Trouble with displaying RTF-Text between Delphi XE8 and Delphi 7


I have trouble displaying RTF-Formatted text between two delphi-Versions.

The TDBRichEdit-Control and TRichEdit-Control seem to have trouble parsing the RTF-text supplied.

Sometimes it seems as if to get it to work in XE8 you simply have to connect a TDBRichEdit to the appropriate Field in the Dataset, but the same Method would mess up the Delphi 7 Version.

So we figured we handle this via Code. Basically we replaced the TDBRichEdits with normal TRichEdits and supply the RTF through a stream.

textstream:=TStringStream.Create(CDS.FieldByName('TEXT').AsString);  
try                                                                                   
  RichEditFAPLAN.Lines.Clear();                                            
  RichEditFAPLAN.Lines.LoadFromStream(textStream);                         
finally                                                                    
  textstream.Free();                                                       
end;

this worked fine until about 1h ago when I decided to move the code above into it's own globally available function.

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;

I tried different Variations of this code. With MemoryStream, Widestring, UTF8 Encoding, AnsiString and what not.

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;

All to no avail, the XE-RTF-Text always comes out looking either like this or as a simple '':

{\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 }

What's more, the original Code with the "textstream", that I commented back in, is also not working anymore.

What I'm looking for is a code-solution that can properly handle RTF-Text between different IDE-Versions.

EDIT:

Here is a sample Project-Code. The thing is, everything works fine in this project. I have no idea why the same code does no longer work in our software and I can not reproduce it.

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;
  • Just Create a new Form1
  • Add 2 TRichEdits, one is called RESource and the other REGoal
  • Add a TClientDataSet and call it CDS
  • Add A Button
  • Assign the OnClick-procedure to the button

I'll try creating the project in D7 and port it to XE8 next, maybe this will reproduce the effect.

EDIT 2: Creating the Project in Delphi 7 and then Opening it in XE8 produces the same result.

My guess is, that there is something happening when the Database-Value is assigned to a String-Variable (or passed directly into the stream) which would be why I'm unable to reproduce the error.

Also maybe the Database is at fault. it's a Firebird 3.0 Database with a VarChar-Field


Solution

  • This IS the working Version of the code. Apparently there was something wrong with the RTF-Code itself due to a bug in our Editor

    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;