Table of Contents

Address Entry and Validation

TTMSFNCIPEdit provides segmented entry for network-style values. Use it when users need to enter IPv4, IPv6, or MAC addresses without manually typing separators in a plain edit control.

IPv4 Entry

Set IPAddressType before assigning values. IPv4Address is available only while the control is in IPv4 mode; using it in another mode raises an exception.

IPv4 editor

procedure TForm1.ConfigureIPEdit;
begin
  TMSFNCIPEdit1.IPAddressType := IPv4;
  TMSFNCIPEdit1.IPAddress := '192.168.0.10';
  TMSFNCIPEdit1.OnChange := TMSFNCIPEdit1Change;
end;

IPv6 and MAC Modes

Switching IPAddressType resets the fields to the default shape for the selected mode. Use IPAddress for formatted IPv6 or MAC strings, and use IPv6Address when you already have the four-part record value.

IPv6 editor

procedure TForm1.ConfigureAddressModes;
begin
  TMSFNCIPEdit1.IPAddressType := IPv6;
  TMSFNCIPEdit1.IPAddress := '0000:0000:0000:0000:0000:0000:0000:0001';

  TMSFNCIPEdit2.IPAddressType := MAC;
  TMSFNCIPEdit2.IPAddress := '00-11-22-33-44-55';
end;

Change Handling

Handle OnChange when the form needs to validate dependent fields, enable an apply command, or store the current address.

procedure TForm1.TMSFNCIPEdit1Change(Sender: TObject);
begin
  Caption := TMSFNCIPEdit1.IPAddress;
end;

Combining address mode, validation, and change handling

The following example drives IPAddressType from a mode selector, checks every segment on each change, and enables a Save command only for a complete address. TTMSFNCIPEdit deliberately exposes no validity flag: IPAddress is assembled from the segment editors on read, so what counts as "complete" is an application decision — and switching IPAddressType is the only built-in reset, which does nothing when the mode is unchanged.

procedure TForm1.cbModeChange(Sender: TObject);
const
  Modes: array[0..2] of TTMSFNCIPEditType = (IPv4, IPv6, MAC);
begin
  { Assigning a different IPAddressType rebuilds the segments and resets them to
    the default shape for that mode. Assigning the mode it already has does
    nothing, so clear explicitly when you want a blank editor in one mode. }
  TMSFNCIPEdit1.IPAddressType := Modes[cbMode.ItemIndex];
  btnSave.Enabled := False;
end;

procedure TForm1.TMSFNCIPEdit1Change(Sender: TObject);
begin
  { There is no IsValid property: IPAddress is assembled from the segment
    editors, so completeness is an application-level check. }
  btnSave.Enabled := AddressIsComplete(TMSFNCIPEdit1);
  lblAddress.Text := TMSFNCIPEdit1.IPAddress;
end;

function TForm1.AddressIsComplete(AEdit: TTMSFNCIPEdit): Boolean;
var
  Separator: Char;
  Segments: TArray<string>;
  Segment: string;
begin
  case AEdit.IPAddressType of
    IPv4: Separator := '.';
    IPv6: Separator := ':';
  else
    Separator := '-';
  end;

  Segments := AEdit.IPAddress.Split([Separator]);
  Result := Length(Segments) > 0;
  for Segment in Segments do
    if Trim(Segment) = '' then
      Result := False;
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  SaveAddress(TMSFNCIPEdit1.IPAddress);
  ResetAddress(TMSFNCIPEdit1);
end;

{ Switching IPAddressType is the only built-in reset, and it does nothing when
  the mode is unchanged - so blank the editor by assigning the zero address for
  the mode it is already in. }
procedure TForm1.ResetAddress(AEdit: TTMSFNCIPEdit);
begin
  case AEdit.IPAddressType of
    IPv4: AEdit.IPAddress := '0.0.0.0';
    IPv6: AEdit.IPAddress := '0000:0000:0000:0000:0000:0000:0000:0000';
    MAC:  AEdit.IPAddress := '00-00-00-00-00-00';
  end;
end;

Styling

Use IPAddressFont for the field text. Fill and Stroke control the surrounding surface, so align them with adjacent edit controls when the address editor appears inside forms or property panels.

Sizing across DPI scales

The high-DPI support added in 1.0.1.0 means the control handles the two things it can see for itself: the insets and separator gaps between segments are computed at paint time from the current scale, and IPAddressFont.Height is rescaled when the form's DPI changes. Two consequences for calling code.

First, choose the field font size once, in design (96 DPI) units. Deriving it from the display scale at runtime scales it twice — once by you and once by the control — and produces oversized text on a dense monitor.

Second, do not pin the editor's width. The segments are laid out by dividing the control's own width by the segment count, so a width that just fits eight IPv6 groups at 100% clips them at 200%. Align or anchor the editor so it grows with its container, and reserve TTMSFNCUtils.GetDPIScale / IsHighDPIScale (unit FMX.TMSFNCUtils) for decisions the control genuinely cannot make for you.

procedure TForm1.ConfigureIPEditForHighDPI;
begin
  { Set the font size once, in design (96 DPI) units. On a DPI change the
    control rescales IPAddressFont itself, so recomputing a size per monitor
    would scale it twice. }
  TMSFNCIPEdit1.IPAddressFont.Name  := 'Segoe UI';
  TTMSFNCUtils.SetFontSize(TMSFNCIPEdit1.IPAddressFont, 10);
  TMSFNCIPEdit1.IPAddressFont.Color := gcBlack;

  { The segments are laid out by dividing the control's own width, so a fixed
    pixel width that just fits eight IPv6 groups at 100% clips them at 200%.
    Let the editor grow with its container instead. }
  TMSFNCIPEdit1.Align := TAlignLayout.Top;
  TMSFNCIPEdit1.Margins.Left  := 8;
  TMSFNCIPEdit1.Margins.Right := 8;

  { Only branch on the display scale for decisions the control cannot make for
    you - here, giving the wider IPv6 layout more room on a dense display. }
  if TTMSFNCUtils.IsHighDPIScale(Self) and (TMSFNCIPEdit1.IPAddressType = IPv6) then
    TMSFNCIPEdit1.Height := Round(TMSFNCIPEdit1.Height * 1.25);
end;

See also