In-place Editing
TTMSFNCLabelEdit displays formatted label text and can switch into an embedded edit control. Use it for editable names, captions, tags, or settings where a separate dialog would interrupt the workflow.

Configure Editing
The control inherits formatted text rendering and adds an Edit control plus accept and cancel buttons. Set Editable to allow user edits, or set it to False for read-only label behavior.
procedure TForm1.ConfigureLabelEdit;
begin
TMSFNCLabelEdit1.Text := 'Project name';
TMSFNCLabelEdit1.Editable := True;
TMSFNCLabelEdit1.HorizontalTextAlign := gtaLeading;
end;
procedure TForm1.StartLabelEdit;
begin
TMSFNCLabelEdit1.EditMode := True;
end;
Commit and Cancel
When the user accepts the edit, OnAccept fires after the text has been committed. When the user cancels, the previous text is restored and OnCancel fires.
procedure TForm1.ConfigureLabelEditEvents;
begin
TMSFNCLabelEdit1.OnAccept := TMSFNCLabelEdit1Accept;
TMSFNCLabelEdit1.OnCancel := TMSFNCLabelEdit1Cancel;
end;
procedure TForm1.TMSFNCLabelEdit1Accept(Sender: TObject);
begin
Caption := TMSFNCLabelEdit1.Text;
end;
procedure TForm1.TMSFNCLabelEdit1Cancel(Sender: TObject);
begin
StatusLabel.Text := 'Edit canceled.';
end;
Edit Lifecycle
Use OnEditStart and OnEditEnd for UI state changes such as highlighting the edited row or enabling validation helpers. OnEditKeyDown is available when keyboard handling needs to intercept a key before the edit completes.
Button Styling
AcceptButton and CancelButton are image controls. Their strokes are exposed through AcceptButtonStroke and CancelButtonStroke, and they inherit the label edit BitmapContainer for shared bitmap usage.
procedure TForm1.ConfigureLabelEditButtons;
begin
TMSFNCLabelEdit1.BitmapContainer := TMSFNCBitmapContainer1;
TMSFNCLabelEdit1.AcceptButtonStroke.Color := gcGreen;
TMSFNCLabelEdit1.CancelButtonStroke.Color := gcRed;
end;
Combining in-place editing, commit/cancel, and lifecycle events
The example below opens the editor from a Rename command, highlights the row for the duration of the edit, validates the committed value, and styles the drawn accept and cancel glyphs.
Two behaviours shape the pattern. Clicking an editable label already enters edit
mode, so code that opens the editor assigns EditMode := True rather than
calling a start method. And every one of the four events is a plain
TNotifyEvent that fires after the fact: OnAccept runs once Text already
holds the new value and edit mode has closed, so a rejected value is undone by
writing the previous one back rather than by vetoing the commit. Capture that
previous value in OnEditStart.
procedure TForm1.FormCreate(Sender: TObject);
begin
TMSFNCLabelEdit1.Text := 'Project name';
TMSFNCLabelEdit1.Editable := True;
TMSFNCLabelEdit1.OnEditStart := DoEditStart;
TMSFNCLabelEdit1.OnEditEnd := DoEditEnd;
TMSFNCLabelEdit1.OnAccept := DoAccept;
TMSFNCLabelEdit1.OnCancel := DoCancel;
{ Style the drawn check and cross, and share the form's bitmap container so
custom glyphs can be resolved by name. }
TMSFNCLabelEdit1.BitmapContainer := TMSFNCBitmapContainer1;
TMSFNCLabelEdit1.AcceptButtonStroke.Color := gcGreen;
TMSFNCLabelEdit1.CancelButtonStroke.Color := gcRed;
end;
{ Clicking an editable label already enters edit mode; there is no StartEdit
method, so code that opens the editor (a Rename command, an F2 shortcut)
assigns EditMode instead. }
procedure TForm1.btnRenameClick(Sender: TObject);
begin
TMSFNCLabelEdit1.EditMode := True;
end;
procedure TForm1.DoEditStart(Sender: TObject);
begin
FPreviousName := TMSFNCLabelEdit1.Text; // keep our own copy to roll back to
HighlightRow(True);
end;
procedure TForm1.DoEditEnd(Sender: TObject);
begin
HighlightRow(False);
end;
{ OnAccept fires AFTER the edited value has been committed to Text and edit mode
has already closed, and it carries no cancel parameter - so a rejected value
is undone by writing the previous one back, not by vetoing the commit. }
procedure TForm1.DoAccept(Sender: TObject);
begin
if Trim(TMSFNCLabelEdit1.Text) = '' then
begin
TMSFNCLabelEdit1.Text := FPreviousName;
ShowMessage('Name cannot be blank.');
Exit;
end;
SaveProjectName(TMSFNCLabelEdit1.Text);
end;
{ OnCancel fires after the control has already restored the previous text. }
procedure TForm1.DoCancel(Sender: TObject);
begin
StatusLabel.Text := 'Rename cancelled';
end;
Note
OnEditKeyDown fires after the control has handled Return and Escape
itself, so it cannot suppress commit or cancel. Use it for additional
shortcuts, and do validation in OnAccept.
Glyph sizing across DPI scales
The high-DPI support added in 1.0.1.0 rescales the accept and cancel button widths along with the rest of the control when the form's DPI changes, so the button size and the stroke width are authored once in design (96 DPI) units and need no runtime arithmetic.
The glyphs themselves are the interesting part: by default they are drawn as
vector strokes from AcceptButtonStroke and CancelButtonStroke, not loaded
from bitmaps, so they are already sharp at any scale. Supplying a bitmap opts
that drawing out — the image renderer takes over — and the bitmap then needs
scaled variants of its own, added to the button's Bitmaps collection with one
entry per display scale.
procedure TForm1.ConfigureLabelEditForHighDPI;
begin
{ By default the accept and cancel glyphs are drawn as vector strokes, not
bitmaps, so they stay sharp at any display scale. Express the button size
and the stroke width in design (96 DPI) units once - the control rescales
both when the form's DPI changes. }
TMSFNCLabelEdit1.AcceptButton.Width := 25;
TMSFNCLabelEdit1.CancelButton.Width := 25;
TMSFNCLabelEdit1.AcceptButtonStroke.Width := 2;
TMSFNCLabelEdit1.CancelButtonStroke.Width := 2;
{ Replacing a glyph with a bitmap opts out of the vector drawing, so that
bitmap now needs scaled variants of its own. AcceptButton and CancelButton
are TTMSFNCImage instances whose Bitmaps property is a TTMSFNCScaledBitmaps
collection: one entry per display scale, picked at paint time.
Turn AutoSize off first: the buttons ship with AutoSize enabled, which
resizes them to the resolved bitmap's raw pixel size - so the 2.0 variant
would make the button twice as wide instead of twice as sharp. }
TMSFNCLabelEdit1.AcceptButton.AutoSize := False;
TMSFNCLabelEdit1.CancelButton.AutoSize := False;
TMSFNCLabelEdit1.AcceptButton.Bitmaps.Clear;
TMSFNCLabelEdit1.AcceptButton.Bitmaps.AddBitmapFromFile('accept.png', 1.0);
TMSFNCLabelEdit1.AcceptButton.Bitmaps.AddBitmapFromFile('accept@2x.png', 2.0);
TMSFNCLabelEdit1.CancelButton.Bitmaps.Clear;
TMSFNCLabelEdit1.CancelButton.Bitmaps.AddBitmapFromFile('cancel.png', 1.0);
TMSFNCLabelEdit1.CancelButton.Bitmaps.AddBitmapFromFile('cancel@2x.png', 2.0);
if TTMSFNCUtils.IsHighDPIScale(Self) then
StatusLabel.Text := Format('Glyphs resolved at %.2fx',
[TTMSFNCUtils.GetDPIScale(Self)]);
end;
Important
Both buttons ship with AutoSize enabled, which resizes them to the resolved
bitmap's raw pixel size. Leave it on and the 2.0 variant makes the button
twice as wide instead of twice as sharp — switch AutoSize off and keep an
explicit Width when you assign scaled bitmaps.