Sie sind auf Seite 1von 40

D E L P H I,

L A Z A R U S,
O X Y G E N E,
S M A R T M O B I L E,
A N D
P A S C AL
R E L A T E D
L A N G U A G E S
A N D R O I D,
I O S,
M A C,
W I N D O W S
&
L I N U X

BLAISE PASCAL MAGAZINE 52

GENERICS EXPLAINED / PART 1


BY DETLEF OVERBEEK
TURBO COCOA FOR DELPHI AND ANDROID
BY VSEVOLOD LEONOV
TMS FNC USER INTERFACE CONTROLS,
A SET OF FRAMEWORK NEUTRAL CONTROLS,
INTRODUCTION
BY BRUNO FIERENS
HUMOR BY KIM MADSEN
SOFTDRAW
BY DAVID DIRKSE
HOW TO BUILD AN APP IN XML WITH FIREMONKEY
INCLUDED STYLE SHEETOVERVIEW
BY DETLEF OVERBEEK
HOW TO DEAL WITH BIG NUMBERS
BY MAX KLEINER

PRINTED ISSUE PRICE 15,00


DOWNLOAD ISSUE PRICE 5,00

BLAISE PASCAL MAGAZINE 52


D E L P H I,
L A Z A R U S, S M A R T M O B I L
A N D
P A S C A L
R E L A T E D
L
A
N
F O R
A N D R O I D,
I O S, M A C,
W I N D O W S

E
S T U D
G
U
A
G
& L I N U X

I
E

O,
S

CONTENTS
ARTICLES
FROM THE EDITOR PAGE 4
GENERICS EXPLAINED / PART 1 PAGE 5
BY DETLEF OVERBEEK
TURBO COCOA FOR DELPHI AND ANDROID PAGE 9
BY VSEVOLOD LEONOV
TMS FNC USER INTERFACE CONTROLS,
A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 15
INTRODUCTION
WHO!? ME!?
BY BRUNO FIERENSW
HUMOR BY KIM MADSEN PAGE 23
SOFTDRAW PAGE 24
BY DAVID DIRKSE
HOW TO BUILD AN APP IN XML WITH FIREMONKEY PAGE 27
INCLUDED STYLE SHEETOVERVIEW
BY DETLEF OVERBEEK
HOW TO DEAL WITH BIG NUMBERS PAGE 36
BY MAX KLEINER

FNC
FRAMEWORK NEUTRAL COMPONENTS

maXbox

Advertisers
BARNSTEN 14
COMPONENTS 4 DEVELOPERS 40
COMPUTER MATH AND GAMES 26
TURBO COCOA 13

Publisher: Foundation for Supporting the Pascal Programming Language


in collaboration with the Dutch Pascal User Group (Pascal Gebruikers Groep)
Stichting Ondersteuning Programmeertaal Pascal

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

Stephen Ball
http://delphiaball.co.uk
@DelphiABall

Peter Bijlsma -Editor


peter @ blaisepascal.eu

Dmitry Boyarintsev
dmitry.living @ gmail.com

Michal Van Canneyt,


michael @ freepascal.org

Marco Cant
www.marcocantu.com
marco.cantu @ gmail.com

David Dirkse
www.davdata.nl
E-mail: David @ davdata.nl

Benno Evers
b.evers
@ everscustomtechnology.nl

Bruno Fierens
www.tmssoftware.com
bruno.fierens @ tmssoftware.com

Primo Gabrijeli
www.primoz @ gabrijelcic.org

Fikret Hasovic
fhasovic @ yahoo.com

Cary Jensen
www.jensendatasystems.com
http://caryjensen.blogspot.nl

Peter Johnson
http://delphidabbler.com
delphidabbler@gmail.com

John Kuiper
john_kuiper @ kpnmail.nl

Wagner R. Landgraf
wagner @ tmssoftware.com

KimMadsen
Madsen
Kim
www.component4developers
kbm
@ components4developers.com

Andrea Magni
www.andreamagni.eu
andrea.magni @ gmail.com
www.andreamagni.eu/wp

Boian Mitov
mitov @ mitov.com

Jeremy North

Detlef Overbeek - Editor in Chief


www.blaisepascal.eu
editor @ blaisepascal.eu

Howard Page Clark


hdpc @ talktalk.net

Heiko Rompel
info@rompelsoft.de

Wim Van Ingen Schenau -Editor


wisone @ xs4all.nl

Peter van der Sman


sman @ prisman.nl

Rik Smit
rik @ blaisepascal.eu
www.romplesoft.de

Bob Swart
www.eBob42.com
Bob @ eBob42.com

B.J. Rao
contact@intricad.com

Daniele Teti
www.danieleteti.it
d.teti @ bittime.it

Anton Vogelaar
ajv @ vogelaar-electronics.com

Siegfried Zuhr
siegfried @ zuhr.nl

Max Kleiner
www.softwareschule.ch
max @ kleiner.com

jeremy.north @ gmail.com

Editor - in - chief
Detlef D. Overbeek, Netherlands Tel.: +31 (0)30 890.66.44 / Mobile: +31 (0)6 21.23.62.68
News and Press Releases email only to editor@blaisepascal.eu
Editors
Peter Bijlsma, W. (Wim) van Ingen Schenau, Rik Smit,
Correctors
Howard Page-Clark, James D. Duff
Trademarks
All trademarks used are acknowledged as the property of their respective owners.
Caveat Whilst we endeavour to ensure that what is published in the magazine is correct, we cannot accept responsibility for any errors or omissions.
If you notice something which may be incorrect, please contact the Editor and we will publish a correction where relevant.
Subscriptions ( 2013 prices )
1: Printed version: subscription 80.-- Incl. VAT 6 % (including code, programs and printed magazine,
10 issues per year excluding postage).
2: Electronic - non printed subscription 50.-- Incl. VAT 21% (including code, programs and download magazine)
Subscriptions can be taken out online at www.blaisepascal.eu or by written order, or by sending an email to office@blaisepascal.eu
Subscriptions can start at any date. All issues published in the calendar year of the subscription will be sent as well.
Subscriptions run 365 days. Subscriptions will not be prolonged without notice. Receipt of payment will be sent by email.
Subscriptions can be paid by sending the payment to:
ABN AMRO Bank Account no. 44 19 60 863 or by credit card: Paypal
Name: Pro Pascal Foundation-Foundation for Supporting the Pascal Programming Language (Stichting Ondersteuning Programeertaal Pascal)
IBAN: NL82 ABNA 0441960863 BIC ABNANL2A VAT no.: 81 42 54 147 (Stichting Programmeertaal Pascal)
Subscription department Edelstenenbaan 21 / 3402 XA IJsselstein, The Netherlands / Tel.: + 31 (0) 30 890.66.44 / Mobile: + 31 (0) 6 21.23.62.68
office@blaisepascal.eu

Copyright notice
All material published in Blaise Pascal is copyright SOPP Stichting Ondersteuning Programeertaal Pascal unless otherwise noted and may
not be copied, distributed or republished without written permission. Authors agree that code associated with their articles will be made
available to subscribers after publication by placing it on the website of the PGG for download, and that articles and code will be placed on
distributable data storage media. Use of program listings by subscribers for research and study purposes is allowed, but not for commercial
purposes. Commercial use of program listings and code is prohibited without the written permission of the author.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

From the editor

he summer just started, and finally it's


getting warmer. You now see butterflies are
all around us, so I found it striking that some
of their patterns and textures sometimes look like
small pictures, and that is how I thought of smart
mobiles: they're everywhere and appear to be some
sort of insects. It's inevitable to be in contact with
them.
So I thought better to be in control of them and
create my own apps for SM (Strange abbreviation).
The first problem one finds is how to use text
exchange on mobile data. But the problem is, at
least in principle, easy to solve: Try XML (eXtensible
Markup Language). So that is what we did.
You can find that in the article on page 27: How
to build an app with XML. During my research I
found that styles from which you can choose when
you use FMX are available, but you can't preview to
make an easy choice. So we helped that out in the
same article. For our subscribers there will be a
special PDF file on a larger format to have a better
view and use it separately in your toolbox.
This article is only the beginning of what I
hope will be a long list of how to create apps for
FMX. I will try to find out how to make your own
styles and write something about that.
Originally, I had planned for an article about
from Delphi code to Raspberry. But it wasn't as
easy as I hoped for: the only way to get that done is
in a number of steps and it will not be easy: first
create your app in (VCL) Delphi. Then set that code
to Lazarus. Go to a Raspberry Pi version of your
choice and make sure Lazarus is running on your
Raspberry Pi. The higher the version the better the
compile time will be.
I have asked Michael van Canneyt to write
down these steps and create an app on it. But be
cautious: making the Delphi project for Lazarus
available won't be easy. It will have to be done with
trial and error. It always is about learning
Spoken of learning: we have just now
established the DELPHI-PASCAL-ACADEMY. The
institute will be officially registered at the CRKBO
(Central Register Kort Beroepsonderwijs, a Dutch
register for professional educations).
Since we have started to do lessons and
seminars, this is a logical next step: we are very
often asked if there is a possibility for creating and
teaching. The educational languages will be
English and Dutch.

This is an institute you can become a member of


as a person or Company. As a person you can then
follow lessons. As a member you will be able to get
study material etc. depending on the subject, and
we will write that material if it is not available.
All other information will soon become available
on the internet and in our Magazine as well on
twitter etc. n our Magazine as well on twitter etc.
Something to learn about: we have started a
series of articles to explain in depth what Generics
is and how to use it and see the advantages they
are huge! We also will talk about Anonymous
methods - what they are and how to use them.
We want to do as much as possible for our
community and therefore please tell us what you
want to know about, or what subjects we should
use for your interest. We have lots of plans:
there is a project that is still on the shelf, such as the
Leap. It is a tremendous challenge because
Windows is changing all the way, and the
hardware might do so as well as the software of the
Leap itself.
What we want with it is still not being picked up by
the Leap itself. I'll write an article how far we have
come until now and show some examples of what
we have done. It is a while ago that we started that
project and want you to know what the position
now is. We still plan to finish it but it is a
tremendous challenge
Speaking about plans: we will publish a new book
(with examples code etc.) to start learning Delphi
from start up to FMX and Android.
Bruno Fierens has started a very special thing
about FNC (framework neutral components) he is
blogging about this subject and he also will explain
how you as a reader could try to create your own
FNC components. I think that's great news.
The best news about Delphi Berlin is that the
designer form is back! It gives you the old
fashioned feeling of Delphi 7 and that in a very
modern version. I am glad Idera did this!
In September 2016 we plan to do the next Big
Delphi Conference and are trying again to have
some guest speakers that will surprise you.
I have always wanted to have a humoristic page
about IT. I found a guy called Kim Bo Madsen. I
hope you like these first two installments. Please let
us know.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

GENERICS EXPLAINED / PART 1

PAGE 1 / 4

type
List<Item> = class
...
end;

BY DETLEF OVERBEEK
starter

to distinguish procedures from lambda


expressions and symbols, to use a single lexical
INTRODUCTION
environment for all variables, and to evaluate the
In this series of articles we want to explain what operator position of a procedure call in the same way as
Generics is and what you can do with it.
an operand position.
By relying entirely on procedure calls to express
We will give you diagrams, overviews, simple
iteration, Scheme emphasized the fact that tailexamples and more complex examples. This all
recursive
procedure calls are essentially goto's that
because Generics is a very important technique
pass
arguments.
Scheme was the first widely used
and can make designs easier better and: faster.
programming language to embrace first class escape
procedures, from which all previously known
HISTORY OF GENERICS
sequential control structures can be synthesized. More
The phrase Generic programming recently, building upon the design of generic
was originated by David Musser and
arithmetic in Common Lisp , Scheme introduced the
Alexander Stepanov.
concept of exact and inexact numbers. Scheme is also
Generics are derivatives of Generic Programming for
the first programming language to support hygienic
Java. This concept specifies the type of the objects
macros, which permit the syntax of a block-structured
stored in a Java Collection. In 1998 Philip Wadler created
language to be extended reliably.)
expert
Delphi 2009 and up

Generic Java, an extension on the Java language to


support generic types.

In 2004 Generics was added to the Java-language,


as a part of J2SE 5.0. Before Generics each variable
declaration needed a specific type.
To container Classes this is a problem:
there is no easy way to create a container which
allows only specific types (Strings or integers etc.)
and accepts them from objects. (Either the container
influences all subtypes of a class). Usually an object
had to be created, or another container class to be
created for each inherited subclass.
Generics will allow type control during compile
time, without creating a lot of container-classes.
Each container contained almost identical code.
Generics make the writing of a program more
efficient because only one container needs to be
created. Besides offering more efficient coding,
some exceptions are changed to Compile-TimeErrors, which is known as Type-Safety.
The desire for a language to better support Generic
Programming led Alexander Stepanov and David
Musser through Scheme *, Ada ** and finally
to C++***, where Generic Programming has
been most successful.
SCHEME *

is a statically scoped and properly tail-recursive


dialect of the Lisp programming language invented by
Guy Lewis Steele Jr. and Gerald Jay Sussman.
It was designed to have an exceptionally clear and
simple semantics and few different ways to form
expressions. A wide variety of programming
paradigms, including imperative, functional, and
message passing styles, find convenient expression in
Scheme. Scheme was one of the first programming
languages to incorporate first class procedures as in
the lambda calculus , thereby proving the usefulness of
static scope rules and block structure in a dynamically
typed language. Scheme was the first major dialect of

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

Lisp

ADA**

is a structured, statically typed, imperative,


wide-spectrum, and object-oriented high-level
computer programming language, EXTENDED
FROM PASCAL AND OTHER LANGUAGES.
It has built-in language support for
design-by-contract, extremely strong typing,
explicit concurrency, offering tasks, synchronous
message passing, protected objects, and nondeterminism. Ada improves code safety and
maintainability by using the compiler to find errors in
favor of runtime errors. Ada is an international
standard; the current version is known as Ada 2012.
Ada was originally designed by a team led by Jean
Ichbiah of CII Honeywell Bull under contract to the
United States Department of Defense (DoD) from
1977 to 1983 to supersede the hundreds of
programming languages then used by the DoD. Ada
was named after Ada Lovelace (18151852), who is
credited with being the first computer programmer.)
C++

is a general-purpose programming language. It has


imperative, object-oriented and generic programming
features, while also providing facilities for low-level
memory manipulation. It was designed with a bias
toward system programming and embedded, resourceconstrained and large systems, with performance,
efficiency and flexibility of use as its design highlights.
C++ is a compiled language, with implementations of
it available on many platforms and provided by various
organizations, including the FSF, LLVM, Microsoft,
Intel and IBM and Embarcaderos Delphi . The current
C++14 standard supersedes these and C++11 , with
new features and an enlarged standard library. C++
was developed by Bjarne Stroustrup at Bell Labs since
1979, as an extension of the C language as he wanted
an efficient and flexible language similar to C, which
also provided high-level features for program
organization.)

GENERICS EXPLAINED / PART 1 PAGE 2/4


WHAT IS SO SPECIAL ABOUT
GENERICS?
As soon as you have written a class that uses
generic type parameters (GENERICS) you can
use that class with whatever type or a type you
have chosen yourself. And that for each sort of
use of a class to create that class.
The chosen type will now become available as
method-parameters, returns types and property
types. You do not have to typecast* the types or
to convert them.
*typecasting changes the data type into another.
Delphi is a strict-type-casting-language , which
means that if you want to use an integer as a
string, just create a string.
But typecasting gives you the possibility of
converting one type into another, like:
(integer) 123456 = (string) '123456'.
So you do not have to convert.
i := integer(f) ;
// Treats f as an integer
i := f as integer ; // Fails with non-object types

As an example: most developers have in the past


used a TObjectList. You can use it as is, and
insert Objects and remove them out again.
But that requires that you collect the Objects from
TObjects each time you use them and turn them
into WhatEverObject_ClassName. You could
also write a descendant class of TObjectList
and override () the TObject-members with
your (custom) types. But that also concerns the
Class that only will work with your own type.
An example:
You use a Generic TObjectList .
TobjectList <TmyCustomType> and the
corresponding methods (procedures or functions)

will accept parameters of the type


TmyCustomType and add the collection
TmyCustomType-objects in stead of Tobject.

So you don't have to wite special code to make it


available for TMyCustomType.
That is one of the advantages that GENERICS
offers. This happens by creating the class with a
placeholder for a runtime-type .
Just watch the < T >. The brackets before and
after are called Angled Brackets (<>).
During runtime, you give the type of the class, as
soon as you declare it.
Then this type replaces your placeholder
by the class if you create it as Object.
The declaration of a Generic Class equals the
declaration of a normal class, record or interface
type.

type
List<Item> = class
...
end;

The difference is that a list - of one or more type


parameters - will be placed between Angled
Brackets (< ... >) type-identifier in the
declaration of a Generic.
A type parameter can be used as a type-identifier
within a container type declaration and a
method-body.
Type
// TKey en TValue zijn type parameters
TPair<Tkey,TValue> = class
FKey: TKey;
FValue: Tvalue;
function GetValue: TValue;
end;
function TPair<TKey,TValue>.GetValue: TValue;
begin
Result:= FValue;
end;

TYPE ARGUMENT
Generic types are created by declaring of typearguments.
In Delphi, you can use whatever type as a type
argument except the following:
a static array,
they are called static because their size is static,
and because they use static memory.
a short string ,
is a counted-array of (ANSII) characters, up to
255 characters in the string. The first byte of this
array stands for the length of the string.
Since this was the most important string type in
Delphi 1 (16 bit Delphi), it now is only used as
the ShortString because of backwardcompatibility.
a record type
which contains a field of a derived (recursive)
type like one or more of these types.

type
TWatDanOok<T> = class
FData: T;
end;
var
F: TWatDanOok<Integer>;
// 'Integer' is het type argument van TwatDanOok<T>
begin

...
end.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

GENERICS EXPLAINED / PART 1 PAGE 3/4


EXPLANATION OF THE DIAGRAM
On the next page you will find a diagram which
describes what the differences are, if you would
use a program that is compiled with generic types
or if you would do that with one of the very often
used types: variants. It shows how much
faster the use of generics is in that case.
VARIANTS
(Partly from the Delphi Helpfiles)
Sometimes we want to juggle with data whose
type varies or cant be found at compile time
because there is no other option.
Then an option would be using variables and
parameters of type Variant, that represent
values which can change type at run time .
Variants are more flexible but need more memory
than regular variables, and working with them
needs more time: they are slower than statically
bound types.
Moreover, not permitted (illegal) operations on
variants mostly result in run-time errors, where
similar mistakes with regular variables would
have created exceptions at compile time.
As default, Variants can hold values of any
type except records, sets, static arrays, files,
classes, class references, and pointers. Variants
can hold anything but structured types and
pointers.
They can hold dynamic arrays , and they can
hold a special kind of static array called a
variant array . Variants can mix with other
variants and with integer, real, string, and
Boolean values in expressions and assignments;
the compiler automatically performs the
necessary type conversions. That why it is more
slow and time consuming.
NOTE:
Variant records are considered inherently
"unsafe."
A variant record is very similar to using the
"absolute" directive because the variant field
parts of the record are literally overlaid in
memory atop each other. You can assign a value
as one type and then read it out as a different
type. If you are using variants, you might see
compiler warnings about unsafe code, such as
W1047 Unsafe code '%s' (Delphi).

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

type
List<Item> = class
...
end;

On 32-bit platforms,
a variant is stored as a 16-byte record.
On 64-bit platforms,
a variant is stored as a 24-byte record.
A variant record consists of a type code and a
value, or a pointer to a value, of the type
specified by the type code. All variants are
initialized on creation to the special value
Unassigned. The special value Null indicates
unknown or missing data.
The standard function VarType returns a
variant's type code.
The varTypeMask constant is a bit mask
used to extract the code from VarType's return
value, so that, for example,
VarType(V) and varTypeMask = varDouble
returns True
if V contains a Double or an array of Double .
(The mask simply hides the first bit, which indicates
whether the variant holds an array.)
The TVarData record type defined in the
System unit can be used to typecast variants and
gain access to their internal representation.
In the coming issues we will go on to explore the
Generic Class , the use of it by creating a number
of programs that show in detail how to handle it
and show the advantages of a not so new trend
of using Generics - but slowly its becoming clear
how great this NEW class is....

type
List<Item> = class
...
end;

GENERICS EXPLAINED / PART 1 PAGE 4/4


ADVANTAGES OF GENERICS IN COMPARISON WITH VARIANTS
USING VARIANT

USING GENERICS

CPU

MEMORY

COMPILER

USING VARIANT

USING GENERICS

SLOWER DURING RUNTIME

MUCH FASTER DURING RUNTIME

Compiles

PROGRAM

PROGRAM

Creates Generics

Program Starts

All kind of types


ra
g ger ay t
te
n
e
i
r
s
e
c
r
t Ar
Li Et
St In
Creates as little as possible units

SLOWER DURING COMPILETIME

Uses Variant type


Create String
Create Int
Create Array
Create String
Create Int
Create Array
Run
Create
Create
Run Array
Run String
Create
Run Int
Run
Run
Run
Run
Run
Free
Run
Run
Run
Free
Free
Free
Free
Free
Free
Free
Free
Free
Free
Free

Program starts
Uses Strings
is already created

Uses Integer
is already created

Uses Array
is already created
Program stops

Compiler clears
Generics

SLOWER DURING RUNTIME,


MUST BE CREATED OVER AND OVER AGAIN

Uses Variant Integer


Uses Variant String
Uses Variant Array
EARLIER

LATER

Program stops

MUCH FASTER DURING


RUNTIME OF THE PROGRAM
SLOWER DURING COMPILE TIME PERIOD

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

SLOW DURING RUNTIME OF THE PROGRAM

COMPILES FAST

SLOWER DURING COMPILE TIME PERIOD

MUCH FASTER DURING RUNTIME OF THE PROGRAM

Compiles

TURBO COCOA FOR DELPHI AND ANDROID PAGE 1/4


BY VSEVOLOD LEONOV
starter

expert

Delphi

INTRODUCTION
Previously, we've considered how TurboCocoa - as
an additional tool for Delphi 10.1 Berlin - can be
used for creating true-native apps for iOS.
In addition, we've discussed why native controls and
native app architecture are important.
Now we'll show, how to make platform oriented
applications for Android with Delphi.
Delphi developers since XE2 have many options in
project types when developing applications from the
viewpoint of platforms. In the world of mobile app
development the choice is between multi-device
projects on the base of the same codebase,
including UI forms, and platform-specific projects
with the help of TurboCocoa and Delphi.
The mechanism of the last approach is simple:
one uses Android Studio as a native development
tool for designing UI, and then use the design only in
Delphi project with full power of modern Object
Pascal and non-visual components, including data
access ones, and any of business logic and
algorithmic code (See Figure 1).

Fig. 1. Schematics of TurboCocoa project.

The reasons of using TurboCocoa with


Delphi are mutiple
App size
Performance
Native look & feel for particular device
/Android version
Same developer capabilities as in case
of use Android Studio
Natural behavior of UI and same UX in
comparison with native app.
The reasons are not of equal importance for
Delphi developers. Some may want the same
power, as Android Studio users. Some may want
to avoid criticism for size and speed, some may
want not to imitate, but secure native UX for
demanding customers.
But we must warn you, to get all these you'll
need to switch from classic way of designing
forms with VCL/FM to Android Studio .
Nevertheless, the form designer is only you
need to know in Android Studio, while
principles of User Interface visual modeling are
the same, and you'll see this further.
First, you need Delphi 10.1 Berlin installed on
your PC.
Second, visit www.turbococoa.com and
download free beta.
Third, install TurboCocoa on your machine as
Delphi add-on, and start a new project from
menu Other . Then select Turbo.Android and
Single Activity Application (See Figuur 2).

Fig. 2. Starting a new project for TurboCocoa Android application

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

TURBO COCOA FOR DELPHI AND ANDROID PAGE 2/4


Once you selected the project type and pressed
button, TurboCocoa generates for you a
specific project, which can build a true native
Android application from Object Pascal source
code and UI design.
For the first time, you may be asked for paths,
which is rather typical. If you ever tried Android
development in Delphi, you know how to set
paths for Android SDK in Delphi IDE SDK Manager.
The dialog is a little bit different, while the paths
are the same, you can just manually copy them
from SDK Manager (See figure 3).
OK

The project doesn't include kind of dfm/fmx


files, which can be used to make a UI design in
Delphi IDE. Instead (according to described
mechanics how TurboCocoa works) you right click
on Android_test_1 node in ProjectManager and
select Launch Android Studio .
Don't be disappointed at first glance, the IDE is
different, the principles are the same.
Just start designing the interface:
In the Palette
window find section
Text Fields

Figuur 3: Paths settings

After finding right paths and setting folder and


project name, it is generated by TurboCocoa, and
we can start looking at its structure (See figure 4
below).

Drag and drop


Plain Text onto
entire area of the
mobile form
Find section Widgets ,
then drag and drop
Button control
onto the form
Find section
Text Fields and put
Plain Text on the form

Please, note, visual controls are located not


they are not anchored in the
traditional way, but are somehow aligned ,
and this is more logical, at least, for mobile
applications, when screen size can be
considerably different and orientation can be
changed during runtime.
You can then find the Properties window
and use it in the ObjectInspector style to change
necessary properties.
In order to set an onClick event for the button,
find the corresponding property in Properties
list and type ButtonClick or something else you
like (See figure 5, next page).
The response will be then programmed in
Delphi with Object Pascal.
Save the project in Android Studio .
Actually, we need only the form design, which
you can see in text form by switching to the Text
tab in the bottom.
Then, go back to Delphi for the programming.
Delphi VCL style ,

Figure 4

10

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

TURBO COCOA FOR DELPHI AND ANDROID PAGE 3/4

Figuur 5: Designing UI in Android Studio for


TurboCocoa project

In Delphi we work with the source file


MainActivity.pas. The project contains the

is in turn responsible for taking the UI


design file to the Delphi project and use it in
building the final Android app.
In MainActivity.pas you see the class

TurboCocoa

other two pas files, but they are mainly generated


automatically and should not be modified.
TMainActivity:
Open MainActivity.pas and have a look
into it. Activity can be roughly considered
TMainActivity = class(TJavaGeneric<JFMXNativeActivity>)
as a form for the first approximation.
private
We've made its design in Android Studio, so
protected
for the further modification you need to right
public
click again on the project name in the Project
procedure onCreate(const savedInstanceState: JBundle);
Manager and select Launch Android Studio/To
procedure onDestroy;
Android Studio.
procedure onPause;
Then you add more controls, save, and go
procedure onResume;
back to Delphi. Let's think of Android Studio
[IBAction]
as a platform specific form designer,
procedure ButtonClick(id: Pointer);
end;
nothing more.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

11

TURBO COCOA FOR DELPHI AND ANDROID PAGE 4/4


The difference in the code above and your code is
the attribute [IBAction ] and the procedure
ButtonClick , which you definitely can type
without problem.
The procedure name should correspond to what
you typed in Android Studio for Button
component, property onClick . Then the main
work is to enter the code for procedure:

Finally, you compile the project, build and

procedure TMainActivity.ButtonClick(id: Pointer);


deploy for the only platform Android (See
var
figure. 6). You can watch the time of
MyLabel: JTextView; MyEdit: JEditText; tmp : string;
deployment and time of launch, as
begin
well as the size of the
MyLabel := TJTextView.Wrap(Super.findViewById(R.id.textView));
mobile app, made in Delphi
MyEdit := TJEditText.Wrap(Super.findViewById(R.id.editText));
with TurboCocoa.
tmp := 'Hello, ' + JStringToString(MyEdit.getText.toString) + '!';
MyLabel.setText(StrToJCharSequence(tmp));
end;

Some explanation needed, and here they are.


In contrast to methods for working with iOS
controls in TurboCocoa (see previous article), we
don't need outlets. We have recognizable control
id-s in Android Studio, and we can manipulate
with them. You can switch to Android Studio,
open Text tab, and look at:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="The text will be there..."
android:id="@+id/textView" />

These are properties of TextView, which is our


Its id is textView, but we don't have to
remember this, only to understand, from where
the corresponding identifier appears in Delphi
code. In the procedure ButtonClick we define
local variables as reference to native controls in
the form. For the reference type we use a type of
controls in Android Studio with prefix J. Then
we bind the reference variable with the native
control in runtime:
MyLabel := TJTextView.Wrap(Super.findViewById(R.id.textView));
Label.

Once we get the proper reference, we can


manipulate with control in object oriented
manner. As in case of iOS development with
TurboCocoa, the string types are different, than
we use in Object Pascal . That's the reason why we
introduce local variable tmp, just to simplify the
code. Converters JStringToString and
StrToJCharSequence are easy to understand from
their names and easy to use. It makes the code a
little bit longer, but this is the only, but not
critical drawback, originated from string
representation difference.
12

Fig. 6. Resulting Android app

SUMMARY:
TurboCocoa helps Delphi developers make true
native UX apps for different platforms Mac
OS/iOS/Android.
Development for Android in Delphi with
TurboCocoa calls for only design skills in Android
Studio, while Object Pascal remains an effective
programming language together with non-visual
components and any legacy code.
The resulting apps are fast, compact, and fully
meet expectations by customers, who value the
native UX.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

http://turbococoa.com/

20% discount on
TURBO COCOA.

PRICING
- $149 for perpetual license
- $39 for annual renewal
- $99 yearly subscription

DISCOUNT COUPON #
BPM 48665

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

13

Registered users of any earlier version qualify for the upgrade price!
If you are currently using any earlier version of RAD Studio, Delphi, C++Builder
or Borland Developer Studio and are looking for the lowest cost to move for ward,
now is the time to upgrade.
Save up to 45% off the new user price
Update Subscription is now included with all licenses, so youll never miss an update again
Plus, you get access to the free bonus pack ebook and software downloads
How to qualify for the upgrade price of 10.1 Berlin and save up to 45%: P urchase 10.1 Berlin at the Upgrade price
through June 20, 2016. Even if the description says Upgrade from XE6 or later,
all earlier version users can upgrade during this special offer period .
Buy Delphi or C++Builder 10.1 Berlin Professional edition and receive a Mobile Add-on
Pack with Update Subscription FREE! Go mobile for less!
How to qualify for a free Mobile Add-on pack when you buy 10.1 Berlin: P urchase
the specially marked Delphi or C++Builder 10.1 Berlin Professional Named User license
with Mobile Add-on through June 20, 2016. Special price includes the full Delphi
or C++Builder Professional license, Mobile Add-on Pack and one year of Update Subscription.

FREE BONUS PACK


Get these Free Bonuses with your purchase of RAD Studio, Delphi or C++Builder 10.1 Berlin
If you are currently using any earlier version of RAD Studio, Delphi, C++Builder or Borland Developer Studio,
and are looking for the lowest cost to move for ward, now is the time to upgrade.
New Object Pascal Handbook by Marco Cantu
Do more with Delphi
This 300-page ebook is a complete guide to the current, modern Object Pascal
programming language by best-selling Delphi books author and Delphi Senior
Product Manager, Marco Cantu. This new language manual for new & existing
Object Pascal developers covers core language features, object-oriented
programming with Object Pascal, and the latest language features like generics,
anonymous methods, and reflection in todays' Delphi compilers.

VCL and FireMonkey Premium Styles


Modernize your apps with premium VCL & FMX styles
Customize the look of your VCL Windows applications with seven premium styles
including the Coral, Diamond, Emerald, Sterling, Jet, Vapor, Radiant and Copper
style. Customize your multi-device applications with nine premium FireMonkey
styles including Jet, Sterling, Diamond, Emerald Crystal, Emerald Dark, Coral
Crystal, Coral Dark, Vapor, Radiant and Copper styles.

or call: +31 (0)235422227


http://www.barnsten.com/default/development-tools/amnesty
14

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

TMS FNC USER INTERFACE CONTROLS,


A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 1 / 8
BY BRUNO FIERENS

FNC
FRAMEWORK NEUTRAL COMPONENTS

From the editor: you wont believe this! I think this is


the best so far that ever could have happened to PASCAL:
developing code on multiple platforms made easy.
I would call I the new F(ea)uture
INTRODUCTION
As your customers use an ever increasing number of
devices & operating systems, it is a daily challenge
for us, software developers to make our software
available for the myriad of target platforms in use.
Fortunately, as Pascal developers, we already have a
huge benefit that Delphi meanwhile targets 4
platforms: Windows, Mac OSX, iOS and Android. Add
Lazarus to that, and Pascal developers can also
target Linux and its derivatives such as Raspbian
and many more. The 3 main frameworks we have
available to create our software for these platforms
are: VCL, FMX and LCL. The framework to use will be
determined by the target and the IDE used. That
implies that the controls that can be used are also
typically determined by this choice and might limit
your abilities when some controls or control features
are not available for one of these frameworks.
Addressing that limitation is exactly one of the
primary goals of the TMS FNC UI Controls. It offers
you a set of powerful & feature-rich UI controls that
you can use in Delphi's VCL framework, FMX
framework and Lazarus LCL framework. It allows to
create Win32, Win64, Mac OS-X, iOS, Android,
Linux, Raspbian, ... applications with a single
codebase and a single learning curve.

First limitation is the design-time form


fileformat that is different between VCL, FMX and
LCL. VCL uses the .dfm file, FMX uses the .fmx
file and LCL uses the .lfm file. For applications
for different devices with different form factors,
it typically already requires to design the form
separately for separate frameworks, so this isn't
too much of a limitation. For other applications,
a solution is to create the controls at runtime.
A second limitation is the namespaces (unit
names).

CONCEPT

FNC controls enable you to write and use 100%


identical Pascal code, be it in a VCL app, FMX app
or LCL APP. The FNC components methods,
properties and events are therefore 100%
identical regardless of the framework being
used. As an example, the following code creates
a new event in our FNC Planner control:
var
plIt: TTMSFNCPlannerItem;
begin
plIt := TMSFNCPlanner1.Items.Add;
plIt.StartTime := Date + EncodeTime(14,0,0,0);
plIt.EndTime := Date + EncodeTime(16,0,0,0);
plIt.Title
:= 'New event';
plIt.Text
:= 'Content';
end;

and from this code, it is impossible to tell


whether it will be from a VCL, FMX or LCL app .
In the application UI, it will also look exactly the
same regardless of framework or operating
system: see image 1 right top...
This means that if you properly separate your
logic or adopt an MVC approach, you can easily
share .PAS files between VCL and FMX projects,
between VCL and LCL projects etc... There are in
this respect actually only two limitations.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

To be able to register identical classnames for


different framework controls in Delphi, it is
required that these live in different
namespaces. As such, the FNC VCL controls unit
names have the prefix VCL. , the FNC FMX
controls unit names have the prefix FMX. and
the FNC LCL controls use prefix LCL (without
dot, to be able to support FPC versions older than
v3.0). In practice, this means that for the
example above with the TMSFNCPlanner, the unit
clauses for the different frameworks would be
as below. To keep using a single source file, a
solution is to set a define at project level
depending on the framework and write:
uses
{$IFDEF VCL}
VCL.TMSFNCPlannerBase, VCL.TMSFNCPlannerData,
VCL.TMSFNCPlanner, VCL.TMSFNCCustomControl;
{$ENDIF}
{$IFDEF FMX}
FMX.TMSFNCPlannerBase, FMX.TMSFNCPlannerData,
FMX.TMSFNCPlanner, FMX.TMSFNCCustomControl;
{$ENDIF}
{$IFDEF LCL}
LCLTMSFNCPlannerBase, LCLTMSFNCPlannerData,
LCLTMSFNCPlanner, LCLTMSFNCCustomControl;
{$ENDIF}

tmssoftware.com
productivity software buiding blocks

15

TMS FNC USER INTERFACE CONTROLS,


A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 2 / 8
In the same way, when used, we could include the
resource of our form file that is different in each
framework via a conditional define:
{$IFDEF VCL}
{$R *.dfm}
{$ENDIF}
{$IFDEF FMX}
{$R *.fmx}
{$ENDIF}
{$IFDEF LCL}
{$R *.lfm}
{$ENDIF}

FNC
FRAMEWORK NEUTRAL COMPONENTS

CONTROLS
In TMS FNC UI Pack v1.0 , there are already 29
controls included. On the tool palette this looks
like: VCL, FMX

These are of course the things you need to take in


to account when you want to create a single
codebase to build projects with multiple
frameworks. In other cases, you do not need to
take care of this and you can enjoy the exact same
feature set of this UI component library
irrespective of the IDE and platform you target.
Another important core concept is the
introduction of the TMS FNC Graphics library that is
included. This enables you to write graphics
code that is framework independent.
This includes framework neutral colors, fill,
stroke, alignment, font, path types and the
TTMSFNCGraphics class using this to draw
everything you need. This is a sample code
snippet of framework neutral drawing:
var
gr: TTMSFNCGraphics;
begin
gr := TTMSFNCGraphics.Create(PaintBox1.Canvas);
gr.Fill.Color
:= gcYellow;
gr.Stroke.Color := gcGray;
gr.DrawRectangle(0,0,100,20);
gr.Font.Color := gcRed;
gr.DrawText(2,0,100,20,'Hello world',false)
gr.Free;
end;

The result is:

and is exactly the same on every framework,


target, device, ...

16

tmssoftware.com
productivity software buiding blocks

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

TMS FNC USER INTERFACE CONTROLS,


A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 3/8

FNC
FRAMEWORK NEUTRAL COMPONENTS

LCL

This includes a grid, planner, richeditor,


treeview, various color, font, fontsize, bitmap ...
picker , toolbar, ... and more.
INTRODUCING THE TMS FNC GRID
The TMS FNC Grid is a high-performance,

not data-bound grid capable of dealing with


hundreds of thousands of rows, has a wide range
of cell types and inplace editors, offers built-in
sorting, filtering and grouping and can import
and export data in several file formats.
To illustrate some of the capabilities of the
TMS FNC Grid ,
begin
As another quick introduction to the
TMSFNCGrid1.FixedRows
:= 2;
grid, this 2 line snippet demonstrates
TMSFNCGrid1.ColumnCount := 7;
how data from a CSV file can be loaded
TMSFNCGrid1.MergeCells(1,0,2,1);
and automatic filtering via a drop down
TMSFNCGrid1.MergeCells(3,0,2,1);
in the column header is enabled:
TMSFNCGrid1.MergeCells(5,0,2,1);
TMSFNCGrid1.Cells[1,0] := 'Monday';
TMSFNCGrid1.LoadFromCSV('e:\tms\cars.csv');
TMSFNCGrid1.HorzAlignments[1,0] := gtaCenter;
TMSFNCGrid1.Options.Filtering.DropDown := true;
TMSFNCGrid1.Cells[1,1] := 'AM';
TMSFNCGrid1.Cells[2,1] := 'PM';
TMSFNCGrid1.Cells[3,0] := 'Tuesday';
TMSFNCGrid1.HorzAlignments[3,0] := gtaCenter;
TMSFNCGrid1.Cells[3,1] := 'AM';
TMSFNCGrid1.Cells[4,1] := 'PM';
TMSFNCGrid1.Cells[5,0] := 'Wednesday';
TMSFNCGrid1.HorzAlignments[5,0] := gtaCenter;
TMSFNCGrid1.Cells[5,1] := 'AM';
TMSFNCGrid1.Cells[6,1] := 'PM';
TMSFNCGrid1.AutoNumberCol(0);
TMSFNCGrid1.AddCheckBox(1,2,false);
TMSFNCGrid1.AddRadioButton(1,3,1);
TMSFNCGrid1.AddProgressBar(3,2,50);
TMSFNCGrid1.Cells[3,3] := 'Hello <B>world</B>';
TMSFNCGrid1.AddBitmapFile(5,2,'e:\tms\calendar.png');
TMSFNCGrid1.AddBitmapFile(5,3,'e:\tms\mail.png');
TMSFNCGrid1.Cells [1,4] := 'Red';
TMSFNCGrid1.Colors[1,4] := gcRed;
TMSFNCGrid1.Cells [3,4] := 'Yellow';
TMSFNCGrid1.Colors[3,4] := gcYellow;
TMSFNCGrid1.Cells [5,4] := 'Lime';
TMSFNCGrid1.Colors[5,4] := gcLime;
TMSFNCGrid1.FontNames [1,4] := 'Courier New';
TMSFNCGrid1.FontStyles[3,4] := [fsBold];
TMSFNCGrid1.FontSizes [5,4] := 12;
TMSFNCGrid1.AddNode(2,2);
end;

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

tmssoftware.com
productivity software buiding blocks

17

TMS FNC USER INTERFACE CONTROLS,


A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 4/8

Of course, this is just a very brief introduction


to the TMS FNC Grid. Just the FNC grid alone
could deserve multiple articles to cover it in
detail. You can familiarize yourself with the
TMS FNC Grid by reading the full PDF
developers guide you can find at
http://www.tmssoftware.biz/download/
manuals/TMSFNCGridDevGuide.pdf or use

the
trial or full version of the component that
comes with several samples.

Some weeks ago, we released the TMS FNC UI Pack,


a set of Framework Neutral Components (FNC), i.e.
UI controls that can be used from VCL Windows
applications, FireMonkey (FMX) Windows, Mac OS-X,
iOS, Android applications and LCL framework based
Lazarus applications for Windows, Linux, Mac OSX,..
The TMS FNC UI Pack contains highly complex &
feature-rich components such as grid, planner, rich
editor, treeview, toolbars. To create such complex
components that work under 3 frameworks and a
myriad of operating systems is not a trivial
excercise and requires intricate knowledge about
the VCL, FMX and LCL frameworks as well as the
operating systems the controls need to work under.
To help ourselves and the users of the TMS FNC UI
Pack, we have introduced several abstractions that
facilitate creating framework neutral components
and this is what we want to cover in this brief
introduction to developing FNC custom controls.

18

tmssoftware.com
productivity software buiding blocks

FNC
FRAMEWORK NEUTRAL COMPONENTS

INTRODUCING THE TMS FNC PLANNER


Our TMS FNC Planner is a scheduling component
with various built-in time-axis options, i.e. a day,
week, month, period, half-day period, timeline
as well as custom time-axis mode where you can
fully control the duration of each timeslot in the
Planner. The Planner supports single and multiresource views and can have the time-axis
horizontal or vertical.
When targeting the Planner to a mobile device, it
will automatically use a touch-friendly approach
to select, insert, delete, pan in the Planner.
As a brief introduction to the TMS FNC Planner,
we'll demonstrate a monthly car rental Planner
with horizontal time axis and several resources
in the left axis.
In this code, we set the time axis
programmatically horizontal and add 9
resources with 3 groups of 3 resources,
representing small, medium and large cars.
Via TMSFNCPlanner.Mode, we set the time line
to a day period timeline and via
TMSFNCPlanner.ModeSettings the period is
set to the month May.
After some further customization of timeline size
and font, some random car rentals are added on
the Planner:

FNC
FRAMEWORK NEUTRAL COMPONENTS

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

TMS FNC USER INTERFACE CONTROLS,


A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 5/8

FNC
FRAMEWORK NEUTRAL COMPONENTS

var
grp: TTMSFNCPlannerGroup;
plIt: TTMSFNCPlannerItem;
i, d: integer;
begin
TMSFNCPlanner1.OrientationMode := pomHorizontal;
TMSFNCPlanner1.Mode := pmDayPeriod;
TMSFNCPlanner1.Positions.Count := 9;
TMSFNCPlanner1.Groups.Clear;
grp := TMSFNCPlanner1.Groups.Add;
grp.StartPosition := 0;
grp.EndPosition
:= 2;
grp.Text
:= 'Small';
grp := TMSFNCPlanner1.Groups.Add;
grp.StartPosition := 3;
grp.EndPosition
:= 5;
grp.Text := 'Medium';
grp := TMSFNCPlanner1.Groups.Add;
grp.StartPosition := 6;
grp.EndPosition
:= 8;
grp.Text
:= 'Large';
TMSFNCPlanner1.Resources.Clear;
for i
:= 0 to 8 do
begin
TMSFNCPlanner1.Resources.Add;
TMSFNCPlanner1.Resources.Items[i].Text := 'Car '+inttostr(i + 1);
end;
TMSFNCPlanner1.TimeLineAppearance.LeftSize
:= 35;
TMSFNCPlanner1.TimeLineAppearance.LeftFont.Size := 10;
TMSFNCPlanner1.TimeLineAppearance.LeftFont.Style := [fsBold];
TMSFNCPlanner1.ModeSettings.StartTime := EncodeDate(2016,5,1);
TMSFNCPlanner1.ModeSettings.EndTime
:= EncodeDate(2016,6,1);
TMSFNCPlanner1.TimeLine.DisplayUnitSize
:= 35;
TMSFNCPlanner1.TimeLine.DisplayUnitFormat := 'd/m';
for i := 0 to 10 do
begin
d := random(20);
plIt := TMSFNCPlanner1.Items.Add;
plIt.StartTime := EncodeDate(2016,5,1) + d;
plIt.EndTime
:= EncodeDate(2016,5,1) + d + 1 + random(5);
plIt.Resource := Random(9);
plIt.Text
:= 'Rental';
plIt.Color
:= gcYellowgreen;
end;
end;

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

tmssoftware.com
productivity software buiding blocks

19

TMS FNC USER INTERFACE CONTROLS,


A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 6/8
INTRODUCING THE TMS FNC
RICHEDITOR
With the TMS FNC Rich Editor you can

assemble a WordPad-style editor or Outlook


style mail application in a matter of minutes.
TMS FNC Rich Editor comes with
capabilities to do WYSIWYG editing of rich
text with images, URLs, bullet lists, custom
graphics, mail merging etc... To make
development even faster, there is a pre-built
toolbar for rich editor editing and formatting
and non-visual components to facilitate the
import and export from HTML & RTF files
and that of course in all frameworks,
operating systems and target devices
supported.
In this introduction sample, drop the
TTMSFNCRichEditor on the form as well as
the TTMSFNCRichEditorFormatToolbar
and assign the TTMSFNCRichEditor to

FNC
FRAMEWORK NEUTRAL COMPONENTS

begin
TMSFNCRichEditor1.AddText('Dear Mr. NAME');
TMSFNCRichEditor1.AddLineBreak;
TMSFNCRichEditor1.AddText('CC: EMAIL');
TMSFNCRichEditor1.SelStart := 9;
TMSFNCRichEditor1.SelLength := 4;
TMSFNCRichEditor1.SetSelectionMergeField('NAME');
TMSFNCRichEditor1.SelStart := 21;
TMSFNCRichEditor1.SelLength := 5;
TMSFNCRichEditor1.SetSelectionMergeField('EMAIL');
end;

When the app is started, the text can be further


decorated by editing & formatting via the toolbar.
When it is ready, following code performs the
merge with the NAME and EMAIL field and is
exported to RTF via TTMSFNCRichEditorRTFIO
and after this, the merge is undone:

TTMSFNCRichEditorFormatToolbar.
RichEditor. Also add a
TTMSFNCRichEditorHTMLIO and
TTMSFNCRichEditorRTFIO non-visual

component on the form and also assign the


TTMSFNCRichEditor to
TTMSFNCRichEditorHTMLIO.RichEditor

and
TTMSFNCRichEditorRTFIO.RichEditor.

The rich editor content can be initialized


with following code to perform a mail-merge
that uses here two merge fields: NAME and
EMAIL.

20

tmssoftware.com
productivity software buiding blocks

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

TMS FNC USER INTERFACE CONTROLS,


A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 7/8

FNC
FRAMEWORK NEUTRAL COMPONENTS

var
sl: TStringList;
begin
sl := TStringList.Create;
try
sl.Add('NAME=Elon Musk');
sl.Add('EMAIL=elon@tesla.com');
TMSFNCRichEditor1.Merge(sl);
finally
sl.Free;
end;
TMSFNCRichEditorRTFIO1.Save('e:\tms\merge.rtf');
TMSFNCRichEditor1.UnMerge;
end;

INTRODUCING THE TMS FNC TREEVIEW

Finally, another large feature-packed control


from the TMS FNC UI Controls set we want to
introduce is the TMS FNC TreeView ,
TTMSFNCTreeView. This is a multi-column
treeview control with regular mode and virtual
mode and designed for and capable of using
millions of nodes. In addition, the nodes support
rich information, text atttributes can be
customized per node cell, HTML formatted text
in node cells is possible, images, checkboxes can
be added and optional inplace editing is
available.
In this introduction we'd like to demonstrate the
difference in regular (node collection) based
mode and virtual mode when using the
TTMSFNCTreeView. The first code snippet
demonstrates an initialization of a 2 column
treeview:

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

var
tn,cn: TTMSFNCTreeViewNode;
begin
TMSFNCTreeView1.BeginUpdate;
TMSFNCTreeView1.Columns.Clear;
TMSFNCTreeView1.Nodes.Clear;
TMSFNCTreeView1.Columns.Add.Text := 'Country';
TMSFNCTreeView1.Columns.Add.Text := 'Capital';
tn := TMSFNCTreeView1.AddNode(nil);
tn.Text[0] := 'Europe';
cn := TMSFNCTreeView1.AddNode(tn);
cn.Text[0] := 'Germany';
cn.Text[1] := 'Berlin';
cn := TMSFNCTreeView1.AddNode(tn);
cn.Text[0] := 'France';
cn.Text[1] := 'Paris';
cn := TMSFNCTreeView1.AddNode(tn);
cn.Text[0] := 'United Kingdom';
cn.Text[1] := 'London';
tn := TMSFNCTreeView1.AddNode(nil);
tn.Text[0] := 'Asia';
cn := TMSFNCTreeView1.AddNode(tn);
cn.Text[0] := 'Japan';
cn.Text[1] := 'Tokyo';
cn := TMSFNCTreeView1.AddNode(tn);
cn.Text[0] := 'China';
cn.Text[1] := 'Peking';
TMSFNCTreeView1.EndUpdate;
end;

tmssoftware.com
productivity software buiding blocks

21

TMS FNC USER INTERFACE CONTROLS,


A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 8 / 8

FNC
FRAMEWORK NEUTRAL COMPONENTS

procedure TForm1.TMSFNCTreeView1GetNodeText(
Sender: Tobject;
Anode: TTMSFNCTreeViewVirtualNode;
AColumn: Integer;
string property.
AMode: TTMSFNCTreeViewNodeTextMode;
In a next step, we'll use the TTMSFNCTreeView in
var AText: string);
virtual mode and insert 1 million nodes! Columns
begin
are not virtual, so this must be initialized and to
if ANode.Level = 0 then AText :=
keep it simple, this will be initialized to one
'Root node '+inttostr(ANode.Index)
column:
else
begin
if ANode.Level = 1 then AText :=
TMSFNCTreeView1.Columns.Clear;
'Child node '+inttostr(ANode.Index)
TMSFNCTreeView1.Columns.Add;
else
TMSFNCTreeView1.Columns[0].Text := 'Large treeview';
if ANode.Level = 2 then AText :=
end;
'Subchild node '+inttostr(ANode.Index);
end;
To use the TTMSFNCTreeView in virtual

Important to note here is that the text in the


multiple columns of the treeview can be simply
accessed with an array indexed Node.Text[]:

mode, two events are crucial:


the OnGetNumberOfNodes() event and the
OnGetNodeText() event. The first is
triggered to know how many nodes at root
level or child level should be added.
The latter is used to retrieve the column text
of the node. Let's start with the
OnGetNumberOfNodes event. This event
has parameters ANode and a var parameter
ANumberOfNodes. ANode is either a node
with ANode.Level set to -1 indicating the
number of root level nodes is requested or it
contains the node for which the number of
child nodes is requested. With the
ANode.Level property, you can know how
CONCLUSION
many hierarchical levels deep the node is. In this We hope this brief introduction of the major controls in the
example, we'll insert 1 million (100x100x100)
TMS FNC UI Pack whetted your appetite to start exploring
the components, discovering the benefits and efficiency of
nodes by inserting 100 root level nodes that
have each 100 children and each child has again having one UI component set to cover all the target
operating systems you want to target and perhaps cook up
100 subchildren.
your first Linux GUI apps with LCL. You can get the trial
procedure TForm1.TMSFNCTreeView1GetNumberOfNodes( version for Delphi from
Sender: Tobject; Anode: TMSFNCTreeViewVirtualNode; http://www.tmssoftware.com/site/
tmsfncuipack.asp and there is also a sample TV Guide
var ANumberOfNodes: Integer);
begin
if ANode.Level = -1 then ANumberOfNodes := 100
else
if ANode.Level = 0 then ANumberOfNodes := 100
else
if ANode.Level = 1 then ANumberOfNodes := 100;
end;
end;

Then, the other event for virtual node handling,


OnGetNodeText is used to return the text for

node columns. Note that this event will be


triggered for each node and for each column for
this node. The column for which the event is
triggered is indicated with the AColumn
parameter. As we have only 1 column in this
example, this is ignored and the node text is
directly returned:

22

tmssoftware.com
productivity software buiding blocks

project that can be used from VCL, FMX and LCL that you
can obtain from

http://www.tmssoftware.com/site/
blog.asp?post=335
We're eager to learn how your experience is going and to
hear your feedback, comments and further wishes and
needs in this direction.
About the author Bruno Fierens
Studied civil electronic engineering at university of
Ghent, Belgium (1987-1992) and started a career as R&D
digital hardware engineer. Besides the fascination for
electronics, Bruno Fierens set the first steps in programming
with Turbo Pascal v3.0 and used all Borland Pascal & Delphi
versions since that time. In 1996, he founded TMS software
for the activity of application and component development
with Delphi. TMS software became Borland Technology
Partner in 1998, developed Delphi Informant award-winning
grid & scheduling components and now has an international
team of software developers working on a large portfolio of
components. Bruno Fierens is from 2012 Embarcadero MVP
and frequent speaker at Delphi conferences world-wide.
He does and oversees VCL, IntraWeb, .NET and FireMonkey
component development

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

Kim Madsen

We would like you


to build us this
No no... you want to have this
Thats the future!
Think about the competition!

Would be nice if it
also solved
this problem

Ok. I think I Know


what you want

But we can only


afford this

Kim Madsen

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

23

SOFTDRAW PAGE 1/2


BY DAVID DIRKSE
starter

expert

Delphi

INTRODUCTION
This article describes the drawing of soft lines and
ellipses.
Soft means that the pen does not follow pixels but
smoothes over pixels. As a result, the lines do not
have steps.

A horizontal oriented line is drawn by a pen


having a height of 1 pixel and a width of .25 pixel.

Below the comparison: the smooth line on top,


below without smoothing.

For a vertical oriented line the pen is


1 pixel in width and 0.25 pixel in height.

Figure 1: Part of the above picture enlarged 10 times:

These pictures are drawn by a modified pen: not


1*1 size but 1 * 0.25 pixel.
Differentiation must be made between horizontaland vertical oriented lines:

We notice that a pixel is divided into 16 (4*4)


subpixels.
We have to record the subpixels that have
been colored by the pen.
Var Blender : array[...., ] of word ;// 1 word
per pixel, array same size as canvas
Correspondence of Blender bits and
subpixels

24

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

SOFTDRAW PAGE 2/2


So, drawing takes 3 steps:
1. blender word bits are set if covered
by the pen
2. Drawing is done in a bitmap.
blender array is scanned , bitmap pixel
color is calculated as average of original
and covered subpixels.
3. bitmap is copied to a paintbox to
become visible.

For people interested in math, see below the


origin of the formula, using implicit
differentiation
For easy calculation, the center of the ellipse is
assumed (0,0).
In reality, x and y bias values have to be added.

if 5 subpixels were covered


then 5/16 of the pen color and 11/16
of the original pixel color make the
new color.

Example:

Two procedures make the core


of soft drawing:
procedure Qpixel(x,y : single) ; // draws a soft pixel using the selected pen
procedure Softline(x1,y1,x2,y2 : smallInt); //draws a softline from (x1,y1) to (x2,y2)

The ellipse is drawn by subsequently calling

If x1 > x2 then the coordinates are traded.


Drawing is always from left to right.

Qpixel(.. , ..);

Please refer to the source code for details.

X runs in quarter pixel steps from -sx to + sx.


Then y runs in quarterpixel steps from -sy to + sy.

ELLIPSES
procedure SoftEllipse(x1,y1,x2,y2 :
SmallInt);

Please refer to the source code for details.

// draws a soft ellipse


Left top is (x1,y1), right bottom of the enclosing
rectangle is (x2,y2).
Additional problem is the pen selection because
an ellipse has horizontal- and vertical oriented
arcs.
In the picture below (sx,sy) is the center point
between the horizontal and vertical orientation.
At this point the pen has to be changed.
Also consider the reflections of (sx,sy) on the
axis.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

25

HOWARD PAGE-CLARK

DAVID DIRKSE COMPUTER MATH & GAMES IN PASCAL

SPECIAL OFFER:

RKSE

DI
D
I
AV

/Co

irkse

vidD

u/Da
at
cal.e
ales
pres laisepas
.b
w
w
w

es.htm

Gam

ath_

terM
mpu

FOR THE SUMMER


BUY THE BOOK FOR 30 EUROS

;
dure
proce
var
9 do
begin := 1 to
for i
n
i
g
e
b

INCLUDING:
53 projects and code fully explained.
The Delphi 3 Delphi Berlin source code
is available together with full explanation.
Most of the projects can be done with
FPC and or Lazarus as well.
For a preview go to:
http://www.blaisepascal.eu/
david_dirkse/
UK_Book_Department_DavData.html
PDF file - excellent readable on your
tablet. Printable.

end;
end;

TH &
A
M
UTER PASCAL
P
M
CO
IN
S
E
M
GA

POCKET EDITION
Also printed in full color.
A fully indexed PDF file is included.

30,00

On tablet

The book contains 87 chapters, 53 projects


with source code and compiled programs
(exe).
The book is highly educational and suitable
for beginners as well as for professionals.

Resize, rotate, compress digital images.


Design your own font, generate and reduce
Truth Tables from Boolean algebra.
And more important: understand how it all
works!

Play board games, solve puzzles, operate a


vintage mechanical calculator, Produce 3dimensional computer art, generate lists of
prime numbers, explore and draw any
mathematical function.

For the games, winning strategies are


explained. For puzzles the search algorithm.
For all projects: the math behind is thoroughly
discussed.

Solve systems of equations, calculate the


area of complex polygons.
Draw lines, circles and ellipses.

http://www.blaisepascal.eu/david_dirkse/UK_Book_Department_DavData.html
26

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

HOW TO BUILD AN APP IN XML WITH FIREMONKEY PAGE 1/9


INCLUDED STYLE SHEETOVERVIEW
BY DETLEF OVERBEEK
starter

expert

Delphi
FireMonkey
In this article some of the possibilities
that are available with xml are explained. The article will
start by giving a short introduction into what XML is and
how it can be used in Delphi. In this article we want to
show how XML works, by creating a very simple
application made in FMX (Embarcadero) showing some
specialties about FMX and explaining some of it, so you
will be able to build an extension of this program
yourself and later on port it to your own Smart Mobile.

First some Wiki knowledge:


(Extensible Markup Language (XML) is a markup
language that defines a set of rules for encoding
documents in a format that is both human-readable
and machine-readable. It is defined by the W3C's
XML 1.0 Specification and by several other related
specifications all of which are free open standards.
The design goals of XML emphasize simplicity,
generality and usability across the Internet. It is a
textual data format with strong support via Unicode for
different human languages. Although the design of
XML focuses on documents, it is widely used for

the representation of arbitrary data


structures such as those used in
web services. Several schema
systems exist to aid in the definition WIKIPEDIA
of XML-based languages, while many application
programming interfaces (APIs) have been
developed to aid the processing of XML data.) If
you want to take a deeper dive:
https://en.wikipedia.org/wiki/XML
We will look into how to create a structure we
can use for this XML and then apply node
values and child nodes.
(See the figure below)

HOW TO CREATE A FIRST XML STRUCTURE.

You can either take Notepad or something like


that and make your own structure and let the
extension be .xml.

Figure 1: the lay out of the application in Delphi Seattle / Win7

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

27

HOW TO BUILD AN APP IN XML PAGE 2/9


WITH FIREMONKEY - INCLUDED STYLE SHEETOVERVIEW
In a following article we will explain how you can
create your xml through coding. For now it would
be best to take the xml we already have created:
Friends.xml. The application makes use of this
at the start of the program: procedure
TXmlApp.FormCreate; It should be available in
your main dir. This first .xml is only used by the
program to alter the text and show what it does.
We have kept it simple so you can of course play
around with this. Next time we will also add
branches and make it therefore more complex.
In the interface section there is the uses and type
section.
Under the uses a number of FireMonkey units
are added because this is a
FireMonkey Multidevice application.
Go to files: new multidevice form.

In the example project there are 2 type


declarations.
The first one is 'TPerson = class'. This class is
used as a container for storing information.
It has been added below. It consist of 3 string
variables and an IXMLDocument.
This class allows us to call the information in
procedures similarly to using global variables.
type
TPerson = class
public
UserID: string;
firstName: string;
lastName: string;
XML: IXMLDocument;
end;
NR.: 1

The second type is the form on which we


added a number of components. These will be
explained later and have therefore not been
listed here. Under strict private we added
FPerson: Tperson;. This is an instantiation
of the TPerson = Class and will be used for
the storage of the information.
It suffices to say that these units are required
similarly to the standard units that are added to a
VCL forms application and FireMonkey of course
will allow you to drop only those components on
the form that are allowed by FMX.
Besides those units in the uses section the following
units have been added XmlIntf and XmlDoc.
XmlIntf and XmlDoc are required for the handling
of the XML.
It contains the component IXMLDocument which
we will be used in the example project.
For extra help refer to:
http://docwiki.embarcadero.com/RADStudio/S
eattle/en/Working_with_XML_Documents

28

strict private
FPerson: TPerson;

NR.: 2

EXPLANATION OF Strict Private.

In Delphi there's a "bug" that makes the


visibility of all members public within the
same unit.
The strict keyword corrects this behaviour,
so that private is actually private, even within
a single unit. For good encapsulation I would
recommend always using the strict keyword.

The function GetNodeText will be used to


extract the nodevalue from the node with a
specific tag. It uses the parameter 'pvTagName' to
find the right node in the 'pvItemNodes' and
then extract the value.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

HOW TO BUILD AN APP IN XML PAGE 3/9


WITH FIREMONKEY - INCLUDED STYLE SHEETOVERVIEW
class function TFormMyFirstApp.GetNodeText(pvItemNodes: IXMLNodeList; const pvTagName: string): string;
var lvNodeName, lvNodeValue: string; lvItemIndex: Integer;
begin
for lvItemIndex := 0 to pvItemNodes.Count - 1 do
begin
lvNodeName
:= pvItemNodes[lvItemIndex].NodeName;
lvNodeValue := pvItemNodes[lvItemIndex].Text;
if (lvNodeName = pvTagName)
The procedure FormDestroy frees the FPerson
then Result
:= lvNodeValue;
object. This is required because it has no owner.
end;
end;
The other functions and procedures are al linked to
NR.: 3

the form and will be freed on its destruction.


The procedure AddNodeText is used for
procedure TFormMyFirstApp.FormDestroy(Sender: TObject);
creating nodes with a nodevalue. The
parameter 'pvPersonNode' is the node that begin
gets added and 'pvKey' is the nodename and FPerson.Free
end;
NR.: 4
the 'pvValue' is the nodevalue.
(In this program however its changed and no
added - we wil safe that for a future article).
class procedure TFormMyFirstApp.AddNodeText(pvPersonNode: IXMLNode; pvKey, pvValue: string);
var lvPersonInformation: IXMLNode;
begin
lvPersonInformation := pvPersonNode.addchild(pvKey);
lvPersonInformation.NodeValue := pvValue;
NR.: 5
end;

The procedure Fill is used to get the information The button btnLoadEditsClick is used for to load the
from 'pvPersonNode' and saved in the FPerson
information from FPerson string variables UserID,
string variables userID Firstname and Lastname. firstName and lastName to the edits.
procedure TFormMyFirstApp.Fill(pvPersonNode: IXMLNode);
NR.: 6
var lvItemNodes: IXMLNodeList;
begin
lvItemNodes
FPerson.userID
FPerson.Firstname
FPerson.Lastname
end;

:= pvPersonNode.ChildNodes;
:= TFormMyFirstApp.GetNodeText(lvItemNodes, 'userID'
);
:= TFormMyFirstApp.GetNodeText(lvItemNodes, 'firstName');
:= TFormMyFirstApp.GetNodeText(lvItemNodes, 'lastName' );

procedure
In the FormCreate procedure we create an
TFormMyFirstApp.btnLoadEditsClick(Sender: TObject);
FPerson object using the variable declared in
begin
the strict private section. Next we create
edtUserID.text := Fperson.UserID;
the IXMLDocument named XML which is located in
edtfirstName.text := Fperson.firstName;
the FPerson object. With the LoadFromFile
edtlastName.text := Fperson.lastName;
procedure we fill the IXMLDocument. Next we
NR.: 7
end
;
set the node to lvPersonNodes. You can set a
node at different levels. You can set the node to the
root by referring to the DocumentElement.
The button ReloadXml calls the procedure
In this case we go 1 node deeper and go straight
ReloadXml. ReloadXml is a separate procedure
for the childnodes - because the information we
which is also called in the FormCreate.
want to retrieve is stored at that level.
procedure TFormMyFirstApp.FormCreate(Sender: TObject);
NR.: 8
var lvPersonIndex: Integer; lvPersonNodes: IXMLNodeList;
begin
FPerson := TPerson.Create;
FPerson.XML := TXMLDocument.Create(nil);
FPerson.XML.LoadFromFile('c:\DelphiProjects\XML Article\friends.xml');
lvPersonNodes := FPerson.XML.DocumentElement.ChildNodes;
for lvPersonIndex := 0 to lvPersonNodes.Count - 1 do
begin
Fill(lvPersonNodes[lvPersonIndex]);
end;
Issue Nr ;4 2016 BLAISE PASCAL MAGAZINE
ReloadXml
end;

29

HOW TO BUILD AN APP IN XML PAGE 4/9


WITH FIREMONKEY - INCLUDED STYLE SHEETOVERVIEW
procedure TFormMyFirstApp.ReloadXml;
NR.: 9
begin
Memo1.Text := ShowText(FPerson.XML.DocumentElement);
// a simple solution to show the content again
end;
ReloadXml

The Procedure ReloadXml uses the function


Showtext (page 31 Nr.:15) to return a string
containing the XML information. The string is not
actual XML but the function mimics the XML
functionality to make the string appear as if it was
XML in Memo1 at the top of the form.
It is important to know that the memo is loaded
the first time with content during the
FormCreate procedure.
Actually the work is done by DoButtonLoadXml

MEMO FIELD

btnLoadEditsClick

procedure TXmlApp.DoButtonLoadXml;
NR.:10
begin
Memo1.Text := ShowText(FPerson.XML.DocumentElement);
end;
Procedure TFormMyFirstApp.ClearEdits;
begin
edtUserID.text := '';
edtfirstName.text := '';
edtlastName.text := '';
NR.:11
end;

Clear edits procedure


procedure TFormMyFirstApp.btnReloadXmlClick(Sender: TObject);
begin
ReloadXml;
NR.:12
end;
Figure 3: The running application

The procedure btnLoadEdits (page 29 Nr.: 7)


Several Edit Fields

The procedure SavePersonClick


saves the text from the edits and adds it to the
FPerson string variables. Then the IXMLDocument
is cleared and the IXMLDocument is loaded with
the data. But to fianalze it you will have to write all
of that to the XML file. (see page 31 Nr.:14

procedure TFormMyFirstApp.SavePersonClick(Sender: TObject);


NR.:13
var lvFriendsNode, lvPersonNode: IXMLNode; lvPersonNodes: IXMLNodeList; lvIndex: Integer;
begin
FPerson.UserID := edtUserID.Text;
FPerson.firstName := edtfirstName.Text;
FPerson.lastName := edtlastName.Text;
FPerson.XML.ChildNodes.Clear;
lvFriendsNode := FPerson.XML.addchild('friends');
begin
lvPersonNode := lvFriendsNode.addchild('person');
begin
TFormMyFirstApp.AddNodeText(lvPersonNode, 'userID', FPerson.UserID);
TFormMyFirstApp.AddNodeText(lvPersonNode, 'firstName', FPerson.FirstName);
TFormMyFirstApp.AddNodeText(lvPersonNode, 'lastName', FPerson.Lastname);
end;
end;
end;

30

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

HOW TO BUILD AN APP IN XML PAGE 5/9


WITH FIREMONKEY - INCLUDED STYLE SHEETOVERVIEW
The procedure btnWriteToXMLClick
procedure TFormMyFirstApp.btnWriteToXMLClick(Sender: TObject);
NR.:14
var XML: IXMLDocument; lvFriendsNode, lvPersonNode: IXMLNode;
lvPersonNodes: IXMLNodeList; lvIndex: Integer;
begin
XML := TXMLDocument.Create(nil);
XML.Active
:= True;
lvFriendsNode := XML.addchild('friends');
begin
lvPersonNode := lvFriendsNode.addchild('person');
begin
TFormMyFirstApp.AddNodeText(lvPersonNode, 'userID', FPerson.UserID);
TFormMyFirstApp.AddNodeText(lvPersonNode, 'firstName', FPerson.FirstName);
TFormMyFirstApp.AddNodeText(lvPersonNode, 'lastName', FPerson.Lastname);
end;
end;
XML.SaveToFile('c:\DelphiProjects\XML Article\friends.xml');
end;
Function TFormMyFirstApp.ShowText(Node: IXMLNode; ident: string = ''): string;
var
i, j: Integer;
attributes: string;
begin
if (Node.NodeType = ntText)
then Result := Node.NodeValue
else
if (Node.NodeType = ntElement) then
begin
for j := 0 to (Node.AttributeNodes.Count -1) do
begin
attributes := attributes + Format(' %s"=%s"', [Node.AttributeNodes[j].NodeName,
Node.AttributeNodes[j].NodeValue]);
end;
Result := #10 + ident + '<'+ node.NodeName + attributes + '>';
for i:= 0 to Node.ChildNodes.Count - 1
do Result := Result + ShowText(Node.ChildNodes[i], ident + '

');

Result := Result + '</' + Node.NodeName + '>' + #13;


end;
NR.:15

end;

Now for the use of FMX its necessary to show


how you can make use of the Styles of FMX.
Drop a component called Style book on your
form. A style book is something that in HTML is
CSS Styles. It contains some ready made
styles you can choose from. For your convenience
we have made images of them used by our
application. (See page32 up to 35).
Now if you doubleclick on the coponent a new
sort of view appears. (See page 35)

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

31

BUILD AN APP IN XML WITH FIREMONKEY - INCLUDED STYLE SHEET OVERVIEW PAGE 6/9

Air_Style

Amakrits_Style

AquaGraphite_style
32

Blend_Style

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

BUILD AN APP IN XML WITH FIREMONKEY - INCLUDED STYLE SHEET OVERVIEW PAGE 7/9

GoldenGraphite_Style

Light_Style

MetropolisUIBlue_Style/
MetropolisUIBlack_Style/
MetropolisUIBlue_touch.Style
MetropolisUIBlack_touch_Style
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

33

BUILD AN APP IN XML WITH FIREMONKEY - INCLUDED STYLE SHEET OVERVIEW PAGE 8/9

MetropolisUIDark.Style/
MetropolisUIDark_touch_Style

MetropolisUIGreen_Style/
MetropolisUIGreen_touch_Style

RubyGraphite_style

Transparent_Style.png

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

34

BUILD AN APP IN XML WITH FIREMONKEY - INCLUDED STYLE SHEET OVERVIEW PAGE 9/9

Win10ModernBlue_Style

Win10ModernDark_Style

Opens the dialog to find your style


Necessary to go back and see the result

Figure 4: The running application

If you click on the left most button a window wil


open up to allow you choose the Style that you
like or want:
Here is the address where it is located:

C:\Program Files (x86)\Embarcadero\Studio\17.0\Redist\styles\Fmx


So if you take the correct name of the style as
you can find in the article, it will load it.
But its not yet done. To see how it really affects
your application, it is necessary to make use of
the Apply and Close Button at the right shown
on the figure number 4.
You will be back in the normal design view.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

Have fun creating your first XML based App!


The code for this app has been written by
Vincent Overbeek

35

HOW TO DEAL WITH BIG NUMBERS PAGE 1/4


BY MAX KLEINER

maXbox Starter 41
A BIG DECIMAL OR BIG INT INTERFACE
Today we step through numbers and infinity.
As you may know there's no simple solution to print,
calculate or store big numbers or decimals.

For example you want to compute 400000078669 /


2000123 your calculator shows (so does my Casio
FX-880P):199987.7401
So this is not the end of the line, a second test is
maxcalcF('400000078669 / 2000123')
and we get: 199987.740088485
And there are even more numbers that need to
compute so we switch to
http://www.wolframalpha.com to get the
real precision thing or at least an
approximation:
199987.7400884845581996707202507045816682274
04014653098834421683066491410778237138415987
416773868407092963782727362267220...
http://www.wolframalpha.com/input/?i=4
00000078669%2F2000123
again as you suppose the numbers go on.
Use "Power Towers" to write them down.
The decimal point is the most important part of a
decimal number like above. Without it, we would
be lost ... and not know what each position meant.

36

maXbox

Dividing decimals is almost the same as


dividing whole numbers, except you use the
position of the decimal point in the dividend to
determine the decimal places in the result. Our
division is always an approximation.
Approximate means you're going to round the
number. Because you're not actually giving the
exact number, all those numbers after the
decimal, the rounded number is called an
approximation:
199987.7401 is roundToPrec4 of:
199987.740088485
Although, you probably wondered how they get
those nice and fancy graphical user interfaces
(GUI) for large numbers, here in maXbox we do
also have one:
maXbox3 568_U_BigFloatTestscript2.pas

Compiled done: 6/18/2015


The idea that you are approximating is that, as
you are only taking the first 50 decimal places as
you can see at the screen-shot.
The same like wolfram goes like this:
199987.740088484558199670720250704581668227
4040146530988344168306649141077823713841598
74167738684070929637827273622672205.
When we try to write this decimal number (or
the well known PI or SQR(2)) in decimal
notation, we get an endless stream of digits.
3.141592653589723.....and so on forever.
But suppose instead, we use fractional notation.

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

HOW TO DEAL WITH BIG NUMBERS PAGE 2/4 maXbox


Then we can write each
part as a precise (irreducible)
400000078669
2000123
A fraction is an exact ratio of 2 numbers, and if
those 2 numbers are integers, or at least rational
numbers, then the fraction can more
appropriately be called a rational number. An
irrational number can be represented as an
approximation to a rational number to an
extremely high degree of accuracy.
It's quite clear that there are fractions which
can't be expressed in finite decimal form!
Now, here's the big problem.
Not every number is rational!
For example there is no fraction for sqrt(2).
That is, no matter what whole numbers m
and n you pick, m/n is not the square root of 2.
Euclid wrote down a real AND beautiful proof
of this fact around 2300 years ago.
Interesting point about those real numbers is
also the possibility to divide
the number to his prime factorization:
2937127^(-1)17915749^(-1)2082607
maxcalcF('29*37*(127^-1)*179*(15749^1)*2082607');
>> 199987.740088485
REAL BIG INTEGER

So what about big integers? For example you


want to compute fact(70), your calculator shows:
fact(70) = 1.19785716699699e+100

or
maxcalcF('70!')
1.19785716699699E100

or even more

With a BigInt Library you'll see the full range of


Fact(70):11978571669969891796072783721
987892755536628009582789845319
680000000000000000

All examples can be found online:


maxbox3\examples\161_bigint_class_maxp
rove2.txt
http://www.softwareschule.ch/examples/
161_bigint_class_maxprove2.txt
The call respectively the calculation goes like
this:
function GetBigIntFact(aval: byte): string;
//call of unit mybigint
var mbRes: TMyBigInt;
i: integer;
begin
mbRes:= TMyBigInt.Create(1);
try
//multiplication of factor
for i:= 1 to aval do
mbRes.Multiply1(mbres, i);
Result:= mbRes.ToString;
finally
//FreeAndNil(mbResult);
mbRes.Free;
end;
end;

Or you want the power of 100 like


2^100 = 12676506002282299670376
function BigPow(aone, atwo: integer): string;
var tbig1, tbig2: TInteger;
begin
tbig1:= TInteger.create(aone);
//tbig2:= TInteger.create(10);
try
tbig1.pow(atwo);
finally
result:= tbig1.toString(false);
tbig1.Free;
end;
end;

1.197857166996989179607278372168909873
6458938142546425857... 10^100

but the maximum range on Pascal, C or Delphi


depends on your operating system types, means
nowadays an int64 range is big.
Now that the "signed" words are finally up-topar with the unsigned integer types, languages
introduce a new 64-bits integer type, called
Int64, with a whopping range of
-2^63..2^63 - 1

Another way is to use a type extended, but the


limitation is precision like
Writeln(FloatToStr(Fact(70)))
it only shows 1.2E+0100 or
1.19785716699698966E100

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

37

HOW TO DEAL WITH BIG NUMBERS PAGE 3/4 maXbox


At least one really big, it's 333^409 6 (10332
decimal digits)!:

I'm trying to move a part of SysTools to


Win64. There is a class TStDecimal which is a
fixed-point value with a total of 38 significant
digits. The class itself uses a lot of ASM code.

8542410589577088732296696591791458471
0138161386222147182917677810495360579
0662731836109375886562057769732224078
7369539815043322468151403276684789485 function BigDecimal(aone: float; atwo: integer): string;
2704687578755031097050417025182159123 begin
1581498325263250655809688846574990085
with TStDecimal.create do begin
9669714028055717222616721730816157657
try
7272999991338993244872051682800307067
//assignfromint(aone)
0499485838754788611631774723703891999
assignfromfloat(aone) //2
6958139536234769725670960895462872160
RaiseToPower(atwo) //23
2617326909732389848441307614286016432
result
:= asstring
3281696899530174488741933479651249141
finally
5546213966841046206162049080873850267
free
4650541288448161671070156327238251274
end
;
3281792004009389099676108083535339433
end;
5725524764503872061091991652109449193
9222603486211588501821307572510489932 end;
0094825429972785833085677027994289424
1606617524881072717128594007583728367
4910402380201480381659625620772921132
SysTools is hosted under Sourceforge:
4307343621431621697813033533870396651
http://www.sourceforge.net/
2798938013065335070551824759826900420
projects/tpsystools
1863795492471837910714543445430478178
The class TStDecimal is defined in the unit
7239952937171734656039024994397675239
StDecMth. It has the following
0512439014099231872228674262774255372
description: StDecMth declares and implements
4933304310551768256663623236667348978
4851223121246465215815916502622714756
TStDecimal. This is a fixed- point value with a
5034147013414617346249445763685652587
total of 38 significant digits of which 16 are to the
2971987877831270158832603817205011322
right
of the decimal point.
6371434556915439803996403854732786566
1366556882568704.2292943165706246
2026993558297850455952524136828406393
1428407486751810074659865765594581378
0192514534642025708505465055466519186
0004262625760818849535769666297091453
It is important to note that Infinity is not a real
7002071987397488841496932636449655414
number, it is an idea.
2960625942272943281855130658659637414
An idea of something without an end.
1177639546182930097371192049744072353
1587803915956018581696810199146742826
Infinity is not "getting larger", it is already fully
1271606169667518376174065032487760281
formed. Sometimes students or people
8378317677730431971470829242037195598
(including
me) say it "goes on and on" which
4142794539461134475921078967271031215
sounds
like
it is growing somehow. But infinity
1288626779198995387011439234510647066
1101764762310248123763791491889455422
does not do anything, it just is.
4081908148706733079384730490856632162
Writeln('')
5640799436867768527108759041690965302
Writeln('Big Lotto Combination 1600
2692727792891817098986146184008177018
of 5000!')
1767033389755570766416722785651840954
Writeln('')
3885689046572793127635154465381472711
Writeln(BinominalCoefficient(5000,
7240451212404891260149108022108352756
1600));
8260609161657527584296850614033467693
Writeln('')
4667568824407601228835743948301133856
Writeln('Same Lotto Comb 6 of 45!')
6729184892015764928314102429169028065
Writeln(BinominalCoefficient(45, 6));
2494545083790886477617437201261672363
-->8145060
7912448112789399431625831010771676068
Writeln('Same Lotto Comb 39 of 45!')
2781353130522059276715028909294777177
Writeln(BinominalCoefficient(45,
8545830155927642694762695926174086054
39)); -->8145060
2034506012289981568628167702061562869
9561954771340366063324712132695944068
OK, 1/3 is a finite number (it is not infinite).
4119059465666117348540308246233404699
But written as a decimal number the digit 3
2360387210154102113393219475674943157
repeats forever (we say "0.3 repeating"):
388839887567715636613
0.333333333333333333333... (etc.)

Etc etc etc...(Takes 3 pages)

38

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

HOW TO DEAL WITH BIG NUMBERS PAGE 4/4 maXbox


There's no reason why the 3s should ever stop:
they repeat infinitely.
Okay, I hope you're not one of those people who
denies 0.999... = 1 , because it sounds like
you're saying 0.333... doesn't exactly equal
1/3.
If there are only a finite amount of 3s, I wouldn't
argue a bit that they're not equal, but with an
infinite amount, they are.
Test the script with F9 / F2 or press Compile.
CONCLUSION

And we can easily create much larger numbers


than those! But none of these numbers are even
close to infinity. Because they are finite, and
infinity is ... not finite!
WISE MEN SPEAK,
BECAUSE THEY HAVE SOMETHING TO SAY;
FOOLS, BECAUSE THEY HAVE TO SAY
SOMETHING . -

APPENDIX STUDY WITH BIGINT DIRECT


// TODO: Copy a file in a connected share path
// this is 333^4096:
function GetBigIntDirect: string;
//Unit mybigint
var mbResult: TMyBigInt; i: integer;
begin
mbResult:= TMyBigInt.Create(333);
try
// Faktoren im Zaehler aufmultiplizieren ---> 2^12=4096
for i:= 1 to 12 do begin
mbResult.Multiply(mbresult, mbresult);
//writeln(inttostr(i)+': '+mbresult.tostring);
end;
Result:= mbResult.ToString;
finally
//FreeAndNil(mbResult);
mbResult.Free;
end;
end;

TMyBigInt = class
private
Len: Integer;
Value: AnsiString;
Plato
procedure Trim;
procedure Shift(k: Integer);
procedure MultiplyAtom(Multiplier1:
TMyBigInt; Multiplier2: Integer);
Feedback @ max@kleiner.com
public
Literature:
constructor Create(iValue: Integer = 0);
Kleiner et al., Patterns konkret, 2003,
procedure Add(Addend1, Addend2: TMyBigInt);
Software & Support
procedure Multiply(Multiplier1, Multiplier2:
http://www.softwareschule.ch/download/
TMyBigInt); overload;
codesign_2015.pdf
procedure
Multiply(Multiplier1: TMyBigInt;
http://www.softwareschule.ch/
Multiplier2
: Integer); overload;
download/XXL_BigInt_Tutorial.pdf
unction
ToString
: string;
http://www.mathsisfun.com/numbers/
procedure
CopyFrom
(mbCopy: TMyBigInt);
infinity.html
https://github.com/maxkleiner/maXbox3/ end;

maXbox

releases

Issue Nr 4 2016 BLAISE PASCAL MAGAZINE

39

WANT TO BECOME A DINOSAUR?

BETTER USE KBMMW...


-

Now multimonitor remote desktop V5 (VCL and FMX)


Rad studio and Delphi 10.1 BERLIN support
High performance LZ4 and Jpeg compression
Impoved NextGen support including IOS 64 bit
Native high performance 100% developer
defined application server with support for
loadbalancing and failover
Native high performance JSON and XML
(DOM and SAX) for easy integration with
external systems
Native support for RTTI assisted object
marshalling to and from XML/JSON,
now also with new fullfeatured XML schema
(XSD) import
High speed, unified database access
(35+ supported database APIs) with
connection pooling, metadata and
data caching on all tiers
Multi head access to the application server,
via AJAX, native binary, Publish/Subscribe,
SOAP, XML, RTMP from web browsers,
embedded devices, linked application
servers, PCs, mobile devices, Java systems
and many more clients
Full FastCGI hosting support. Host PHP/Ruby
/Perl/Python applications in kbmMW!
AMQP support

Supports Delphi/C++ Builder/RAD Studio


2009 to 10.1 Berlin (32 bit/64 bit, Android,
IOS 32/64 and OSX where applicable)"
kbmMemTable is the fastest and most feature rich
in memory table for Embarcadero products.
- Easily supports large datasets
with millions of records
- Easy data streaming support
- Optional to use native SQL engine
- Supports nested transactions and undo
- Native and fast build in M/D,
aggregation /grouping,
range selection features
- Advanced indexing features for
extreme performance
Warning!

kbmMemTable and kbmMW


are highly addictive!
Once used, and you are hooked for life!

( Advanced Message Queuing Protocol)


-

Added AMQP 0.91 client side gateway


support and sample.
Fully end 2 end secure brandable Remote
Desktop with near REALTIME HD video,
8 monitor support, texture detection,
compression and clipboard sharing.

COMPONENTS
DEVELOPERS

EESB, SOA,MoM, EAI TOOLS FOR INTELLIGENT SOLUTIONS. kbmMW IS THE PREMIERE N-TIER PRODUCT FOR DELPHI /
C++BUILDER BDS DEVELOPMENT FRAMEWORK FOR WIN 32 / 64, .NET AND LINUX WITH CLIENTS RESIDING ON WIN32 / 64,
.NET, LINUX, UNIX MAINFRAMES, MINIS, EMBEDDED DEVICES, SMART PHONES AND TABLETS.

Das könnte Ihnen auch gefallen