People using Android or iOS mobile devices rely on touchscreens for data input, interacting on social media platforms, or launching various applications. Also, many all-in-one computers running Windows have touchscreens. This makes user interaction more intuitive. Controlling a device through touch and gestures is more convenient than using traditional input tools, such as a keyboard or a mouse.
Previously, we explored how to use gestures in our Embarcadero Delphi FMX app.
In this article, we will demonstrate how to enable drawing on an Android device by handling multi-touch input.
Setting Up Multi-Touch in Delphi FMX
Modern smartphones and tablets support up to 10 simultaneous touchpoints. Our application consists of a single main form.

We declare the MaxFingers constant. This constant defines the maximum number of touch points (in our case, it is 10).
We also define the ColorArr constant that contains 10 possible line colors for multi-touch drawing (in our case, up to 10 simultaneous touches). To select a color, we use the static class TAlphaColors (for example, when choosing the red color, we use TAlphaColors.Red).

To store the coordinates of the user’s touch points and finger movements on the mobile screen, we declare a dynamic array, FPathArr, of type TPathData as a private field of the TForm1 class.
And we also declare an Integer field, FTouchCount, to hold the number of simulteneous touches.

In the OnCreate event handler of the main form, we set the size of the FPathArr array using the SetLength method. Since the maximum number of touches is 10, the array will contain 10 elements. Each element of FPathArr will contain the coordinates for each touch separately. These coordinates correspond to the positions of the lines that will be drawn on the mobile screen.
For the app to run correctly, we must call the default constructor for each element in the FPathArr array (FPathArr[I] := TPathData.Create).
To draw lines on the form, we need to configure the fill type (Form1.Fill.Kind). Also, set it to a solid fill (Form1.Fill.Kind := TBrushKind.Solid). We must choose the fill color form using Form1.Fill.Color (we’ll set it to a light gray: Form1.Fill.Color := TAlphaColors.Lightgray).

Touch processing is done with the handler of the main form OnTouch.

Handling Touch Events and Drawing Logic
In the OnTouch event handler, we will need the input parameters, such as Touches and Action.

Touches (type TTouches) is an array that stores the number of touch points on the screen (main form). Also, it contains the coordinates of each touch. The number of touches is determined using the Length function (FTouchCount := Length(Touches)).
Action (type TTouchAction) allows us to process the state of each touch. For example, a screen touch can be handled using TTouchAction.Down.
In this case, we add the touch coordinates to each element of the FPathArr array (type TPathData) using the MoveTo method. MoveTo moves the current position in the FPathArr array to the touch point Touches[I].Location (FPathArr[I].MoveTo(Touches[I].Location)). The integer variable I contains the index of each touch on the screen.
Using TTouchAction.Move, we can track finger movements on the screen. The LineTo method adds a line to the corresponding element of the FPathArr array (type TPathData) based on the coordinates of the current touch (FPathArr[I].LineTo(Touches[I].Location)).
TTouchAction.Up allows us to handle the release of each finger. All actions related to TTouchAction.Up are similar to those for TTouchAction.Down. To prevent errors in the app, we limit the number of touches to 10 (if I < MaxFingers then).
The lines of each touch are drawn in the main form’s OnPaint method. To do this, we call Form1.Invalidate. The Invalidate method forces a re-drawing of the form to display lines.

Let’s explore the details of drawing lines as each touch moves. We use the OnPaint method of the main form.

Drawing in FMX is done within the blocks BeginScene() and EndScene() blocks. Using the attribute Font (TCanvas), we configure font settings, such as size and style to display the number of touches on the main form (Font.Size := 2, Font.Style := [TFontStyle.fsBold]).
The Fill.Color property is used to set the text color. To display the touch count, we use the FillText method of the TCanvas class (FillText(TRectF.Create(0, 0, 200, 20), ‘Touches = ‘ + FTouchCount.ToString, False, 1.0, [TFillTextFlag.RightToLeft], TTextAlign.Center,TTextAlign.Center)).
To draw the lines, we use the Stroke mode. Lines are drawn according to the coordinates of each touch (those coordinates are stored in the elements of the FPathArr array for each respective touch).
We set the color and thickness of each line (Stroke.Color := ColorArr[I + 1], Stroke.Thickness := 10). Then, we draw the line for each touch using the TCanvas method DrawPath (DrawPath(FPathArr[I], 1.0)).
The first input parameter of the DrawPath method is the corresponding element of the FPathArr array for each touch.
The second parameter specifies the line opacity. which is 1.0 (fully opaque) in our case.

The complete code of the application is below:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 | unit Main;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs;
const
MaxFingers = 10;
ColorArr: array [1..MaxFingers] of Cardinal = (TAlphaColors.Red,
TAlphaColors.Green, TAlphaColors.Yellow, TAlphaColors.Blue,
TAlphaColors.Darkorange, TAlphaColors.Aliceblue, TAlphaColors.Aquamarine,
TAlphaColors.Beige, TAlphaColors.Blueviolet, TAlphaColors.Chocolate);
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
procedure FormTouch(Sender: TObject; const Touches: TTouches;
const Action: TTouchAction);
private
{ Private declarations }
FPathArr: TArray<TPathData>;
FTouchCount: Integer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.FormCreate(Sender: TObject);
var I: Integer;
begin
FPathArr := nil;
SetLength(FPathArr, MaxFingers);
for I := 0 to Length(FPathArr) – 1 do
FPathArr[I] := TPathData.Create;
Form1.Fill.Kind := TBrushKind.Solid;
Form1.Fill.Color := TAlphaColors.Lightgray;
end;
procedure TForm1.FormPaint(Sender: TObject; Canvas: TCanvas;
const ARect: TRectF);
var I: Integer;
begin
with Form1.Canvas do
begin
BeginScene();
Font.Size := 20;
Font.Style := [TFontStyle.fsBold];
Fill.Color := TAlphaColors.Green;
FillText(TRectF.Create(0, 0, 200, 20), 'Touches = ' +
FTouchCount.ToString, False, 1.0, [TFillTextFlag.RightToLeft],
TTextAlign.Center,TTextAlign.Center);
for I := 0 to Length(FPathArr) – 1 do
begin
Stroke.Color := ColorArr[I + 1];
Stroke.Thickness := 10;
DrawPath(FPathArr[I], 1.0);
end;
EndScene;
end;
end;
procedure TForm1.FormTouch(Sender: TObject; const Touches: TTouches;
const Action: TTouchAction);
var I: Integer;
begin
FTouchCount := Length(Touches);
case Action of
TTouchAction.Down:
begin
for I := 0 to Length(Touches) – 1 do
begin
if I < MaxFingers then
FPathArr[I].MoveTo(Touches[I].Location);
end;
end;
TTouchAction.Move:
begin
for I := 0 to Length(Touches) – 1 do
begin
if I < MaxFingers then
FPathArr[I].LineTo(Touches[I].Location);
end;
end;
TTouchAction.Up:
begin
for I := 0 to Length(Touches) – 1 do
begin
if I < MaxFingers then
FPathArr[I].MoveTo(Touches[I].Location);
end;
end;
end;
Form1.Invalidate;
end;
end.
|
Testing the App on Android
Let’s test our Embarcadero Delphi FMX application on the Android platform.



