Customization
Custom drawing
TTMSFNCTreeView exposes paired OnBeforeDraw* / OnAfterDraw* events for every visual element: nodes, node text, node icons, checkboxes, expand/collapse icons, column headers, and groups. Use the After variant to draw on top of the default rendering.
Example: highlight nodes by value
The sample below draws a red indicator circle in the year column for rows built in 2012 or later:
uses
System.SysUtils, System.Types, FMX.TMSFNCGraphics, FMX.TMSFNCGraphicsTypes,
FMX.TMSFNCTreeView;
procedure TForm1.TreeView1AfterDrawNodeText(Sender: TObject;
AGraphics: TTMSFNCGraphics; ARect: TRectF; AColumn: Integer;
ANode: TTMSFNCTreeViewVirtualNode; AText: string);
var
v: Integer;
begin
if TryStrToInt(AText, v) and (AColumn = 1) and (v >= 2012) then
begin
AGraphics.Fill.Kind := gfkSolid;
AGraphics.Fill.Color := gcRed;
AGraphics.DrawEllipse(
RectF(ARect.Right - 12, ARect.Top + 2, ARect.Right - 2, ARect.Top + 12), gcrmNone);
end;
end;
void __fastcall TForm1::TreeView1AfterDrawNodeText(TObject *Sender,
TTMSFNCGraphics *AGraphics, const TRectF &ARect, int AColumn,
TTMSFNCTreeViewVirtualNode *ANode, UnicodeString AText)
{
int v;
if (TryStrToInt(AText, v) && (AColumn == 1) && (v >= 2012))
{
AGraphics->Fill->Kind = gfkSolid;
AGraphics->Fill->Color = gcRed;
AGraphics->DrawEllipse(
RectF(ARect.Right - 12, ARect.Top + 2, ARect.Right - 2, ARect.Top + 12), gcrmNone);
}
}
Available drawing events
| Event group | Description |
|---|---|
OnBeforeDrawNode / OnAfterDrawNode |
Full node background |
OnBeforeDrawNodeText / OnAfterDrawNodeText |
Node cell text |
OnBeforeDrawNodeIcon / OnAfterDrawNodeIcon |
Node icon |
OnBeforeDrawNodeCheck / OnAfterDrawNodeCheck |
Checkbox/radiobutton |
OnBeforeDrawNodeExpand / OnAfterDrawNodeExpand |
Expand/collapse icon |
OnBeforeDrawColumn / OnAfterDrawColumn |
Column header area |
OnBeforeDrawColumnHeader / OnAfterDrawColumnHeader |
Column header text area |
OnBeforeDrawGroup / OnAfterDrawGroup |
Group header |
Assign the handlers you need once, typically when the form is created. After handlers paint on top of the default rendering; Before handlers can also suppress it. The sample wires three of the events:
uses
System.SysUtils, System.Types, FMX.TMSFNCGraphics, FMX.TMSFNCGraphicsTypes,
FMX.TMSFNCTreeView;
procedure TForm1.ConfigureDrawEvents;
begin
// After* events draw on top of the default rendering. Before* events
// additionally let the handler suppress the default drawing.
TreeView1.OnAfterDrawNode := TreeView1AfterDrawNode;
TreeView1.OnAfterDrawNodeText := TreeView1AfterDrawNodeText;
TreeView1.OnAfterDrawColumnHeader := TreeView1AfterDrawColumnHeader;
end;
// Draw a thin separator under every node.
procedure TForm1.TreeView1AfterDrawNode(Sender: TObject;
AGraphics: TTMSFNCGraphics; ARect: TRectF; ANode: TTMSFNCTreeViewVirtualNode);
begin
AGraphics.Stroke.Color := gcSilver;
AGraphics.DrawLine(PointF(ARect.Left, ARect.Bottom),
PointF(ARect.Right, ARect.Bottom));
end;
// Mark the text of the first column with a small dot.
procedure TForm1.TreeView1AfterDrawNodeText(Sender: TObject;
AGraphics: TTMSFNCGraphics; ARect: TRectF; AColumn: Integer;
ANode: TTMSFNCTreeViewVirtualNode; AText: string);
begin
if AColumn = 0 then
begin
AGraphics.Fill.Kind := gfkSolid;
AGraphics.Fill.Color := gcSteelblue;
AGraphics.DrawEllipse(
RectF(ARect.Left + 2, ARect.Top + 2, ARect.Left + 8, ARect.Top + 8), gcrmNone);
end;
end;
// Underline every column header.
procedure TForm1.TreeView1AfterDrawColumnHeader(Sender: TObject;
AGraphics: TTMSFNCGraphics; ARect: TRectF; AColumn: Integer;
AKind: TTMSFNCTreeViewCacheItemKind);
begin
AGraphics.Stroke.Color := gcSteelblue;
AGraphics.DrawLine(PointF(ARect.Left, ARect.Bottom - 1),
PointF(ARect.Right, ARect.Bottom - 1));
end;
void __fastcall TForm1::ConfigureDrawEvents()
{
// After* events draw on top of the default rendering. Before* events
// additionally let the handler suppress the default drawing.
TreeView1->OnAfterDrawNode = TreeView1AfterDrawNode;
TreeView1->OnAfterDrawNodeText = TreeView1AfterDrawNodeText;
TreeView1->OnAfterDrawColumnHeader = TreeView1AfterDrawColumnHeader;
}
// Draw a thin separator under every node.
void __fastcall TForm1::TreeView1AfterDrawNode(TObject *Sender,
TTMSFNCGraphics *AGraphics, const TRectF &ARect,
TTMSFNCTreeViewVirtualNode *ANode)
{
AGraphics->Stroke->Color = gcSilver;
AGraphics->DrawLine(PointF(ARect.Left, ARect.Bottom),
PointF(ARect.Right, ARect.Bottom));
}
// Mark the text of the first column with a small dot.
void __fastcall TForm1::TreeView1AfterDrawNodeText(TObject *Sender,
TTMSFNCGraphics *AGraphics, const TRectF &ARect, int AColumn,
TTMSFNCTreeViewVirtualNode *ANode, UnicodeString AText)
{
if (AColumn == 0)
{
AGraphics->Fill->Kind = gfkSolid;
AGraphics->Fill->Color = gcSteelblue;
AGraphics->DrawEllipse(
RectF(ARect.Left + 2, ARect.Top + 2, ARect.Left + 8, ARect.Top + 8), gcrmNone);
}
}
// Underline every column header.
void __fastcall TForm1::TreeView1AfterDrawColumnHeader(TObject *Sender,
TTMSFNCGraphics *AGraphics, const TRectF &ARect, int AColumn,
TTMSFNCTreeViewCacheItemKind AKind)
{
AGraphics->Stroke->Color = gcSteelblue;
AGraphics->DrawLine(PointF(ARect.Left, ARect.Bottom - 1),
PointF(ARect.Right, ARect.Bottom - 1));
}
JSON viewer
Use ViewJSON to load and display any JSON document as a navigable tree. Key names appear in one column and values in another.
uses
FMX.TMSFNCTreeView;
procedure TForm1.LoadJSON;
var
o: TTMSFNCTreeViewViewJSONOptions;
begin
o := TTMSFNCTreeViewViewJSONOptions.Create;
try
o.ArrayItemPrefix := 'Item ';
o.NameHTMLTemplate := '<B><#NAME></B>';
o.ValueHTMLTemplate := '<FONT color="gcRed"><#VALUE></FONT>';
TreeView1.ViewJSON('mydata.json', o);
finally
o.Free;
end;
end;
void __fastcall TForm1::LoadJSON()
{
TTMSFNCTreeViewViewJSONOptions *o = new TTMSFNCTreeViewViewJSONOptions();
try
{
o->ArrayItemPrefix = "Item ";
o->NameHTMLTemplate = "<B><#NAME></B>";
o->ValueHTMLTemplate = "<FONT color=\"gcRed\"><#VALUE></FONT>";
TreeView1->ViewJSON("mydata.json", o);
}
__finally
{
delete o;
}
}
#NAME and #VALUE are mandatory placeholders in the HTML templates. Omit TTMSFNCTreeViewViewJSONOptions to use defaults.
TMS Mini HTML rendering
The tree renders HTML-formatted text natively in any node column. No property needs to be enabled — the component switches to HTML mode automatically when node text starts with <.
Supported tags:
| Tag | Effect |
|---|---|
<B>, </B> |
Bold |
<I>, </I> |
Italic |
<U>, </U> |
Underline |
<S>, </S> |
Strikethrough |
<FONT face="..." size="..." color="..."> |
Font face, size, color |
<A href="url_or_value"> |
Hyperlink or anchor |
<IMG src="name"> |
Image from BitmapContainer |
<P align="..."> |
Paragraph with alignment |
<BR> |
Line break |
<UL> / <LI> |
Unordered list |
<SUB>, <SUP> |
Subscript/superscript |
<IND x="N"> |
Indent N pixels |
<SHAD> |
Text shadow |
<Z> |
Hidden text |
Example:
uses
FMX.TMSFNCTreeView;
procedure TForm1.SetHTMLNodeText(ANode: TTMSFNCTreeViewVirtualNode);
begin
// Virtual nodes expose Text read-only; set it on the backing collection node.
if ANode.Node <> nil then
ANode.Node.Text[0] := '<B>Embarcadero</B> <FONT color="gcRed">Delphi</FONT>';
end;
void __fastcall TForm1::SetHTMLNodeText(TTMSFNCTreeViewVirtualNode *ANode)
{
// Virtual nodes expose Text read-only; set it on the backing collection node.
if (ANode->Node != nullptr)
ANode->Node->Text[0] = "<B>Embarcadero</B> <FONT color=\"gcRed\">Delphi</FONT>";
}
Anchor click handling
When a user clicks an <A href="value"> element where value is not a URL:
uses
FMX.Dialogs, FMX.TMSFNCTreeView;
procedure TForm1.TreeView1NodeAnchorClick(Sender: TObject;
ANode: TTMSFNCTreeViewVirtualNode; AColumn: Integer; AAnchor: string);
begin
ShowMessage('Anchor clicked: ' + AAnchor);
end;
void __fastcall TForm1::TreeView1NodeAnchorClick(TObject *Sender,
TTMSFNCTreeViewVirtualNode *ANode, int AColumn, UnicodeString AAnchor)
{
ShowMessage("Anchor clicked: " + AAnchor);
}
Set Interaction.AutoOpenURL := True to open http://, https://, and mailto: links automatically via the system browser.
TTMSFNCCheckedTreeView
TTMSFNCCheckedTreeView is a preconfigured subclass that adds a checkbox to every node automatically. Its API is identical to TTMSFNCTreeView; there is no need to set CheckTypes per node.
Combining custom drawing, HTML text and anchors
The custom drawing events, HTML rendering and anchor clicks are most useful together. HTML text gives you styled, clickable content without owner drawing, while an After draw event adds decoration that markup cannot express, such as a status badge, and the anchor event turns the rendered link into an action. Reach for the combination when a node must look rich and also respond to the user, for example a product list with a "details" link and a highlight for recent entries. The sample below fills two columns with HTML text, draws a badge in the year column and shows the clicked anchor value.
uses
System.SysUtils, System.Types, FMX.Dialogs, FMX.TMSFNCGraphics,
FMX.TMSFNCGraphicsTypes, FMX.TMSFNCTreeView;
procedure TForm1.SetupCombinedCustomization;
var
n: TTMSFNCTreeViewNode;
begin
TreeView1.BeginUpdate;
TreeView1.ClearNodeList;
TreeView1.ClearNodes;
TreeView1.ClearColumns;
TreeView1.Columns.Add.Text := 'Product';
TreeView1.Columns.Add.Text := 'Year';
// HTML text: the tree switches to HTML rendering when the text starts with '<'
n := TreeView1.AddNode;
n.Text[0] := '<B>Delphi</B> <A href="delphi">details</A>';
n.Text[1] := '2024';
n := TreeView1.AddNode;
n.Text[0] := '<I>C++Builder</I> <A href="cppbuilder">details</A>';
n.Text[1] := '2009';
// Custom drawing and anchor handling layered on the HTML text
TreeView1.OnAfterDrawNodeText := TreeView1AfterDrawNodeBadge;
TreeView1.OnNodeAnchorClick := TreeView1NodeAnchorClickCombined;
TreeView1.EndUpdate;
end;
procedure TForm1.TreeView1AfterDrawNodeBadge(Sender: TObject;
AGraphics: TTMSFNCGraphics; ARect: TRectF; AColumn: Integer;
ANode: TTMSFNCTreeViewVirtualNode; AText: string);
var
v: Integer;
begin
if (AColumn = 1) and TryStrToInt(AText, v) and (v >= 2020) then
begin
AGraphics.Fill.Kind := gfkSolid;
AGraphics.Fill.Color := gcRed;
AGraphics.DrawEllipse(
RectF(ARect.Right - 12, ARect.Top + 2, ARect.Right - 2, ARect.Top + 12), gcrmNone);
end;
end;
procedure TForm1.TreeView1NodeAnchorClickCombined(Sender: TObject;
ANode: TTMSFNCTreeViewVirtualNode; AColumn: Integer; AAnchor: string);
begin
ShowMessage('Anchor clicked: ' + AAnchor);
end;
void __fastcall TForm1::SetupCombinedCustomization()
{
TreeView1->BeginUpdate();
TreeView1->ClearNodeList();
TreeView1->ClearNodes();
TreeView1->ClearColumns();
TreeView1->Columns->Add()->Text = "Product";
TreeView1->Columns->Add()->Text = "Year";
// HTML text: the tree switches to HTML rendering when the text starts with '<'
TTMSFNCTreeViewNode *n = TreeView1->AddNode();
n->Text[0] = "<B>Delphi</B> <A href=\"delphi\">details</A>";
n->Text[1] = "2024";
n = TreeView1->AddNode();
n->Text[0] = "<I>C++Builder</I> <A href=\"cppbuilder\">details</A>";
n->Text[1] = "2009";
// Custom drawing and anchor handling layered on the HTML text
TreeView1->OnAfterDrawNodeText = TreeView1AfterDrawNodeBadge;
TreeView1->OnNodeAnchorClick = TreeView1NodeAnchorClickCombined;
TreeView1->EndUpdate();
}
void __fastcall TForm1::TreeView1AfterDrawNodeBadge(TObject *Sender,
TTMSFNCGraphics *AGraphics, const TRectF &ARect, int AColumn,
TTMSFNCTreeViewVirtualNode *ANode, UnicodeString AText)
{
int v;
if ((AColumn == 1) && TryStrToInt(AText, v) && (v >= 2020))
{
AGraphics->Fill->Kind = gfkSolid;
AGraphics->Fill->Color = gcRed;
AGraphics->DrawEllipse(
RectF(ARect.Right - 12, ARect.Top + 2, ARect.Right - 2, ARect.Top + 12), gcrmNone);
}
}
void __fastcall TForm1::TreeView1NodeAnchorClickCombined(TObject *Sender,
TTMSFNCTreeViewVirtualNode *ANode, int AColumn, UnicodeString AAnchor)
{
ShowMessage("Anchor clicked: " + AAnchor);
}
Related API
TTMSFNCTreeView— drawing events,ViewJSON,BitmapContainer
See also
- Nodes — checkbox and extended nodes
- Interaction — anchor click and interaction properties