Blog

All Blog Posts  |  Next Post  |  Previous Post

Extensions for TMS WEB Core for Delphi

Thursday, April 14, 2022

TMS Software Delphi  Components

1. Introduction

TMS WEB Core is a framework that allows the user to write JavaScript web client applications with the Object Pascal language. Therefore the Object Pascal code is transpiled to JavaScript with the pas2js compiler .

TMS WEB Core supports the three IDEs Embarcadero RAD Studio with Delphi, Microsoft Visual Studio Code and Lazarus.

This article is primarily concerned with Delphi and shows four options to extend the TMS WEB Core product:

  1. Creating design-time packages
  2. Writing custom WEB Core components
  3. Using & registering base web form classes
  4. Registering custom Frames


2. Demo

The above mentioned options are practically shown in the demo DemoPackage (download here) which contains a run-time package, a design-time package, a TMS WEB Core application and a VCL application.


3. Packages

Delphi projects can contain packages, either for regular programs and for the IDE. A package is a Delphi specific library, similar to a DLL (Dynamic Link Library) on Windows. Packages end with the extension .BPL (Borland Package Library) and are created by the compiler after compilation. When starting an application, the packages are loaded statically.

We have to differentiate between two sorts of packages. These are run-time packages and design-time packages.


3.1. Run-time Packages

A run-time package is a library that includes parts of the source code and provides parts of the functionality of the application. Instead of having one single executable, it is split into a small executable and multiple packages.


3.2. Design-time Packages

Design-time packages are used by the Delphi IDE to make components load dynamically. Therefore components must be registered. Doing this, the IDE tool palette will list the components and this allows the designer to display the components.

It is good practice to split the code into run-time code for the run-time package and register code (and any other code that might be only needed and used at design-time) for the design-time package. This design-time package for this demo is DemoPackageIDE.dproj.


3.3. How to set design-time and run-time packages

The options of a project can be set in the so called “Project Options”. There is a radio button in the section “Description”, in which the options “Run-time only” and “Design-time only” can be selected.

The option “Design-time and Runtime” can be selected, but is as mentioned above not recommended.

TMS Software Delphi  Components


3.4. Build control

It is also recommended to select “Explicit rebuild” since the option “Rebuild as needed” often leads to problems with packages that are distributed over several project groups.

TMS Software Delphi  Components


4. Writing custom TMS WEB Core components

The demo contains the unit MyFloatEdit with the component TMyFloatEdit which is a small improvement of a TWebEdit.


4.1. Registering a Component

The Delphi IDE calls all public procedures named “Register” from design-time packages. These procedures are called when the design-time package is loaded. Inside a Register procedure components can be registered. The Demo shows how this looks like:

interface

procedure Register;
implementation
procedure Register;
begin
  RegisterComponents('My TMS WEB components!!', [TMyFloatEdit]);
end;


4.2. DesignIDE package

In order to call RegisterComponents it is necessary to require the DesignIDE package in a Designtime package. The Demo shows this:

requires
...
  DesignIDE,
...


4.3. Platforms

In order to register a component the Delphi designer needs to be informed which platforms the component shall be used for (e.g. Win32, Win64 and WEB).

In the Delphi IDE all TMS WEB Core projects are treated as Windows projects. Therefore, Win32 and Win64 should be specified as compatible platforms. Since the components should be used in the Web, the WEB platform must be added as well.

For these three platforms TMS provides the constant TMSWebPlatform. It is defined in the unit WEBLib.Controls.


Here is an example of TMyFloatEdit:

uses
  ..., WEBLib.Controls;
type
  [ComponentPlatforms(TMSWebPlatform)]
  TMyFloatEdit = class(TWebEdit)
...
TMSWebPlatform = pidWin32 + pidWin64 + pidWeb;


Note: The Delphi IDE uses a platform attribute caching system. That means that when you install a package with classes with these platform attributes and then later make changes, the IDE might not immediately pick up the modified attributes. If you forget for example to add the pidWeb value in the attribute, the component will not appear in the tool palette when you have a TMS WEB Core form open. To make the IDE forget the cached attribute, you can force this by deleting the package from the registry under: HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\XX.0\Package Cache with XX the version of the IDE you are using.


5. Using base web form classes

In regular Delphi VCL applications, forms are usually derived from the class TForm. In TMS WEB Core applications things work differently. Here, forms are derived from the class TWebForm. For the Delphi IDE this means as a consequence that the regular Designer cannot be used, but a Custom Designer is needed.

This special Custom Designer is quite similar to the regular Designer that is used for TForm, with the difference that it only allows to drop Web components on the form. This means, only those components, that do have the Web attribute (containing pidWeb) TMSWebPlatform are valid and can be selected. Components, that do not have the Web attribute are filtered and cannot be selected.

For self-written base form classes the Custom Designer can be used, but the IDE has to be informed. The following code example from the Demo explains how this has to be done. Here is the base form class:

unit MyBaseForm;

interface
uses
  WEBLib.Forms;
type
  TMyBaseForm = class(TWebForm)

And this is the Register code:
procedure Register;
begin
  RegisterCustomModule(TMyBaseForm, TCustomModule);
end;


5.1. Wizard for custom web forms

To make the creation of custom web forms easier for the user the example contains a wizard that allows to create a custom web form.

TMS Software Delphi  Components

The code of the wizard is written in the unit MyWizards.pas. The interesting classes are TMyFormWizard, TMyFormCreator, TMyFormFile, TMyFormUnitFile and TMyFormHTMLFile. The HTML file is needed since every web form except the so called web direct form needs an HTML file. That is why the wizard automatically creates an HTML file for a web form.

TMS Software Delphi  Components

The IDE manages the HTML file with the {*.html} directive.

The wizard achieves this behavior with supporting the IOTAAdditionalFilesModuleCreator interface. A detailed description on how to support this interface can be seen in the source code and is perhaps part of a further article.


6. Registering custom frames

Frames are some kind of sub-forms and can be very helpful. Multiple components can be included in a single frame and can be dropped on a form in one step.

Another huge advantage is that frames are not tied to one single project, but can be used cross-project. This can save a lot of time in daily work.

The Demo shows how to create a Custom Frame that can be used in the same way as the Delphi TFrame. Therefore a wizard is needed and both, Frame and Wizard have to be registered.


6.1. Frame

Here is a typical definition of a Custom Frame:

type
  [ComponentPlatforms(TMSWebPlatform)]
  TMyBaseFrame = class(TCustomFrame)
  end;

The Custom Frame does not contain further code and should only illustrate an example.


6.2. Wizard

Creating a Wizard is very extensive, therefore only the most important points will be examined in this article.

For a Frame Wizard it is necessary to derive from a TNotifyObject and further interfaces, like IOTAWizard have to be added. Here is an example:

type
  TMyFrameWizard = class(TNotifierObject, IOTAWizard, IOTARepositoryWizard, IOTAFormWizard, IOTARepositoryWizard80, IOTARepositoryWizard160
   {$IF COMPILERVERSION > 31}, IOTARepositoryWizard190{$IFEND}
   {$IF COMPILERVERSION > 32}, IOTARepositoryWizard260{$IFEND})


6.3. Registering a Custom Frame

procedure Register;
const
  cPage = 'My TMS WEB components!!';
var
  lWizard: TMyFrameWizard;
  lWizardServices: IOTAWizardServices;
begin
  RegisterCustomModule(TMyBaseFrame, TFrameModule);
  RegisterSprigType(TMyBaseFrame, TRootSprig);
  FWizard := -1;
  if Supports(BorlandIDEServices, IOTAWizardServices, lWizardServices) then
  begin
    lWizard := TMyFrameWizard.Create;
    FWizard := lWizardServices.AddWizard(lWizard);
  end;
end;

Here, the Wizard is registered. It has to be added to the Wizard services. Please note that such a Wizard has to be unregistered if the Package is unloaded. Here it is shown how it can be done:

class procedure TMyRegister.Unregister;
var
  lWizardServices: IOTAWizardServices;
begin
  if Supports(BorlandIDEServices, IOTAWizardServices, lWizardServices) then
  begin
    if FWizard > -1 then
      lWizardServices.RemoveWizard(FWizard);
  end;
end;


Then a CustomModule is registered and this has to be done for the same reason as for the base form in the previous chapters.

RegisterSprigType also has to be called. RegisterSprigType properly prevents the designer to select, accidentally move or delete controls inside your frame, but only directly.


7. Outlook

This article gives an overview about Packages, Custom Components, Custom Forms and Custom Frames. It shows how to use these techniques in combination with the TMS WEB Core product. Particularly the Custom Frames chapter is so extensive that only the basics are shown. According to the feedback we will show further details concerning these difficult technologies.



Masiha Zemarai




This blog post has not received any comments yet.



Add a new comment

You will receive a confirmation mail with a link to validate your comment, please use a valid email address.
All fields are required.



All Blog Posts  |  Next Post  |  Previous Post