Delphi: RichEdit Text Background Color

Something I needed in a project recently was to put some makeup into a richedit control. This is pretty easy with the SelAttributes field in the class. However, to my disappointment I found that the TTextAttributes class (SelAttributes) does not contain a field to set the background color of your text even though it is supported by the control. So I set out to find a solution to the problem on Google, but everything I could find required you to externally use the windows api to force this property onto the window.

I didn’t quite like this solution, so I came up with a cleaner one. I created a class helper for the TTextAttributes class. I first had a look at this class and noticed that the way the Color property is set and read does not require much work. Since I “can’t” access any of the class’ private methods I simply copied the few ones I needed to my class helper, being SetAttributes and GetAttributes. However, I couldn’t do the same with the 2 private fields in the class which I needed, so I made a small workaround for this. Note that this workaround will only work as long as VCL is changed. I created a small class with the same private fields. When casting the original object to this class, you can use it to access those private fields. If the name of the fields is changed in VCL, this small workaround has to be updated as well.

Here’s the header code:

01uses
02  ComCtrls, Graphics, RichEdit;
03 
04type
05  __TTextAttributes = class
06  private
07    RichEdit: TCustomRichEdit;
08    FType: TAttributeType;
09  end;
10 
11  TTextAttributesH = class helper for TTextAttributes
12  private
13    function GetBackColor: TColor;
14    procedure SetBackColor(const Value: TColor);
15    procedure GetAttributes(var Format: TCharFormat2);
16    procedure SetAttributes(var Format: TCharFormat2);
17  public
18    property BackColor: TColor read GetBackColor write SetBackColor;
19  end;

And the body:

01{ TTextAttributesH }
02 
03procedure TTextAttributesH.GetAttributes(var Format: TCharFormat2);
04var
05  RichEdit: TCustomRichEdit;
06begin
07  RichEdit := __TTextAttributes(Self).RichEdit;
08  InitFormat(Format);
09  if RichEdit.HandleAllocated then
10    SendGetStructMessage(RichEdit.Handle, EM_GETCHARFORMAT,
11      WPARAM(__TTextAttributes(Self).FType = atSelected), Format, True);
12end;
13 
14function TTextAttributesH.GetBackColor: TColor;
15var
16  Format: TCharFormat2;
17begin
18  GetAttributes(Format);
19  with Format do
20    if (dwEffects and CFE_AUTOBACKCOLOR) <> 0 then
21      Result := clWindow
22    else
23      Result := crBackColor;
24end;
25 
26procedure TTextAttributesH.SetAttributes(var Format: TCharFormat2);
27var
28  Flag: Longint;
29  RichEdit: TCustomRichEdit;
30begin
31  RichEdit := __TTextAttributes(Self).RichEdit;
32  if __TTextAttributes(Self).FType = atSelected then
33    Flag := SCF_SELECTION
34  else
35    Flag := 0;
36  if RichEdit.HandleAllocated then
37    SendStructMessage(RichEdit.Handle, EM_SETCHARFORMAT, Flag, Format);
38end;
39 
40procedure TTextAttributesH.SetBackColor(const Value: TColor);
41var
42  Format: TCharFormat2;
43begin
44  InitFormat(Format);
45  with Format do
46  begin
47    dwMask := CFM_BACKCOLOR;
48    if Value = clWindowText then
49      dwEffects := CFE_AUTOBACKCOLOR
50    else
51      crBackColor := ColorToRGB(Value);
52  end;
53  SetAttributes(Format);
54end;

Note that this only works in versions of Delphi that support class helpers. You can also use this method to add other missing properties.

Read More