Connecting toolbars to an editor
The format toolbar, edit toolbar, and horizontal ruler are companion controls: on their own they do nothing, but once bound to a TTMSFNCRichEditor they render the matching command buttons or ruler markers and keep themselves in sync with the editor. Every companion inherits a single RichEditor property from the shared base class TTMSFNCRichEditorToolBar, so the binding is identical for all three. Reach for this pattern whenever you want a Word-style editing surface: dock the toolbars along the top, place the ruler beneath them, and let the editor fill the rest of the form.
Binding the companions
Set each control's RichEditor property to the same editor instance. Because the property is shared through the base class, one editor can drive any combination of the three companions, and multiple toolbars can target the same editor at once.
procedure TForm1.FormCreate(Sender: TObject);
begin
// All three companions bind to the same editor through the RichEditor
// property they inherit from TTMSFNCRichEditorToolBar.
TMSFNCRichEditorEditToolBar1.RichEditor := TMSFNCRichEditor1;
TMSFNCRichEditorFormatToolBar1.RichEditor := TMSFNCRichEditor1;
TMSFNCRichEditorHorizontalRuler1.RichEditor := TMSFNCRichEditor1;
// Dock the edit and format toolbars along the top, the ruler just below
// them, and let the editor fill the rest of the form.
TMSFNCRichEditorEditToolBar1.Align := TAlignLayout.Top;
TMSFNCRichEditorFormatToolBar1.Align := TAlignLayout.Top;
TMSFNCRichEditorHorizontalRuler1.Align := TAlignLayout.Top;
TMSFNCRichEditor1.Align := TAlignLayout.Client;
end;
Docking with Align (or a TTMSFNCDockPanel) gives the classic layout: edit and format toolbars at the top, the ruler directly below them, and the editor filling the client area.
Automatic selection synchronisation
Once bound, a toolbar reflects the editor's current selection automatically — move the caret into bold text and the bold button shows as active, into a differently-sized run and the font-size picker updates. You do not wire anything for this; the companion listens to the editor and refreshes its own button and marker states. The ruler likewise mirrors the active paragraph's margins and indents.
Design-time auto-connect
When you drop a horizontal ruler on a form that already contains a
TTMSFNCRichEditor, the ruler assigns that editor to its RichEditor property
automatically at design time, so the ruler is live the moment it appears. This
is a convenience for the common one-editor form, and worth knowing the exact
rule for: the ruler walks its owner form's components and takes the first
TTMSFNCRichEditor it finds, then stops. It applies only to the ruler — the two
toolbars are never auto-connected — and only at design time; a ruler created in
code starts with RichEditor at nil.
Two situations therefore need an explicit assignment. On a form with more than
one editor the auto-pick may not be the editor the user starts in, and in a
tabbed or split editor the binding has to follow the active document. Assigning
RichEditor at run time overrides whatever the designer stored.
procedure TForm1.FormCreate(Sender: TObject);
begin
{ The ruler bound itself at design time to whichever TTMSFNCRichEditor it
found first on this form, which on a two-editor form may not be the one the
user starts in. Make the intended binding explicit at run time. }
BindCompanionsTo(TMSFNCRichEditor1);
end;
{ Assign RichEditor on each companion - the property is inherited from the
shared base class, but binding one companion does not bind the others. }
procedure TForm1.BindCompanionsTo(AEditor: TTMSFNCRichEditor);
begin
TMSFNCRichEditorEditToolBar1.RichEditor := AEditor;
TMSFNCRichEditorFormatToolBar1.RichEditor := AEditor;
TMSFNCRichEditorHorizontalRuler1.RichEditor := AEditor;
end;
{ In a tabbed or split editor, re-point the companions whenever the active
document changes; the toolbars and ruler then follow the new editor's
selection, margins and indents without any further wiring. }
procedure TForm1.TMSFNCTabSet1ChangeTab(Sender: TObject;
APreviousTabIndex: Integer; ACurrentTabIndex: Integer);
begin
case ACurrentTabIndex of
0: BindCompanionsTo(TMSFNCRichEditor1);
1: BindCompanionsTo(TMSFNCRichEditor2);
end;
end;
{ When an editor is created and freed at run time, clear the binding before
freeing it. The companions do detect the destruction through Delphi's
notification mechanism, but doing it explicitly keeps the intent visible. }
procedure TForm1.CloseDocument(AEditor: TTMSFNCRichEditor);
begin
if TMSFNCRichEditorHorizontalRuler1.RichEditor = AEditor then
BindCompanionsTo(nil);
AEditor.Free;
end;
Pitfalls
- Every companion needs its own
RichEditorassignment. Binding the format toolbar does not bind the edit toolbar or the ruler — setRichEditoron each control you drop. - Clear the binding before freeing an editor you own. If you create and free the editor at runtime independently of the toolbars, the companions detect the editor being destroyed through Delphi's notification mechanism, but reassigning
RichEditortonilfirst keeps intent explicit.