Table of Contents

Theming

TTMSFNCRibbon ships with 11 predefined themes that colour the entire ribbon — page control, toolbars, QAT, groups, caption, and system menu — in one line of code.


Predefined themes

Value Name
rbtLightBlue Default light blue
rbtBlue Deeper blue
rbtCrimson Red accent
rbtGreen Green accent
rbtSeaGreen Teal
rbtOrange Orange accent
rbtPurple Purple
rbtDarkGray Dark grey with accent
rbtBlack Near-black
rbtWhite Light with accent colour
rbtCustom Fully custom
TMSFNCRibbon1.Theme := rbtLightBlue;
rbtLightBlue theme
rbtOrange theme
rbtWhite theme
rbtDarkGray theme
rbtBlack theme

Custom accent colour

rbtWhite, rbtDarkGray, and rbtCustom use CustomThemeColor to tint the file button, groups, and other accent elements:

// Apply a predefined theme
TMSFNCRibbon1.Theme := rbtLightBlue;

// White theme with custom accent color for the file button and groups
TMSFNCRibbon1.Theme := rbtWhite;
TMSFNCRibbon1.CustomThemeColor := gcDarkred;

// Override theming on one group specifically
with TMSFNCRibbon1.Groups.Add do
begin
  Text := 'Group';
  StartPageIndex := 1;
  EndPageIndex := 2;
  UseDefaultAppearance := False;  // opt out of theme-driven fill
  Color := gcLimegreen;
  TextColor := gcWhite;
  BorderColor := gcGreen;
end;

// Implement ITMSFNCRibbonTheme on a custom control
// so it adapts automatically when Theme changes.
type
  TTMSFNCRibbonRectangle = class(TRectangle, ITMSFNCRibbonTheme)
  public
    procedure SetTheme(ATheme: TTMSFNCRibbonTheme;
      ACustomThemeColor: TTMSFNCGraphicsColor);
  end;

procedure TTMSFNCRibbonRectangle.SetTheme(ATheme: TTMSFNCRibbonTheme;
  ACustomThemeColor: TTMSFNCGraphicsColor);
begin
  Fill.Color := GetThemeTabHoverColor(ATheme, ACustomThemeColor);
  Stroke.Color := Fill.Color;
end;
rbtWhite theme with a dark red custom accent
Two groups — one theme-driven, one custom green

Overriding group colours

Set UseDefaultAppearance := False on a TTMSFNCRibbonGroup to override the theme-driven appearance for that group:

with TMSFNCRibbon1.Groups.Add do
begin
  StartPageIndex := 4;
  EndPageIndex := 6;
  UseDefaultAppearance := False;
  Color := gcLimegreen;
  TextColor := gcWhite;
  BorderColor := gcGreen;
end;

Theme events

Assigning Theme (or calling ApplyTheme) walks every child control of the ribbon and applies the theme colours to each one that supports ITMSFNCRibbonTheme. The two theme events let you step into that sweep: use them when a single command must keep a brand colour regardless of the active theme, or when the theme palette is a good starting point that still needs a small adjustment.

Event Signature Description
OnBeforeApplyTheme (Sender: TObject; AObject: TObject; var ABeforeApplyTheme: Boolean) Raised for each control before it is themed. AObject is the control; set ABeforeApplyTheme := False to leave it untouched.
OnAppliedTheme (Sender: TObject; AObject: TObject) Raised after AObject has been themed, so any colour assigned here overrides the theme value.
procedure TForm1.TMSFNCRibbon1BeforeApplyTheme(Sender: TObject;
  AObject: TObject; var ABeforeApplyTheme: Boolean);
begin
  // AObject is the control that is about to be themed. Setting
  // ABeforeApplyTheme to False leaves it exactly as it is, so a
  // brand-coloured command keeps its own appearance in every theme.
  if (AObject is TTMSFNCRibbonToolBarButton) and
     (TTMSFNCRibbonToolBarButton(AObject).Text = 'Publish') then
    ABeforeApplyTheme := False;
end;

procedure TForm1.TMSFNCRibbon1AppliedTheme(Sender: TObject; AObject: TObject);
var
  btn: TTMSFNCRibbonToolBarButton;
begin
  // Raised only for controls that were actually themed. The theme colours
  // are already assigned here, so adjustments made now survive.
  if AObject is TTMSFNCRibbonToolBarButton then
  begin
    btn := TTMSFNCRibbonToolBarButton(AObject);
    btn.Appearance.DownFill.Color := gcDarkslategray;
    btn.Appearance.DownStroke.Color := gcDarkslategray;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  TMSFNCRibbon1.OnBeforeApplyTheme := TMSFNCRibbon1BeforeApplyTheme;
  TMSFNCRibbon1.OnAppliedTheme := TMSFNCRibbon1AppliedTheme;

  // Assigning Theme walks every child control and raises both events.
  TMSFNCRibbon1.Theme := rbtDarkGray;
end;

Both events fire once per control, on every theme change. Keep the handlers short and free of side effects that trigger another ApplyTheme call, and prefer UseDefaultAppearance := False on a TTMSFNCRibbonGroup when only a group's colours need to differ — the events are for control-level exceptions.


Shared group label and frame styling

Groups are painted by the ribbon itself, not by the toolbars they span, so their look is controlled by one object rather than per toolbar: GroupAppearance holds the font, fill, separator stroke, accent stroke, and text layout used for every group. Reach for it when the group band should follow your own brand instead of the active theme, and use a per-group override only for the one or two groups that must stand out.

procedure TForm1.FormCreate(Sender: TObject);
var
  grp: TTMSFNCRibbonGroup;
begin
  TMSFNCRibbon1.BeginUpdate;
  try
    // GroupAppearance is the single object every group label and frame is
    // painted with, so one assignment restyles all of them.
    TMSFNCRibbon1.GroupAppearance.Font.Name := 'Segoe UI';
    TMSFNCRibbon1.GroupAppearance.Font.Size := 11;
    TMSFNCRibbon1.GroupAppearance.Font.Color := gcWhite;
    TMSFNCRibbon1.GroupAppearance.Fill.Kind := gfkSolid;
    TMSFNCRibbon1.GroupAppearance.Fill.Color := gcDarkslateblue;
    TMSFNCRibbon1.GroupAppearance.Stroke.Color := gcDarkslateblue;

    // BorderStroke is not the outline of the whole group: it paints the
    // narrow accent bar along the top edge, and only in the title-bar
    // toolbar area.
    TMSFNCRibbon1.GroupAppearance.BorderStroke.Color := gcOrange;

    TMSFNCRibbon1.GroupAppearance.TextAlign := gtaCenter;
    TMSFNCRibbon1.GroupAppearance.Trimming := gttWord;
    TMSFNCRibbon1.GroupAppearance.WordWrapping := False;

    grp := TMSFNCRibbon1.Groups.Add;
    grp.Text := 'Review';
    grp.StartPageIndex := 2;
    grp.EndPageIndex := 3;

    // A per-group override replaces the three colours and the text layout,
    // but never the font family or size - those always come from
    // GroupAppearance.Font, whose Color alone is swapped for TextColor.
    grp.UseDefaultAppearance := False;
    grp.Color := gcSeagreen;
    grp.TextColor := gcWhite;
    grp.BorderColor := gcDarkgreen;
    grp.TextAlign := gtaLeading;
  finally
    TMSFNCRibbon1.EndUpdate;
  end;
end;

Two details of the painting order are easy to trip over:

  • BorderStroke is not the outline of the group. It fills a narrow accent bar along the top edge of the group rectangle, and only in the title-bar toolbar area - the band drawn behind the tab pages has no accent bar.
  • UseDefaultAppearance := False on a TTMSFNCRibbonGroup swaps in that group's Color, TextColor, BorderColor, TextAlign, WordWrapping, and Trimming. It does not swap the font: the family and size always come from GroupAppearance.Font, and only the font colour is replaced by TextColor. To give one group a different type size, draw it yourself with the events below.

Custom drawing group backgrounds and labels

The four group draw events let you paint a group yourself when appearance properties are not enough - a gradient band, a status badge, an icon beside the label. Use them for decoration that the appearance object cannot express, and prefer GroupAppearance or a per-group override for anything that is only a colour change.

Event Signature Fires
OnBeforeDrawGroupBackground (Sender: TObject; AGraphics: TTMSFNCGraphics; AGroup: TTMSFNCRibbonGroup; ARect: TRectF; var ADefaultDraw: Boolean) Before the group rectangle is filled. Set ADefaultDraw := False to take the background over completely.
OnAfterDrawGroupBackground (Sender: TObject; AGraphics: TTMSFNCGraphics; AGroup: TTMSFNCRibbonGroup; ARect: TRectF) After the rectangle and accent bar have been painted.
OnBeforeDrawGroupText (Sender: TObject; AGraphics: TTMSFNCGraphics; AGroup: TTMSFNCRibbonGroup; ARect: TRectF; AText: String; var ADefaultDraw: Boolean) Before the group label is drawn. Set ADefaultDraw := False to render the label yourself.
OnAfterDrawGroupText (Sender: TObject; AGraphics: TTMSFNCGraphics; AGroup: TTMSFNCRibbonGroup; ARect: TRectF; AText: String) After the label has been drawn.
procedure TForm1.RibbonBeforeDrawGroupBackground(Sender: TObject;
  AGraphics: TTMSFNCGraphics; AGroup: TTMSFNCRibbonGroup; ARect: TRectF;
  var ADefaultDraw: Boolean);
begin
  if AGroup.Text <> 'Review' then
    Exit;

  AGraphics.Fill.Kind := gfkGradient;
  AGraphics.Fill.Color := gcDarkslateblue;
  AGraphics.Fill.ColorTo := gcMidnightblue;
  AGraphics.DrawRectangle(ARect);

  // False skips the built-in rectangle *and* the accent bar, and the matching
  // OnAfterDrawGroupBackground is not raised for this group either.
  ADefaultDraw := False;
end;

procedure TForm1.RibbonAfterDrawGroupText(Sender: TObject;
  AGraphics: TTMSFNCGraphics; AGroup: TTMSFNCRibbonGroup; ARect: TRectF;
  AText: String);
var
  r: TRectF;
begin
  // DataInteger is free per-group storage; here it carries a pending-item
  // count that is painted as a badge on top of the label the ribbon just drew.
  if AGroup.DataInteger <= 0 then
    Exit;

  r := RectF(ARect.Right - 18, ARect.Top, ARect.Right, ARect.Top + 14);
  AGraphics.Fill.Kind := gfkSolid;
  AGraphics.Fill.Color := gcRed;
  AGraphics.Stroke.Kind := gskNone;
  AGraphics.DrawRectangle(r);

  AGraphics.Font.Color := gcWhite;
  AGraphics.DrawText(r, IntToStr(AGroup.DataInteger), False,
    gtaCenter, gtaCenter, gttNone);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  TMSFNCRibbon1.OnBeforeDrawGroupBackground := RibbonBeforeDrawGroupBackground;
  TMSFNCRibbon1.OnAfterDrawGroupText := RibbonAfterDrawGroupText;
end;

Pitfalls

  • A group is painted twice per repaint: once in the title-bar toolbar area and once as a band behind the tab pages. The background events therefore fire twice per group per paint, with a different ARect each time. Keep the handlers cheap, and derive any position from ARect rather than caching it.
  • The two text events fire only for the title-bar pass, because the band behind the tab pages draws no label. A handler that expects one text event per background event will be out of step.
  • Setting ADefaultDraw := False in OnBeforeDrawGroupBackground also skips the accent bar and suppresses OnAfterDrawGroupBackground for that group, so do all of the drawing in the before-handler once you take it over.
  • AGraphics is the live canvas with Fill, Stroke, and Font already loaded from GroupAppearance. Any change you make to them persists into the next element the ribbon paints, so set every property your drawing depends on instead of assuming a default.

ITMSFNCRibbonTheme interface

Custom controls hosted inside the ribbon can participate in theming by implementing ITMSFNCRibbonTheme:

type
  TMyRibbonControl = class(TRectangle, ITMSFNCRibbonTheme)
  public
    procedure SetTheme(ATheme: TTMSFNCRibbonTheme;
      ACustomThemeColor: TTMSFNCGraphicsColor);
  end;

procedure TMyRibbonControl.SetTheme(ATheme: TTMSFNCRibbonTheme;
  ACustomThemeColor: TTMSFNCGraphicsColor);
begin
  // Use theme helper functions from FMX.TMSFNCRibbon
  Fill.Color := GetThemeTabHoverColor(ATheme, ACustomThemeColor);
  Stroke.Color := Fill.Color;
end;
Custom rectangle implementing ITMSFNCRibbonTheme

Available theme helper functions:

Function Returns
GetThemeColor Primary theme colour.
GetThemeHoverColor Hover state colour.
GetThemeDownColor Pressed state colour.
GetThemeActiveFontColor Active item font colour.
GetThemeFontColor Default font colour.
GetThemeTabColor Page tab background colour.
GetThemeTabHoverColor Page tab hover colour.
GetThemeTabDownColor Page tab pressed colour.
GetThemeTabFontColor Page tab text colour.

Combining predefined theme with custom accent and per-group override

Apply a named theme, set a custom accent colour, and override one contextual group to make it stand out from the rest:

procedure TForm1.FormCreate(Sender: TObject);
var
  grp: TTMSFNCRibbonGroup;
begin
  // Base theme: white with a dark-red accent on the file button and groups
  TMSFNCRibbon1.Theme := rbtWhite;
  TMSFNCRibbon1.CustomThemeColor := gcDarkRed;

  // After-theme event for fine-tuning the file button
  TMSFNCRibbon1.OnAppliedTheme := DoAfterTheme;

  // One contextual group styled independently from the theme
  grp := TMSFNCRibbon1.Groups.Add;
  grp.StartPageIndex := 2;
  grp.EndPageIndex   := 3;
  grp.Text := 'Drawing Tools';
  grp.UseDefaultAppearance := False;
  grp.Color       := gcLimeGreen;
  grp.TextColor   := gcWhite;
  grp.BorderColor := gcGreen;
end;

procedure TForm1.DoAfterTheme(Sender: TObject);
begin
  // Optionally tighten the accent after the theme engine has run
  TMSFNCRibbon1.FileButton.Appearance.Fill.Color := gcDarkRed;
end;

See also