InterBase CodeRage 28th-30th November

CodeRage 9Register NOW and join me live at #CodeRage!

CodeRage is a fantastic Object Pascal programming and C++ Programming event – highly recommended for any developer, and best of all – REGISTRATION IS FREE!!

Missed it or got a meeting? – Don’t worry, register and you can still get to see the replays!

My two InterBase CodeRage Sessions!

I will be presenting two InterBase CodeRage sessions on Thursday 30th November 2014

  • the InterBase Keynote (8am Pacific / 4pm UK / 5pm CET) where we will be revealing some of the exciting new developments we are working on with InterBase with project DeltaForce!
  • I will also be talking about InterBase’s free edition that can be used on Windows, Mac OS X, Android and iOS – IBLite in the session Embedding local and remote data access into your applications with IBLite (3pm – C++ & 6pm – Object Pascal)

For times and details of all sessions visit the CodeRage website – See you there!!

 

Adding VCL Styles at runtime

VCL Styles

An example before & after

Screen Shot 2014-10-22 at 06.09.20VCL Styles at run time

VCL Styles provide a great way to update the look and feel of your VCL applications.  VCL Styles can be easily added into an application before you compile through  project options > appearance options.

Adding VCL Styles to Project : Options : Appearance
Adding VCL Styles via Project : Options : Appearance

While you can add VCL Styles into the application binary this way, they will increase the size of the application. If you want to avoid this, (or maybe run a mix of compiled in and dynamically loaded) you can distribute styles along side your application.

By default, VCL Styles are located at the following file path when installing your IDE.

C:\Users\Public\Documents\Embarcadero\Studio\15.0\Styles

A full overview of them is available on docwiki  http://docwiki.embarcadero.com/RADStudio/XE7/en/VCL_Styles_Overview

TStyleManager

Styles are managed via TStyleManager, a class located in unit VCL.Themes.

TStyleManager is a sealed class with a number of class methods that allow you to interact with the global application settings for the styles.

Some key properties on TStyleManager

  • TStyleManager.StyleNames – an array of the styles available in the application.
  • TStyleManager.SetStyle(StyleName : string) – the call to set the application style to a new style

Using these basic methods, its possible to implement code that loops the styles in the application and makes them available to a menu that can then be used at run time to choose which style is selected.

  • TStyleManager.IsValidStyle(FileName: string) – checks a file is a valid style
  • TStyleManager.LoadFromFile(FileName : string) – loads a style up from file.

With the additional file based calls its possible to check for style files and load those into your application as well.  – So lets do that!

VCL Styles code example

The MastApp demo that is installed by default with RAD Studio has an example of using TStyleManager. You can find the demo at:

C:\Users\Public\Documents\Embarcadero\Studio\15.0\Samples\Object Pascal\Database\IBX\IBMastApp

This demo uses 2 code parts and 1 design time selection element to provide styles in the demo.

Part 1 – Compiling VCL Styles into your application.

Open the project and then choose Project > Options and go to appearance. As above, select a couple of styles and run the application. You will then see the Styles menu is updated to show these styles.

The initial code to build the menu loops the StyleNames, creates a menu item for each style, adds then links to an OnClick event to change the style.

Part 2 – Building the style list menu

procedure TMainForm.FormCreate(Sender: TObject);
var
 Style: String;
 Item: TMenuItem;
begin
 //Add child menu items based on available styles.
 for Style in TStyleManager.StyleNames do
 begin
   Item := TMenuItem.Create(StyleMenu);
   Item.Caption := Style;
   Item.OnClick := StyleClick;
   if TStyleManager.ActiveStyle.Name = Style then
     Item.Checked := true;
   StyleMenu.Add(Item);
 end;
end;

Step 3 – OnClick event for the Style selected.

procedure TMainForm.StyleClick(Sender: TObject);
var
 StyleName: String;
 i: Integer;
begin
 //get style name
 StyleName :=   StringReplace(TMenuItem(Sender).Caption, '&', '',
 [rfReplaceAll, rfIgnoreCase]);
 //set active style
 TStyleManager.SetStyle(StyleName);
 //check the currently selected menu item
 (Sender as TMenuItem).Checked := true;
 //uncheck all other style menu items
 for I := 0 to StyleMenu.Count -1 do begin
   if not StyleMenu.Items[i].Equals(Sender) then
     StyleMenu.Items[i].Checked := false;
 end;

end;

So: We have styles working, but you can also load them from file with very little change to the application.

Loading Styles from file and displaying them in the list of styles

VCL Styles can be loaded at run time easily using TStyleManager.LoadFromFile

Using the existing demo, its possible to have it check for a styles sub folder and read any file in there to see if its a valid style.  To do this, we just need to use FindFirst, iterate the returned files and then if they are valid (something we can use TStyleManager.IsValidStyle to determine) load the files.

So the updated code looks something like this block below where we first build the path to check for VCL Style files; then check the folder exists, and if it does check each file to see if its a valid VCL Style (before loading it).  Secondly, using a TStringList the styles loaded are sorted and then the sorted list is used now to build a menu for selecting the styles.

procedure TMainForm.FormCreate(Sender: TObject);
var
 Style: String;
 Item: TMenuItem;
 i: integer;
 searchResults : TSearchRec;
 SearchDir: string;
 SLStyles: TStringList;
begin
 SearchDir := ExtractFilePath(ParamStr(0))  
                 +'styles'+ PathDelim;
 if DirectoryExists(SearchDir) then begin
   if FindFirst(SearchDir+'*.*',  
                faAnyFile - faDirectory,
                searchResults) = 0 then
   repeat
     try
       if TStyleManager.IsValidStyle(
            SearchDir+searchResults.Name) then
          TStyleManager.LoadFromFile(
             SearchDir+searchResults.Name);
     except
       // Who cares.. try the next one.
     end;
   until FindNext(searchResults) <> 0;
 end;
 // Sort the styles using a StringList 
 SLStyles := TStringList.Create;
 try
   SLStyles.Duplicates := TDuplicates.dupIgnore;
   for Style in TStyleManager.StyleNames do
     SLStyles.Add(Style);
   SLStyles.Sort;

   PMStyles.Items.Clear;
   // build menu from sorted list of styles
   for Style in SLStyles do begin
     Item := TMenuItem.Create(StyleMenu);   
     Item.Caption := Style; 
     Item.OnClick := StyleClick; 
     if TStyleManager.ActiveStyle.Name=Style then 
       Item.Checked := true; 
     StyleMenu.Add(Item);
   end;
 finally
   SLStyles.Free;
 end;
end;

Thats it! You can now create a sub folder for VCL styles that you ship along side your application or deploy at a later point.

For C++ use the same classes and units, just with the C++ Loops and constructs. more on VCL Styles with C++ can be found on docwiki

 

Expanding FireMonkey TPlatformServices

Over this post, I want to introduce the concept of an Interface and then look at how using Interfaces allows you to expand the FireMonkey TPlatformServices in XE7 – using an example of adding custom support for FullScreen mode on iOS, where it currently isn’t supported out the box.

Interfaces & OOP – Quick Introduction.

For those of you who are aware of what an interface is, you way want to skip the first sections.

Delphi & AppMethod are built on top of the Object Pascal programming language which, as its name suggests is an Object Orientated Programming language – OOP.

Part of OOP is the concept of Interfaces;  Interfaces are in short a contract that classes can then implement and support. Unlike object inheritance (where you can only descend from a single object), an object can introduce and support multiple interfaces at the same time. The great thing about Interfaces is the ability to ask an object if it supports a specific Interface, and if it does, telling it to go do a specific supported method.

Example of an Interface – ISteeringWheel

I am sure we all know what a steering wheel is so lets imagine we have defined in our code an interface ISteeringWheel that can be turned left and turned right with two method TurnLeft and TurnRight

type 
  ISteeringWheel = Interface
  ['{F4F8536B-FCA6-48D1-B3D4-AF4EE9B90964}']
    procedure TurnLeft;
    procedure TurnRight;
  end;

But where are we going to use this SteeringWheel? It could be on a TCar or a TBoat or even a TAirplane.

The job of implementing the code and what happens when you call a method of an Interface is down to the object that supports that interface.

TCar = class(TInterfacedObject, ISteeringWheel)
public
  // Turns wheels
  procedure TurnLeft;
  procedure TurnRight;
end;

TBoat = class(TInterfacedObject, ISteeringWheel)
public
  // Changes the rudder
  procedure TurnLeft;
  procedure TurnRight;
end;

How does this relate to Platform Services?

If we think about phones, tablets, laptops etc, not all devices support the same capabilities; e.g. my iPad doesn’t have a sim card so doesn’t support making calls.  FireMonkey works with this complexity by defining Interfaces that can be queried at run time to determine if a device supports specific capabilities.  By having a contract in code, the platforms are then able to provide to you an object that supports the platform, but also the Interface.

Using our example above, lets imagine, TCar and TBoat are like Android and iOS, and the SteeringWheel is a compass, then you would start to understand that by asking at run time if the compass is supported, we get an iOS or Android object that we know how to talk to as it supports the appropriate interface, but under the hood calls the platform specific API’s.

TPlatformServices and IFMXFullScreenWindowService

So now we understand about Interfaces and how to use them, lets look into a real implementation and how we can use this to update the way the system works by providing a supported Interface.

The IFMXFullScreenWindowService interface supports 3 methods that allow you to find out if the application is running in FullScreen mode (Get), or put it into FullScreen mode (Set) and also define if the Icon is seen.

(I’ve removed the parameters here to make it more readable)

IFMXFullScreenWindowService = interface(IInterface)
  ['{103EB4B7-E899-4684-8174-2EEEE24F1E58}']
  procedure SetFullScreen(....);
  function GetFullScreen(....): Boolean;
  procedure SetShowFullScreenIcon(....);
end;

This Interface has been used by TCommonCustomForm and descendants (of which TForm is the one you will probably be using) and wrapped up into an easy to call property – FullScreen.

To change between full screen and non full screen at run time is as simple as

procedure TForm1.Button1Click(Sender: TObject);
begin
  FullScreen := not FullScreen;
end;

This property was introduced in RAD Studio XE7 / Appmethod September 2014 release and works on Windows, Mac OS X, and Android (Immersive mode). However, there is not an implementation for iOS.

While each platform behaves differently according to its design and platform norms, I want to show you how you can add support for iOS without having to change the common code that works on the other platforms.

Under the hood – FullScreen & TPlatformServices

So first, before we add the service I also want to cover for other examples how you check for a supported PlatformService Interface.

FireMonkey’s TPlatformServices (defined in FMX.Platform)  exposes the instance of TPlatformServices using the Current property.

TPlatformServices.Current

Once you have the Current TPlatformServices instance it can be queried for support of specific interfaces. One of those new interfaces is the IFMXFullScreenWindowService. To find out if it is supported we need to create a variable to point to the service and then ask if its supported. e.g.

var 
  FFullScreenSrvice: IFMXFullScreenWindowService;
begin
  TPlatformServices.Current.SupportsPlatformService(IFMXFullScreenWindowService, FFullScreenSrvice);
  if FFullScreenSrvice <> nil then 
    // its supported - make full screen
    FFullScreenSrvice.SetFullScreen(True);
end;

Once you have an instance of the Interface, you can then just call its methods. There is no need to free an interface as they are reference counted on all platforms.

Adding a new Interface implementation to TPlatformServices

To add a new platform service we again go back to TPlatformServices. There is a method called AddPlatformService. This takes 2 parameters, Firstly the interface you want to add and secondly the instance of an class supporting that Interface.

Using what we learned earlier about creating an object that supports and interface we first need to define a class (TFullScreenServiceiOS) defined  as a TInterfacedObject supporting the desired interface (IFMXFullScreenWindowService).

Full code can be downloaded from code central so you can see how GetFullScreen and SetFullScreen were fully implemented in code.

TFullScreenServiceiOS = class(TInterfacedObject,   IFMXFullScreenWindowService)
public
  function GetFullScreen(....): Boolean;
  procedure SetFullScreen(....);
  procedure SetShowFullScreenIcon(....);
end;

WIth the object defined and implemented, you can then register an instance with the application at run time.  As I only want this to register for iOS, one approach is to use IFDEF’s to call a register procedure during the initialisation of the application.

procedure RegisterFullScreenServiceiOS;
begin
  FullScreeniOS := TFullScreenServiceiOS.Create;
  TPlatformServices.Current.AddPlatformService(
     IFMXFullScreenWindowService, FullScreeniOS);
end;

{$IFDEF IOS}
initialization
  RegisterFullScreenServiceiOS;
{$ENDIF}

With this code in place, it is now possible to run the same application code on iOS and see the FullScreen := not FullScreen move the application in and out of FullScreen mode as it is now supported in iOS.

Summary

Thats it! –  Creating a new class that implements code and supports the interface and registering the class to the TPlatformServices is all you need to do to expand and modify the TPlatformServices.

The full source code for the TPlatformServices and IFMXFullScreenWIndowServices example can be downloaded from code central  http://cc.embarcadero.com/item/30023

Mobile Development Lessons – Delphi & C++

Free series of mobile development lessons for Android and iOS based on C++ and Object Pascal.

Earlier in the year the 2nd edition of the mobile development summer school was run by David I and Jim McKeeth. It was great fun doing the first edition and its amazing to see how some of the tech has moved on further in the year since we first ran summer school. This years was more popular than ever and has been made available on YouTube

YouTube Playlist for video replays

https://www.youtube.com/playlist?list=PLwUPJvR9mZHhLj-gegxc0KpGE0wL2zVBo

Blogs for slides and samples:

To get started is easy!

Download your free trial of RAD Studio https://downloads.embarcadero.com/free/rad_studio

or your FREE edition of Appmethod (C++ Free for Android mobile)
http://www.appmethod.com 

Happy Coding!