Table of Contents

Spin Edit Guide

TTMSFNCSpinEdit is a numeric spin box: a value bounded by Min and Max that the user nudges up and down with plus and minus buttons, or types directly into when the field is editable. Reach for it whenever you need a constrained number — a quantity, a font size, a percentage, a count — and want the value kept in range without writing validation by hand. It supports horizontal and vertical button layouts, a configurable step per click, repeat-click for continuous change while a button is held, decimal precision for floating-point values, and full styling of the buttons and value field. This guide covers the value range and step, the editable field and keyboard, appearance and repeat-click, and wiring the value into live validation.

TTMSFNCSpinEdit

Basic value range and step

Set Min, Max, and Value to define the allowable range. Use Interaction.Frequency to control how much the value changes per button click.

// Basic numeric spin edit from 0 to 100 with step size 5
TMSFNCSpinEdit1.Min := 0;
TMSFNCSpinEdit1.Max := 100;
TMSFNCSpinEdit1.Value := 25;
TMSFNCSpinEdit1.Interaction.Frequency := 5;   // each click moves by 5

procedure TForm1.TMSFNCSpinEdit1ValueChanged(Sender: TObject; AValue: Single);
begin
  Label1.Caption := Format('Value: %.0f', [AValue]);
end;

OnValueChanged fires after each committed change, whether from a button click or from direct editing.

Orientation, repeat-click, and decimal precision

The Appearance property controls button shape and orientation. Interaction.RepeatClick and Interaction.RepeatInterval enable continuous change while the button is held. EditFieldPrecision sets the number of decimal places when the field is editable.

// Vertical layout with repeat-click enabled and an editable value field
TMSFNCSpinEdit1.Min := -50;
TMSFNCSpinEdit1.Max := 50;
TMSFNCSpinEdit1.Value := 0;

TMSFNCSpinEdit1.Appearance.Orientation := tboVertical;
TMSFNCSpinEdit1.Appearance.ButtonShape := bsRounded;

// Editable field lets the user type a value directly
TMSFNCSpinEdit1.Interaction.Editable := True;
TMSFNCSpinEdit1.Interaction.RepeatClick := True;   // hold button for continuous change
TMSFNCSpinEdit1.Interaction.RepeatInterval := 80;  // ms between repeats

// Two decimal places for floating-point editing
TMSFNCSpinEdit1.EditFieldPrecision := 2;

The editable field and keyboard

When Interaction.Editable is True, the user can type a value directly instead of only clicking the buttons. Typed input is still clamped to Min/Max on commit. EditFieldPrecision sets how many decimal places the field accepts and displays, and EditFieldPrecisionDisplay controls how trailing precision is shown. On mobile targets, EditFieldKeyboardType selects the on-screen keyboard (for example a numeric pad) so users are not shown a full alphabetic keyboard for a number.

For advanced scenarios the underlying editor is reachable through the exposed Edit property, letting you adjust editor-level behaviour the spin edit does not surface directly.

TMSFNCSpinEdit1.Interaction.Editable := True;
TMSFNCSpinEdit1.EditFieldPrecision   := 2;   // accept and display two decimals
// EditFieldKeyboardType (a TVirtualKeyboardType) selects the on-screen keyboard on mobile.

Combining with live validation

Wiring OnValueChanged to a validation handler keeps dependent UI (buttons, labels, warnings) in sync with the spin value without a separate polling mechanism. The example below combines a clamped range, repeat-click, and an editable field with a handler that disables an action when the value leaves an acceptable band.

// Combine spin edit with live range validation:
// clamped Min/Max and an OnValueChanged handler that updates a label
// and disables an action when the value leaves an acceptable range.

TMSFNCSpinEdit1.Min := 1;
TMSFNCSpinEdit1.Max := 999;
TMSFNCSpinEdit1.Value := 100;
TMSFNCSpinEdit1.Interaction.Frequency := 1;
TMSFNCSpinEdit1.Interaction.Editable  := True;
TMSFNCSpinEdit1.Interaction.RepeatClick := True;

procedure TForm1.TMSFNCSpinEdit1ValueChanged(Sender: TObject; AValue: Single);
begin
  LabelQty.Caption := IntToStr(Round(AValue)) + ' units';
  // Disable checkout when quantity exceeds available stock
  ActionCheckout.Enabled := AValue <= StockLevel;
end;

High-DPI button artwork

The spin edit rescales its own DPI-sensitive metrics when the display scale changes — Appearance.ButtonSize and Appearance.ValueFont — so those are authored once at design DPI and need no runtime arithmetic. Bitmaps are the exception. Appearance.MinButtonBitmap, MinButtonDownBitmap, PlusButtonBitmap, and PlusButtonDownBitmap are single TTMSFNCBitmap surfaces with a fixed pixel count, so a glyph authored for a 100% display turns soft at 150% or 200% — there is nothing for the control to scale up from. Read the control's ResourceScaleFactor (the display scale it resolves image resources against) and load the variant that matches.

uses
  System.SysUtils, FMX.TMSFNCUtils, FMX.TMSFNCTrackBar, FMX.TMSFNCSpinEdit;

procedure TForm1.LoadScaledSpinButtons;
var
  Suffix: string;
begin
  { ResourceScaleFactor is the display scale the control resolves image
    resources against: 1.0 at 96 DPI, 1.5 at 144 DPI, 2.0 at 192 DPI. }
  if TMSFNCSpinEdit1.ResourceScaleFactor >= 2 then
    Suffix := '@2x'
  else if TMSFNCSpinEdit1.ResourceScaleFactor >= 1.5 then
    Suffix := '@1.5x'
  else
    Suffix := '';

  TMSFNCSpinEdit1.BeginUpdate;
  try
    TMSFNCSpinEdit1.Appearance.PlusButtonBitmap.LoadFromFile('plus' + Suffix + '.png');
    TMSFNCSpinEdit1.Appearance.PlusButtonDownBitmap.LoadFromFile('plus-down' + Suffix + '.png');
    TMSFNCSpinEdit1.Appearance.MinButtonBitmap.LoadFromFile('minus' + Suffix + '.png');
    TMSFNCSpinEdit1.Appearance.MinButtonDownBitmap.LoadFromFile('minus-down' + Suffix + '.png');

    { ButtonSize and ValueFont stay in design units - the spin edit rescales
      them itself when the display scale changes, and the artwork above
      supplies the extra pixels. }
    TMSFNCSpinEdit1.Appearance.ButtonSize := 20;
    TMSFNCSpinEdit1.Appearance.ValueFont.Size := 11;
  finally
    TMSFNCSpinEdit1.EndUpdate;
  end;

  if TTMSFNCUtils.IsHighDPIScale(Self) then
    StatusLabel.Text := Format('Spin buttons loaded at %.2fx',
      [TTMSFNCUtils.GetDPIScale(Self)]);
end;

Keep ButtonSize at the design value while doing this: it frames the glyph, and the scaled artwork supplies the pixels. Appearance.ButtonSpacing is not part of the control's own DPI pass, so leave it at its small design value rather than computing it from the scale.

Common pitfalls

  • Step lives on Interaction, not the control. The per-click increment is Interaction.Frequency; there is no Step property on the spin edit itself.
  • Decimal input needs EditFieldPrecision. With the default precision the field rounds to whole numbers; set EditFieldPrecision before expecting decimal entry.
  • Editing requires Interaction.Editable. If typing into the field does nothing, the field is display-only — enable Interaction.Editable.
  • Value is a Single. The OnValueChanged handler receives AValue: Single; round or format it for integer-only displays.

See also