Table of Contents

Coloring segments and custom drawing

Each LED in the bar carries its own colors, so the strip can do more than show a single-color level: a green-amber-red layout turns the bar into a zoned meter that signals safe, warning, and danger ranges at a glance. When the per-segment colors are not enough — you want icons, labels, or fully bespoke shapes — the control exposes before- and after-draw hooks for each LED. This chapter covers both: per -segment coloring through the Leds items and custom rendering through the draw events.

Per-segment colors

Every entry in the Leds collection is a TTMSFNCWidgetLEDBarItem with three color properties and an explicit State:

Property Meaning
OnColor Color drawn when the LED is lit. Defaults to red.
OffColor Color drawn when the LED is unlit. Defaults to maroon.
BaseColor Convenience setter: assigning it sets OnColor to the base color and OffColor to a darker variant. Defaults to red.
State Whether this individual LED is lit. The control's Value sets this for you.

These are direct TTMSFNCGraphicsColor values — write Led.OnColor := gcLime, not Led.OnColor.Color := …. (The bar's own Fill and Stroke are graphics objects with a .Kind/.Color, but the per-LED item colors are plain color values.) Setting BaseColor is the quickest way to theme a zone, because it derives a matching dimmed off-color automatically.

Custom draw hooks

Two hooks let you take over rendering for individual LEDs:

  • OnBeforeDrawLed(Sender, AGraphics, ARect, AIndex, var ADefaultDraw) fires before each LED is painted. Set ADefaultDraw := False to suppress the built-in LED and draw your own; leave it True to keep the default and just overlay extra content.
  • OnAfterDrawLed(Sender, AGraphics, ARect, AIndex) fires after the default LED is drawn, for overlays such as a tick mark or a label on top of the segment.

AGraphics is the drawing surface, ARect is the bounds of that LED, and AIndex is its zero-based position in the bar.

Combining zones with a custom hook

The snippet below builds a green-amber-red meter through BaseColor, then wires an OnBeforeDrawLed handler that keeps the default LED rendering and frames every second segment — combining per-segment coloring with custom drawing on one bar.

procedure TForm1.StyleLEDBarZones;
var
  I: Integer;
  Led: TTMSFNCWidgetLEDBarItem;
begin
  FBar.Leds.BeginUpdate;
  try
    for I := 0 to FBar.Leds.Count - 1 do
    begin
      Led := FBar.Leds[I];
      // Item colors are direct TTMSFNCGraphicsColor values (not stroke objects).
      if I < 6 then
        Led.BaseColor := gcLime          // sets OnColor and a darker OffColor
      else if I < 8 then
        Led.BaseColor := gcGold
      else
        Led.BaseColor := gcRed;
    end;
  finally
    FBar.Leds.EndUpdate;
  end;

  // Combine zones with a custom draw hook for the lit/unlit split.
  FBar.OnBeforeDrawLed := DoBeforeDrawLed;
  FBar.Value := 7;
end;

procedure TForm1.DoBeforeDrawLed(Sender: TObject; AGraphics: TTMSFNCGraphics;
  ARect: TRectF; AIndex: Integer; var ADefaultDraw: Boolean);
begin
  // Keep the built-in LED rendering; only annotate every second segment.
  ADefaultDraw := True;
  if (AIndex mod 2 = 0) then
  begin
    AGraphics.Stroke.Kind := gskSolid;
    AGraphics.Stroke.Color := gcSilver;
    AGraphics.DrawRectangle(ARect);
  end;
end;

Pitfalls

  • Item colors are plain color values. Use Led.OnColor := gcRed; there is no .Color sub-property on the item colors. Only the bar-level Fill/Stroke graphics objects use .Kind/.Color.
  • BaseColor overwrites OnColor and OffColor. Assign BaseColor first, then override OnColor/OffColor individually if you need a custom off shade — not the other way around.
  • Value resets every State. Setting the control's Value recomputes the lit/unlit state of all LEDs. If you toggle Leds[i].State by hand, do it after the last Value assignment, or it will be overwritten.
  • In OnBeforeDrawLed, forgetting to keep ADefaultDraw := True leaves the LED blank when you only meant to overlay — set it explicitly.

See also