Skip to main content
Table of Contents

Editing and formatting

Text selection

Inline example 1PascalC++
// Select all
RichEditor1.SelectAll;

// Select a range (character offset, length)
RichEditor1.Select(10, 5);

// Deselect
RichEditor1.ClearSelection;
// Select all
RichEditor1->SelectAll;

// Select a range (character offset, length)
RichEditor1->Select(10, 5);

// Deselect
RichEditor1->ClearSelection;

Character formatting

Apply formatting to the current selection or the cursor position (affects new typing):

Method Description
SetSelectionBold(Boolean) Bold text
SetSelectionItalic(Boolean) Italic text
SetSelectionUnderline(Boolean) Underline
SetSelectionStrikeOut(Boolean) Strikethrough
SetSelectionSuperscript(Boolean) Superscript
SetSelectionSubscript(Boolean) Subscript
SetSelectionFontName(string) Font family
SetSelectionFontSize(Integer) Font size in points
SetSelectionColor(TTMSFNCGraphicsColor) Text color
Inline example 2PascalC++
// Make selected text bold and red
RichEditor1.SetSelectionBold(True);
RichEditor1.SetSelectionColor(gcRed);
// Make selected text bold and red
RichEditor1->SetSelectionBold(true);
RichEditor1->SetSelectionColor(gcRed);

Reading the same properties returns the formatting at the cursor or in the selection.

Paragraph formatting

Alignment is applied through SetSelectionAttribute with a TAlignment value (taLeftJustify, taCenter, taRightJustify). LineSpacing is an Integer property (default 0) that adds spacing between lines.

Inline example 3PascalC++
RichEditor1.SetSelectionAttribute(taCenter);
RichEditor1->SetSelectionAttribute(taCenter);

Lists

SetSelectionBullets applies a bullet or number style to the selected lines, and toggles it off when the caret is already in a list of the same type. Use RemoveSelectionBullets to clear it explicitly.

Inline example 4PascalC++
// Numbered list: btNumber; bulleted list: btCircle, btSquare, btArrow, btTick, btStar
RichEditor1.SetSelectionBullets(btNumber);
RichEditor1.SetSelectionBullets(btCircle);
RichEditor1.RemoveSelectionBullets;
// Numbered list: btNumber; bulleted list: btCircle, btSquare, btArrow, btTick, btStar
RichEditor1->SetSelectionBullets(btNumber);
RichEditor1->SetSelectionBullets(btCircle);
RichEditor1->RemoveSelectionBullets;

Indentation

Inline example 5PascalC++
RichEditor1.SetSelectionIndent(24);   // left indent of the selected paragraphs
RichEditor1.SetSelectionIndent(0);    // remove the indent
RichEditor1->SetSelectionIndent(24);   // left indent of the selected paragraphs
RichEditor1->SetSelectionIndent(0);    // remove the indent

Undo and redo

Inline example 6PascalC++
if RichEditor1.CanUndo then RichEditor1.Undo;
if RichEditor1.CanRedo then RichEditor1.Redo;
if (RichEditor1->CanUndo) RichEditor1->Undo;
if (RichEditor1->CanRedo) RichEditor1->Redo;

Inserting text

Inline example 7PascalC++
// Insert at cursor position
RichEditor1.InsertText('Hello, world!');
// Insert at cursor position
RichEditor1->InsertText("Hello, world!");

Reading content

Inline example 8PascalC++
// Plain text
var plain := RichEditor1.PlainText;

// HTML
var html := RichEditor1.HTML;
// Plain text
var plain = RichEditor1->PlainText;

// HTML
var html = RichEditor1->HTML;

Clipboard: cut, copy, and paste

The editor exchanges more than plain text with the clipboard: a copy carries the selection as an internal rich-text stream, as RTF, and as plain text at the same time, so a paste back into the editor keeps its formatting while a paste into a plain-text field still works. Reach for the clipboard events when the document must not accept everything a user might paste - stripping tabs out of spreadsheet text, or refusing a multi-megabyte screenshot.

Member Purpose
CopyToClipboard Copies the selection in every format the editor produces.
CutToClipboard Copies the selection, then deletes it. A selected image is copied as a picture.
PasteFromClipboard Pastes the clipboard content over the selection. Returns the plain text that was inserted.
ClipboardHasContent True when the clipboard holds a format the editor can paste - use it to enable a Paste command.
ClipboardFormats The TClipboardFormat set (cfRTE, cfRTF, cfText, cfHTML, cfBMP, cfFile) the editor is willing to accept.
CopyRTFToClipboard, CopyHTMLToClipboard Place only the RTF or only the HTML representation on the clipboard.
Event Signature
OnPasteText (Sender: TObject; var AText: string; var Allow: boolean)
OnPasteBitmap (Sender: TObject; ABitmap: TTMSFNCBitmap; var Allow: boolean)
OnPasteFormattedText (Sender: TObject; AStream: TStream)
Filtering and restricting clipboard operationsPascalC++
procedure TForm1.RichEditorPasteText(Sender: TObject; var AText: string;
  var Allow: boolean);
begin
  // AText is a var parameter, so rewriting it here changes what is inserted.
  AText := StringReplace(AText, #9, ' ', [rfReplaceAll]);
  Allow := Trim(AText) <> '';
end;

procedure TForm1.RichEditorPasteBitmap(Sender: TObject;
  ABitmap: TTMSFNCBitmap; var Allow: boolean);
begin
  // Keep an oversized screenshot out of the document rather than scaling it
  // after the fact.
  Allow := (ABitmap.Width <= 1600) and (ABitmap.Height <= 1600);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  TMSFNCRichEditor1.OnPasteText := RichEditorPasteText;
  TMSFNCRichEditor1.OnPasteBitmap := RichEditorPasteBitmap;

  // Accept rich text and plain text on paste, but never a bitmap.
  TMSFNCRichEditor1.ClipboardFormats := [cfRTF, cfText];
end;

procedure TForm1.PasteButtonClick(Sender: TObject);
var
  s: string;
begin
  // Use ClipboardHasContent to drive the enabled state of a Paste command;
  // it reports whether any pastable format is present at all.
  if not TMSFNCRichEditor1.ClipboardHasContent then
    Exit;

  // The result is the plain text that was inserted. It is empty when the
  // clipboard delivered rich text or a bitmap instead.
  s := TMSFNCRichEditor1.PasteFromClipboard;
  StatusLabel.Text := Format('Pasted %d characters of plain text', [Length(s)]);
end;

procedure TForm1.CopyButtonClick(Sender: TObject);
begin
  if TMSFNCRichEditor1.HasSelection then
    TMSFNCRichEditor1.CopyToClipboard
  else
    TMSFNCRichEditor1.SelectAll;
end;

procedure TForm1.CutButtonClick(Sender: TObject);
begin
  if TMSFNCRichEditor1.HasSelection then
    TMSFNCRichEditor1.CutToClipboard;
end;
void __fastcall TForm1::RichEditorPasteText(TObject *Sender, System::UnicodeString &AText,
  bool &Allow)
{
  // AText is a var parameter, so rewriting it here changes what is inserted.
  AText = StringReplace(AText, "\t", " ", TReplaceFlags() << rfReplaceAll);
  Allow = Trim(AText) != "";
}

void __fastcall TForm1::RichEditorPasteBitmap(TObject *Sender,
  TTMSFNCBitmap *ABitmap, bool &Allow)
{
  // Keep an oversized screenshot out of the document rather than scaling it
  // after the fact.
  Allow = (ABitmap->Width <= 1600) && (ABitmap->Height <= 1600);
}

void __fastcall TForm1::FormCreate(TObject *Sender)
{
  TMSFNCRichEditor1->OnPasteText = RichEditorPasteText;
  TMSFNCRichEditor1->OnPasteBitmap = RichEditorPasteBitmap;

  // Accept rich text and plain text on paste, but never a bitmap.
  TMSFNCRichEditor1->ClipboardFormats = TClipboardFormats() << TClipboardFormat::cfRTF << TClipboardFormat::cfText;
}

void __fastcall TForm1::PasteButtonClick(TObject *Sender)
{
  // Use ClipboardHasContent to drive the enabled state of a Paste command;
  // it reports whether any pastable format is present at all.
  if (!TMSFNCRichEditor1->ClipboardHasContent())
    return;

  // The result is the plain text that was inserted. It is empty when the
  // clipboard delivered rich text or a bitmap instead.
  System::UnicodeString s = TMSFNCRichEditor1->PasteFromClipboard();
  StatusLabel->Text = Format("Pasted %d characters of plain text", ARRAYOFCONST((s.Length())));
}

void __fastcall TForm1::CopyButtonClick(TObject *Sender)
{
  if (TMSFNCRichEditor1->HasSelection())
    TMSFNCRichEditor1->CopyToClipboard();
  else
    TMSFNCRichEditor1->SelectAll();
}

void __fastcall TForm1::CutButtonClick(TObject *Sender)
{
  if (TMSFNCRichEditor1->HasSelection())
    TMSFNCRichEditor1->CutToClipboard();
}

Paste order and pitfalls

PasteFromClipboard walks the available formats in a fixed order - rich-text stream, then RTF, then bitmap, then plain text - and inserts the first match in each group it is allowed to use. Four consequences are worth knowing:

  • Rich text wins over plain text. The plain-text branch is skipped once a rich-text or RTF paste succeeded, so OnPasteText does not fire for a formatted paste. A sanitiser that only lives in OnPasteText is bypassed by any clipboard that also carries RTF; remove cfRTF from ClipboardFormats if plain text must always be the route in.
  • A bitmap is not mutually exclusive. The bitmap branch is not skipped by a preceding rich-text paste, so a clipboard holding both RTF and an image can insert both in one call.
  • The return value only reflects the plain-text branch. It is an empty string after a formatted or bitmap paste, which is not an error.
  • On FMX targets ClipboardFormats gates pasting only. A copy always publishes plain text, RTF, and (except on Android) the internal rich-text stream regardless of the set, so narrowing ClipboardFormats does not reduce what other applications see when they paste from your document.

Combining programmatic editing, formatting, and content retrieval

Build a formatted report programmaticallyPascalC++
procedure TForm1.BuildReport;
var
  Html: string;
begin
  RichEditor1.Clear;

  // Centered bold heading
  RichEditor1.AddText('Project Report', 18, 'Arial', [TFontStyle.fsBold], taCenter);
  RichEditor1.AddLineBreak;

  // Left-aligned paragraph
  RichEditor1.AddText('This report summarizes the work completed in Q2.', 12, 'Arial', [], taLeftJustify);

  // Bulleted list: AddBullet starts a new line and adds the bullet marker
  RichEditor1.AddBullet(btCircle);
  RichEditor1.AddText('Feature A completed');
  RichEditor1.AddBullet(btCircle);
  RichEditor1.AddText('Feature B in progress');

  // Retrieve the result as HTML
  Html := RichEditor1.ContentAsHTML;
end;
void __fastcall TForm1::BuildReport()
{
  System::UnicodeString Html;
  RichEditor1->Clear();

  // Centered bold heading
  RichEditor1->AddText("Project Report", 18, "Arial", TFontStyles() << TFontStyle::fsBold, taCenter);
  RichEditor1->AddLineBreak();

  // Left-aligned paragraph
  RichEditor1->AddText("This report summarizes the work completed in Q2.", 12, "Arial", TFontStyles(), taLeftJustify);

  // Bulleted list: AddBullet starts a new line and adds the bullet marker
  RichEditor1->AddBullet(Fmx::Tmsfncricheditorbase::btCircle);
  RichEditor1->AddText("Feature A completed");
  RichEditor1->AddBullet(Fmx::Tmsfncricheditorbase::btCircle);
  RichEditor1->AddText("Feature B in progress");

  // Retrieve the result as HTML
  Html = RichEditor1->ContentAsHTML();
}
Rich editor document with a bold heading, a paragraph with coloured, bold and italic runs, a bulleted list, and a selected word Rich editor document with a bold heading, a paragraph with coloured, bold and italic runs, a bulleted list, and a selected word
  • TTMSFNCRichEditor — SetSelectionBold, SetSelectionItalic, SetSelectionUnderline, SetSelectionFontName, SetSelectionFontSize, SetSelectionColor, InsertText, SelectAll, Undo, Redo

See also

  • Images and links — embed images and insert hyperlinks
  • Toolbar — connect the toolbar for interactive formatting