Jump to content
Denis Dresse

TRichEdit in Delphi 11.1 ("Courier New" font broken with formatting characters))

Recommended Posts

Hello,

We just installed the Delphi 11.1.

But there is a problem with the TRichEdit.

When we add a line including formatting characters as "alt 205" or "alt179" or "alt196", with the "Courier New" font, then the police changes to an other police (Segoe UI Symbol) and the result is ugly.

We uses the following instruction for adding this line : myRichEdit.SelText := myString.

This way of reporting was used for years without problem in many places of our application.

Is it a documented bug, are there any turnarounds ?

Any help would be appreciated,

Denis Dresse

 

image.thumb.png.f0ab2cb35ea0b4b732eeeff44b2fc602.png

 

Share this post


Link to post

Can you show the actual code that is populating the TRichEdit and the formatting of its lines?

Share this post


Link to post
1 hour ago, Denis Dresse said:

Hello,

We just installed the Delphi 11.1.

But there is a problem with the TRichEdit.

When we add a line including formatting characters as "alt 205" or "alt179" or "alt196", with the "Courier New" font, then the police changes to an other police (Segoe UI Symbol) and the result is ugly.

We uses the following instruction for adding this line : myRichEdit.SelText := myString.

This way of reporting was used for years without problem in many places of our application.

Is it a documented bug, are there any turnarounds ?

 

Are you setting up SelAttributes correctly before assigning text to SelText? D11.1 uses a newer version of the rich edit common control (4.x), which has more capabilities than the old 2.x version used by prior Delphi versions.

  • Like 1

Share this post


Link to post

Hello,

 

Here is a little sample program.

- When the line "DDD════DDD" is added, the letters DDD remain well in Courier New, but the ════ text (characters alt 205) is in "Segoe UI Symbol".

- And the same for the line "───────────"  (characters alt 196).

So the alignment is not uniform.

 

Denis

image.png

Unit1.pas

Unit1.dfm

Share this post


Link to post

Yikes. Mixing UTF8 (from direct source code) and Unicode is asking for trouble.

And Alt+205... what is that? You need to work with exact correct encoding.

Doing Alt+205 might insert a complete other character in the code editor.

When I open your Unit1.pas, I get a square with a line through it for your "alt 205" character.

 

Try this:

add('DDD' + Widechar(#$2550) + Widechar(#$2550) + Widechar(#$2550) + Widechar(#$2550) + Widechar(#$2550) + 'DDD');

 

Share this post


Link to post

Hello,

Thanks for your answer.

We added the line as you suggested, but the result is the same.

 

image.thumb.png.b719f144678c451b9b03a0ff4740685d.png

 

In the "selText", the special characters seem not to be available in "Courier New", so it switches to the other font.

It was not the case in Delphi 10.4.2

Share this post


Link to post
On 8/26/2022 at 8:40 PM, PeterBelow said:

Are you setting up SelAttributes correctly before assigning text to SelText? D11.1 uses a newer version of the rich edit common control (4.x), which has more capabilities than the old 2.x version used by prior Delphi versions.

Hello,

Have you a link to the specs/docs of this new version of rich edit common control (4.x) ?

Share this post


Link to post

Have you tried this in BBInitClick

RE.DefAttributes.name := 'Courier New';
RE.DefAttributes.size := 8;

And alternatively this in add()

RE.SelAttributes.name := 'Courier New';
RE.SelAttributes.size := 8;
RE.SelText := myText;

 

Sometimes SelAttributes are not hold after you have set SelText.


 

Share this post


Link to post
21 hours ago, Denis Dresse said:

Hello,

Have you a link to the specs/docs of this new version of rich edit common control (4.x) ?

https://docwiki.embarcadero.com/Libraries/Alexandria/en/Vcl.ComCtrls.TRichEdit

https://docwiki.embarcadero.com/RADStudio/Alexandria/en/What's_New#TRichEdit_Component_updated_to_RichEdit_4.1_.28MSFTEDIT.dll.29

 

There are new events, e.g. OnLinkClick and extensions to the TTextAttribute type used by SelAttributes.

Share this post


Link to post
19 hours ago, rvk said:

Have you tried this in BBInitClick


RE.DefAttributes.name := 'Courier New';
RE.DefAttributes.size := 8;

And alternatively this in add()


RE.SelAttributes.name := 'Courier New';
RE.SelAttributes.size := 8;
RE.SelText := myText;

 

Sometimes SelAttributes are not hold after you have set SelText.


 

We had exactly the same lines in our program :

image.png.3b6da860abb6c72c89b2c1182672c4fe.png

 

And the proposition with "DefAttributes" do not work either.

Share this post


Link to post
4 hours ago, PeterBelow said:

Thanks for this links,

but it do not adress the TRichEdit.SelText problematic, which transforms the "Courier New" font, when some special characters are given to SelText (ex : ═  alt 205 et ─ alt 196...)

Denis

Edited by Denis Dresse

Share this post


Link to post
27 minutes ago, Denis Dresse said:

Thanks for this links,

but it do not adresses the TRichEdit.SelText problematic, which transform the "Courier New" font, when some special characters are given to SelText (ex : ═  alt 205 et ─ alt 196...)

Denis

I quick google search returned this one: https://devblogs.microsoft.com/math-in-office/richedit-font-binding/

I have to warn you that this is a bug in MS Richedit implementation. I've entered into Microsoft Word using Courier New 11 ──────────────────────────────. No problem there, then copied to the clipboard and pasted to Wordpad.exe the result wordpad changed the font to Segoe UI Symbol 11.

Share this post


Link to post

That Microsoft link brought back some memories!  Murray Sargent, who wrote the article, is the author of the PMATE text editor, which I used as a programming editor over 30 years ago; some of its keyboard shortcuts I still configure in the editors I use today.  And he had many other careers before joining Microsoft and becoming a RichEdit guru.

Share this post


Link to post
40 minutes ago, Lajos Juhász said:

I have to warn you that this is a bug in MS Richedit implementation. I've entered into Microsoft Word using Courier New 11 ──────────────────────────────. No problem there, then copied to the clipboard and pasted to Wordpad.exe the result wordpad changed the font to Segoe UI Symbol 11.

Pff. It's one of the reasons I still ship a RICHED20.DLL with my program.

Although not advised (and even not allowed), the many versions of riched20.dll all have their own problems.

If it's not alignment issues (resetting back to left align-tab after a right alignment tab) then it's some font issue (and there are lots of other issues).

I was so fed up with it (I never knew which one was shipped with Windows and which one was loaded at the client) that I took one for which I knew what issues there were and could program against that.

 

Share this post


Link to post
2 hours ago, Denis Dresse said:

Thanks for this links,

but it do not adress the TRichEdit.SelText problematic, which transforms the "Courier New" font, when some special characters are given to SelText (ex : ═  alt 205 et ─ alt 196...)

Denis

Have you tried to use the correct UTF16 code points instead, e.g. #$2012 etc.? Check the proper codes to use in the Windows Charmap application.

Share this post


Link to post

Hello,

My colleague found a turnaround (without using the problematic SetText procedure)

 

0- As before, we add the lines with 'Courier New' and special characters. 

Result is ugly as shown before.

But for each line of the memo, we store the font color and the size (in a memory object ALineSpecial).

 

1- At the end of the addings I place : RE.font.Name := 'Courier New';

All the text is now well aligned, but we lost the colors and the size.

 

2- I parse all the lines, and when needed, set the color and the size of the concerned line :

   myLineIndex := ALineSpecial.getInt1(i);                                 // get the index of the line

   RE.SelStart  := Perform(EM_LINEINDEX, myLineIndex, 0);       // set start position of the selection
   RE.SelLength := length(Lines[myLineIndex]);                          // set lenght of the selection (the line)
   myColor := TColor(ALineSpecial.getO(i));                               // get the color to apply (it comes from the memory object)
   RE.SelAttributes.Color := myColor;                                        // apply the color to the selection

 

And the result is OK

 

image.thumb.png.096ab48453e39efe64526c181d76dfcf.png

 

Many thanks for your contributions,

Denis

  • Thanks 1

Share this post


Link to post
10 hours ago, Denis Dresse said:

2- I parse all the lines, and when needed, set the color and the size of the concerned line :

   myLineIndex := ALineSpecial.getInt1(i);                                 // get the index of the line

   RE.SelStart  := Perform(EM_LINEINDEX, myLineIndex, 0);       // set start position of the selection
   RE.SelLength := length(Lines[myLineIndex]);                          // set lenght of the selection (the line)
   myColor := TColor(ALineSpecial.getO(i));                               // get the color to apply (it comes from the memory object)
   RE.SelAttributes.Color := myColor;                                        // apply the color to the selection

Just a small nitpick - you can change this:

RE.SelStart  := Perform(EM_LINEINDEX, myLineIndex, 0);
RE.SelLength := length(Lines[myLineIndex]);

To this instead:

var myLineStart: Integer;
myLineStart := Perform(EM_LINEINDEX, myLineIndex, 0); 
RE.SelStart := myLineStart;
RE.SelLength := Perform(EM_LINELENGTH, myLineStart, 0);

That will avoid a memory allocation trying to retrieve the actual String of the line in question.  The RichEdit already knows how many characters are on the line without needing to access the actual characters.

 

An then to can be optimized further by using EM_EXSETSEL directly instead of the SelStart/Length properties:

var rng: CHARRANGE;
rng.cpMin := Perform(EM_LINEINDEX, myLineIndex, 0);
rng.cpMax := rng.cpMin + Perform(EM_LINELENGTH, rng.cpMin, 0);
Perform(EM_EXSETSEL, 0, LParam(@rng));

Further speed optimizations can be accomplished using EM_SETCHARFORMAT/2 and EM_SETEVENTMASK messages, see Faster Rich Edit Syntax Highlighting for details.

Share this post


Link to post
19 hours ago, Remy Lebeau said:

Just a small nitpick - you can change this:


RE.SelStart  := Perform(EM_LINEINDEX, myLineIndex, 0);
RE.SelLength := length(Lines[myLineIndex]);

To this instead:


var myLineStart: Integer;
myLineStart := Perform(EM_LINEINDEX, myLineIndex, 0); 
RE.SelStart := myLineStart;
RE.SelLength := Perform(EM_LINELENGTH, myLineStart, 0);

That will avoid a memory allocation trying to retrieve the actual String of the line in question.  The RichEdit already knows how many characters are on the line without needing to access the actual characters.

 

An then to can be optimized further by using EM_EXSETSEL directly instead of the SelStart/Length properties:


var rng: CHARRANGE;
rng.cpMin := Perform(EM_LINEINDEX, myLineIndex, 0);
rng.cpMax := rng.cpMin + Perform(EM_LINELENGTH, rng.cpMin, 0);
Perform(EM_EXSETSEL, 0, LParam(@rng));

Further speed optimizations can be accomplished using EM_SETCHARFORMAT/2 and EM_SETEVENTMASK messages, see Faster Rich Edit Syntax Highlighting for details.

Thanks for this new optimisations

Denis

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×