Posts tagged ‘FireMonkey’

XE Plus Pack – Release 17

After a much longer testing phase than expected, the newest release of XE Plus Pack for Delphi XE6 and Delphi XE7 is now available for download.

XE6 Plus Pack – Download for XE6
XE7 Plus Pack – Download for XE7

The main new feature for Release 17 is the ability to quickly generate and apply all of the required icon and splash images required for a mobile (iPhone or Android) application.

Image Generator

This new feature is called Image Generator and is accessible from the Project menu in the IDE. It is only available when a FireMonkey project is loaded within the IDE.

Image Generator - Design

You have the ability to add use three elements to compose your splash images.

  1. App Icon
  2. Backgroun
  3. Company Logo

Image Generator - Output

Once the images have been generated, you can review the final creations before applying the images to the correct elements in the active project. The images are applied for All Configurations. It does not support selecting whether to apply the images to Debug and/or Release. An enhancement for the next release – if deemed necessary.

The details of the design can be save to an “xeppsettings” file in the same folder as the project. Currently this is a binary file, however it will be changed to an XML or text readable file for easier use with source control.

More information about the Image Generator expert will be available soon.

View Units Dialog

An enhancement has been made to the View Units dialog which is updated due to the Visual Forms feature. This new dialog now gives the option of viewing either the selected files thumbnail (if available) or all available thumbnails. Additional options will be added to the View Units dialog in future releases.

View Units - Single View

To toggle the thumbnail view mode, use F8.

View Units - Thumbnail View

XE4 Mobile Tip #2 – Loading local HTML content

I’ve already answered this on the newsgroups however it deserves a little more attention.

The most important thing to do when deploying additional files with your app is to make sure they are prefixed with “StartUp/”. This tells the deployment manager to deploy these files with the application and place them in the folder specified after the StartUp/ prefix. This prefix is case sensitive.

Here is a screen capture of the deployment manager for the sample project available for download at the end of this post.

Deployment Manager

Verify file is included without running the app

You can even verify that the files have been deployed with the app by looking in the Applications section of your device in the XCode Organizer.

XCode Organizer

Sample code

The code below loads the content of the file into the WebBrowser control that is on the form.

unit Unit288;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types,
  FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.WebBrowser, FMX.StdCtrls, FMX.Layouts;

type
  TForm288 = class(TForm)
    LoadHtmlButton: TButton;
    WebBrowser1: TWebBrowser;
    Layout1: TLayout;
    procedure LoadHtmlButtonClick(Sender: TObject);
  end;

var
  Form288: TForm288;

implementation

uses
  IOUtils;

{$R *.fmx}

procedure TForm288.LoadHtmlButtonClick(Sender: TObject);
var
  LFilename: string;
begin
  LFilename := TPath.GetDocumentsPath + '/index.html';
  if TFile.Exists(LFilename) then
    WebBrowser1.Navigate('file://' + LFilename)
  else
    MessageDlg(Format('File not found: %s', [LFilename]), TMsgDlgType.mtError, [TMsgDlgBtn.mbClose], 0);
end;

end.

Works on my device!

Device Test (portrait)
Device Test (landscape)

Download the Code

Download the sample project.

A couple of notes

  • You wouldn’t deploy a static file to the Documents folder unless you wanted it to be backed up (via iTunes or iCloud) with other user data.
  • The best location for static files is Library/Application Support/, this is content that is generated when the application runs, or is included with the application.

XE4 Mobile Tip #1 – Disable the GPU Canvas

If you don’t like circles with jagged edges, you can disable the GPU canvas.

Using the GPU Canvas:

GPU Canvas

Not using the GPU Canvas:

Non-GPU Canvas

Full image comparison at 200% using Beyond Compare. Click to enlarge to full size (2600 x 1540).

Canvas Comparison

NOTE: If you see other drawing issues, enable the GPU canvas again just to see if it is a canvas issue.

Disabling the GPU Canvas

To disable the GPU canvas you must modify the project file source.

Add FMX.Platform and FMX.Consts to the uses clause. I suggest adding these items after the FMX.Forms entry but before any other units. You MUST leave System.StartUpCopy as the first unit in the uses clause.

Before Application.Initialize is called, enter this line:

TPlatformServices.Current.GlobalFlags.Add(GlobalDisableiOSGPUCanvas, True);

FireMonkey: Extending TFloatAnimation to support maximum loops

Background

In response to a QC report I wrote early last year I decided to implement a LoopCount property on the TFloatAnimation component.

Report No: 105140 Status: Open
Add a LoopCount property to the TAnimation class
http://qc.embarcadero.com/wc/qcmain.aspx?d=105140

Class Definition

  TJSCustomLoopCountFloatAnimation = class(TFloatAnimation)
  public
    type
      TAnimationLoopEvent = reference to procedure (Sender: TObject; const LoopNumber: Integer; var Cancel: Boolean);
  private
    FLoopCount: Integer;
    FCheckingLooping: Boolean;
    FOnLoop: TAnimationLoopEvent;
  protected
    FLoopsComplete: Integer;
    procedure FirstFrame; override;
    procedure DoLoop(var ACancel: Boolean); virtual;
    procedure ProcessAnimation; override;
  public
    constructor Create(AOwner: TComponent); override;
    property LoopCount: Integer read FLoopCount write FLoopCount default 3;
    property OnLoop: TAnimationLoopEvent read FOnLoop write FOnLoop;
  end;

Nothing that interesting in the new descendant. New property called LoopCount to control the number of loops and a new event that gets triggered each time a loop completes.

The published component publishes the new property and event but also changes the default values for two existing properties. It makes sense to set Loop to true when the new class is for enhancing the looping ability and if you’re looping, generally AutoReverse will be set to true.

  TJSLoopCountFloatAnimation = class(TJSCustomLoopCountFloatAnimation)
  published
    property AutoReverse default True;
    property Loop default True;
    property LoopCount;
    property OnLoop;
  end;

Implementation

I won’t post all of the code here because you can download from the link provided below, just a couple of snippets.

We need to override the FirstFrame method to initialise a couple of variables we use.

  • Checking to see if the LoopCount property is valid (raise an exception if it isn’t)
  • Initialise the variable to zero that counts the interactions
  • Make sure we are going to be checking the animation process for loops

Most of the work occurs in the overridden ProcessAnimation method.

procedure TJSCustomLoopCountFloatAnimation.ProcessAnimation;
var
  LCtx: TRttiContext;
  LType: TRttiType;
  LField: TRttiField;
  LCancel: Boolean;
begin
  inherited;
  if FCheckingLooping then
  begin
    LType := LCtx.GetType(Self.ClassInfo);
    if Assigned(LType) then
    begin
      LField := LType.GetField('FTime');
      if LField <> nil then
      begin
        if LField.GetValue(Self).AsExtended = 0 then
        begin
          Inc(FLoopsComplete);
          LCancel := False;
          if FLoopsComplete > 1 then
            DoLoop(LCancel);
          // The first time through, FTime is 0 so we need to offset this by
          // adding 1 when checking for completion
          if LCancel or (FLoopsComplete = LoopCount + 1) then
          begin
            LField := LType.GetField('FRunning');
            if LField <> nil then
              LField.SetValue(Self, False);
          end;
        end;
      end;
    end;
  end;
end;

Thanks to extended RTTI we can access a couple of private fields that we need to determine if a loop has been completed. This occurs when the FTime variable is zero. There is one issue with using this value and that is that the first “Loop” should be ignored since the first time ProcessAnimation is called FTime is zero so by the logic used, a loop has completed. This is why the DoLoop method is only called if the FLoopsComplete variable is greater than one.

Naturally it is possible to handle this one-off situation differently using a “First Time Through” variable but under the circumstances, I decided to go with the solution in place.

Once the LoopsComplete value is one greater than the LoopCount (refer to the above two paragraphs if you’ve already forgotten about why) the private field FRunning is set to False. Setting FRunning to false, stops the animation immediately.

Why not just call the public Stop method instead of going to the trouble of setting a private field? The answer to that is found in the ProcessTick method of the animation control (incidently, why isn’t this method virtual?).

  ...
  ProcessAnimation; // <==== We set FRunning to false here
  DoProcess;

  if not FRunning then
  begin
    if Assigned(AniThread) then
      TAniThread(AniThread).FAniList.Remove(Self);
    DoFinish;
  end;
  ...

By setting FRunning to false within our ProcessAnimation override, we are avoiding another frame being processed before the animation is stopped. This is because the Stop method calls ProcessAnimation and DoProcess as well.

Download

You can download the component and a cheesy demo application from the link provided. There is no package for the component to install it into your IDE, this is left as an exercise for the reader :-).

Loop Animation Demo (short video – 39KB)

Download LoopCount Component and Demo

NOTE: Before downloading the source code you must agree to the license displayed below.

License Start

This space intentionally left blank…

License End

Fixing FireMonkey: TMemo/TEdit – OnExit

Currently in the Delphi XE3 release there is a bug in the OnExit processing of TMemo and TEdit (possibly others) controls.

Issue

If you make a change in a TEdit or TMemo control and then exit the control, after the OnExit event is called, another OnChange event is called. This shouldn’t happen.

This doesn’t occur in the VCL framework and shouldn’t happen in FireMonkey.

Solution

TEdit

The fix for the TEdit cause is pretty simple. Since the FNeedChange field in TCustomEdit is protected we can use a class cracker to fix it. You could put the fix into either a new control or in either an OnExit or OnChange handler in your application.

type
  TEditClass = class(TEdit);
...
procedure Form1.OnExit(Sender: TObject);
begin
  TEditClass(Edit1).FNeedChange := False;
end;

It’s interesting to note for TEdit, FNeedChange is protected. This is because in the TCustomEditBox descendant (used by TSpinBox and TNumberBox controls), the FNeedChange field is set to False after the overriden Change method is called. Perhaps this should have triggered the developer making that change, to actually fix the issue in the ancester class.

TMemo

The fix for TMemo is more interesting because unlike the TCustomEdit class, FNeedChange is private. Thankfully extended RTTI comes into play.

I put this code where the memo content was saved to disk, you could put the code in the same spot in your applications (if applicable), or place it in either OnChange or OnExit events.

var
  LCtx: TRTTIContext;
  LField: TRttiField;
  LInst: TRttiInstanceType;
begin
  // save your memo contents
  LInst := LCtx.GetType(Memo1.ClassType).AsInstance;
  LField := LInst.GetField('FNeedChange');
  if LField <> nil then
    LField.SetValue(Memo1, False);
end;

If your save is triggered by the user selecting a control that takes focus from the memo, the OnExit event will trigger before executing the fix above. Under these circumstances, moving the fix to the OnExit event of the memo is advised.

Another TMemo Issue

The OnChange event is only triggered after typing two characters in a TMemo, the first character typed into the memo doesn’t trigger the OnChange event.

FireMonkey Style – TStyleTag

There appears to be an oversight by Embarcadero with the TStyleTag component not being registered for use.

TStyleTag is a handy little component that allows you to add it to a style definition and have it store an Integer, Float or String value. This is used in some of the default styles, one place being the TTrackBar where it is used to hold the default thumb size of the track item.

This allows you to retrieve the thumb size depending on the default style (Windows or Mac) and adjust your user interface depending on the value.

TStyleTag Component

I’ve created a package that your can compile and install into the IDE to register this component.

Download Package

The component doesn’t have to only be used in a style definition, you can drop it directly on your form if you have a use for its functionality.

NOTE: While the component is used in the default Windows and Mac styles, it doesn’t seem to be used in the other FireMonkey styles. Although I did only look in a couple of them. Perhaps something that will be address in an update.