Wednesday 12 September 2018

Delphi - Add an icon to a Node in TTreeView


1. Add your tree view to the form.

2. Add an TImageList to the form.

3. Double click on the ImageList component and add some images in.

4. Go to the Properties of the TreeView > Drop down the 'Images' property and select the name of the ImageList you've added.


5. Now in your code, where you're populating the treeview, you can add in code to set an icon/image to each node by referncing the image index:

//This will set the image of the node when resting
MyNode.ImageIndex := 0;  

//This will set the image of node when selected
MyNode.SelectedIndex := 0;

The index number refers to the image in the IMageList. This is zero based so the first image would be 0, the second would 1 and so on...

 

Monday 30 July 2018

Delphi - Sort an Object List by Property


Below is a quick example of how to use the .Sort function. In this case i have two objects declared in the Type seciton. On form create i am creating an instance of TPersons, then creating a number of dummy TPersons and adding them to my 'Persons'. Then behind a button click i am sorting the order of the Persons using the following code:

Persons.Sort(TComparer<TPerson>.Construct(
      function (const L,R: TPerson): integer
      begin
        if L.Name > R.Name then
          Result := 1
        else if L.Name < R.Name then
          Result := -1
        else
          Result := 0;
      end
      ));
  end;


To recreate this simple example, drop a memo and a button on a form. The make your code look like this:

unit Unit2;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls, Generics.Collections, FMX.ScrollBox,
  FMX.Memo, Generics.Defaults;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TPerson = class(TObject)
    Name: string;
    Age: integer;
  end;

  TPersons = class(TObjectList<TPerson>)
  end;


var
  Form2: TForm2;

implementation

{$R *.fmx}

var
  Persons: TPersons;


procedure TForm2.Button1Click(Sender: TObject);
var
  Person: TPerson;
  I: Integer;
begin
  for Person in Persons do
  begin
    Persons.Sort(TComparer<TPerson>.Construct(
      function (const L,R: TPerson): integer
      begin
        if L.Name > R.Name then
          Result := 1
        else if L.Name < R.Name then
          Result := -1
        else
          Result := 0;
      end
      ));
  end;

  for I := 0 to Persons.Count -1 do
  begin
    Memo1.Lines.Add(Persons[I].Name);
  end;
end;

procedure TForm2.FormCreate(Sender: TObject);
var
  Person: TPerson;
  I: Integer;
begin
  Persons := TPersons.Create(true);

  Person := TPerson.Create;
  Person.Name := 'John';
  Person.Age := 34;
  Persons.Add(Person);

  Person := TPerson.Create;
  Person.Name := 'James';
  Person.Age := 31;
  Persons.Add(Person);

  Person := TPerson.Create;
  Person.Name := 'Sally';
  Person.Age := 21;
  Persons.Add(Person);
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
  Persons.Free;
end;

end.

Monday 23 July 2018

Delphi FMX/Firemonkey - Fill a Rect/RoundRect/Ellipse with a Image/Bitmap

Here is a simple example of how to fill a given shape (TRectangle, TRoundRect, TEllipse etc) with the bitmap which belongs to an image. In this example i have created a new project, dropped a button and an RoundRect onto the form. On the Button Click i have the following code:

procedure TForm1.Button1Click(Sender: TObject);
var
  Image: TImage;
begin
  Image := TImage.Create(self);
  Image.Bitmap.LoadFromFile('C:\Temp\Test.jpg');


  RoundRect1.Fill.Kind := TbrushKind.Bitmap;
  RoundRect1.Fill.Bitmap.WrapMode := TWrapMode.TileStretch;
  RoundRect1.Fill.Bitmap.Bitmap := Image.Bitmap;
end;


This will create a new instance of a TImage. Load my Test.jpg file into its Bitmap property. Then set the Image to fill the space in the RoundRect.

Thursday 19 July 2018

Delphi - Set Font Property of a Component in Firemonkey/FMX

In order to set the font property of a component in FMX there are two ways you can do it:

1) In design time. By dropping a component onto the form and then changing its properties in the Object Inspector you can alter the properties of the font (font fmaily, size, color etc).

2) At run time. If, for example, you have a project which drops a series of labels onto a form when a button is clicked then you'll need to handle the changing of the font in your code.

 Option 1 is pretty straight forward but it's worth noting that if you make this change, you can view the effect this has had by saving your project and then opening up the .fmx file in notedpad and looking to see what has changed. In my project, i added a label to my form and changed the Text Settings > Font Color to be 'crimson'. In my .fmx file i can see that there are now two new lines:

    object Label1: TLabel
      Position.X = 120.000000000000000000
      Position.Y = 352.000000000000000000
      TextSettings.FontColor = claCrimson

      StyledSettings = [Family, Size, Style]
      Text = 'Label1'
    end 


This shows us what the impact was of changing the font color. The first change is to be expected since the property we changed was the FontColor. The second change is important, however, since it shows us what other change delphi made under the covers - namely that delphi altered the StyledSettings. The styled settings tell delphi whether to pull down the projects style settings (i.e. those which may be applied through a stylebook) for a given setting. Thus if you go back to design time and drop down the StyledSettings option, you'll see that 'FontColor' is currently unchecked. If you check the box against it, the font in the label will cease to be red.  

Thus, if you're creating new components at run time and need to alter some property of the font style, you'll need to include two lines - one to set the font setting and one to uncheck the relevant setting in StyledSettings:

MyLabel.TextSettings.FontColor := TAlphaColor($FF009900);
MyLabel.StyledSettings := [TStyledSetting.Family, TStyledSetting.Size, TStyledSetting.Style]; 

Monday 9 July 2018

Delphi - Load Image From Project Resource (FMX) - Simple Example

For this example i have a created a new FMX (firemonkey) form. I have added a button and an image onto the. I have then gone to Project > Resources and Images, and loaded in a bitmap image. I have set:
Resource Identifier: 'Bitmap_1'.
Resource Type: 'RCDATA'
Back on my form i have double clicked on the button and behind the button click put the code to instantiate a resource stream, load the image into it, assign it to a bitmap and then set it to be the image on the form.


unit Unit2;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Objects,
  FMX.Controls.Presentation, FMX.StdCtrls;

type
  TForm2 = class(TForm)
    Image1: TImage;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.fmx}

procedure TForm2.Button1Click(Sender: TObject);
var
  B: TBitmap;
  RS: TResourceStream;
begin
  RS := TResourceStream.Create(HInstance, 'Bitmap_1', RT_RCDATA);
  try
    B := TBitmap.Create;
    B.LoadFromStream(RS);
    Image1.Bitmap := B;
  finally
    RS.Free;
  end;
end;

end.

Thursday 26 April 2018

Delphi - TFileStream - Simple Example

TFileStream can be handy for looking at a file without having to actually load it into memory since it just provides a more efficient way to view it on disk. Below is a very simple example illustrating how to locate a character in a filestream:

procedure TForm1.Button1Click(Sender: TObject);
var
  FS: TFileStream; 

  X: char;  
begin
  FS := TFileStream.Create('C:\Temp\Example.txt', fmOpenRead);
  try
    FS.Position := 0;
    FS.Read(X,2);  

    ShowMessage(X);  
 finally
    FS.Free;
  end;
end;


This will create a filestream based on the information fed to the constructor, i.e. the file and the mode of operation. 

It will then set the position of the filestream to 0, i.e. what is my start point in the stream (it's 0 by default but if you wanted to alter your start point, this is how you'd do it).

It will then perform a Read on the string. It will start at the current position (in this case 0) and then read the number of bytes specified (in this case 2) and it will store these bytes in memory at a given location (in this case X). 

It will then show a message of the first character in the text file. 

Finally we free the filestream which ensures there is no memory leak.

NB, it is important to declare the X var at the start, since this will ensure that memory space is created. This space will then be used by FS.Read later to store data extracted from the filestream. In this example i have set it to be a char, since a char is 2 bytes of memory and i was just extracting the first two bytes of the stream but you could set it to something different so long as that something requires the same (or greater) memory than the amount of information you plan to extract from the filestream.