📜 ⬆️ ⬇️

Using TTreeView in Firemonkey Applications

The other day I had to deal with the TTreeView component. The customer insisted on his usual component - “Tree”, and wanted the application to look like it used to in the VCL.

In this article I would like to talk about the TTreeView component (tree branch) and its use in Firemonkey applications, as well as consider the differences between the VCL and FireMonkey implementation.

In the VCL of each branch to add your picture was not difficult. All that is required for this is to add a TImageList component, “load into it” pictures and assign this list to the TreeView.Images property: = ImageList;

image
')
Now 2 times click on the tree and add branches. For each we specify the sequence number of the image that we want to display on the branch.

image

After compilation we get the following result:

image

In FireMonkey, the tree has changed slightly. First, there is no TTreeNode class in FMX. Secondly, there is no Images property. And thirdly, in the TTreeViewItem class there are no properties responsible for the use of pictures.

Internet for the query "how to add image to treeviewitem firemonkey". suggests using a fairly standard, I think, way to change the standard components, expanding them by changing the style: monkeystyler.com/blog/entry/adding-images-to-a-firemonkey-treeview

The example has the full right to life and is completely necessary when you want to see immediately the results of style changes, including in the IDE. But there is another way, especially - if you do all the manipulations in Run-Time.

The method is based on the features of the FireMonkey architecture. If we look in the documentation, we will see the following line:

FireMonkey Controls Have Owners, Parents, and Children ( http://docwiki.embarcadero.com/RADStudio/XE7/en/Arranging_FireMonkey_Controls ). This means that each component can, if necessary, act as a container for “any” other components (TfmxObject). What I use.

First of all, we will inherit a new class of the branch and slightly “expand” it:

type TNode = class(TTreeViewItem) strict private FImage: TImage; private procedure SetImage(const aValue: TImage); public constructor Create(Owner: TComponent; const aText: String; const aImageFileName: String); reintroduce; destructor Destroy; override; published property Image: TImage Read FImage Write SetImage; end; { TTestNode } constructor TNode.Create(Owner: TComponent; const aText: String; const aImageFileName: String); begin inherited Create(Owner); Self.Text := aText; //   FImage := TImage.Create(Owner); //   FireMonkey,  -       Self.AddObject(FImage); //   FImage.Align := TAlignLayout.Right; //   FImage.Bitmap.LoadFromFile(aImageFileName); //    FImage.SendToBack; end; destructor TNode.Destroy; begin Image.FreeOnRelease; inherited; end; procedure TNode.SetImage(const aValue: TImage); begin FImage := aValue; end; 


The next step is to place several components on the form:

TTreeView
Timage
2 TButton
TOpenDialog
I also added the TStyleBook component, but it is not obligatory, but only changes the standard style to one of the out-of-box styles that Embarcadero provides with the IDE.

After performing the previous operations, my IDE acquired the following form:

image

Add the button processing code and the TreeChange event for the tree:

 procedure TMainForm.AddNodeClick(Sender: TObject); var Node : TNode; begin //     OpenImage.Options := OpenImage.Options - [TOpenOption.ofAllowMultiSelect]; if OpenImage.Execute then begin //     MainImage.Bitmap.LoadFromFile(OpenImage.Files[0]); //        Node := TNode.Create(MainTree, ExtractFileName(OpenImage.Files[0]), OpenImage.Files[0]); //    ,    if MainTree.Selected = nil then MainTree.AddObject(Node) else //     ,       MainTree.Selected.AddObject(Node); end; end; //      ,           procedure TMainForm.AddImageListClick(Sender: TObject); var ImageFileName: string; Node : TNode; begin OpenImage.Options := OpenImage.Options + [TOpenOption.ofAllowMultiSelect]; if OpenImage.Execute then begin for ImageFileName in OpenImage.Files do begin Node := TNode.Create(MainTree, ExtractFileName(ImageFileName), ImageFileName); MainTree.AddObject(Node); end; MainImage.Bitmap.LoadFromFile(OpenImage.Files[0]); end; end; procedure TMainForm.MainTreeChange(Sender: TObject); begin //   ,       if MainTree.Selected is TNode then MainImage.Bitmap := (MainTree.Selected as TNode).Image.Bitmap; end; 


After launch, the application took the form:

image

This would be the end, but I would like to draw special attention of readers to the features of TFMXObject. Namely, the AddObject method, which allows us to refine our components on the fly.

Let's now add our branch, for example, a button. To do this, analogously to the example, expand our class and add a button initialization to the constructor:

 type TNode = class(TTreeViewItem) strict private FImage: TImage; FButton: TButton; private procedure SetImage(const aValue: TImage); procedure TreeButtonClick(Sender: TObject); procedure SetButton(const Value: TButton); public constructor Create(Owner: TComponent; const aText: String; const aImageFileName: String); reintroduce; destructor Destroy; override; published property Image: TImage Read FImage Write SetImage; property Button: TButton Read FButton Write SetButton; end; constructor TNode.Create(Owner: TComponent; const aText: String; const aImageFileName: String); begin inherited Create(Owner); Self.Text := aText; //   FImage := TImage.Create(Owner); //   FireMonkey,  -       Self.AddObject(FImage); //   FImage.Align := TAlignLayout.Right; //   FImage.Bitmap.LoadFromFile(aImageFileName); //    FImage.SendToBack; //    ,   OnClick FButton := TButton.Create(Owner); FButton.Text := 'Hi World'; Self.AddObject(FButton); FButton.Align := TAlignLayout.Center; FButton.SendToBack; FButton.OnClick := TreeButtonClick; end; procedure TNode.TreeButtonClick(Sender: TObject); begin //          ShowMessage('Hello World'); end; 


Compile the application:

image

In the same way, add the input field:

image

Code:

 { TTestNode } constructor TNode.Create(Owner: TComponent; const aText: String; const aImageFileName: String); begin inherited Create(Owner); Self.Text := aText; FButton := TButton.Create(Owner); FButton.Text := 'Send'; Self.AddObject(FButton); FButton.Align := TAlignLayout.Center; FButton.SendToBack; FButton.OnClick := TreeButtonClick; //  TEdit FEdit:= TEdit.Create(Owner); Self.AddObject(FEdit); FEdit.Position.X := 150; FEdit.Position.Y := 25; FEdit.SendToBack; FImage := TImage.Create(Owner); Self.AddObject(FImage); FImage.Align := TAlignLayout.Right; FImage.Bitmap.LoadFromFile(aImageFileName); FImage.SendToBack; end; 


This is how to simply expand your own components in Run-Time. And thanks to FireMonkey, our application is also cross-platform.

Thanks to everyone who read this article. Thanks to everyone who helped. Waiting for comments and comments.

Link to the repository with an example: yadi.sk/d/lwuLryOwcsDyp

Source: https://habr.com/ru/post/243933/


All Articles