Вы находитесь на странице: 1из 40

BLAISE

BLAISE PASCAL
PASCAL MAGAZINE
MAGAZINE
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
A N D R O I D, I O S,
R E L A T E D
M A C,
L A N G U A G E S
W I N D O W S & L I N U X
39
39

MOTION

Book Review By Jim Duff


Getting Started with Lazarus and Free Pascal
Learning By Doing Author: Menkaura Abiola-Ellison
ClientDataSets and FDMemTables Compared: Part 1
By Cary Jensen
Accessing Preferences and Databases in Android (FPC)
By Michael van Canneyt
Painting 3D Lissajous figures
By David Dirkse
Checking your Android device is ready for development
By Stephen Ball

Publisher: Foundation for Supporting the Pascal Programming Language


in collaboration with the Dutch Pascal User Group (Pascal Gebruikers Groep)
Stichting Ondersteuning Programmeertaal Pascal
BLAISE
BLAISE PASCAL MAGAZINE 39
PASCAL MAGAZINE 39
D E L P H I, L A Z A R U S, S M A R T M O B I L E S T U D I O,
A N D P A S C A L R E L A T E D L A N G U A G E S
F O R 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

CONTENTS
Articles
Book Review By Jim Duff
Getting Started with Lazarus and Free Pascal
Learning By Doing Author: Menkaura Abiola-Ellison
Page 5

ClientDataSets and FDMemTables Compared: Part 1


By Cary Jensen Page 11

Accessing Preferences and Databases in Android (FPC)


By Michael van Canneyt Page 22

Painting 3D Lissajous figures


By David Dirkse Page 31

Checking your Android device is ready for development


By Stephen Ball Page 36

MOTION

BLAISE
BLAISE PASCAL
PASCAL MAGAZINE
MAGAZINE

Advertisers

Barnsten 9
BetterOffice 29
BLAISE PASCAL MAGAZINE 4
Cary Jensen (Jensen Data Sytems) 19
Components 4 Developers 40
Computer Math & Games 30
Daniel Teti 10
FAST REPORT 20/21
Raize Software 35

2 COMPONENTS
DEVELOPERS 4 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
Alexander Alexeev Peter Bijlsma Michal Van Canneyt,
www.alexander@blaisepascal.ru -Editor peter @ blaisepascal.eu michael @ freepascal.org
Alexander @ blaisepascal.ru

Marco Cant David Dirkse Daniele Teti


www.marcocantu.com www.davdata.nl www.danieleteti.it
marco.cantu @ gmail.com E-mail: David @ davdata.nl d.teti@bittime.it

Bruno Fierens Primo Gabrijeli Fikret Hasovic


www.tmssoftware.com www. www.
bruno.fierens @ tmssoftware.com primoz @ gabrijelcic.org

Cary Jensen Max Kleiner Wagner R. Landgraf


www.jensendatasystems.com www.softwareschule.ch
http://caryjensen.blogspot.nl max@kleiner.com

Sergey Lyubeznyy Kim Madsen Felipe Monteiro de Cavalho


www.component4developers

Mattias Gaertner Jeremy North Benno Evers


b.evers
jeremy.north @ gmail.com @everscustomtechnology.nl

Detlef Overbeek Howard Page Clark Rik Smit


www.blaisepascal.eu E-mail: hdpc @ talktalk.net
Email:editor @ blaisepascal.eu

Bob Swart Wim Van Ingen Schenau


www.eBob42.com -Editor
Bob @ eBob42.com wisone @ xs4all.nl

Please note: extra space characters have been deliberately added around the @ symbol in
these email addresses, which need to be removed if you use them.
editor @ blaisepascal.eu
Authors in alphabethical order
A Alexander Alexeev L Wagner R. Landgraf, Sergey Lyubeznyy
B Peter Bijlsma, K Max Kleiner
C Michal Van Canneyt, Marco Cant, M Kim Madsen, Felipe Monteiro de Cavalho
D David Dirkse, Daniele Teti N Jeremy North,
F Bruno Fierens O Tim Opsteeg, Inoussa Ouedraogo
G Primo Gabrijeli, P Howard Page-Clark,
H Fikret Hasovic S Rik Smit, Bob Swart,
J Cary Jensen

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 65.-- Incl. VAT 6 % (including code, programs and printed magazine,
10 issues per year excluding postage).
2: Electronic - non printed subscription 45.-- 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 1 2015 BLAISE PASCAL MAGAZINE


COMPONENTS
DEVELOPERS 4 3
PAGE-CLARK
LEARN TO PROGRAM
HOWARD
USING LAZARUS HOWARD PAGE-CLARK

USING LAZARUS
LEARN TO PROGRAM

25
HARDCOVER POCKET ELECTRONIC POCKET SALE

VE09206 Delphi AVR


Controller with SDK

RPi-B+ Raspberry Pi 2

16 GB 1421
Vogelaar Electronics
RPi ArchVE
RPi-ArchVE
Complete IO

Delphi AVR development board with SDK

VE08201 DelphiStamp with SDK

GREAT NEW OFFERS AT OUR WEBSITE:


WWW.BLAISEPASCAL.EU
Book Review By Jim Duff
Getting Started with Lazarus and Free Pascal
The author has worked in medical electronics for 25
years, from ICU to Dental Systems Development,
and found Pascal to rise to all the challenges of the
fast changing software world.
He felt that Lazarus / Free Pascal has been in
the shadows for far too long, and believes that
when considering a first language or more, that this
is a great language to use.
In the many years he has worked as a software
engineer, few programming languages have stood
the test of time as well as Pascal.
Menkaura has used Pascal for low-level systems
work, networking, process thread, database
application, medical device management,
embedded assembly coding, web applications and
operating remote control devices, to name a few.
He has been using Lazarus for the past three
years, and believes it is ready to step out of the
shadows of Delphi.

What this book covers


Chapters 1 to 5, introduces the reader to Lazarus and
Free Pascal. Here the reader will learn how to
download, install and setup Lazarus for their chosen
platform. The reader will first learn how to write
command-line programs using a text editor, and Free
Pascal compiler.
Learning By Doing
Author: Menkaura Abiola-Ellison Chapters 6 to 11, advances the readers knowledge
It is relevant to provide the following opening part by introducing more advanced topics such as arrays
of the book to show both the background of the and more. The reader will also learn the
author and then, based on his technical experience, fundamentals of Object Orientation Programming.
his initial set of rules as to how to start using These chapters will introduce the reader to the
Lazarus. Lazarus Integrated Development Environment (IDE),
In addition to starting up the engine, he also seeing Lazarus and OOP in action.
includes the logical creation of the various sets of
elements you are going to create and code. Such
explanations are provided to ensure that not only Chapters 12 to 16, delves further into Lazarus
does the software operate properly, but can be programming, and looks at such topics as errors and
easily maintained for ongoing support and Exception handling, Lazarus packages and how to
upgrading, or expansion to newer hardware create your own packages. The reader will learn
elements etc. in this day and age. about Lazarus Components Library (LCL) and how
About the Author to use them to build applications, including writing
Menkaura Abiola-Ellison has over 30 years of 2D, 3D, and animation. Using LCL, the reader will
experience as a software engineer and programmer. learn how to program for themselves.
He began his early years writing assembly code and Chapters 13 to 23, the reader will learn in these
BASIC in the 1980s, on his Acorn Atom, that his chapters how to write applications for: file handling,
parents purchased. He later went to university to dataset and database applications, and Web
study computer science, where he gained a BSc. application development. The reader will also learn
Hon, and later an MBA in business.
how to apply various debugging techniques using
For over 20 years he has programmed in various Lazarus debugging tools. Learning to document your
forms of Pascal from P-code, Module-2, Turbo code is an important part of application
Pascal, to Delphi / Lazarus. development; this will be covered in these chapters.
The chapter ends with a look at the various devices
In addition, he has commercial and technical that Lazarus and Free Pascal uses, for example, in
experience in other languages such as C++, Java, Android, smartphones' Embedded systems, and
JavaScript, Visual Basic, along a variety of web
Raspberry Pi, to name a few.
tools, but he finds he keeps coming back to Free
Pascal time and time again.

Issue Nr 1 2015 BLAISE PASCAL MAGAZINE


COMPONENTS
DEVELOPERS 4 5
Book Review: Getting Started with Lazarus and Free Pascal (Continuation 1)
These are now some contents of the book to let you Then enter the following ms-dos commands to
know what it is all about, and what its objectives are. compile and execute. You then receive the required
output:

As soon as you have completed this first step, you


Along the way this icon introduces: Type, compile are then moved straight on to Chapter 3 - Command-
and run the following source code. Name it xxxx.pas. line Programs - where the introduction of object
Lazarus is a free, cross-platform, visual IDE for oriented design is provided. This shows a sample
rapid application development (RAD) using Free that contains two 'classes', named THelloWorld
Pascal compiler, which supports Object Pascal, to and TThisWord, and then follows up by
varying degrees. One of the important features for converting the single program into two separate
Free Pascal is that of write once, compile anywhere. sources, therefore converting the two 'units' into two
This basically means that you only need to write your 'objects'.
source code once and compile it to target your This object method is a main aspect of the early
distribution (for such platforms as Windows, Linux, Mac, part of the book, to get users into the more
Android, FreeBSD, Unix, Raspberry Pi and others). elementary and productive method of creating code
However, in spite of the fact the Lazarus makes as programs are developed.
Free Pascal programming quick and easy, the Chapter 4 is a popular program subject
beginner is up against the initial hurdle of regarding Working with numbers: Functions,
understanding the concepts of object-oriented procedures and methods. What's the
programming (OOP). The aim of this book is to help difference?
you get past the initial learning stage and If you search the internet you will be presented with
confidently enter the world of OOP. as many answers as there are stars in the sky!
By contrast, Free Pascal is object-oriented. This book will attempt to simply explain the
In the Free Pascal approach to Object Oriented difference.
Programming, everything revolves around the This chapter contains basic arithmetic laws, and
concept of "classes". A class can be seen as a pointer gives definitions of sines, cosines and tangents
to an object, or a pointer to a record, with methods relating to triangles in order to create code for these
associated with it... view points. Again, another good set of examples,
As we go along in the book, comparison between this time working with algebra and geometry.
classes and objects will become clearer. In summary, Once getting past these introductory chapters to
we can say that a class is a general concept (like an give users the way to start using Lazarus, this initial
Animal), whereas, an object is a very specific sub-list of chapters provides you, and hopefully lots
embodiment of that class, with a limited lifespan (like of new Lazarus/Delphi developers, with a broad
a cat, dog or mouse). introduction of the major aspects of using this
Before we dive into classes & objects and how to language and software.
create & use them, we need to obtain and install OOP (Object Oriented Program)
Lazarus. http://www.lazarus.freepascal.org Fundamentals;
Once you have downloaded Lazarus, you then create Lazarus IDE (Integrated Development
the initial ms-dos based "Hello, world" program via Environment);
the Windows cmd: Notepad.exe hello.pas then press Dealing with Errors and Exception Handling;
the enter-key. You write your 'first' program as Graphics, 2D, 3D and Animation;
described here. File Handling;
Dataset Handling;
Lazarus and the Web;
Lazarus and Other Devices, Pi, Android,
Smartphones, and Embedded systems.

6 COMPONENTS
DEVELOPERS 4 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
Book Review: Getting Started with Lazarus and Free Pascal (Continuation 2)
SUMMARY The Book
As provided at the start of this review, the author is Getting Started with Lazarus
an experienced Pascal person, and his book has been and Free Pascal
introduced to attract new users for Lazarus and Free Learning By Doing
Pascal. Given the ongoing changes and introductions Author:
of new types of hardware and software, it is relevant Menkaura Abiola-Ellison
to attract new (young and old) starters into this
positive and productive set of development tools. First published January 2015
Published by Mka Publishing Communications
CONTENTS
House
Preface
290 Moston Lane Manchester
Why use Lazarus with Free Pascal?
M40 9WB
What this book covers
ISBN 13: 978-1507632529
What you need for this book
Reader feedback
Review by
Who this book is for
James D (Jim) Duff
Conventions
Long time programmer and developer.
Errata
1 Introducing Lazarus with Free Pascal
Reader feedback
2 Setting up Lazarus
Feedback from readers is always welcome. Let us
3 Command-line Programs
know what you think about this book, what you like
4 Working with numbers
or may have disliked.
5 Some input, some logic
6 Arrays and other topics
To send us general feedback
7 OOP Fundamentals
simply send an e-mail to
8 Lazarus IDE mka.feedback@gmail.com,
9 A New Look and mention the book title.
10 OOP in action
11 Using constructors and destructors
12 Dealing with Errors and Exception Handling
13 Lazarus Packages
14 Lazarus Component Library (LCL)
15 Building An Application with LCL
16 Graphics, 2D, 3D and Animation
17 File Handling
18 Dataset handling
19 Database Introduction
20 Lazarus and the Web
21 Debugging the Code
22 Documenting the code
23 Lazarus and Other Devices, Pi, Android,
Smartphones,
and Embedded systems
24 Method glossary
25 What Next
26 Index

Issue Nr 1 2015 BLAISE PASCAL MAGAZINE


COMPONENTS
DEVELOPERS 4 7
Book Review: Getting Started with Lazarus and Free Pascal (Continuation 3)

8 COMPONENTS
DEVELOPERS 4 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
UPGRADE OR BUY
RAD STUDIO XE7,
DELPHI XE7 OR
C++BUILDER XE7
AND GET THE
NEXT MAJOR RELEASE
FOR FREE!

or call: +31 (0)235422227


http://www.barnsten.com/default/xe7promo
HOICE A
SC
R BLAISE

M
TO

AZING
PASCAL

DI
MAGAZINE
E

Chapter 3: Going Cross Platform with FireMonkey


Giving a new appearance to the
standard FireMonkey
controls using styles
Creating a styled TListBox
Impressing your clients with animations
Using master/details with LiveBindings
Showing complex vector shapes using paths
Quick answers to common problems
Using FireMonkey in a VCL application
Chapter 4: The Thousand Faces of Multithreading
Synchronizing shared resources with TMonitor

Delphi Cookbook Talking with the main thread using


a thread-safe queue
Synchronizing multiple threads using TEvent
Displaying a measure on a 2D graph like an
50 hands-on recipes to master the power of Delphi for oscilloscope
cross-platform and mobile development on Windows, Chapter 5: Putting Delphi on the Server
Mac OS X, Android, and iOS Web client JavaScript application with WebBroker
on the server
Converting a console service application to a
Windows service
Serializing a dataset to JSON and back
Daniele Teti Serializing objects to JSON and back using RTTI
Sending a POST HTTP request
encoding parameters
Implementing a RESTful interface
using WebBroker
Table of Contents
Controlling remote applications using UDP
Chapter 1: Delphi Basics
Using App Tethering to create a companion app
Changing your applications look and feel with
Creating DataSnap Apache modules
VCL styles and no code
Chapter 6: Riding the Mobile Revolution with
Changing the style of your VCL application at runtime
FireMonkey
Customizing TDBGrid
Taking a photo, applying effects, and sharing it
Using the owners draw combos and listboxes
Using listview to show and search local data
Creating a stack of embedded forms
Do not block the main thread!
Manipulating JSON
Using SQLite databases to handle a to-do list
Manipulating and transforming XML documents
Using a styled TListView to handle
I/O in the twenty-first century knowing streams
a long list of data
Putting your VCL application in the tray
Taking a photo and location and sending it to
Creating a Windows service
a server continuously
Associating a file extension with your
Talking to the backend
application on Windows
Making a phone call from your app!
Chapter 2: Become a Delphi Language Ninja
Fun with anonymous methods using higher- Tracking the applications life cycle
order functions Chapter 7: Using Specific Platform Features
Writing enumerable types Using Android SDK Java classes
RTTI to the rescue configuring your class Using iOS Objective-C SDK classes
at runtime Displaying PDF files in your app
Duck typing using RTTI Sending Android intents
Creating helpers for your classes Letting your phone talk using the Android
Checking strings with regular expressions TextToSpeech engine

See our special offer:


The book including two years of download
subscription and shipment 100

http://www.blaisepascal.eu/index.php?actie=./subscribers/UK_Book_Department
ClientDataSets and FDMemTables Compared: Part 1
starter expert by Cary Jensen
Delphi XE 7
In addition, the ClientDataSet can be configured to
For more than a year now I have been writing
communicate SQL parameters, as well as entire SQL
about FireDAC, Delphi's newest data access
framework. During this time I have focused on a statements, from the DataSnap client to the DataSnap
variety of FireDAC features, including Local SQL, server, where its DataSetProvider can bind those
the SQL preprocessor, array DML, FDMemTables, parameters and SQL statements to server-side
and much more. TDataSets.
FDMemTables, you might recall, are in- The FDMemTable is also an in-memory dataset,
memory datasets, similar to Delphi's and it is included in the FireDAC data access
ClientDataSets. Since I am considered an expert framework that ships with Delphi since XE3. It was
on ClientDataSets, having published two books
originally designed as a general in-memory dataset,
on the subject, there is one question that I've
been asked over and over. "Can I replace the
with particular attention to interaction with other
existing ClientDataSets in my applications with FireDAC datasets, such as FireDAC's FDQuery and
FDMemTables?" FDStoredProc components.
Unlike ClientDataSets, which, when paired with
For some developers the answer is yes. But for most a DataSetProvider, can load its data from any
developers the answer is no, at least not yet. While TDataSet descendant, FDMemTables are currently
FDMemTables can do many of the things that designed to work primarily with FireDAC data sets.
ClientDataSets can do, they cannot do everything. If If you are using the FireDAC TDataSets, such as
your applications use ClientDataSets only for those FDQuery, you will likely use FDMemTables only
things that an FDMemTable can do today, then the when needing an in-memory dataset, as many of the
answer is yes. And, since FDMemTables are the features supported by both ClientDataSets and
future of in-memory tables in Delphi, you can go FDMemTables can be found in the other FireDAC
ahead and replace your ClientDataSets with DataSets. These features include support for cached
FDMemTables as time permits. On the other hand, if updates, dataset persistence, aggregates and group
you are using ClientDataSets for features that are not state, and filter navigation.
currently supported by FDMemTables, replacing In fact, it is through an FDMemTable that
those ClientDataSets at this time will result in a FireDAC data sets such as FDQuery get their
potentially significant loss of features. advanced features. Specifically, internally an
This brings me to the topic of this, and the next, FDQuery engages the services of an FDMemTable, an
article in my database series. In these next two FDTableAdapter, and an FDCommand.
installments, I am going to examine the similarities
and differences between ClientDataSets and Similarities
FDMemTables. Hopefully this will give you the ClientDataSets and FDMemTables are cross-
information you need before you start replacing your platform, in-memory tables that descend from
ClientDataSets with FDMemTables, or at least TDataSet.
understand which of the ClientDataSets you are Features supported by both ClientDataSets and
currently using can be replaced. FDMemTables include:
Before I continue, let me make one thing clear. Data and change cache persistence
While I am a fan of ClientDataSets, I understand that Support for XML
FDMemTables are superior in a number of ways. As Cached updates
a result, when the time comes that FDMemTables Cloned cursors
support all of the capabilities we require from Nested data sets
ClientDataSets, FDMemTables will be preferred. InternalCalc and Aggregate persistent fields
Until that time, you will want to use ClientDataSets Cross platform compilation by all of RAD
for those features not supported by FDMemTables, Studio's compilers
and use FDMemTables when you have a choice.
OK. Enough said. Let's get to it. Because of their common TDataSet ancestor,
ClientDataSets and FDMemTables share a large
Because the ClientDataSet was originally designed number of methods through inheritance. There are
for use with MIDAS (the multi-tier framework that also a large number of properties and methods that
became DataSnap) it supports a number of features they share, but which are not inherited. These shared
that are of particular value when used in a features provide a fair amount of API compatibility. I
distributed environment. These include being able to say "fair amount" because, though there are a number
transfer sophisticated master-detail relationships, as of properties and methods with the same names, in
well as arbitrary binary data, between the DataSnap some cases there are significant differences in how
server and client. they operate. I will focus more on the differences in
the following section.
Issue Nr 1 2015 BLAISE PASCAL MAGAZINE 11
ClientDataSets and FDMemTables Compared: Part 1 (Continuation 1)

While these non-TDataSet properties and methods cached updates, nested datasets, DataSnap, and
give ClientDataSets and FDMemTables similar finally, a collection of differences that I'll call
interfaces, they cannot be treated polymorphically miscellaneous.
with respect to these properties and methods. This is In the following sections I will take a look at
because these properties and methods are not design time operations, record persistence, and query
inherited from a common ancestor, and are not the configuration. I will following this up in the next
result of a common interface implementation. issue of Blaise Pascal Magazine with a look at cached
Properties shared by ClientDataSets and updates, nested datasets, DataSnap, and the
FDMemTables, but not inherited from TDataSet, miscellaneous topics.
include Aggregates, AggregatesActive,
ChangeCount, CommandText, Data, Delta, Design Time Operations
FetchOnDemand, FileName, IndexDefs, In this section I am going to address features of
IndexFieldNames, LogChanges, MasterFields, ClientDataSets and FDMemTables that you can
MasterSource, PacketRecords, RecordStatus, access at design time. Let's begin with creating the in-
SavePoint, StatusFilter, and XMLData. Methods that memory structure from within Delphi's IDE.
fall into this category (found in both classes but not These differences can be demonstrated using the
inherited from TDataSet) include ApplyUpdates, project named DesignTime. This project includes
CancelUpdates, CloneCursor, three memo fields that describe the areas of
GetOptionalParameters, LoadFromFile, difference and provide specifics about the
LoadFromStream, MergeChangeLog, SaveToFile, ClientDataSet and FDMemTable implementations.
SaveToStream, and SetOptionalParameters. There On the right-hand side of the project's main form
may be some additional properties and methods reside a ClientDataSet and an FDMemTable, both
supported by both ClientDataSets and FDMemTables hooked up to a DBGrid through a DataSource. These
that are not inherited from TDataSet and which are components can be used to demonstrate the specific
not listed here. differences. The main form of the DesignTime project
is shown in Figure 1.
Differences
There are a number of areas where FDMemTables
and ClientDataSets differ. These include design time
operations, record persistence, query configuration,

12 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE


ClientDataSets and FDMemTables Compared: Part 1 (Continuation 2)

Defining Structure
Whether you are using ClientDataSets or For an FDMemTable, you right-click the
FDMemTables, you define the structure (the fields FDMemTable and select Assign DataSet from the
and their data types) using either FieldDefs or FDMemTable's component editor. The
TFields. To use FieldDefs, you click the ellipsis FDMemTable's component editor will display a
button on the FieldDefs property in the Object dialog box listing all of the data sets that are visible to
Inspector, and then use the FieldDefs collection the FDMemTable. Complete the process by selecting
editor to define individual FieldDef definitions. To one of the data sets within scope of the FDMemTable.
use the Fields Editor, right-click the ClientDataSet or Loading a Previously Save File
FDMemTable and select Fields Editor. From the Loading data from a previously saved file is also very
Fields Editor, right-click and select New field (or simple for both ClientDataSets and FDMemTables.
press Ctrl-N). For ClientDataSets, point the FileName property to a
Once you have defined one FieldDef or TField for previously saved ClientDataSet file and then set
each column you want in the subsequent structure, Active to True. For an FDMemTable, set the
right-click the ClientDataSet and select Create FDMemTable's ResourceOptions.PersistentFileName
DataSet from the ClientDataSet's component editor. property to a previously saved FDMemTable, after
With an FDMemTable, simply set Active to True. which you set Active to True.
You clear data from both ClientDataSets and
Creating Indexes
FDMemTables using the same technique. Right-click
Creating persistent indexes at design time is pretty
the component and select Clear Data. You might also
much the same for both ClientDataSets and
have to manually delete any FieldDefs or persistent
FDMemTables. Using the IndexDefs property editor
TFields before using the ClientDataSet or
you add one IndexDef for each index that you want
FDMemTable with some other data structure.
to define. The one difference is that FDMemTables
support expression indexes, and these can use
Loading From Another DataSet
functions from FireDAC's SQL pre-processor.
To load a ClientDataSet from another data set, right-
ClientDataSets do not support expression indexes.
click the ClientDataSet and select Assign Local Data
Creating temporary indexes is also nearly
from the ClientDataSet's component editor. Select the
identical. Set the IndexFieldNames property to a
data set whose data you want to load into the
comma-separated list of the fields on which to
ClientDataSet from the displayed dialog box.
index. The one major difference here is that,
when using an FDMemTable, you can identify
one or more of the field names in the comma-
separated list to indicate you want the field
sorted in ascending order (the default) or
descending order. Follow the field name with a
colon and an A to indicate an ascending sort
order, and a colon and a D to indicate a
descending sort order. (The documentation
states that you can use an N to indicate a case-
insensitive sort, but that is the default. It does not
appear that there is a character that indicates a
case-sensitive sort order.)
As a result, assigning the following string to
an FDMemTable's IndexFieldNames property
will sort the data first by PartNo, in ascending
order, and then by Quantity in descending order.

PARTNO;QUANTITY:D

ClientDataSet indexes based on the


IndexFieldNames property are always sorted in
ascending order, and are case insensitive.

Figure 1. The DesignTime project

Issue Nr 1 2015 BLAISE PASCAL MAGAZINE 13


ClientDataSets and FDMemTables Compared: Part 1 (Continuation 3)

Figure 2. An FDMemTable is filtered using an expression that includes a FireDAC SQL preprocessor function

FireDAC Expressions
The final difference in design time usage is related to I've listed the use of sort order in temporary indexes
expressions. Expressions are used in filters, index and FireDAC expression engine functions in filters,
expressions, aggregates, and constraints. expression indexes, and constraints, in this section on
ClientDataSets can only use the standard design time usage. Obviously, these features are also
ClientDataSet special filter expressions, which available at runtime.
includes a collection of string, date/time, and Record Persistence
miscellaneous functions. FDMemTables, by Both ClientDataSets and FDMemTables can write
comparison, can use functions from the FireDAC their data to a file or stream. However, these
expression engine in these expressions. This is the operations are not compatible. Specifically, you
same expression engine used by the FireDAC SQL cannot load an FDMemTable with a previously
pre-processor. persisted ClientDataSet, and visa versa. While both
ClientDataSets and FDMemTables support both
The DesignTime project contains a DataModule that binary and XML-based formats, they are
includes an FDQuery. Here is the SQL statement incompatible. Importantly, FDMemTables support a
associated with that query: third format, JSON (JavaScript Object Notation), a
more current and popular format.
SELECT * FROM Customer
Record persistence is demonstrated in the project
If the FDMemTable on the main form of this project named RecordPersistence. The running main form is
is loaded from this query, the following value can be shown in Figure 3.
assigned to the Filter property.

EXTRACT('year', LASTINVOICEDATE) < 1990

After that, if the Filtered property is set to True, the


filter expression, which includes the FireDAC
function EXTRACT, will result in a filtered view, as
shown in Figure 2.

14 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE


ClientDataSets and FDMemTables Compared: Part 1 (Continuation 5)

Figure 3. The RecordPersistence project FDMemTable uses FDformat.ext, where format is


demonstrates ClientDataSet and FDMemTable record
binary, XML, or JSON, and ext is FDS, XML, or JSON.
persistence
Clicking Show Content also displays a dialog box
When you click the button labeled Show Content, the showing the content. This content, however, is not
selected dataset is persisted to file using a call to formatted, since not all versions of Delphi support
SaveToFile, where the ClientDataSet file is named the FormatXML function. Figure 4 shows how the
CDSformat.ext where format is binary or XML, and CDSXML.xml file appears in the provided viewer.
the ext is either .cds or .xml. SaveToFile for an
Issue Nr 1 2015 BLAISE PASCAL MAGAZINE 15
ClientDataSets and FDMemTables Compared: Part 1 (Continuation 6)

Figure 4. The XML format for a ClientDataSets.


By comparison, Figure 5 shows how an FDMemTable persists itself to XML.

Figure 5. The XML format for an FDMemTable

16 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE


ClientDataSets and FDMemTables Compared: Part 1 (Continuation 7)
FDMemTables support a third format not supported FDMemTables support a CommandText property
by ClientDataSets. Specifically, FDMemTables can and a ParamByName method, but these are not
persist their data using a JSON format. The Figure 6 nearly as straightforward to use.
displays the JSON format of an FDMemTable in the
provided viewer.

Figure 6. FDMemTables can persist their data using JSON


To begin with, this property and method are public,
and cannot be configured at design time. The
Query Configuration ClientDataSet properties, by comparison, are
ClientDataSets were designed to interact with published, and can easily be configured at design time.
DataSetProviders, including those running in another In addition, the use of the CommandText property
process (and even on a server visible to your requires that the FDMemTable point to an
network). These interactions include the ability of a FDTableAdapter, which in turn must employ at least
ClientDataSet to send query parameters to the one FDCommand.
DataSetProvider, which in turn binds those
parameter values to the parameters of its DataSet's
And, unlike the ClientDataSet and its
parameters. Indeed, the ClientDataSet can send the
entire query, including a parameterized query and DataSetProvider, these components must be running
the query parameters. This can be seen in the in the same process. The following code uses an
following code sample, where the DataSetProvider is FDMemTable to perform a task similar to that shown
pointing to an FDQuery. in the preceding ClientDataSet code.
ClientDataSet.Close; FDMemTable.Close;
DataSetProvider.Options := FDCommand1.Connection :=
DataSetProvider.Options + [poAllowCommandText]; DataModule1.FDConnection1;
ClientDataSet.CommandText := FDTableAdapter1.SelectCommand := FDCommand1;
'SELECT * FROM Employee ' FDMemTable.CommandText :=
'SELECT * FROM Employee'
+ 'WHERE Salary > :val;';
+ 'WHERE Salary > :val;';
ClientDataSet.Params[0].AsFloat := FDMemTable.ParamByName('val').AsFloat :=
StrToFloat(SalEdit.Text); StrToFloat(SalEdit.Text);
ClientDataSet.Open; FDMemTable.Open;

Issue Nr 1 2015 BLAISE PASCAL MAGAZINE 17


ClientDataSets and FDMemTables Compared: Part 1 (Continuation 8 - end)

Configuring queries using ClientDataSets and


FDMemTables is demonstrated in the
QueryConfiguration project, whose main form is
shown in Figure 7.

Figure 7. The QueryConfiguration projects demonstrates You can download the sample projects described in
runtime query configuration using ClientDataSets and
this article using the following URL:
FDMemTables
http://www.jensendatasystems.com/CDSFDM
emTable1.zip
When an FDMemTable is not in the cached updates
mode, and it is hooked up through an Summary
FDTableAdapter and FDCommand, it will apply ClientDataSets and FDMemTables share many
similarities, but a number of significant differences
changes to the underlying database on a record-by- as well. In this article I have discussed the
record based. To achieve the same effect using a similarities and have started to outline the
ClientDataSet, you would have to add a call to differences. In the next issue of Blaise Pascal I will
take a look at the differences between
ApplyUpdates to each of the following event ClientDataSets and FDMemTables with respect to
handlers: AfterPost, AfterInsert, and AfterDelete. cached updates, nested datasets, DataSnap, and a
few additional areas. I will wrap up that article with
This default behavior of an FDMemTable, of being some final conclusions about where and when to
able to write changes to the underlying database use ClientDataSets and FDMemTables.
automatically, will occur even with the configuration
shown in the preceding code. Specifically, even About the Author
though the FDTableAdapter has only one Cary Jensen is Chief Technology Officer of Jensen
Data Systems. Since 1988 he has built and deployed
FDCommand, and that FDCommand holds only a database applications in a wide range of industries, and
is available for development, consulting, and training.
SELECT statement, Specifically, even though the Cary is an Embarcadero MVP, a best selling author of
FDTableAdapter has only one FDCommand, and more than 20 books on software development, and
that FDCommand holds only a SELECT statement, holds a Ph.D. in Engineering Psychology, specializing in
human-computer interaction. He is also co-presenter
that statement can be used by the FDTableAdapter to with Ray Konopka on this year's Delphi Developer Days
create DELETE, INSERT and UPDATE SQL 2015 tour.
statements at runtime. This is possible because the
SELECT statement is homogenous, selecting data Visit
http://www.DelphiDeveloperDays.com
from a single table without employing subqueries or to learn more.
calculations.

18 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE


Issue Nr 1 2015 BLAISE PASCAL MAGAZINE 19
Accessing Preferences and Michal Van Canneyt
Databases in Android The use case where the administrative
starter expert aid does a round of all school buildings and
classrooms necessitates some order in the display of
the groups: Ideally, the order in which the classrooms
Abstract are visited. This can be modeled using a preference:
A previous article we've shown how to construct a
for simplicity, we'll assume that there are 2 orders:
basic Android application using Free Pascal and
the Java API. In this article, we'll show how to ascending and descending.
access the Preferences API and how to create and In reality, there would probably be one or two
access a database under Android, as well as ordering fields in the database.
showing how data-bound controls work in Likewise, some people prefer the names of students
the Android API. to be sorted on first name, others on last name. This
Introduction can be set using a second preference. In reality, each
Armed with the techniques of the previous student will maybe have a number assigned to him
contribution about the Android API, it is possible to (this is certainly the case in Flanders, Belgium), so
take further steps in the Android world. In this ordering on this number could also be an option.
contribution, we'll explore 2 important parts of the
Activities in the application
Android API:
The application will have 3 activities:
Preference management Android offers
a rich API for fetching and setting preferences. It TGroupsActivity
offers the possibility to display a preferences dialog, This is the main activity of the application: a list
without having to write a single line of code. activity that displays a list of groups. One of the
groups must be selected to display the second
Database management Every Android activity: TPupilsActivity.
device has the sqlite engine installed. Applications
can create and access an arbitray number of sqlite TPupilsActivity
databases stored on the device using the Android This is again a list activity which displays a list of
API. Controls can be bound to the result of queries students, with a checkbox next to each student. This
on this sqlite database, making it easy to create data- activity is started whenever the user selects a group
aware applications. in the main activity. When the 'back' button is
To demonstrate this, a small application is built: pressed, the activity exits, and control returns to the
an application to register the presence or absence of main activity.
students (pupils) in a school (we'll call it 'absenteeapp').
The use scenario is a teacher or administrative aid TAbsenteePreferenceActivity
who does a round of the school buildings, visits all This is the activity which will allow the user to set the
classrooms, and on his Android device notes who is preferences. It is invoked from the options menu of
absent in each class: he or she selects a group (by the main activity. The following android manifest file
name), and gets a dialog which contains all students describes these 3 activities:
that should - theoretically - be present in this group.
She or he ticks off whoever is absent. At the end of
the round, the data can be transferred to some kind of
administrative software.
An alternative use case is that all teachers can -
on their own Android device - simply note the absent
students for the group they are teaching currently,
and transfer the result for their classes whenever they
feel like. To be able to do this, we'll need a database
with 4 tables:

Groups
A table with the name of groups.
Pupil
A table with the names of students (pupils).
PupilGroup
A table which keeps track of which student is
part of which group: we assume that a studentl
can be part of more than one group.
presence
a table that notes who is present today.
22 COMPONENTS
DEVELOPERS 4 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
Accessing Preferences and Databases in Android FPC (continuation 1)
<?xml version="1.0" encoding="utf-8"?> TAbsenteeDBHelper =
<manifest class(ADSSqliteOpenHelper)
xmlns:android=" public
http://schemas.android.com/apk/res/android" constructor Create(aContext: ACContext);
package="eu.blaisepascal.absenteeapp" procedure onCreate(
android:versionCode="1" aDatabase: ADSSqliteDatabase);
android:versionName="1.0"> override;
<uses-sdk procedure onUpgrade(
android:minSdkVersion="9" aDatabase: ADSSqliteDatabase;
android:targetSdkVersion="9" /> aOldVersion,
<application android:label="@string/app_name" aNewVersion: jint); override;
android:icon="@drawable/icon"> procedure onOpen(aDatabase: ADSSqliteDatabase);
<activity android:name=".TGroupActivity" override;
android:label="@string/app_name"> end;
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="TPupilsActivity"/>
<activity android:name="TAbsenteePreferenceActivity"/>
</application>
</manifest>

The format of this manifest file has been discussed Some of these methods have an aDatabase parameter
in the previous article, it will not be repeated here of type ADSSqliteDatabase: This is because the
ADSSqliteOpenHelper is a helper class used in
A database back end database life cycle management that does not offer
The list of groups and students in the groups and
any real database functionality. Instead, the
presence records are stored in an SQLite database on
ADSSqliteDatabase class presents the actual
the device. This database must be created by the app
interface to an SQLite database. It offers methods
if it does not yet exist: It cannot be stored in the
to run queries, and retrieve data using cursors.
resources of the application.
When a new database must be created, the
Luckily, Android offers an API which takes care of
OnCreate method is called. It executes the
creating (and even updating) a database:
necessary SQL statements to create the database.
This functionality is present in a class called
This is done using the ADSSqliteDatabase
ADSSqliteOpenHelper.
interface, which offers an ExecSQL Method.
An application which needs to use SQLite databases
should create a descendant of this class and override The ExecSQL method gets an SQL statement as a
some methods: parameter, which it executes, much like TSQLQuery
in FPC.
onCreate procedure TAbsenteeDBHelper.onCreate(aDatabase:
ADSSqliteDatabase);
this method must create an empty database by
executing some DDL SQL statements. begin
OnUpgrade aDatabase.execSQL(CreateTableGroup);
Each database created by the Android SQLite helper aDatabase.execSQL(CreateTablePupil);
API gets a version number (an integer). If a database aDatabase.execSQL(CreateTablePupilGroup);
aDatabase.execSQL(CreateTablepresence);
must be upgraded, this method is called. The current end;
and new version are passed to this routine, and it
should execute all SQL statements needed to update SQL statements executed like this must not return a
the database. result. The 4 SQL statements that create the absentee
onOpen database are specified in 4 string constants, which
This method is called whenever the database is the interested reader can check in the sources.
opened. Since the application needs some data, some sample
Create The constructor of this class. It must set the data is inserted in the tables. In a real-world
expected current database version. This version will application, this data would be fetched from a
be checked against the version of an existing central administrative system. Here we simply create
database, and will call 'OnUpgrade' if they do not some sample data:
match.For the absentee application, the helper class is
called TAbsenteeDBHelper.
It overrides the above 4 methods:
Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
COMPONENTS
DEVELOPERS 4 23
Accessing Preferences and Databases in Android FPC (continuation 2)
// Create Groups The main activity
For I:=1 to 6 do The Group activity is the main activity.
begin
n:=JLLong.Create(i).toString;
It displays a simple list of group names (fetched from
Q:='insert into Group (gr_name) values the database), from which one must be selected.
(''Group '+n+'A'')'; Because such an activity is very common, Android
aDatabase.ExecSQL(Q); offers a ready-made list activity class:
Q:='insert into Group (gr_name) values
AAListActivity.
(''Group '+n+'B'')';
aDatabase.ExecSQL(Q); The groups activity will therefor be a descendent of
end; this list activity. It is defined as follows:
TGroupActivity = class(AAListActivity,
Pupils are created and linked to the groups with
AWAdapterView.InnerOnItemClickListener)
similar statements. protected
The other methods of the ADSSqliteOpenHelper FGroupsDescending : Boolean;
subclass are empty, except the Create method: FPupilsFirstName : Boolean;
fAdapter: AWSimpleCursorAdapter;
constructor TAbsenteeDBHelper.Create fDataHelper: TAbsenteeDBHelper;
(aContext: ACContext); fSelectedID: jlong;
begin procedure FillItems(isRefresh: Boolean);
inherited Create(aContext,'absentees', Nil, 1); public
end; procedure onCreate(
The second argument is the name of the database. No savedInstanceState: AOBundle); override;
Function onCreateOptionsMenu(
path should be specified: The Android API stores all
AMenu: AVMenu) : boolean ; override;
databases in a default, application-specific, location. Function onOptionsItemSelected(
The last argument is the version. AItem: AVMenuItem) : Boolean; override;
The Android API will check for the existence of this procedure onItemClick(
database: if it does not exist, it will call onCreate to aParent: AWAdapterView;
aView: AVView;
create it. If it exists, but has the wrong version, the aPosition: jint; aID: jlong);
'onUpgrade' method will be called instead. end;
The ExecSQL call cannot be used to run a select
The declaration contains 2 booleans which we'll use to
query, since it cannot handle a result set. To handle a
store the preference values. The
result set, the rawQuery method of the
AWAdapterView.InnerOnItemClickListener
ADSSqliteDatabase interface must be used.
interface is needed to respond to a click event from the
To get an instance of the ADSSqliteDatabase interface
list. The Group Activity is also the main activity of the
in a TAbsenteeDBHelper method, the
application, and the preferences dialog should also be
getWritableDatabase method must be used: this
launched from this. That means that we must create
ensures that an instance of ADSSqliteDatabase is
and populate the options menu. We've seen how to do
returned which can write to the database. Using this
this in the previous article:
we can now write a method that returns the names of
all the groups, sorted either ascending or descending: function TGroupActivity.onCreateOptionsMenu(
AMenu: AVMenu): boolean;
function TAbsenteeDBHelper.GetAllGroups
(sortdesc : Boolean): ADCursor; begin
var inherited;
query: String; AMenu.add(0,AVMenu.FIRST,0,R.strings.Preferences);
begin Result:=True;
query := 'select gr_id as _id, gr_name from end;
Groups order by gr_name ';
if SortDesc Getting preferences
then query := query + ' desc' Android supports saving and retrieving application
else query := query + ' asc'; preferences in a simple and straightforward way,
Result := using the PreferenceManager class. The default
getWritableDatabase.rawQuery(query, Nil);
way is to save preferences in a standardly named file
end;
in a standard directory, using XML:
Since the result is a read-only record set, we could /data/data/eu.blaisepascal.absenteeapp/
have used getReadableDatabase as well: shared_prefs/
it returns an instance which is able to read from the eu.blaisepascal.absenteeapp_preferences.xml
database, but can not necessarily write to it. The use of XML is hidden in the API, all the user of
The TAbsenteeDBHelper class has some other the API needs to know is how to read or write
methods to retrieve a list of students and set the settings.
presence or absence of a pupil, but these methods
are similar to the methods above.

24 COMPONENTS
DEVELOPERS 4 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
Accessing Preferences and Databases in Android FPC (continuation 3)
The PreferenceManager class has a function The FillItems method of the
getDefaultSharedPreferences which returns an TGroupActivity call fills the listview
interface of type ACSharedPreferences that can with items.
be used to manage the preferences. A list in Android is - just as in Gtk or Qt, but unlike
It has the functions one would expect from an API to as in windows - just a container widget: it displays a
manage preferences: list of other widgets, and simply scrolls these
function getString(para1: JLString; widgets on the display. Even simple text lists are
para2: JLString): JLString; rendered using TextView widgets. From this it
function getStringSet(para1: JLString; follows that we must tell the list view which widgets
para2: JUSet): JUSet; it needs to load and display. This is done using a
function getInt(para1: JLString;
para2: jint): jint;
layout: each widget is created from a layout, and for
function getLong(para1: JLString; our list of groups, this is the layout we'll use:
para2: jlong): jlong; <?xml version="1.0" encoding="utf-8"?>
function getFloat(para1: JLString; <LinearLayout
para2: jfloat): jfloat; xmlns:android=
function getBoolean(para1: JLString; http://schemas.android.com/apk/res/android"
para2: jboolean): jboolean; android:layout_width="fill_parent"
function contains(para1: JLString): jboolean; android:layout_height="fill_parent"
android:weightSum="100"
These calls are not very special, in fact they resemble android:orientation="horizontal" >
the methods found in the TIniFile class. <TextView
android:id="@+id/group_name"
android:layout_width="fill_parent"
Creating the Group activity android:layout_height="wrap_content"
When the group activity starts, it must do 2 things: android:layout_weight="30"
get the preferences, and connect to (or create) the android:padding="10dip"
database connection to get the group names. All this android:textSize="16sp" >
must be done in the onCreate method of the </TextView>
</LinearLayout>
activity, which can look like this:
This layout describes 1 item in the listview. In the
Const example above, it is a linear layout, containing
PrefGroups = 'GroupsDescending'; 1 TextView widget. The values of the various
PrefPupils = 'PupilsFirstName';
attributes are mostly self-explaining, and most of
procedure TGroupActivity. them have been discussed in the previous article.
onCreate(savedInstanceState: AOBundle); The widget has an ID associated with it: this is
specified by the android:id attribute: The value
Var "@+id/group_name" tells the resource packager
Prefs : ACSharedPreferences;
that it must create an ID that will identify the widget
begin instance - relative to its parent.
inherited onCreate(savedInstanceState); The value of this ID is written to the resource file and
setTitle(R.strings.name_groups); can be used to designate the widget in code,
Prefs:=APPreferenceManager.
getDefaultSharedPreferences(GetBaseContext( )); we'll get back to this later.
FGroupsDescending:=Prefs.getBoolean(PrefGroups,False); A listview gets its items from a
FPupilsFirstName:=Prefs.getBoolean(PrefPupils,False); ListAdapter class. This is an abstract
fDataHelper := TAbsenteeDBHelper.Create(Self); class from which descendants can be made. One of
FillItems(False);
these descendants is the AWArrayAdaptor class,
getListView.setOnItemClickListener(Self);
end which simply takes an array of strings (or Java objects)
and converts each item in the array to a listview
The code starts by setting the title of the activity: widget. That corresponds to the default use of a
since there is no resource file associated with the stringlist in Delphi or Lazarus.
activity, it must be set manually. It then reads the A second class, called
preferences using the preference manager: this is AWSimpleCursorAdapter, takes a database
done prior to creating the database. When the query result cursor and creates an item for each
preferences have been read, the database helper is record in the database query result: this is the data-
created: this will create and populate the database, if aware version of the ListAdaptor.
it didn't exist yet. For the Absentee application, this means a query
Last but not least, the list view is filled with items in must be run that returns all groups: Such a cursor is
the FillItems call, and the list created in GetAllGroups in the database helper
InnerOnItemClickListener is set so the class. This cursor can be used to fill the listview with
listview can react to clicks. the names of the groups with the following code:

Issue Nr 1 2015 BLAISE PASCAL MAGAZINE


COMPONENTS
DEVELOPERS 4 25
Accessing Preferences and Databases in Android FPC (continuation 4)
procedure TGroupActivity.FillItems(isRefresh:
Boolean);

var
cur: ADCursor;
colfrom: array[0..0] of JLString;

begin
if Not isRefresh then
begin
cur :=
fDataHelper.GetAllGroups(FGroupsDescending);
startManagingCursor(cur);
colfrom[0]:=TAbsenteeDBHelper.ColumnGroupName;
fAdapter:=AWSimpleCursorAdapter.Create(Self,
R.layout.group_list_item, cur,
colfrom, [R.id.group_name]);
setListAdapter(fAdapter);
end
else
fAdapter.getCursor.reQuery;
end;

If the list is not being refreshed, then the cursor is


created: it is the select query presented earlier, which
selects all the groups in the groups database.
The StartManagingCursor tells the activity that as
soon as it stops, the query should be deactivated.
When the cursor is fetched, the adaptor
AWSimpleCursorAdapter is created. The constructor
needs several arguments:
The layout to use when creating an item.
The layout is specified using its ID.
The cursor, this is the cursor created with
GetAllGroups.
an array of field names to use.
an array with ids of the items to fill with the fields
specified in the preceding argument.
Figure 1: A list of student Groups
In our example, there is only 1 item which must be
filled with the content of the group name field.
Once the adaptor is created, it is assigned to the list
view. The result looks as in figure .

Displaying the students and noting


absentees
The TGroupActivity instance was set as the item click
listener of the listview. This means that the
onItemClick method of the TGroupActivity
instance will be called whenever the user clicks an
item. The idea is that when a group is clicked, the
list of students is shown.
Opening the list of students, can be coded as follows:
procedure TGroupActivity.onItemClick(aParent: AWAdapterView;
aView: AVView;
aPosition: jint;
aID: jlong);
var
intent: ACIntent;
begin
intent := ACIntent.Create(Self, JLClass(TPupilsActivity));
intent.putExtra('eu.blaisepascal.absenteeapp.ID', aID);
intent.putExtra('eu.blaisepascal.absenteeapp.SortFirstName',FPupilsFirstName);
startActivity(intent);
end;

26 COMPONENTS
DEVELOPERS 4 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
Accessing Preferences and Databases in Android FPC (continuation 5)
The intent constructor needs 2 parameter: a context, procedure TPupilsActivity.FillItems(
Isupdate: Boolean);
and an Activity class to start. The context is the var
group itself, and the class is obviously the pupils cur : ADCursor;
activity. colfrom : array[0..1] of JLString;
An intent can carry parameters, which are simply b : TCheckBoxListBinder;
named values: These parameters are then made begin
available in the receiver of the intent. For the students if IsUpdate then
dialog, one parameter to pass is obviously the ID of fAdapter.getCursor.requery
else
the group for which the students must be shown. A begin
second (boolean) parameter is the preference setting cur:=fDataHelper.GetPupilPresenceFromGroup(
for the sort order of the students. FID,fSortFirstName);
The list of students is similar to the list of groups, startManagingCursor(cur);
colfrom[0] := 'pu_name';
except that there should be a check box for each
colfrom[1] := 'pr_code';
pupil, to mark whether the student is present or fAdapter := AWSimpleCursorAdapter.Create(
absent. To achieve this, the layout of the groups Self, R.layout.pupil_list_item, cur,
listview can be copied, but must be enhanced with colfrom, [R.id.pupil_name,R.id.present]);
the following entry after the TextView tag: b:= TCheckBoxListBinder.Create;
b.flistener:=Self;
<CheckBox fadapter.setViewBinder(b);
android:id="@+id/present" setListAdapter(fAdapter);
android:layout_width="wrap_content" end;
android:layout_height="wrap_content" end;
android:layout_alignParentRight="true"
android:layout_marginLeft="4px" The custom binder class is used to format each item in
android:layout_marginRight="10px" > the list with the data from the list, for this it
</CheckBox> implements the
The changed layout can be saved as AWSimpleCursorAdapter.InnerViewBinder
pupil_list_item.xml. The id attribute shows class.
that the check box will have an ID assigned to it, TCheckBoxListBinder = Class(JLObject,
called present. The code for the students (pupils) AWSimpleCursorAdapter.InnerViewBinder)
FListener :
listview activity is almost identical to the one
AWCompoundButton.InnerOnCheckedChangeListener;
for the groups. There are some small differences: for Function setViewValue(view: AVView;
instance, in the onCreate method, the extra cursor: ADCursor;
parameters passed with the intent must be retrieved, colindex : jint) : jboolean;
end;
so it can be used in the query to retrieve all students
in the group: The FListener field is an interface that is
passed to this object: the binder will pass
procedure TPupilsActivity.onCreate(savedInstanceState:
AOBundle);
this interface to each checkbox it formats:
the checkbox will call this interface when
Const the checkbox is checked or unchecked..
SPrefSort = 'eu.blaisepascal.absenteeapp.SortFirstName'; The setViewValue method of the interface,
SParamID = 'eu.blaisepascal.absenteeapp.ID';
which does the actual formatting (or
begin binding) is implemented as follows:
inherited onCreate(savedInstanceState);
fDataHelper:=TAbsenteeDBHelper.Create(Self);
fSortFirstName:=getIntent.getBooleanExtra(SPrefSort,False);
fID:=getIntent.getLongExtra(SParamID, 0);
if (fID=0) then
Raise EAbsenteeData.Create('No ID for absentee app given');
SetTitle(R.strings.name_pupils);
FillItems(False);
end;
The Intent instance can be retrieved with getIntent,
it offers several methods to retrieve extra data in a variety of
data types. Note that, together with the ID of the student group,
the preference for sorting the students is also fetched. The code
to fill the list of items is virtually identical to the one for groups,
with the difference that a different query is used: There are 2
fields: one for the name, one for the absence indicator. To
respond to the user checking or unchecking a name, a custom
binder is used:
Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
COMPONENTS
DEVELOPERS 4 27
Accessing Preferences and Databases in Android FPC (continuation 6)
function TCheckBoxListBinder.setViewValue( Managing preferences
view: AVView; cursor: ADCursor; Besides an API for getting and setting
colindex: jint): jboolean;
preferences, Android offers also an API to create a
Var cb : AWCheckbox; puID,i : jint; s : string;
begin dialog in which the user can manipulate the
Result:=(colIndex=2); preferences: it offers a PreferenceActivity class which
if Result then shows a dialog to manage the preferences of an
begin
application. This class can be used as-is, and does not
cb:=AWCheckBox(view);
puID:=cursor.getint(0); need any additional code to manage the settings: it
cb.setTag(TIDTag.Create(puID)); must be constructed using a special set of views, each
i:=cursor.getColumnIndex('pr_code'); of which is connected to a preference setting, using a
if not Cursor.IsNull(i) then name. All that needs to be done, is specify a layout:
begin
s:=cursor.getstring(i);
<?xml version="1.0" encoding="utf-8"?>
cb.setChecked(s='+');
<PreferenceScreen
xmlns:android=
end;
cb.setOnCheckedChangeListener(flistener); "http://schemas.android.com/apk/res/android">
end; <PreferenceCategory
end; android:summary="View settings"
android:title="GUI Settings" >
The code is pretty straightforward: if the passed view <CheckBoxPreference
is the checkbox -- this can be determined from the android:key="GroupsDescending"
column index -- then it gets a tag associated with it. android:summary="When checked,
The tag can be any object. In this case a small custom groups are sorted descending"
defined object that just contains the ID of the pupil: android:defaultValue="false"
android:title="Sort groups descending"/>
this will be used in the OnCheckedChange listener. <CheckBoxPreference
After setting the tag, the check marker is set or android:key="PupilsFirstName"
cleared, based on the value of the pr_code field (a '+' android:summary="When checked,
or '-'). Finally, the OnCheckedChange listener of the pupils are sorted on firstname"
checkbox is set to the interface in FListener. android:defaultValue="false"
This OnCheckedChange listener interface is android:title="Sort pupils on first name"/>
</PreferenceCategory>
implemented in the TPupilsActivity class. It starts by
</PreferenceScreen>
getting the tag value which was added during the
bind operation: it contains the students ID, and uses The layout is divided in categories (for simplicity
this to save the value of the check to the database there is only 1 category : "Gui setting''), which can
using the data helper class: have a title and summary. These act as a purely
procedure TPupilsActivity.onCheckedChanged( visual divider of the activity. In each category,
cb: AWCompoundButton; checked: jboolean); several preference widgets can be shown. There are
Var puID : Integer; different preference widgets, depending on the kind
begin
puID:=TIDTag(cb.getTag()).ID;
of preference that must be managed. Android offers
FDataHelper.Pupilpresence[puID]:=cb.isChecked; out of the box a CheckboxPreference (or a
end; SwitchPreference) for boolean values,
The actual queries will not be presented, they are EditTextPreference, ListPreference,
MultiselectListPreference: the names speak
straightforward and simple. The activity, once called
for themselves.
from the main groups activity, looks as in figure 1.
Each preference has a title and summary, and a
default value. The key attribute gives the name of the
preference, which should of course match the name
used to retrieve the preference in code.
All that is needed to show the above preferences, is
to declare the activity class, and load the preferences
resource in the onCreate method:
TAbsenteePreferenceActivity =
class(APPreferenceActivity)
public
procedure onCreate(
savedInstanceState: AOBundle); override;
end;

Procedure
TAbsenteePreferenceActivity.onCreate(savedInstanc
eState: AOBundle);
begin
inherited onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.prefs);
Figure : The students, absent or present end;

28 COMPONENTS
DEVELOPERS 4 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
Accessing Preferences and Databases in Android FPC (continuation 7 -end)

function TGroupActivity.onOptionsItemSelected(
AItem: AVMenuItem): Boolean;
var intent: ACIntent;
begin
if AItem.getItemId()=AVMenu.First then
begin
intent := ACIntent.Create(Self,
JLClass(TAbsenteePreferenceActivity));
startActivity(intent);
Exit(True);
end
else
Result:= Inherited
onOptionsItemSelected(AItem);
end;

All in all, surprisingly litle code to create and show a


preferences dialog. Android has more goodies when
programming a preferences dialog, but it would lead
too far to discuss them all in this article. in figure ,
the dialog is shown in action.
Figure : The preferences dialog
conclusion
That is all there is to creating a (simple) preferences In this article, we've shown how to create a
dialog. The preferences activity must be shown when database backend for an Android application.
the user selects the 'Preferences' item in the options Additionally we've shown how to set, store and
menu, which means it must be implemented in the retrieve preferences: both tasks are part of
onOptionsItemSelected method of the group almost any application, and Android makes
activity. Showing the preferences dialog is done in them particularly easy. In a future contribution
we'll show how to connect to internet: a
the same way as showing any other activity, using an
commonplace operation on a mobile device.
intent:

better office benelux | asterlaan 6 5582EH waalre | 040 222 26 43 gtan@better-office.com


DAVID DIRKSE
presales at
www.blaisepascal.eu/DavidDirkse/ComputerMath_Games.html

procedure ;
var
begin
for i := 1 to 9 do
begin

end;
end;

BLAISE PASCAL MAGAZINE


is proud to announce the first
edition of David Dirkses book:

COMPUTER MATH &


GAMES IN PASCAL
Painting 3D Lissajous figures By David Dirkse
In mathematics, a Lissajous curve , also known as
In this article we will produce computer art
Lissajous figure or Bowditch curve , is the graph
by means of 3 dimensional Lissajous figures.
of a system of parametric equations.
Lissajous (1822..1880) was a French
Pattern produced by the intersection of two sinusoidal
mathematician, famous for his research on
curves the axes of which are at right angles to each
waves. Below is a reduced picture of the
other. First studied by the American mathematician
program at work:
Nathaniel Bowditch in 1815, the curves were
investigated
independently by the
French mathematician
Jules-Antoine Lissajous
in 185758.
Lissajous used a narrow
stream of sand pouring
from the base of a
compound pendulum to
produce the curves.

WIKIPEDIA

What are Lissajous figures?


A normal function has the format y = ..x.... where
the dots stand for constants and operators.
For each substituted value of x the function produces
one value for y.
So, it is not possible to paint circles, ellipses or spirals.
This may be overcome by a tric, we write

x = ..t...
y = ..t...
This circle, having a radius of 5 and center (0,0) may
X and Y are now functions themselves of interim be described by
variable t. x = 5cos(t)
A value of t now yields a value for x and also for y. y = 5sin(t)
This is called a parametric function. t has to be incremented from 0 to 360 degrees for the
Another sort of function is the periodic function. complete circle. The result of a sine or cosine function
Examples are: is -1...+1 Lissajous figures emerge when periodic
functions are written in parametric form.
y = sin(x) and also y = cos(x) More interesting shapes than circles may be
generated by applying constants or the addition or
x is an angle. multiplication of several sine or cosine functions.
See the figure below to refresh your mind: On the next page is a 2D example:

COMPUTER MATH &


Issue Nr 1 2015 BLAISE PASCAL MAGAZINE 31
GAMES IN PASCAL
Painting 3D Lissajous figures (Continuation 1)

This picture is the result of

x = 2cos(t)
y = sin(t) + sin(3t)

The 2 dimensional screen coordinates are painted in


3D
blue, the 3 dimensional are red.
For three dimensions, we have to add a z coordinate
The effect of depth is accomplished by a shift in the Z
to the x,y coordinate system.
direction.
(z is perpendicular to the x- and y-axis)
Point D has coordinates (x,y,z) = (0,0,0) where A is
at (0,0,1) .
The Z value of A is translated into a x shift of -0.5
and a y shift of 0.5
In general:

3D Lissajous figures have the general format:

x = cos(..t)
y = sin(..t)
z = sin(..t)
When the Z axis is painted with angle a to the x axis,
Note: the sine and cosine functions are then:
interchangeble.
px = x zcos(a)
The computer screen (still) is 2 dimensional, so for a 3 py = y + zcos(a)
dimensional illusion we have to implement a tric.
Please look at the picture below: where (px,py) are pixel coordinates of the screen and
(x,y,z) are the 3 dimensional coordinates.

Here we choose a = 45 degrees so sin(a) = cos(a) = 1

COMPUTER MATH &


32 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
GAMES IN PASCAL
Painting 3D Lissajous figures (Continuation 2)
The screen

The screen is 800 * 800 pixels.


For the xy plane, 500 * 500 pixels are assigned, for the
Z shift an addional 125 pixels.
The range of the sine and cosine functions is -1..+1, so
the scale is 250 : 1.
250 adjacent pixels represent a length of 1.
For the Z scale we choose a scale of 125 : 1.
The equation of the circle is
A z shift of 1 causes a 125 pixel shift for x and y.
(i-15) + (j-15) = 225
From the center (400,400) we may paint over a
distance of 375 = 250 + 125 pixels.
where i is the horizontal- and j the vertical position.
A test for a pixel being part of the circle is:
In our system, the functions therefore look like:
225 ((i-15) (j-15) >= 0
x = 250cos( )
y = 250sin(...)
However, this does not result in a nice circle, because
z = 125sin(...)
points (16,0) and (17,0) are missing.
This is fixed by replacing 225 (=15) by 15 + 2 = 229
Note: a later version has the screen center at
The test is now:
(385,385). The pen position (0,0) is at the left top
corner. This results in the center (15,15) over
229 ((i-15) (j-15) >= 0
(400,400). Nothing changes but some calculations are
saved.
Height
The sphere pen itself is 3 dimensional. For each pixel,
Depth
the height must be calculated.
Another problem of 3D drawing is that a deeper pixel
The equation of a sphere with radius r and center
may not overwrite a higher positioned pixel.
(0,0,0) is:
An array is added, registring the depth (z value) of
each pixel on the screen.
x + y + z = r
See the next picture.
Points P and Q occupy the same screen pixel, but ZP
We can use the same calculation as above, only a
> ZQ, so P must be written, not Q.
square root and division by 2 must be added. So the
height of pixel (i,j) in the pen is:
Painting the sphere pen.
There are 4 pen types: sphere, cube, square and circle.
0,5* (229 ((i-15) (j-15) )
The pen has an image of 31*31 pixels. The center is at
(15,15).
Pixels outside the circle are given a depth of -1000,
A quarter pen is pictured top right:
which prohibits drawing in all circumstances.
The screen pixels are preset to a depth of -400.

COMPUTER MATH &


Issue Nr 1 2015 BLAISE PASCAL MAGAZINE 33
GAMES IN PASCAL
Painting 3D Lissajous figures (Continuation 3)
Colors procedure paintImage(x,y,z : smallInt);
Emperically it shows that a realistic sphere may be //x,y are left-top coordinates of pen
painted by using the Pythagoras theorem and linear //paint pen at x,y,z
var p,p1 : dword; px,py : word;
functions only. Zsph : smallInt; i,j : byte;
begin
We choose the lightest point somewhere left top and with map do
begin
the darkest point right bottom. The ligthest point has for j := 0 to 30 do
intensity $ff , the darkest 0. begin
py := y + j;
p1 := p0 - py*pStep;
We place the lightest pixel at position (10,10). Using
for i := 0 to 30 do
the Pythagoras theorem, we find the darkest pixel at begin px := x + i;
(26,26). The distance between the lightest and the Zsph := z + SZ[i,j];
dark spot is 23 pixels, so the intensity decreases if (Zsph > ZBuffer[px,py])
100/23 4% per pixel distance from position (10,10). then
begin p := p1 + (px shl 2);
So, the intensity decrease I is: ZBuffer[px,py] := Zsph;
PDW(p)^ := SPixels[i,j];
I = D . $ff. 0,04 end;
end;//for i
where D = ( (i-10) + (j-10) ). end;//for j
end;//with
end;
Data formats
Notes:
type Tpixels = array[0..30,0..30] of dword; Drawing is in a bitmap to be copied later to a
TZ = array[0..30,0..30] of smallInt; paintbox on form1. Reason is speed. Bitmap pixels
var Zbuffer : array[0..799,0..799] of smallInt;
may be addressed directly in memory.
//Z value per screen pixel Pointer p0 = scanline[0] points to row 0, column 0 of
SPixels : Tpixels; //pen pixel colors the bitmap.
SZ : TZ; //pen Z value Pstep is the pointer difference between two rows.
The pointers are saved as dwords, which are
Making the sphere pen typecasted to pointers when needed..
...........
Type PDW = ^dword
{vr,vg,vb are extracted 8 bit rgb colors}
.............
for j := 0 to 30 do Smooth
for i := 0 to 30 do Variable t increments from 0...stepcount.
begin For each value of t the pen is
d := 229 - sqr(j-15) sqr(i-15);
if d >= 0 then
painted on the screen at the
begin SZ[i,j] := trunc(0.5*sqrt(d)+0.5); calculated (x,y,z) position.
if (abs(i) < 4) and (abs(j) < 4) then d := 1 In smooth mode also the
else d := 1 - sqrt(sqr(i-10) + sqr(j-10)+0.5)*0.04; in-between points are
r := trunc(vr*d);
painted, so a more smooth
g := trunc(vg*d);
b := trunc(vb*d); picture is the result.
Spixels[i,j] := r + (g shl 8) + (b shl 16);
end; The Lissajous 3D project
end; This consists of form1 with unit1 and unit2.
Drawing the pen on the screen Form1,unit1 take care of the user interface, controls
Following has to be done: and events.

- add z value of pen pixel to z value of pen on screen Unit2 stands on its own and contains the data
- write pixel if this height (z value) is greater than the formats, procedures and functions to draw the pens
screen z value and the Lissajous graphics.
Right top is the code
There is choice out of three sets of formulas, 7 colors
and 4 pen styles.
Constants may be altered by left (+) and right ()
mouseclicks. The new formulas are pictured at each
change. Settings may be saved, reloaded or a picture
may be saved as bitmap. Please refer to the source
code for more details.

COMPUTER MATH &


34 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
GAMES IN PASCAL
BLAISE 2015
Checking your Android device is ready By Stephen Ball
for development If it shows under Other Devices with a yellow alert,
starter expert then you will need to update the drivers.
Delphi XE 7 You will still need to confirm on the phone when you
finally have it all setup and you plug the phone in for
In this small article I want to take you through the
steps for getting your Android device working with the first time, but this is the first steps.
the standard USB device drivers, including steps
to follow to check if what you have done has Phone drivers installed?
worked.
Jim McKeeth did a blog post a while back about
installing custom specified Android devices that is
worth reading if your device does not work with
the standard drivers, however I would recommend
trying this first.

Developer mode Enabled?


When you plug in your Android device, you will
need to ensure you have enabled developer mode
and confirmed that you want to enable USB Figure 1: Nexus 4 showing in Device Manager when
its not installed correctly
Debugging.
You can download the drivers if you search the web
Under Setting, you should be able to see for them and point to those, or you can download
{ } Developer options as a menu item. and install them easily with the Android SDK
If you dont, tap About phone menu item 5 times to Manager.
start the messages about going into developer mode.
Launching the Android SDK Manager
It is also worth checking at this point that USB To launch the Android SDK Manager, first open a
Debugging is enabled under developer options. command prompt and navigate to the android SDK
On Windows, you need to have the drivers installed tools folder. With Appmethod / RAD Studio they
for the phone to enable it for developer work. Once will be installed by default in the public documents.
you plug the device in, check the device manager. You can reach them using the cd command. e.g.

Figure 2: Android SDK Manager, USB Drivers ready to update

36 COMPONENTS
DEVELOPERS 4 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
Checking your Android device is ready for development (Continuation 1)
cd
\Users\Public\Documents\Embarcadero\Stud
io\14.0\PlatformSDKs\adt-bundle-windows-
x86-20131030\sdk\tools

From the SDK tools folder type in Android and hit


enter and the SDK manager will open.

Installing the USB Drivers


With the Android SDK Manager launched you can
now see the packages installed / to update.
Specifically we are looking for the Google USB Driver.
(see image below) Once found, choose Install xx Figure 3: Update Driver in Device Manager
packages button at the bottom of the screen. Choose to browse the computer and go back to the
PlatformSDKs folder (path above) and choose to
Android SDK Manager, USB Drivers ready search sub folders. See Figure 4 at the bottom.
to update
Note: If you dont see it,
then install any packages that are
pending update, close and re-open.
It should then connect back to
the Internet and refresh the list
and make the Google USB Driver
visible ready to install.

Updating the device driver


Once you have the drivers
on your machine, the next step is
to update the driver back in the
device manager. See Figure 3.
Figure 5: Confirm Install

If you have not already said to always trust google


inc. You should see immediately be asked to confirm
installing the driver.

Confirm Install
Once installed the Android Composite ADB Interface
driver will be installed and you will get confirmation.

Figure 4: Set path to find Android SDK for Appmethod / RAD Studio

Issue Nr 1 2015 BLAISE PASCAL MAGAZINE


COMPONENTS
DEVELOPERS 4 37
Checking your Android device is ready for development (Continuation 2)

Figure 6: Confirmed, Driver Installed


At this point, you should be able to see in the device cd \Users\Public\Documents\Embarcadero\
manager the device is installed. Studio\14.0\PlatformSDKs\
adt-bundle-windows-x86-20131030\
sdk\platform-tools
Once your command prompt window is open at
Platform Tools, run the following command to view
the connected devices.
adb devices
The following screen below shows the output.
Here I have my android device connected, but as yet
I have not confirmed the connection on my phone as
being allowed. This causes the device to show as
unauthorized.
Figure 7: Android Device Installed
With the phone drivers installed, it is now time to
check the ADB command line can see your device. If
it can, then you are ready to use it for development.

Checking ADB can see your Android


device
To check that ADB can see your device, its time to
head back to the command line and run the ADB
application. ADB.exe lives in the ..sdk\platform-
tools folder. From the command line you should be
able to get there with something like

Figure 8:Un-authroised Device


If the android device shows as unauthorized then unlock the phone and choose to Allow USB debugging.

38 COMPONENTS
DEVELOPERS 4 Issue Nr 1 2015 BLAISE PASCAL MAGAZINE
Checking your Android device is ready for development (Continuation 3)
At this point you are ready to use your android
device for development!
Refresh your Android devices in your IDE (right
click on Android as a Target platform in the
Project Manager and it will become visible.)

Figure 11 The visible Android Device

About the Author:


Stephen Ball has lead development teams for
over a decade within the UK and across
Europe working with a range of blue chip
companies including Hilton, American
Express, Fitness First, Virgin Active;

Stephen is a Chartered IT Professional and is


the Associate Product Manager for InterBase
and also a Product Evangelist for RAD
Studio, regularly speaking across EMEA.

Figure 9: Approving Debugging for Android

Once the device is approved, you should be able to


re-run the ADB devices command and see the device
id nows shows the status of device.

Figure 10: ADB for approved device

Issue Nr 1 2015 BLAISE PASCAL MAGAZINE


COMPONENTS
DEVELOPERS 4 39
KBMMW V. 4.60 AMQP support
( Advanced Message Queuing Protocol)

- Added AMQP 0.91 client side gateway Supports Delphi/C++Builder/RAD Studio 2009
support and sample. to XE7 (32 bit, 64 bit and OSX where applicable).
- Updated StreamSec TLS transport plugin kbmMW for XE5 to XE7 includes full support for
component (by StreamSec). Android and IOS (client and server).!
- Improved performance on Indy TCP/IP
kbmMemTable is the fastest and most feature rich
Client messaging transport for large number in memory table for Embarcadero products.
of inbound messages.
- Easily supports large datasets
- Native high performance 100% developer with millions of records
defined application server with support for - Easy data streaming support
loadbalancing and failover - Optional to use native SQL engine
- Native high performance JSON and XML - Supports nested transactions and undo
- Native and fast build in M/D,
(DOM and SAX) for easy integration with
aggregation /grouping,
external systems range selection features
- Native support for RTTI assisted object - Advanced indexing features for
marshalling to and from XML/JSON, now also extreme performance
with new fullfeatured XML schema
(XSD) import Warning!
- High speed, unified database access kbmMemTable and kbmMW
(35+ supported database APIs) with
connection pooling, metadata and
are highly addictive!
Once used, and you are hooked for life!
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

COMPONENTS
4
and many more clients
- Full FastCGI hosting support.
Host PHP/Ruby/Perl/Python applications in
kbmMW! 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.

Вам также может понравиться