Jump to content
Chester Wilson

Scaley drawings

Recommended Posts

I have a problem with image scale being different under android and under windows.  I have tried to simplify this for Delphi Praxis.

It started with trying to draw a black box around tEdit components on Android, so you can actually see them!

On windows, the image.scale is left to the default (1,1).

On android (at least on my phone), it has to be set to (0.31, 0.31) or the results are weird / awful.

 

To duplicate it, make a new FMX project in a simple window.  On the form place a tImage and 2 x tEdit (with some text in each).

Use the code below, and put Resize into the Form.Resize in the object inspector.  Run it on android and on windows and you should

see the oddity.

 

I do not know whether there may be something about using / not using high DPI on the android: ClientWidth x ClientHeight

shows as 338 x 660, whereas the Samsung S22 is supposed to have a screen of 1080 x 2340, but I do not know how to access

this.

 

I will be interested in your ideas and findings please.

unit Unit1;

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.Edit, FMX.Memo.Types, FMX.ScrollBox, FMX.Memo,
  FMX.Objects;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Image1: TImage;

    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: tForm1;

implementation

{$R *.fmx}

procedure tForm1.FormResize(Sender: TObject);
var
   Rect, e1Rect, e2Rect : tRectf;
begin
   Image1.Position.X := 20;
   Image1.Position.Y := 30;

   Edit1.Position.X := 40;
   Edit1.Position.Y := 60;

   Edit2.Position.X := ClientWidth - Edit2.Width - 60;
   Edit2.Position.Y := 60;

   //Create rectangle positions for edit boxes with respect to the image.
   e1Rect := tRectf.Create(
      Edit1.Position.X - Image1.Position.X,
      Edit1.Position.Y - Image1.Position.Y,
      Edit1.Position.X - Image1.Position.X + Edit1.Width,
      Edit1.Position.Y - Image1.Position.Y + Edit1.Height);
   e2Rect := tRectf.Create(
      Edit2.Position.X - Image1.Position.X,
      Edit2.Position.Y - Image1.Position.Y,
      Edit2.Position.X - Image1.Position.X + Edit2.Width,
      Edit2.Position.Y - Image1.Position.Y + Edit2.Height);

// --------------- Problem Area -------------------

   //Need this for Android:

   Image1.Scale.X := 0.31;
   Image1.Scale.Y := 0.31;

   Image1.Height := 200 * 3;
   Image1.Width := 3 * (ClientWidth - 40);
   Image1.Bitmap.SetSize(round(Image1.Width), round(Image1.Height));

   //Need this for Windows
{
   Image1.Height := 200;
   Image1.Width := (ClientWidth - 40);
   Image1.Bitmap.SetSize(round(Image1.Width), round(Image1.Height));
}
// -------------------------------------------------


   Image1.Bitmap.Canvas.Stroke.Kind := tBrushKind.Solid;
   Image1.Bitmap.Canvas.Stroke.Color := tAlphaColorRec.Black;
   Image1.Bitmap.Canvas.Stroke.Thickness := 2;

   Image1.Bitmap.Canvas.BeginScene;

   //Colour the whole image first
   Image1.Bitmap.Canvas.Clear(tAlphaColorRec.Lightsalmon);

   //Now white out the bits where we want to place the edit boxes
   //Left one:
   Rect.Left := e1Rect.Left - 1;
   Rect.Right := e1Rect.Left + Edit1.Width + 1;
   Rect.Top := e1Rect.Top;
   Rect.Bottom := e1Rect.Top + Edit1.Height + 1;

   Image1.Bitmap.Canvas.ClearRect(Rect, tAlphaColorRec.Yellow);

   //Right one:
   Rect.Left := e2Rect.Left - 1;
   Rect.Right := e2Rect.Left + Edit2.Width + 1;
   Rect.Top := e2Rect.Top;
   Rect.Bottom := e2Rect.Top + Edit2.Height + 1;

   Image1.Bitmap.Canvas.ClearRect(Rect, tAlphaColorRec.Yellow);


   //Now draw the rectangles

   Rect.Left := e1Rect.Left - 1;
   Rect.Right := e1Rect.Left + Edit1.Width + 1;
   Rect.Top := e1Rect.Top - 1;
   Rect.Bottom := e1Rect.Top + Edit1.Height + 1;

   Image1.Bitmap.Canvas.DrawRect(Rect, 1);

   Rect.Left := e2Rect.Left - 1;
   Rect.Right := e2Rect.Left + Edit2.Width + 1;
   Rect.Top := e2Rect.Top - 1;
   Rect.Bottom := e2Rect.Top + Edit2.Height + 1;

   Image1.Bitmap.Canvas.DrawRect(Rect, 1);

   Image1.Bitmap.Canvas.EndScene;
end;

end.

 

Edited by Sherlock
Please use the code tags for better readability

Share this post


Link to post

Have you tried your code on Windows set to 150% or any other scale? You need to find out, what the DisplayMetrics are and react accordingly. I use something like this

  if TBehaviorServices.Current.SupportsBehaviorService(IDeviceBehavior,
    DeviceBehavior, Context) then
  begin
    DisplayMetrics := DeviceBehavior.GetDisplayMetrics(Context);
    Scale := DisplayMetrics.ScreenScale;
    ppi := DisplayMetrics.PixelsPerInch;
  end
  else
    ShowMessage('Help?!');

 

  • Like 1

Share this post


Link to post

Thanks, Sherlock.  It works fine on windows with the scale set to 1 (the default), and I have no problem with that.  It is with bloody android!

I have put your code in, thanks - but I need to know what to include in the USES.  I have found FMX.BehaviourManager, but cannot find where

AService is defined (for DeviceBehavior), or how to define DisplayMetrics.  Please would you mind filling in the gaps?

 

Share this post


Link to post

OK you'll need:

uses FMX.Types, FMX.BehaviourManager, FMX.Platform;

 

And even if you only develop for yourself, you should consider different DPI and scaling in your application because you might treat yourself to a monitor with higher resolution at some point.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×