Author: Jonas Bilinkevicius
I need to set the character format in a RichEdit control to subscript or
superscipt. When I produce an RTF file including this formatting, the Delphi
TRichEdit shows it correctly. But I cannot set the formatting by code. I tried to
send a EM_SETCHARFORMAT message to the TRichEdit with dwEffects set to
CFE_SUBSCRIPT but this doesn't have the desired effect.
Answer:
Solve 1:
You have to use a little API here since the TTextAttributes class used to implement
DefAttributes does not surface this ability (since it was designed to be compatible
to TFont). You should be able to set sub/ superscripts by sending an
EM_SETCHARFORMAT message to a TRichedit. Something like this:
1 var
2 format: TCharFormat; {defined in Unit RichEdit}
3
4 FillChar(format, sizeof(format), 0);
5 with format do
6 begin
7 cbSize := Sizeof(format);
8 dwMask := CFM_OFFSET;
9 yOffset := 60; {superscript by 60 twips, negative values give subscripts}
10 end;
11 richedit1.Perform(EM_SETCHARFORMAT, SCF_SELECTION, LongInt(@format));
The message affects the current selection. If there is none it will affect new text
inserted via seltext.
The problem with this is that the rich edit common control version 1 does not
properly adjust the line spacing in lines containing super- or subscripted text. So
if you don't reduce the font size as well, the text may be cut off at top or
bottom. This version of the control also has no way to manually adjust the
linespacing. There are wrappers for version 2 and 3 of the control around, e.g. the
TRxrichEdit component in RXLib. These versions handle sub/superscripted text
correctly but they require riched20.dll on the target system and it may not be
present on all of them.
Solve 2:
Pressing the Up arrow sets to SuperScript, the down arrow to SubScript and the Left
arrow back to normal.
12
13 procedure TForm1.RichEdit1KeyDown(Sender: TObject; var Key: Word; Shift:
14 TShiftState);
15 var
16 ref: TCharFormat;
17 begin
18 FillChar(ref, sizeof(ref), 0);
19 if ssAlt in Shift then
20 case Key of
21 VK_UP:
22 begin
23 with ref do
24 begin
25 cbSize := Sizeof(ref);
26 dwMask := CFM_OFFSET;
27 yOffset := 60;
28 end;
29 end;
30 VK_DOWN:
31 begin
32 with ref do
33 begin
34 cbSize := Sizeof(ref);
35 dwMask := CFM_OFFSET;
36 yOffset := -60;
37 end;
38 end;
39 VK_LEFT:
40 begin
41 with ref do
42 begin
43 cbSize := Sizeof(ref);
44 dwMask := CFM_OFFSET;
45 yOffset := 0;
46 end;
47 end;
48 end;
49 (Sender as TRichEdit).Perform(EM_SETCHARFORMAT, SCF_SELECTION, LongInt(@ref));
50 end;
Solve 3:
51 { ... }
52 type
53 TCharacterFormat = (CFM_Superscript, CFM_Subscript, CFM_Normal);
54
55 procedure RE_SetCharFormat(RichEdit: TRichEdit; CharacterFormat: TCharacterFormat);
56 var
57 {The CHARFORMAT structure contains information about character formatting
58 in a rich edit control}
59 Format: TCharFormat;
60 begin
61 FillChar(Format, SizeOf(Format), 0);
62 with Format do
63 begin
64 cbSize := SizeOf(Format);
65 dwMask := CFM_OFFSET;
66 {Character offset, in twips, from the baseline. If the value of this member
67 is positive, the character is a superscript; if it is negative, the
68 character is a subscript}
69 case CharacterFormat of
70 CFM_Superscript: yOffset := 60;
71 CFM_Subscript: yOffset := -60;
72 CFM_Normal: yOffset := 0;
73 end;
74 end;
75 {The EM_SETCHARFORMAT message sets character formatting in a rich edit control.
76 SCF_SELECTION: Applies the formatting to the current selection}
77 Richedit.Perform(EM_SETCHARFORMAT, SCF_SELECTION, Longint(@Format));
78 end;
79
80 //Examples:
81
82 {Apply Subscript to the current selection}
83
84 procedure TForm1.Button1Click(Sender: TObject);
85 begin
86 RE_SetCharFormat(RichEdit1, CFM_Superscript);
87 end;
88
89 {Apply subscript to the current selection}
90
91 procedure TForm1.Button2Click(Sender: TObject);
92 begin
93 RE_SetCharFormat(RichEdit1, CFM_Subscript);
94 end;
|