Putting it together
A complete rich-editor surface usually combines the edit toolbar, format toolbar, and horizontal ruler around one TTMSFNCRichEditor. Bind every companion to the same editor, trim the visible command sets to match the application, wire events that update surrounding UI, and configure the ruler layout before the form is shown.
Build the surface
The following routine combines the three companion controls in the order most applications need: bind them, restrict commands, wire apply/save events, configure ruler margins and tabs, then apply a small appearance theme.
procedure TForm1.BuildEditorSurface;
begin
// 1. Bind all three companions to the same editor.
TMSFNCRichEditorEditToolBar1.RichEditor := TMSFNCRichEditor1;
TMSFNCRichEditorFormatToolBar1.RichEditor := TMSFNCRichEditor1;
TMSFNCRichEditorHorizontalRuler1.RichEditor := TMSFNCRichEditor1;
// 2. Restrict each toolbar to the commands this app exposes.
TMSFNCRichEditorEditToolBar1.Options :=
[etoOpenFile, etoSaveFile, etoCut, etoCopy, etoPaste, etoUndo, etoRedo];
TMSFNCRichEditorFormatToolBar1.Options :=
[ftoFontName, ftoFontSize, ftoBold, ftoItalic, ftoUnderline,
ftoAlignLeft, ftoAlignCenter, ftoAlignRight,
ftoTextColor, ftoBullets, ftoNumbering];
// 3. Reflect the applied font in the status bar and track saves.
TMSFNCRichEditorFormatToolBar1.OnApplyFontName := DoFontNameApplied;
TMSFNCRichEditorEditToolBar1.OnSaveFile := DoDocumentSaved;
// 4. Configure the ruler: margins, a set of tab stops, and auto-position.
TMSFNCRichEditorHorizontalRuler1.Layout.LeftMargin := 50;
TMSFNCRichEditorHorizontalRuler1.Layout.RightMargin := 46;
TMSFNCRichEditorHorizontalRuler1.Layout.AutoPosition := True;
TMSFNCRichEditorHorizontalRuler1.Layout.TabMove := tmStep;
TMSFNCRichEditorHorizontalRuler1.Tabs.BeginUpdate;
try
TMSFNCRichEditorHorizontalRuler1.Tabs.Clear;
TMSFNCRichEditorHorizontalRuler1.Tabs.AddTab(20);
TMSFNCRichEditorHorizontalRuler1.Tabs.AddTab(45);
finally
TMSFNCRichEditorHorizontalRuler1.Tabs.EndUpdate;
end;
// 5. Give the ruler a light, branded surface.
TMSFNCRichEditorHorizontalRuler1.Appearance.RulerFill.Kind := gfkSolid;
TMSFNCRichEditorHorizontalRuler1.Appearance.RulerFill.Color := gcWhite;
TMSFNCRichEditorHorizontalRuler1.Appearance.TabColor := gcSteelblue;
end;
procedure TForm1.DoFontNameApplied(Sender: TObject; AFontName: string);
begin
StatusBar1.Panels[0].Text := 'Font: ' + AFontName;
end;
procedure TForm1.DoDocumentSaved(Sender: TObject);
begin
StatusBar1.Panels[1].Text := 'Saved';
end;
When to split the setup
Keep one setup routine while the editor surface is simple. Split it when the four parts start running on different schedules, which is the real signal — not the length of the routine:
| Part | Runs |
|---|---|
| Binding the companions | Once, at form creation. |
| Toolbar command set | Whenever permissions or the application mode change. |
| Ruler layout and tab stops | Per document, after loading it. |
| Ruler appearance | Once, or whenever the application theme changes. |
Folding all four into one FormCreate forces the whole block to re-run to
change any one of them, and it hides the ordering constraint that matters most:
ruler layout must be applied after LoadFromFile, because an existing
document restores its own margins, indents and tab stops.
procedure TForm1.FormCreate(Sender: TObject);
begin
{ Runs once: the wiring never changes for the lifetime of the form. }
BindCompanions;
ApplyRulerTheme;
{ Runs when the signed-in user changes. }
ApplyCommandSet(CurrentUser.MayEditDocuments);
end;
procedure TForm1.OpenDocument(const AFileName: string);
begin
TMSFNCRichEditor1.LoadFromFile(AFileName);
{ Runs per document, AFTER loading - an existing document restores its own
margins, indents and tab stops, so applying defaults first would be undone
and applying them last would overwrite the document. }
ApplyRulerLayoutFor(AFileName);
end;
{ 1. Binding - fixed for the lifetime of the form. }
procedure TForm1.BindCompanions;
begin
TMSFNCRichEditorEditToolBar1.RichEditor := TMSFNCRichEditor1;
TMSFNCRichEditorFormatToolBar1.RichEditor := TMSFNCRichEditor1;
TMSFNCRichEditorHorizontalRuler1.RichEditor := TMSFNCRichEditor1;
end;
{ 2. Command set - depends on permissions, so it is its own routine and can be
re-run whenever those change. }
procedure TForm1.ApplyCommandSet(AMayEdit: Boolean);
begin
if AMayEdit then
begin
TMSFNCRichEditorEditToolBar1.Options := AllEditOptions;
TMSFNCRichEditorFormatToolBar1.Options := AllFormatOptions;
end
else
begin
TMSFNCRichEditorEditToolBar1.Options := [etoOpenFile, etoCopy];
TMSFNCRichEditorFormatToolBar1.Options := [];
end;
end;
{ 3. Ruler layout - document-specific, so it is re-applied per document. }
procedure TForm1.ApplyRulerLayoutFor(const AFileName: string);
begin
TMSFNCRichEditorHorizontalRuler1.Layout.AutoPosition := True;
TMSFNCRichEditorHorizontalRuler1.Layout.TabMove := tmStep;
TMSFNCRichEditorHorizontalRuler1.Layout.LeftMargin := 50;
TMSFNCRichEditorHorizontalRuler1.Layout.RightMargin := 46;
TMSFNCRichEditorHorizontalRuler1.Tabs.BeginUpdate;
try
TMSFNCRichEditorHorizontalRuler1.Tabs.Clear;
TMSFNCRichEditorHorizontalRuler1.Tabs.AddTab(20);
TMSFNCRichEditorHorizontalRuler1.Tabs.AddTab(45);
finally
TMSFNCRichEditorHorizontalRuler1.Tabs.EndUpdate;
end;
end;
{ 4. Appearance - comes from the application theme, not from this form, so it
is kept apart from everything above. }
procedure TForm1.ApplyRulerTheme;
begin
TMSFNCRichEditorHorizontalRuler1.Appearance.RulerFill.Kind := gfkSolid;
TMSFNCRichEditorHorizontalRuler1.Appearance.RulerFill.Color := AppTheme.SurfaceColor;
TMSFNCRichEditorHorizontalRuler1.Appearance.TabColor := AppTheme.AccentColor;
end;
Pitfalls
- Bind each companion explicitly. Sharing an editor instance does not cascade from one toolbar to another.
- Apply document-specific ruler values after loading the document. Defaults are useful for new documents, but existing documents should restore their own margins, indents, and tabs.
- Keep event handlers focused on surrounding UI. Toolbar commands already update the editor; handlers are best used for status bars, dirty flags, telemetry, and related application state.