Table of Contents

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.

Rich editor formatting toolbar with font, style, alignment, colour, and list buttons Rich editor formatting toolbar with font, style, alignment, colour, and list buttons

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.

See also