0% found this document useful (0 votes)
52 views40 pages

Blaise Pascal Magazine 8

Uploaded by

jadielsn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
52 views40 pages

Blaise Pascal Magazine 8

Uploaded by

jadielsn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 40

BLAISE PASCAL MAGAZINE

ALL ABOUT DELPHI AND DELPHI PRISM(.Net) , LAZARUS & PASCAL


Pascal 8 AND RELATED LANGUAGES

Delphi 2010 – what a feeling! - Bob Swart page 7


Gestures could be the new ’must’ in our computers future
Counters - David Dirkse page 11
Learning counting again, - could wel be a hobby...
Virus in Delphi? - Nick Hodges page 14
Nick explains how to get rid of the virus and block it.
Dezign for databases - Marco Roessen page 16
A fantastic alternative for its expensive competitors, and it’s even cheaper.
Customizing the T-Field data display - Henk Schreij page 18
Diving deeper into the possibility’s
Using Free Pascal and Lazarus to create applications for OSX - Jeremy North page 20
Working on the Mac is hot
Writing Delphi Components II:
Custom Properties and Windows Controls - Marco Cantù page 22
In the new Delphi versions it looks all different.
My Top Five Delphi 2010 New Features - Pawel Glowacki page 24
Except for guestures ther is a lot of news...
Fast Graphic deformation by using Scanlines - Peter Bijlsma page 28
Control your own image or blow it up! Berlusconi on the edge
Wide Information Bus (Introduction) - Fikret Hasovic page 33
What is it and what the use for it?
Freehand Drawing (Introduction) - David Dirkse page 36
shows how to create your own paint program

October 2009
Publisher: Foundation for Supporting the Pascal Programming Language
in collaboration with the Dutch Pascal User Group (Pascal Gebruikers Groep)
© Stichting Ondersteuning Programeertaal Pascal
Cover price Europe: € 10.00 / UK £ 10.00 / US $ 10.00
BLAISE PASCAL MAGAZINE 8
ALL ABOUT DELPHI AND DELPHI PRISM(.Net) ,LAZARUS & PASCAL AND RELATED LANGUAGES

CONTENTS Volume 8, ISSN 1876-0589

Articles Editor in chief


Detlef D. Overbeek, Netherlands
Tel.: +31 (0)30 68.76.981 / Mobile: +31 (0)6 21.23.62.68
Delphi 2010 – what a feeling! - Bob Swart page 7
Gestures could be the new ’must’ in our computers future News and Press Releases
Counters - David Dirkse page 11 email only to [email protected]
Learning counting again, - could wel be a hobby...
Authors
Virus in Delphi? - Nick Hodges page 14 B Peter Bijlsma,
Nick explains how to get rid of the virus and block it. C Marco Cantù,
Dezign for databases - Marco Roessen page 16 D David Dirkse, Frans Doove,
A fantastic alternative for its expensive competitors, and it’s even cheaper. G Primož Gabrijel! i! ,
N Jeremy North,
Customizing the T-Field data display - Henk Schreij O Tim Opsteeg,
page 18 P Herman Peeren,
Diving deeper into the possibility’s S Henk Schreij, Rik Smit, Bob Swart,
V Hallvard VassBotn.
Using Free Pascal and Lazarus to
Editors
create applications for OSX - Jeremy North page 20 Rob van den Bogert, W. (Wim) van Ingen Schenau,
Working on the Mac is hot M.J. (Marco) Roessen.
Writing Delphi Components II: Custom Properties Corrector
A.W. (Bert) Jonker, M. L. E. J.M. (Miguel) van de Laar
and Windows Controls - Marco Cantù page 22 Translations
In the new Delphi versions it looks all different. M. L. E. J.M. (Miguel) van de Laar,
My Top Five Delphi 2010 Kenneth Cox (Official Translator)
New Features - Pawel Glowacki page 24
Copyright See the notice at the bottom of this page.
Except for guestures ther is a lot of news... Trademarks All trademarks used are acknowledged as
Fast Graphic deformation by using Scanlines the property of their respective owners.
- Peter Bijlsma page 28 Caveat Whilst we endeavour to ensure that what is
Control your own image or blow it up! Berlusconi on the edge published in the magazine is correct, we cannot accept
responsibility for any errors or omissions. If you notice
Wide Information Bus (Introduction) something which may be incorrect, please contact the Editor
- Fikret Hasovic page 33 and we will publish a correction where relevant.
What is it and what the use for it?
Freehand Drawing (Introduction) Subscriptions (prices have changed)
1: Printed version: subscription € 50.--
- David Dirkse page 36 (including code, programs and printed magazine, 4 issues
shows how to create your own paint program per year including postage.
2: Non printed subscription € 30.--
(including code, programs and download magazine)
= Code Downloadable
in the pdf file: click and you go straight Subscriptions can be taken out online at
to the download link www.blaisepascal.eu
or by written order, or by sending an email to
[email protected]
Subscriptions can start at any date. All issues published in the
calendar year of the subscription will be sent as well.
Cover price in Europe:
Columns € 12.50 / UK £ 12.00 / US $ 18.00 plus postage.
Subscriptions are parallel to the calender
Foreword, page 4 year. Subscriptions will not be prolonged without notice.
Books - Frans Doove Receipt of payment will be sent by email. Invoices will be
sent with the March issue.
View at the new Windows 7 page 5 Subscription can be paid by sending the payment to:
DELPHI CONTEST is prolongued until november ABN AMRO Bank Account no. 44 19 60 863
or by credit card: Paypal or TakeTwo
Advertisers Foundation for Supporting the Pascal Programming Language
(Stichting Ondersteuning Programeertaal Pascal)
Advantage Database Server page 3 IBAN: NL82 ABNA 0441960863
Components for Developers page 40 BIC ABNANL2A VAT no.: 81 42 54 147
Datanamic page 6 (Stichting Programmeertaal Pascal)
Fastreport for VCL page 38
Subscription department
Fastreport for .Net page 39 Edelstenenbaan 21 3402 XA IJsselstein, The Netherlands
RT science page 15 Tel.: + 31 (0) 30 68.76.981/Mobile: + 31 (0) 6 21.23.62.68
[email protected]
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.

Page 2 / 2116 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Foreword by Detlef Overbeek Editor
The summer holidays are over and we all are back to However, one thing is true:
business. For us as editors, things were a bit different. Due Write once, Run anywhere.
to all the extra work with the special issue and publishing That's what “we” are missing badly. Espacially for the
the first Portuguese edition, we had to abandon our holiday Mac. We need the future and the future is twofold:
plans. multi O.S. and Internet.

Now we have reached issue eight, with some very Second,


interesting articles about the new Delphi 2010 – which I it's nearly impossible for beginners to get acquainted with
think is the best yet – and a nice article about how to Delphi. There's the 30-day trial version, but you can't
morph your own portrait. Just for fun, we did this with a learn Delphi in 30 days. This is not only bad; it's short-
picture of Berlusconi, an interesting politician whom sighted.
claims to be the ultimate defender of freedom. But the
coding is also very interesting. I can easily imagine that Codegear is very busy creating
the next generation - which is why we would like to
With Delphi 2010, we all hoped there would be the first suggest to Embarcadero: if you don’t have the time or
cross compiler for Linux and Mac. man power to produce a special version, please offer
Too bad. international user groups - with registered members –
It didn't work out that way. to purchase an educational license.
We still have to wait.
Nothing needs to be changed, perhaps there could be
There are some major improvements: The help file is better some sort of splash screen: 'Licensed exclusively for non-
than ever: easy and quickly accessible, more items, more commercial use'.
specific about Delphi and one thing I do love particularly is Leave it up to the user groups to determine which of their
the tagged button bar with the components - classic, but members are eligible for this version. With this, we would
very effective. be in a position to convince people of the enormous
Great. quality of Delphi.
The total program is much faster and more stable.
It’s very much faster to install, it was quite annoying with It is nonsense to think that people can't get their hands on
2009. But… a pirated copy: the internet is huge.
You should trust people. Most of them don't want a
Now some things that aren't so good. For Delphi to be pirated copy; they use it in their work or their hobby,
attractive to a very large group of programmers, two major and they want their own, legal copy – but at an acceptable
changes are necessary. price. People who use it professionally should pay the
commercial price, but students (of Delphi), hobbyists and
First, a cross compiler must be available as soon as starters should be able to have ready access to a less
possible. Very soon. expensive version.

To illustrate my point: in order to better understand object We need the starters and beginners.
oriented aspects of programming I took a course on Java
at the University of Amsterdam. Besides learning a lot and Two years ago, when Embarcadero took over Codegear,
obtaining insight into many issues, I soon realized how it was promised to me personally.
much we are pampered with our Delphi IDE. I was very enthusiastic.
But now, going into the third year, there is still nothing
Java still does not have anything comparable to RAD. Java available. I regard this as unacceptable.
is a beautiful language, but it cannot compete with
Delphi (Pascal) : it's not fast, , coding is labour-intensive, I sincerely hope that this problem can be resolved quickly.
its graphic support is not very sophisticated and what
sometimes is forgotten, at low level the Java compiler is Detlef Overbeek,
almost never competitive in terms of speed and there for it
is almost impossible to run technical applications at low e-mail: [email protected]
(engine) level. Skype Detlef.Overbeek
+ 31 (0)30 6876981
But it runs on a lot of Platforms. mobiel + 31 (0)6 21.23.62.68
- which is nice until you discover that under Linux the
Eclipse environment moves at a snail's pace.

Page 4 / 2118 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Book reviews by Frans Doove
Paul McFedries: Here it is evident that the author has the reader in mind; he
Microsoft Windows 7 Unleashed writes for both IT professionals and home users of the software.
Part 1 (Chapters 1–5) lets the user get acquainted with this
2010, Pearson Education version of Windows and become familiar with it.
ISBN 13: 978–0–6723–3069–8 Part 2 discusses the maintenance of the Windows 7 system.
ISBN 10: 0–672–33069–5 Part 3 discusses relatively advanced topics.
Part 4 discusses security aspects,
English; paperbound, 791 pages (including table of contents). Part 5 addresses problem solving,
Recommended price: € 40. Part 6 deals with networking, and
Part 7 discusses scripting.

My opinion of this book is very positive. It has many extensive


and clearly worded explanations, as well as many code examples
and overviews.
Readers have the option of registering the book. When a
definitive version of Windows 7 is released, registered readers
will receive an updated version of the book free of charge, along
with all the examples and code in the book.
As far as I can determine, at the time of writing of this review
this is the only book on Windows 7 that is actually available in
English or Dutch, although dozens of books on Windows 7 (in
English) have been announced.

After getting acquainted with a sizeable new book, I often arrive at


the conclusion that the there is a direct relationship between the
size of the book and the degree of difficulty of the software
forming the subject of the book (and I also had this fear with the
present book). This conclusion arose from my experience with
comparable books on Windows Vista.
I must admit that I was not previously acquainted with any books
by this author, but it turns out that he has written a large number of
books on similar subjects.

As a native Dutch speaker, I found the title somewhat puzzling at


first. According to my English–Dutch dictionary, 'unleashed' has
several possible meanings, and the examples include a flood of
words and venting your rage. My impression is that the author did William R. Stanek:
not have the latter intention in mind, but instead aimed to write an Windows 7 Administrator's Pocket Consultant
introduction to a new, complex and extensive bit of software that
can do a lot of things and hopefully will cause fewer problems 2010, Microsoft Press,
than its predecessor. ISBN 978– 0–7356– 600–7,
English, paperbound, 680 pages.
The first thing that struck me about this book was its extensive Recommended price: € 30.
table of contents. First there is a high-level overview on two pages
divided into seven sections, followed by a full table of contents of This book has an introduction and seventeen chapters. Each
the 31 chapters that extends over fourteen pages and is in turn chapter consists of roughly 40 pages, which is a consequence of
followed by a seven-page introduction. the systematic approach.
The principal target group of the author is not individual users of
I consider such an extensive table of contents extremely important Windows 7, but instead system administrators. The author
as an introduction and an aid to studying the book, and especially further differentiates this group into administrators who already
useful to obtain an overview of the topics addressed by the book work with Windows, users with a certain amount of
and thereby the capabilities of the software it describes. Naturally, responsibility for computer administration, and administrators
it is difficult to master a subject discussed in a book totalling who migrate to Windows 7 from an earlier version of Windows
nearly 800 pages, and the table of contents is an essential aid in or from an entirely different system.
this regard.
This book is actually an extensive user's guide to Windows 7. My However, I think that individual users can also use this book to
impression is that the author does not assume that readers are fully considerable benefit, although the book devotes more attention
familiar with the previous version of Windows, but instead aims to the everyday activities of system administrators than to the
the book at all users. specific aspects of Windows 7. These aspects are actually
The book consists of 31 chapters and two appendices, grouped embedded in the text, but I fear that this makes the book more
into in seven sections. The sixteen-page table of contents gives an difficult for individual users, despite the fact that the text has an
overview of the topics discussed in the book open and accessible style.

October 2009 BLAISE PASCAL MAGAZINE 8 Page 5 / 2119


COMPONENTS
DEVELOPERS 4
Book reviews (continuation)
The book begins with an extensive table of contents for the Chapter 3 deals with major topics such as user policies and
seventeen chapters, grouped into sections. It occupies seventeen computer policies, which are the rules that govern the users and
pages. I always find an extensive and readily comprehensible
the computer for activities such as using a network.
table of contents a very positive feature, not only because it
Chapter 4 is dedicated to automation of the Windows 7
gives the reader a quick overview of the book and makes it
configuration.
easier to find everything, but also because it helps the reader
Chapter 5 discusses the administration of user access and
grasp the subject matter. I regard this as extremely important
security. Chapter 6 deals with configuring computers under
from a learning perspective.
Windows 7. Chapter 7 discusses the configuration of Windows 7
features and options, which differ from those of previous
The following capsule description of the contents is intended to
Windows versions. Chapter 8 discusses the operation of the
give an idea of how the author presents the topics.
hardware devices (options) and drivers. Chapter 9 deals with
Chapter 1 provides an introduction to Windows 7, including
program installation and maintenance.
installation and architecture. Chapter 2 discusses working with
Windows PE (the replacement for MS DOS) and the recovery
environment (RE).

Page 6 / 2120 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Delphi 2010 – what a feeling! by Bob Swart
Touch en Gestures
starter expert Biolife Fields
DELPHI 2010 / Win32
With the data persistent in the TClientDataSet, we can double-
One of the new features of Delphi 2010 is the native support click on this component to start the Fields Editor. Right-click in
for touch, gestures and multi-touch (supported by Windows 7). the Fields Editor and select “Add All Fields” to see the available
Although it has always been possible to support simple touch fields from the biolife table in the Fields Editor. In order to see
in Delphi applications, where the touch screen simply emulates them all (except one) on the form, we can simple drag them from
a mouse (so you can touch the buttons on the screen without the Fields Editor and drop them on the form. All, except for
using a keyboard or mouse), it was not yet possible to have Length_In, which I don't need (unless you don't use centimetres as
Delphi (out-of-the-box) respond to special gestures or multi- your measurement type, in which case you could decide to skip the
touch events. These features are now possible with the release Length (cm) field instead of course). Each of these fields will be
of Delphi 2010, and hence the topic of this article. transformed into a label and data-aware control when dragged onto
the form. Most fields will end up being represented by a TDBEdit
In order to play along, you need a copy of Delphi 2010 (you can control, with the exception of Notes (inside a TDBMemo) and
download and install the 30-day trial edition if you wish). Start Graphic (in a TDBImage). After moving the TDBImage controls
Delphi 2010. In order to create a new application, I do File | around, my version of the form looks as follows:
New – Other, which brings me to the Object Repository. This is
the first area where we can see some changes already: a handy
filter option at the top, to hide the icons and wizards that I'm not
looking for. Just enter a few characters like “App” in order to
filter the contents of the Object Repository down to the App-
specific icons and wizards. A nice way to help me find my way
without getting lost in the dozens of items.

Figure 2: Note that I'm not using a TDBNavigator control on


purpose, since I want to use the touchscreen with the simple
touch and gesture functionality for navigation.
Touch and Action
Speaking of touch: now we're getting to the interesting part of
the article: the touch and gesturing support in Delphi 2010. We
need to start by adding a TActionList component on the form.
Figure 1: This will help to connect gestures to (standard) actions later.
to start with Delphi 2010 already contains a number of pre-defined gestures,
which can be connected to actions (saving a lot of work
This filter is especially important now that the Object Inspector
compared to writing individual event handling code), as I'll
shows all icons in all catagories, even when they are not
show shortly. The TActionList component does not have to be
applicable at this time (for example in the ActiveX category,
“filled” with (standard) actions right away, because we can do
where a number of wizards cannot be used until an AxtiveX
library project has been created first). The benefit is that you will that “on the fly” (when needed). However, we do need a special
always see what's possible, even if it's not applicable just yet. The TGestureManager component on the form as well
filter will also hide these items, although this is not visible in the (see screenshot above), and we should assign this
screenshot above. TGestureManager component to the GestureManager
After starting a new VCL Forms Application, we first continue by subproperty of the Form's Touch property.
building a small database application. Just use a TclientDataSet in Gestures
order to produce a stand-alone executable (without the need for Using the Object Inspector, we can expand the Touch property
database drivers). As data contents, I'd like to show the biolife in order to view the GestureManager subproperty (assigned to
table, which can be found in the biolife.xml file in the Common the TGestureManager control on the form). We also see a
Files\CodeGear Shared\Data directory (in the future this might Gestures subproperty, with a list of standard (and later also
become the Common Files\Embarcadero Shared\Data directory custom) gestures supported by Delphi 2010. The list of standard
perhaps).
gestures starts with Left, Right, etc. Next to each gesture in the
As soon as the FileName property of the TClientDataSet
Object Inspector, we see a checkbox (to indicate that the gesture
component is pointing to the biolife.xml file, we can use the
is “hooded” to an action or event) as well as a little drawing that
Object Inspector to set the Active property of the TClientDataSet
to True to show all data at design-time. By clearing the FileName depicts the gesture movement (albeit without direction, so the
property while Active is set to True, the data remains visible, but horizontal line for “Left” and “right” looks the same).
this time we force the data to be stored in the DFM file itself, and For each gesture we can use the Object Inspector to create a
no longer outside of the application. This is a special trick that I New Action (for which we then need to implement the
use every now and then, to embed the data inside the executable. OnExecute event handler), or we can select an existing standard
Note that there are consequences to this approach: first of all, the action (which is then added to the TActionList component). For
DFM file will become about 2 MB in size (so it takes a while to our example, let's connect the Left gesture to a Standard Action
save or compile the project – especially the linking stage). from the Database category, namely TDataSetPrior (in order to
Second, and sometimes worse, is the fact that since the data is move to the previous record). The screenshot on the next page
embedded in the executable itself, you cannot make any changes shows the different submenus that have to be used to connect the
to the data. This may often be a show stopper, unless you're TDataSetPrior action to the Left gesture.
building a brochure or catalog that you don't want or need people
to change anyway (like a city plan with pictures for example). For Delphi 2010 has just been released at the time of writing – see
our demo, I'm assuming we do not need the biolife data to be http://www.eBob42.com and http://www.bobswart.nl for more
changed by the user, so we're on our way to produce a standalone information and ordering possibilities of Delphi 2010 en RAD
executable indeed. Studio 2010.

October 2009 BLAISE PASCAL MAGAZINE 8 Page 7 / 2121


COMPONENTS
DEVELOPERS 4
Delphi 2010 – what a feeling! (continuation 1)

Figure 3: the steps to get to the list of gestures


After we've connected the Left gesture, it's just as easy to connect
the Right gesture to the TDataSetNExt action, the ChevronLeft
gesture to the TDataSetFirst, and the ChevronRight gesture to the
TDataSetLast action. The two chevron gestures can be compared
to “bigger than” and “smaller than” characters, but then drawn
with your finger on the touchscreen.

Action!
The only thing left to do is compile the project and run it. If you
have a touch screen (like the LG L1510SF 1024x768 Flatron that I
purchased for a good price) then you can move your finger over
the screen to make the gesture movements required. If you do not
have a touch screen, then you can still emulate this behaviour by
using the mouse: click with the left mouse button and “drag” the
gesture movement around the screen. It's not the same, but at least
you can test your gesture movements without the need to purchase
a touchscreen yourself. Either way, you can use the Left, Right,
ChevronLeft and ChevronRight gestures now to navigate through
the records of the biolife table without the need for a keyboard or
TDBNavigator control.

Custom Gestures
Apart from the built-in standard gestures, we can also create our Figuur 4: zorro is in the air?
own custom gestures with Delphi 2010. This can be done with the (a famous tv-character in The Netherlands about an outlaw hero
TGestureManager control: right-click on it, and select Custom who uses his sword to draw a “Z” on the chest of his
Gestures. Inside the dialog that follows, you can click on the government victims) When making custom gestures, it's
Create button to create a new gesture, where you need to move important to realise that the gesture must be one fluent
your finger over the touch screen (or drag with the mouse) to draw movement. As a result, you cannot make an X gesture, since that
the initial path of the gesture. Once the initial path is drawn, we requires two separate gestures. For the X-gesture that I created,
can still make some modifications to it, to ensure it will be I had to change the sensitivity, which is set to 80% by default, to
recognised correctly. As an example, let's draw the “Z” character ensure that it's easily possible to have the “Z”-gesture be
(see next screenshot), and give it the name “Zorro” recognised when drawn on screen by an end user.

Page 8 / 2122 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Delphi 2010 – what a feeling! (continuation 2)
A high sensitivity requires that you redraw the blue dots After all this work, it's very fortunate that we do not have to draw
exactly, and lower sensitivity extend the grey area around them the custom gestures for each new application, but we can simply
(until it gets too fuzzy where you might confuse one gesture store (export to a .dgf file – Delphi Gesture File) and load or
with another). We can also use the Custom Gesture dialog to import the .dgf in the TGestureManager of another application
remove dots from the gesture line, add new dots, zoom in again. Once we have a custom gesture, we can work with it (i.e.
and/or out, modify the coordinates and play a simulation of the respond to the recognised gesture) in two ways. First of all, we can
gesture, as well as a test where you need to redraw the gesture use the OnGesture event of the form itself. In this event handler,
to see if it is recognised correctly. It may take a while, but in the we get the EventInfo of type TGestureEventInfo, as well as a var
end you will have a near perfect custom gesture. parameter Handled to indicate – when set to True - that we've
When you click on OK, you are returned to the Custom Gesture handled this gesture.
dialog of the GestureManager component where a preview of Note that we will only get inside the OnGesture event handler if
the gesture shape is drawn as well as the name we've given it, we didn't make one of the standard and already connected gestures
and the ID (which starts by -1 and counts further down). such as the Left, Right, ChevronLeft or ChevronRight gestures.
When inside the OnGesture event handler, we can use the
EventInfo.GestureID field to identify the ID of the custom gesture.
In our case, that value was -1, so my event handler can be
implemented as follows:
procedure TForm1.FormGesture(Sender: TObject;
const EventInfo: TGestureEventInfo; var Handled: Boolean);
begin
if EventInfo.GestureID = -1 then
ShowMessage('Zorro')
else
ShowMessage(IntToStr(EventInfo.GestureID))
end;
If an unrecognised gesture is made, then the GestureID is equal
to 0 (which may be an indication that you need to work on the
sensitivity of your custom gestures, or explain more clearly how
the users should make their gesture).
We have to remember for ourselves what the ID values are of
our custom gestures, of course. Fortunately, there is also another
way to connect an action to the custom gesture. If you take a
look at the third screenshot again, you'll see the Object Inspector
with the Touch property and the Gesture subproperty.
Figure 5: Zorro is listed now

October 2009 BLAISE PASCAL MAGAZINE 8 Page 9 / 2123


COMPONENTS
DEVELOPERS 4
Delphi 2010 – what a feeling! (continuation 2)
Right below that, the standard gestures are listed. However, as The following screenshot shows the TTouchKeyboard on my
soon as we add a custom gesture, a new entry “Custom” is machine, using the US-International keyboard layout, at the
shown in the Object Inspector – right above the standard bottom of the Touching Biolife form:7 Obviously, placing the
gestures. virtual keyboard at the bottom of the form is not a very effective
Custom contains the list of (currently only one) custom gestures way to handle input. It would be more convenient to use some
that have been added to the TGestureManager. In this case, just kind of pop-up dialog that shows the virtual keyboard only when
the Zorro gesture, including the image preview of the “Z”, as we needed for example. But once the virtual keyboard is shown, we
saw before in the Custom Gesture dialog. can use the keys on the screen as touch buttons and click on the
This means that we can now make a connection between the keys to produce the input text. And if you have no touch screen
gesture and an action. In this case, I'd like to create a new action, but a mouse attached to your machine, then you can obviously
select this action in the Object Inspector when done, and then still use the mouse to click on the buttons (so as a software
implement the OnExecute event handler of the new action, for developer you do not need to have a touch screen to work with
example as follows: the TTouchKeyboard – only when it comes to multi-touch and
interactive gestures you need Windows 7 and the special
procedure TForm1.Action1Execute(Sender: TObject);
begin
hardware).
ShowMessage('Zorro also likes to touch Delphi 2010')
end;

Once the gesture is connected to a custom action and its


OnExecute is implemented, the Ongesture event handler of
the form will no longer respond to his Zorro gesture (have a
try for yourself if you wish).
Running the demo project we've created so far – and which
I've called Touching Biolife – does not show a GUI
different from a “normal” non-touching GUI. If you take a
look at the next screenshot, there's no indication (yet) we're
dealing with a touch- and gesture-enabled application. The
lack of a TDBNavigator may lead you to wonder how to
navigate to the next record, but that's about it.

Figure 8: the virtual touchpad

Deployment
A final word: in order to turn the current demo application into a
Figure 7: now you can try really standalone executable, we should add the MidasLib unit to
Sweeping your finger over the screen from left to right (for the the uses clause of the project, so we do not need to deploy the
next record) or from right to left (for the previous one) may be a MIDAS.DLL. This results in a truly standalone executable that
bit strange at first, but you'll quickly get the hang of it. The effect we can place on a USB-stick for example in order to show an
is of course much nicer if the form would contain a city map or application that doesn't need mouse or keyboard in order to run.
street plan, where you can “move” the map around with your
fingers. This can also be done with gestures, and even better with Bob Swart
the so-called Multi-Touch support which can be found in
Windows 7 (but which also requires special, more expensive,
hardware). Using Multi-Touch and interactive gestures, the To get more information about Delphi 2010
EventInfo structure of the Ongesture event will hold field values licenses, please see my website at
for the inertia (speed of the gesture), as well as the start and stop http://www.bobswart.nl/CodeGear
coordinates of the gesture. Since this is only supported by or send me an e-mail at
Windows 7, in combination with special hardware compatible [email protected]
with the multi-touch and interactive gestures, I'll leave an
example behind for now (until I can get my hands on the special (also to ask about subscription or renewals).
multi-touch hardware that is).
Bob Swart - is Reseller for BeNeLux
Touch Keyboard
One more thing I can show you is the final step to make the
(Belgium Netherlands Luxemburg)
application completely independent from mouse and keyboard:
for deployment in a kiosk or bus station for example. Since these
applications sometimes still need some textual input, Delphi
2010 contains a special TTouchKeyboard component. One
which shows the keyboard layout for the current locale (which
means that users from France will get the accents available on
the keyboard when they need them).

Page 10 / 2124 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Counters by David Dirkse
starter expert DELPHI / Win32
Using a calculator:
This article covers some fundamental arithmetic operations in
1208 : 44 = 27.4545... remove digits right of the decimal point
ICT applications with emphasis on the operators mod and div.
1208 div 44 = 27.
div also is an operator, like + - * or mod
Computers are only able to handle numbers. Only problems that
are expressable in numbers can be solved by a computer. Rounding
In daily life , numbers may be grouped in the following Assume a drawing application, using a paintbox with squares
categories: of 20 * 20 pixels. A MouseMove generates an event and
category example supplies
quantity Kilogram, degrees,meters,seconds the (x,y) coördinates. X div 20 is the number of squares left of
factor 15%, half, double the mouse X so.......
index 4 stars hotel, 2nd left, house number (X div 20) * 20 ..... is the X position rounded down to a
code Pincode, bus 147, ASCII code multiple
of 20. In case we want to round to the nearest multiple of 20 we
Arithmetic and math start with counting. calculate:
Below, a simple counting device is pictured ((X + 10) div 20) * 20..........{note: 10 = 20 div 2 }
To round upward to the next multiple of 20:
((X + 19) div 20) * 20..........{note: 19 = 20 - 1}

Two dimensional tables

Figure1: note: 'stand' is Dutch for 'state'.


0, 4 are the lowest and highest state.

It is not interesting how this counter performs it's functions. It


may be mechanical, by pinwheels, electronical or electro-
mechanical using relays. Figure: 2 two dimensions
The “reset” signal forces the counter in it's first state '0'.
A next increment signal forces the next state '1'. In state '4', the The fields are numbered 0 to 23.
highest of this counter, a next increment again forces state '0' Calling N the number of a field, than N = column + row * 6.
and an 'overflow'signal is generated. In digital technology, this For the columns, we notice a modulo 6 counter.
overflow is called a 'carry'. ( example: 23 mod 6 = 5)
Assume that N increments take place after a reset. Table below For a known value of N, the column and row can be calculated :
lists state T of the counter after increment N. column = N mod 6
row = N div 6
N 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 The computer memory is a one dimensional table of bytes.
In case of a two dimensional table, a small calculation is necessary
T 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 to obtain the memory location.
We notice that the counter has 5 distinct states Therefore it is In Delphi, the elements of a two dimensional array are stored in
called a modulo 5 counter. To express T as a function of N , the memory as outlined in the table below: (values 0,1,2,3,... in
some (new) notation is required, we write : T = N mod 5 sequential order)
T is the remainder of the division of N by 5.
mod is an operator, just like + - *
In the table above we read 14 mod 5 = 4
In case of a modulo 44 counter (counting 0..43)
which received 1208 increments, it's state will be
T = 1208 mod 44
To program this operation in delphi, we simply write:
T := 1208 mod 44.
Using a handheld calculator we proceed :
1208 : 44 = 27.4545... remove digits left of the decimal
point and multiply 0.4545... * 44 = 20
Please note : in rare occasions a very small rounding number is Figure 3: Let's define above structure both as a one- and as a two
necessary to obtain an integer number. dimensional table by using the absolute directive.
var A1 : array[0..23] of byte;
The number of state transitions from highest to 0 we call C , A2 : array[0..5 , 0..3] of byte absolute A1; // A1,A2
the number of carries. So, A1[9] is the same element as A2[2,1]
Notation: In general, using an array of rcount rows :
C = N div 5
A2[ col, row] = A1[col * rcount + row].
is the number of carries out of a modulo 5 counter after N A1[ i + 4] adresses the element 1 right of i, A1[ i – 3] adresses
increments.
the element left down of i.
We notice, that C is the integer division of N by 5.
This approach may result in considerable time saving with some
board games requiring extensive analyses. Using simple + and –
To program the calculation in Delphi, type C := 1208 div 44
operations, fields can be scanned up, down or diagonally. More
time consuming operations like multiplication are avoided.

October 2009 BLAISE PASCAL MAGAZINE 8 Page 11 / 2125


COMPONENTS
DEVELOPERS 4
Counters (continuation 1)
Location on the screen The total counter T0..T3 may be regarded as a
modulo (2 * 4 * 5 * 3) = 120 counter.
N = 120 causes state 0 0 0 0 and one carry out of T3.
Say N = 68. What will be the state of each individual counter?
68 mod 2 = 0, so T0 = 0
86 div 2 = 43, is the number of carries out of T0 ,
increments to T1
T1 = 43 mod 4 = 3
43 div 4 = 10, increments to T2
T2 = 10 mod 5 = 0.
10 div 5 = 2, increments to T3
T3 = 2 mod 3 = 2.
Figure 4: So, counter states are 2 0 3 0 (written left to right)
In figure 4 above a black rectangle constitutes 100 * 100 pixels At this point, the reader may get worried about the usefulness of
on the screen. this exercise. Continue reading and see.........:
A mouse move presents the (x,y) coördinates of the cursor so A pancake restaurant offers the following choices:
column i = x div 100 type of flour: white(0) of whole wheat (1) ...counter 0
row j = y div 100 size : small(0) medium(1) large(2) extra large(3) ...counter 1
Each field has an orange area. type : plain(0) apple (1) porc (2) cheese(3) banana(4).counter 2
finish : sugar(0) molasses(1)jam (2) ...counter 3
To test if we are positioned in this area, we program :
var orange : boolean; We want to convert an order into a smallest possible number, so
x100 , y100 : word; to encode an order.
...........
x100 := x mod 100; Now note, that each choice is represented by an individual
y100 := y mod 100; counter stage mentioned before. The counter state 2 0 3 0
orange := (X100 > 25) applies to the order
and (x100 < 75) white flour.....extra large.....plain......jam
and (y100 > 25)
and (y100 < 75); code N for this order is : 68.

Sudoku
How do we encode order .......whole wheat(1), large(2),
A Sudoku puzzle typically has a board with columns 1..9, rows apple(1), sugar(0) ?
1..9 and groups 1..9. So counter state = 0 1 2 1, asked is N.
Refer to the picture below. T2 is increased once, this requires 2 * 4 increments of T0 since
T0T1 together constitute a modulo 2 * 4 = 8 counter.
So, N = 8 for the moment.
T1 is increased 2 times, this requires 2 * 2 increments of T0.
So now N = 8 + 4 = 12. T0 is increased once which makes
N = 12 + 1 = 13, which is the -pancake-code of this order.
Note: to obtain state T of an individual counter stage requires
N = T * (modulus of preceding counters) increments into T0.

Number systems

Figure 5:
Notice, that we count from 1..9, which is unsuitable for mod and
div operations. Therefore , conversion is needed from 1..9 to 0..8 Above is pictured an 8 stage counter we recognize as a byte.
before mod and div operators may be applied. Given column i, An individual counter , counting 0,1,01... is called a bit. 11100110
row j , we want to calculate the field that contains this element. is a shorthand notation we are used to in number sytems. The
This can be done using following function: modulus of the byte is 2^8 = 256. If we replace the counters by
function IJtoGroupNr(i,j : byte) : byte; modulo 10 types, counting 0...9, N would appear as a decimal
//return group Nr of field [i,j] number. Conversion from the binary (2) to the decimal (10) number
var x,y : byte;
begin system is accomplished by connecting N also to modulo 10
x := (i-1) div 3; counters. N mod 10 than is the state of T0 after N increments. N div
y := (j-1) div 3; 10 is the number of carries out of T0 into T1 etc. Program below
result := x + 3*y + 1;
end;
converts a positive integer (in binary in the computer memory) to a
string of decimal digits. (displayed in component edit2)
procedure setN(nn : cardinal; t : byte);
Serially connected counters //displays number with base t
const digitconvert = '0123456789abcdef';
var s : string; m : byte;
begin
if nn = 0 then begin form1.edit2.text := '0';
exit; end;
s := '';
repeat
m := nn mod t;
Figure 5: schematic view nn := nn div t;
In the picture above, 4 counters are serially connected. The carry of insert(digitconvert[m+1],s,1);
until nn = 0;
a stage is the increment of the next. Counter T0 is modulo 2, T1 is form1.edit2.text := s;
modulo 4, T2 is modulo 5 and counter T3 is of the type modulo 3. end;

Page 12 / 2126 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Counters (continuation 1)
Bit fields Remarks:
mod and div are relatively slow operations because they involve
division. For reason of speed it is better to avoid them. This is 1. 6K + 2 cannot be prime, since is is a multiple of 2.
6K+3 is a multiple of 3.
possible if the modulus is a multiple of 2. N div 2 yields the same
result as N shr 1, a shift of 1 bit to the right.. only 6K-1 (or 6K+5, which amounts to the same) and 6K+1
In general: N div (2 ^ i) = N shr i may be prime.
also N mod (2 ^ i) = N and (2^ i – 1)
2. A number P is a multiple of m if P mod m = 0
Instead of N mod 8 the operation N and 7 has the same answer and Say P = 63 and m = 7. Than 63 div 7 = 9 and 63 mod 7 = 0 ,
is much faster. 63 is not prime.
Suppose P = 67, we test P for being prime by division by
3,5,7,11,13...
Suppose we are programming a game and we need a 67 div 7 = 9 and 67 div 11 = 6, but .....6 < 11 , for the
2 dimensional array of first time the quotient is smaller than the divisor. We can
1000 * 1000 bits and 3 procedures/functions: savely assume now that P is prime, because a prime factor
should be found earlier.
1. The procedure setbit(i , j : word) forces the value '1' into
column i, row j 3. The program uses 2 goto statements and labels.
2. procedure clearbit(i , j : word) makes column i, row j a '1' Some programmers consider this an atrocity but here it results
3. Function testbit(i , j : word) : byte; in easy readable code.
supplies the value of column i, row j. Reason is the two crossing loops. If anybody knows a nice
way to rebuilt the code according to the rules of 'structured
How to program this structure? programming' , please let me know.
We simply put all bits in a 1 dimensional array of bytes, for reasons
of fast access. Calculation of the GCD (greatest common divisor)
So this array must contain 1000 * 1000 / 8 = 125000 bytes. The GCD of two numbers is best calculated using the 'Euclidian
Theorem'.
This amounts to the arithmetic rule ......GCD(A,B) = GCD(A-B , B).
Var BitArray : array[0..124999] of byte; An example:
procedure setbit(i,j : word); GGD(3094,2310) = GGD(3094-2310,2310) = GGD(784,2310) =
var AbitNr : integer; GGD(2310,784) = GGD(1526,784) = GGD(742,784) =
byteNr,bitNr : byte; GGD(784,742) = GGD(42,742) = GGD(742-17*42,42) =
begin GGD(28,42) = GGD(14,28) = GGD(0,14) = 14
ABitNr := i + 1000 * j ;
// bitnumber in array , counted 0..999 in row 0, 1000..1999 in row 1
Program below calculates the GCD of numbers A and B by
ByteNr := ABitNr shr 3; //div 8 = index in byte array repeatedly applying the Euclidian Theorem.
bitNr := AbitNr and $7; //bitnumber in byte function GGD(A,B : cardinal) : cardinal;
BitArray[byteNr] := BitArray[byteNr] or (1 shl bitNr); var r : cardinal;
end; begin
repeat
procedure clearbit(i,j : word); r := A mod B;
var AbitNr : integer; A := B;
byteNr,bitNr : byte; B := r;
begin until r := 0;
ABitNr := i + 1000 * j ; result := A;
// bitnumber in array , counted 0..999 in row 0, 1000..1999 in row 1 end;
ByteNr := ABitNr shr 3; //div 8 = index in byte array
bitNr := AbitNr and $7; //bitnumber in byte This concludes my article.
BitArray[byteNr] := BitArray[byteNr] and ($ff xor (1
shl bitNr));
end;
David Dirkse
function testbit(i,j : word) : byte; Born 1945 in Amsterdam, David joined Control Data
var AbitNr : integer; Corporation in 1968, after studying electrical
byteNr,bitNr : byte;
begin engineering. As a hardware engineer, he was
ABitNr := i + 1000 * j; // bitnumber in array responsible for the installation and maintenance of
ByteNr := ABitNr shr 3; //div 8 = index in byte array mainframes at scientific data centers in the
bitNr := AbitNr and $7; //bitnumber in byte Netherlands.
result := (BitArray[byteNr] shr bitnr) and $1; With the decline of CDC around 1990, he studied
end;
mathematics and became a math teacher.
His hobbies are programming, in particular
educational software, math algorithms, and puzzle
The next 250 primes solving.
A -non prime- number may be written as a unique product of http://home.hccnet.nl/david.dirkse
prime factors. Primes play an important role in coding theory
and in mathematics in general. For this occasion I wrote a small
program to generate the next 250 primes.

To avoid redundant work the following trics are applied:

– any prime ( > 3) has may be written as


6K-1 or 6K+1, where K = 1,2,3,4.......
– P is prime when (P mod m <> 0) and (P div m < m)
– where divisor m performs steps
5,7,11,13,17,19,23,25,29..... so alternating 2,4
– increments.

October 2009 BLAISE PASCAL MAGAZINE 8 Page 13 / 2127


COMPONENTS
DEVELOPERS 4
Frequently Asked Questions over de
W32/Induc-A Virus (Compile-A-Virus) door Nick Hodges
starter expert DELPHI 4-5-6-7 The virus creates this file as part of its actions. If that file is
present, you are likely infected (unless you know that you
Abstract: This is a set of Frequently Asked Questions about the
yourself created this file for some reason).
W32/Induc-A “compile-a-virus” virus that can attack old
If you have a SYSCONST.BAK in your \lib directory, then you
versions of the Delphi development tool.
can open up SYSCONST.DCU in a hex editor or even in a text
editor like notepad. You can search for the code
What versions of Delphi are affected?
"CreateFile(pchar(d+$bak$),0,0,0,3,0,0);" in that DCU file. If it
This virus affects only Delphi versions 4 – 7 released between
is present, you are infected.
1998 and 2002. The W32/Induc virus does not affect newer
versions of Delphi from v2005 thru v2009 or the upcoming
If I have it, how did I get it?
v2010. If you have the virus, you got it buy running an EXE or DLL file
on your machine that was already infected with this virus.
What versions of Delphi are NOT affected? Delphi is a very popular development tool, particularly among
This virus does not affect more current versions of Delphi. ISV and MicroISV developers. Ii you received an infected binary
Delphi 2006, 2007, 2009, and the new 2010 release are not you may have received it from an application download.
affected by this virus.
What are the implications of being infected?
What is this virus? If your machine is infected, the EXE and DLL files that you
This virus is called "Compile-a-Virus". It is also referred to as produce will infect any unprotected machine where your EXE or
"W32/Induc-A". DLL is run and that has Delphi 4 – 7 installed.
But note again that this virus doesn't do anything malicious apart
Is the Delphi IDE or the language distributing this virus? from spreading itself. However, if you detect that you have the
No, the versions of Delphi that are vulnerable to this attack (v4 virus and have distributed known infected files, it is prudent to
thru v7) do not come with this virus nor is the virus in the notify file recipients and point them to this FAQ for more
language. It is “caught” by downloading and running an infected information.
EXE or DLL.
How do I remove the virus from my Delphi installation?
Is Delphi Prism affected? To remove the virus you should
No, Delphi Prism is not affected by this virus. - Delete the infected SYSCONST.DCU file on your system
- Replace it with the SYSCONST.DCU file from your
What does this virus do? installation media. Delphi versions 4 -7 include a complete
This virus does nothing to versions of Delphi newer than Delphi install image on their CD, so you can simply copy that file
7 (2002). If a machine is infected, the virus W32/Induc-A from your DVD to your installation.
doesn't do anything malicious or create damage other than
spread itself. How do I make sure that it doesn't come back? or
What the virus does do is embed itself into an installation of I don't have the virus. How do I make sure that I don't get it?
Delphi version 4, 5, 6 or 7. Then, when an infected version of This virus does not affect Delphi version 2005 thru 2010.
Delphi builds an EXE or a DLL, it embeds itself into that However, if you are running older copies of Delphi v4 thru v7
resulting binary. When the code for that EXE or DLL is run, it then the most effective way to ensure that you don’t get the virus
then looks for installed versions of Delphi 4 thru 7 and replicates is to move your copy of DCC32.EXE to a different directory.
itself into any installations that it finds. Then, that installation The IDE of these older versions doesn’t require the command
will in turn produce EXE and DLL files that will look to line compiler, so this will not affect the execution of the product.
replicate itself anywhere it is run. You can also prevent the virus from doing anything to your
Again, the virus looks only for an installation of Delphi 4 -7. installation again by leaving a file named SYSCONST.BAK in
Specifically, if it finds one of those Delphi versions, it searches the same location where you found it. The file can be empty.
for the SYSCONST.PAS file. It opens that file, injects code into The virus checks for the presence of this file, and if it finds it, it
it, compiles the file, and replaces the shipped version of does nothing. Leaving a blank SYSCONST.BAK file in the
SYSCONST.DCU with the new infected version. It then deletes same location as your SYSCONST.DCU file will ensure that the
the SYSCONST.PAS file it created. (The virus doesn’t alter any virus will do nothing.
*.PAS files on the system). The injected code simply causes the In addition, you can mark all of the files in your \lib directory as
execution of code containing SYSCONST.DCU to replicate the read-only. This will prevent the virus from changing them.
virus.
How do I tell if I have executable files on my system that are
Is this a problem unique to Delphi? spreading this virus?
This particular virus seeks out Delphi v4 thru v7 but this type of This is a relatively new virus, and so virus scanning software is
virus is not in any way unique to Delphi and could effect any just starting to recognize it. A number of vendors are already
development environment from Eclipse to Visual Studio. identifying binaries with this infection, and undoubtedly, most
will follow suit soon. The best way to detect the virus is to
Who is vulnerable to this infection? ensure that your anti-virus software knows about W32/Induc-A
Installations of Delphi 4 - 7 can be affected by W32/Induc-A. If and run a virus scan on your system.
an infected EXE or DLL file is run on a machine without Delphi The binaries I am producing are infected, what can I do?
4 - 7 installed on it, then the virus does nothing. Virus scanners Of course you first need to rid your system of the virus – See
are now starting to report this infection as a virus to those people above.The only way to get rid of the virus that is already in an
with infected binaries. existing EXE or DLL is to recompile that binary with a clean
system.
How do I know if I've been infected?
Detecting if your Delphi installation has been infected is fairly Does this affect packages built with Delphi 4 - 7?
easy. It only affects Delphi version from 4 to 7. The easiest way It is possible but unlikely. By default, packages are not affected.
to tell if you have been infected is to search for the presence of A package can become infected if you manually choose not to
SYSCONST.BAK in the <delphi>\lib directory of your Delphi link against our RTL.DCP file and manually link in an infected
installation. SYSCONST.DCU.

Page 14 / 2128 COMPONENTS


DEVELOPERS 4 October 2009 BLAISE PASCAL MAGAZINE 8
FAQ’s over de W32/Induc-A Virus (Compile-A-Virus) - vervolg
The overwhelming majority of developers will not have done Is C++Builder affected?
this, and if you have, then you’ll be able to recompile those No. It is theoretically possible for a C++Builder EXE to become
packages with a clean system. infected, but a C++Builder developer would have to take a
rather lengthy set of steps and actively change and recompile a
What else can I do to protect myself? number of different things on his system in order for the virus to
There are a number of additional things you can do to protect affect C++Builder binaries.
yourself against this virus. As mentioned above, you can mark I produce shareware and/or an ISV application built with
all of the DCU files in your \lib directory as read-only. And Delphi? What does this mean?
while you are at it, you might consider labeling all of the source If you are running newer versions of Delphi 2005 thru 2010 then
code in the <delphi>\source directory as read-only as well. it doesn’t affect you. If you are a Shareware or ISV vendor
running an older version of Delphi v4 thru v7, then you should
To be absolutely safe, you can do a file compare between your check that your machine is not infected. If it is infected you
\lib directory and the \lib directory on the install image on your should clean it.
CD. If you have distributed infected executables to your customers,
If you need a file compare tool, there is a very powerful, open you should immediately recompile your product and distribute a
source tool called FreeFileSync which can be found at: new, cleaned version. It would also be prudent to notify file
http://sourceforge.net/projects/freefilesync/ recipients and point them to this FAQ for more information. As
Keep in mind that it is possible that you may have altered these anti-virus programs begin to see this virus in binaries, customers
DCU files yourself, so if they show up as different, be sure that will be getting reports of your binaries being infected and you’ll
you yourself haven’t altered them. So far, this virus only affects want to be ready with a clean binary for them.
the SYSCONST.DCU file.
In any event, it is highly recommended that you ensure that the
files in the \lib directory of your Delphi 4 – 7 installation match
those of the install image on your CD.

October 2009 BLAISE PASCAL MAGAZINE 8 Page 15 / 2129


COMPONENTS
DEVELOPERS 4
DeZign for Databases v5 by Marco Roessen
starter expert all DELPHI versions
First impressions
Many applications use a database for storing data. A database When you install DeZign for Databases and run it the first time,
usually is a collection of tables with their internal relations. you will automatically be presented a demo database. This demo
Creating a database can be done completely from code. database gives us the opportunity to discover the possibilities of
Another possibility is to use a tool supplied with the database DeZign for Databases.
engine. Using these tools a database can be visually designed; Figure 1 shows the two main interface elements: the designer on the
the tables and their relations are graphically represented. right-hand side and the “object browser” on the left-hand side.
Examples of these tools are mysqladmin used for MySQL Double clicking a table in the designer or Object browser will open
databases and SQL Server Management Studio for MSSQL an interface. This interface is used for adding, removing or
databases. Often databases created with these tools and the modifying fields (figure 2).
chosen data types are specific for these database engines. It is
not easy to convert these designs to other database engines.
Creating a new database
This article is about DeZign for Databases v5, a database
Creating a new database design is relatively easy. When you create
engine independent tool for designing and creating databases.
a new project you will be asked which database engine you will be
DeZign for Database is one the products developed by the using. The currently supported database engines are DB2, dBase,
relatively young Dutch company Datanamic. The products they DBISAM, ElevateDB, Firebird, FoxPro, Informix, Interbase,
have developed are:
- DeZign for Databases V5
Powerful database design and modeling tool. Design, create,
reverse engineer and modify databases.
- DB Data Difftective V1
Compare and synchronize database content.
- DB Schema Difftective V1
Compare and synchronize database schemas (structure).
- DB Data Generator V2
Quickly generate test data for your databases.
- DB MultiRun V1
Execute multiple SQL scripts against multiple databases.
- DB Zipper V2
Archive and extract database data. An easy way to migrate
and backup data.
DeZign for Databases is Datanamic's most prominent product.
You can download trial versions of all of the above products.
Please check the website (www.datanamic.com) for more details.
Figure 2: Modifying the properties of a table

Figure 1: DeZign for Databases designer overview

Page 16 / 2130 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
DeZign for Databases v5 (continuation)
MaxDB, MS Access, MS SQL server, MySQL, NexusDB, Oracle, When generating a database it is possible to add a version to the
Paradox, Pervasive PostgreSQL, SQL Anywhere Studio, SQLite design. By using versions, it is always possible to revert to an
and Sybase ASE. For a complete list of the supported database older version of the design. You can also create a so called SQL
engine versions and functionality you can check the complete modify script. This script can be used to modify an existing
overview available at database structure to fit the structure of an older or newer design
http://www.datanamic.com/dezign/supporteddatabases.html.
It is also possible to create your own DBMS database definition Importing a database structure
file. These definition files can be used by DeZign for Databases to Another nice feature is the possibility of importing an existing
support database engines that are (not yet) supported by default. database structure. This feature is useful for investigating an
You can find more information about this subject in the extensive already existing database structure. All tables, relations, triggers,
help file. After choosing the database engine, you will be code, etc are displayed clearly. You can modify this imported
presented an empty workspace where you can add tables. When structure with the same tools that are available when designing a
tables are added you will be presented a dialog containing the new database (modify tables and fields, create a database or a SQL
properties of this newly created table. You use this dialog to set modify script, etc). One of the properties of a database design is
table properties and add fields. the target database engine. If you have to modify your initial
A nice feature of the program is called “Domains”. A domain is an choice for some reason (e.g. use a more powerful database engine)
alias for a specific data type with specific properties set. If you, for this is possible. The project will be converted to the other database
instance, use the VARCHAR data type with the property maxchars engine target. If there are incompatibilities, they will be displayed.
set to 75 a lot, you can create a domain with these properties. You This function is also useful for converting imported databases to
can give this domain a descriptive name. This domain will be another target engine. There is one thing I want to warn you about
available from the list with data types (starting with an @). If you when using DeZign for Databases: If you want to change the
have to modify the data type or one of the properties for some structure of an existing database (filled with data) using an SQL
reason, you will only have to modify the domain. All fields using modify script, you have to take good care that there will be no loss
this domain will be updated automatically. of data. When a modification of the structure of a database is
incompatible with the current existing database (e.g. changing a
When all tables are defined, we can set the internal connections by
string field to an integer field), there is a possibility that you will
adding “Relationships”. For instance you can add an “Identifying
lose all existing data. In these cases the SQL script created will
relationship” by clicking the corresponding toolbar button. After
remove the existing table (DROP TABLE) and therefore all
clicking the button you can draw a line between the tables that existing data and create a new table from scratch. It is wise to
have to be linked. Default the table relation will be set between the check the script and backup the database before executing the SQL
fields that have the same name in both tables. If this is not the modify script. It would be nice if DeZign for Databases warned
intended relationship, you can manually change it (figure 3). you about the possible loss of data.
Creating the database Conclusion
When the whole database design is ready, you can check it DeZign for Databases is an excellent tool for designing and
(Database / Check model Ctrl+F9). If there are any problems or modifying databases. Its database engine independency is big plus.
warnings they will be displayed in the bottom window: the The program is easy to use and gives you all the tools necessary
MessageWindow. When all problems and warnings have been for every day database design. The automatic versioning feature is
resolved, you can create the database (F9). An SQL script will be also very useful. DeZign for Databases is relatively cheap
created for SQL based database engines. Other (non-SQL) compared to other database design tools, despite the extensive set
databases will be created as a file (e.g. an MSAccess.mdb file). of features.

About the author:

Marco Roessen
Graduated HTS-Electronics,
specialisation Technical
ComputerScience, in 1993.
Since then he has been
working as an informatics
engineer at the Centre for
sleep and wake research
firstly at Leiden University
since 1995 at Medisch
Centrum Haaglanden, Den
Haag.
There he develops tailored
sleep research software;
started with assembler
and MS Pascal, later using
Turbo, Borland and Delphi
Pascal. Currently also C#.
He is co-developer of
algorithms for automatic
biomedical signal analysis.
Figure 3: Changing a relationship

October 2009 BLAISE PASCAL MAGAZINE 8 Page 17 / 2131


COMPONENTS
DEVELOPERS 4
Customizing the T-Field data display by Henk Schreij
starter expert DELPHI 2..2010 / Win32

When you display a database field, you sometimes want to show


something other than what is stored in the field. For example,
you might want to show 'male' or 'female' when the stored
value is '1' or '0', or show figures with two decimal places, such
as 1.50 instead of 1.5. The usual approach in such cases is to
create persistant fields and use their OnGetText events or
Display Format properties. You can also achieve the desired
result without persistant fields, as described in this article.

Persistant fields
For a change, here we use SqlServerExpress (Microsoft's free
database application) for our example. For those of you who are
used to working with Paradox or Access, it's easy to do the same
Figure 4. Specifying the DisplayFormat property
thing with these applications.
of the persistant field 'Paid'
The example table in Figure 1 has four fields: ID
(autoincrement), Name (string 15), Amount (float or real; may be A FloatField has the propertyDisplayFormat, but some other field
empty), and Date (date and time; may be empty). types (such as StringField) do not. The specific properties depend
on the field type. For example, a Boolean field has the
DisplayValues property (Yes; No or T; F), an Integer field has the
MaxValue and MinValue properties, and so on.

Figure 1. Structure of the test table in SqlServer 2005


If you fill the table with some data and display it as an AdoTable
in a DBGrid, the presentation of the numbers leaves something
to be desired. We are used to seeing numbers with two decimal
Figure 5. Rendering of floating-point values
places instead of the numbers shown in Figure 2.
with DisplayFormat set to '0.00'
Persistant fields are thus very handy when you have special
wishes for fields that are not available at runtime. However, they
also have disadvantages. To start with, they end up in your code:
type
TForm1 = class(TForm)
ADOTable1: TADOTable;
ADOTable1ID: TAutoIncField;
ADOTable1Name: TStringField;
ADOTable1Paid: TFloatField;
ADOTable1Date: TDateTimeField;
DBGrid1: TDBGrid;
Figure 2. Default display of floating-point numbers DataSource1: TDataSource;
private
The usual solution here is to right-click AdoTable1 (or Table1 if {Private declarations }
you're using Paradox) to bring up the Fields Editor. In the Fields public
Editor, you again right-click and select 'Add all Fields' as shown {Public declarations }
in Figure 3. end;

With a large number of tables, this can result in pages full of


'filler' code.
A more serious problem is that your fields are no longer flexible.
If there are any persistant fields (even just one), no fields are
created at runtime and all non-persistant fields are hidden. This
can drive you crazy when (perhaps years later) you add a field to
table and it remains invisible no matter what you do. You usually
end up deleting the table (or AdoTable) and building it again
from scratch, after which the field is suddenly visible. However,
it's easy to forget to check the properties, such as DisplayFormat,
Figure 3. Using 'Add all Fields' to make persistant fields and then other things are suddenly messed up. For these reasons,
persistant fields are not especially popular.
This gives you what are called persistant fields, which remain
permanently in your program. This is an extension to the normal
DisplayFormat without persistant fields
situation in which the fields are created at runtime when the
It's also possible to specify the DisplayFormat property without
table is opened.
creating persistant fields. To do this, you have to specify the field
The advantage of persistant fields is that you can configure the
property in the code immediately after you open the table.
properties and events of each field separately. The Object
You can use the table's OnAfterOpen event for this, as shown in
Inspector gives you convenient access for viewing or setting the
Figure 6.
configurations, such as in Figure 4 where you see the Display
(Note: If you open the table in the event OnShow of your form,
Format property of the Amount field. If you type '0.00' here, the
you do not need to use OnAfterOpen. In this case, you can
numbers will always be displayed with two decimal places as
specify the property in the OnShow event immediately after the
illustrated in Figure 5.
line containing AdoTable1.Open.)

Page 18 / 2132 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Customizing the T-Field data display (continuation 1)

Figure 6. DisplayFormat is not one of the listed properties


Figure 8. Using OnGetText to convert 0 and 1 to 'm' and 'f '
Unfortunately, you won't see DisplayFormat in the dropdown list
if you simply try to specify this property, since DisplayFormat is OnGetText without persistant fields
not a general TField property, but instead only a property of a Using OnGetText without persistant fields is a bit more difficult.
number field or date field. For this reason, you need a typecast to Two steps are necessary in this case. First you have to tell the
TFloatField or its general ancestor TNumericField. program that the OnGetText event of the Gender field points to a
specific procedure, and then you have to specify this procedure.
procedure TForm1.ADOTable2AfterOpen(DataSet: TDataSet);
begin
(AdoTable2.FieldByName('Paid') as Incidentally, this is how Delphi always works. You can see this if
TNumericField).DisplayFormat := '0.00'; you examine the previous example in Figure 8 more closely. To
end; do this, you have to look in the code of the form itself (the .dfm
This lets you specify the properties of a TField without creating file), where the OnGetText event is linked to the procedure. It's
persistant fields. very easy to view the code in the .dfm file: simply right-click the
form, select 'View as Text', and look for the persistant field,
where you will see:
Using OnGetText with persistant fields
In the introduction to this article we mentioned that you may object ADOTable1Sex: TIntegerField
FieldName = 'Sex'
have a table where '0' and '1' stand for 'male' and 'female', which OnGetText = ADOTable1SexGetText
you want to show as 'm' and 'f, and that you can do this by using end;
OnGetText.
To restore the normal form view, right-click this code and select
To try this out, add a Gender field (of type Integer) to your table 'View as Form'.
in SqlServer (or Access, Paradox, or whatever you're using). Here
again you have two options: 'with' or 'without' persistant fields. Now: how it works without persistant fields.
The first step is the code that references the procedure:
First: how it works with persistant fields.
procedure TForm1.ADOTable2AfterOpen(DataSet: TDataSet);
If you already had persistant fields before you added the Gender begin
field, you won't see the new field in the DBGrid. (AdoTable2.FieldByName('Paid') as
What's worse, if you use Add Fields as shown in Figure 3, there's TNumericField).DisplayFormat := '0.00';
a good chance that you won't even see the field itself. This is AdoTable2.FieldByName('Sex').OnGetText :=
SexGetText;
because AdoTable1 can't see that a new field has been added end;
unless you have AdoTable1 open at design time. To achieve this,
set the Active property of the table to True before you invoke Add Incidentally, you can also put the code for the first step in the
Field. OnCreate event of the form (which is actually the usual practice).
Once you have added the Gender field to the table as a persistant
field, you can view the events of this field as shown in Figure 7. The second step is to specify the action in SexGetText. An
OnGetText event expects three parameters (Sender, Text, and
DisplayText), so you have to specify them as well. See the Help
entry for OnGetText for more explanation. The resulting code is:

procedure TForm1.SexGetText(Sender: TField;


var Text: string; DisplayText: Boolean);
begin
if Sender.AsInteger = 0 then
Text:= 'm'
else Text:= 'f';
end;
Figure 7. Events of the persistent Integer field 'Gender' Don't forget to declare this procedure, including its parameters,
If you double-click OnGetText, you will see a framework. Put in the private declarations. The easiest way to do this is to use
the following code in this framework Ctrl+Shift+C to complete the code automatically.
procedure TForm1.ADOTable1SexGetText(Sender: Also be sure to set the ReadOnly property of this DBGrid field to
TField; var Text: string; DisplayText: Boolean); True. It's very confusing for users if what is displayed is not the
begin same as what they have to enter, so you have to arrange for data
if Sender.AsInteger = 0 then
Text:= 'm' entry outside your DBGrid.
else Text:= 'f';
end; There is also a way to accept data entry that does not match the
Here you should note that the type of Sender is TField rather field content and have it be stored in the table. For this, you use
than TObject, which means that you can use AsInteger to read the counterpart of OnGetText, which is called OnSetText.
the numerical value directly, and that Text is a variable that you
can use specify the text to be displayed. Unfortunately, it isn't possible to use OnSetText to enter a letter
The result is shown in Figure 8. (such as 'm' or 'f') in an integer field, since a number field won't
accept letters. You'll hear an error beep before you even get to
OnSetText.

October 2009 BLAISE PASCAL MAGAZINE 8 Page 19 / 2133


COMPONENTS
DEVELOPERS 4
Customizing the T-Field data display (continuation 2)
Consequently, we have to devise another example for OnSetText. procedure TForm1.FormCreate(Sender: TObject);
begin
OnSetText without persistant fields AdoTable1.FieldByName('Sex').OnGetText:=
GeslachtGetText;
For our example for OnSetText we will use a date field, since a AdoTable1.FieldByName('Date').OnSetText:=
date field accepts all characters. DatumSetText;
The objective here is to have the current date be stored when the end;
user enters a space character. procedure TForm1.ADOTable1AfterOpen(DataSet: TDataSet);
begin
This can be done with or without persistant fields; the example (AdoTable1.FieldByName('Paid') as
TNumericField).DisplayFormat:= '0.00';
here is without persistant fields. The full code, including the end;
previous DisplayFormat and OnGetText, is as follows:
procedure TForm1.SexGetText(Sender: TField;
unit Unit1; var Text: string; DisplayText: Boolean);
begin
interface if Sender.AsInteger = 1 then
Text:= 'm'
uses Windows, Messages, SysUtils, Variants, Classes, else Text:= 'f';
Graphics, Controls, Forms, DB, Grids, DBGrids, ADODB; end;
type procedure TForm1.DateSetText(Sender: TField;
TForm1 = class(TForm) const Text: string);
ADOConnection1: TADOConnection; begin
DBGrid1: TDBGrid; if Trim(Text) = '' then
DataSource1: TDataSource; Sender.AsDateTime:= Date
ADOTable1: TADOTable; else Sender.AsDateTime:= StrToDateTime(Text);
procedure FormShow(Sender: TObject); end;
procedure FormCreate(Sender: TObject);
procedure ADOTable1AfterOpen(DataSet: TDataSet); end.
private
procedure SexGetText(Sender: TField; This example, which stores the current date when a space
var Text: string; DisplayText: Boolean); character is entered or nothing is entered, can easily be extended
procedure DateSetText(Sender:TField; const Text:string); to provide other useful functions, such as storing yesterday's date
public
{Public declarations } or tomorrow's date if the user enters '–' or '+', entering the date
end; and time without seconds, and so on. You can also add a good
var Form1: TForm1; automatic error handling mechanism, such as adding the month
implementation
{$R *.dfm}
and year automatically if only the day is entered.

procedure TForm1.FormShow(Sender: TObject); One final remark: the example shows how this works with a
begin
ADOTable1.Open;
DBGrid, but it also works with a DBEdit or the like, since the
end; code is linked to a TField rather than the component that
displays the data.

Using Free Pascal and Lazarus to create


applications for OSX. by Jeremy North starter expert

Having come from using Delphi and Visual Studio development run. Follow the installation instructions found on the website to
environments and constantly hearing how an OSX based system install each package. After you have installed both Free Pascal and
does everything better than a Windows based system I was Lazarus, run Lazarus. By default Lazarus installs into the
bitterly disappointment when I started exploring the XCode and /Developer/lazarus folder.
Interface Builder developer tools by Apple.
If you want to use a Pascal language on OSX your options are
pretty limited. One option is Free Pascal. Free Pascal has been
around for a number of years now and is updated regularly. It
supports many operating systems include Win32, Linux, WinCE
and OSX. To support Free Pascal there is an open source
integrated development environment called Lazarus. Let's be
honest here, Lazarus is pretty much a knock off of the old
Borland IDE circa Delphi 7, which can be both a positive and
negative, with a few nice additions thrown in. Lazarus has its own
version of the VCL called LCL. It is basically compatible with
Delphi's VCL. I say basically because it isn't 100% and in some
areas it is far from it. You need to download the appropriate
packages from the Free Pascal and Lazarus websites for your
version for your MAC. Make sure you download the correct
packages. Figure 1: the IDE of Lazarus
Free Pascal - (http://www.freepascal.org/) Launch Lazarus and go into the Environment | Options dialog.
Lazarus - (http://www.lazarus.freepascal.org/) Make sure that the Compiler Path and FPC Source Directory
Before installing either package be sure to install the Apple options are set to the install location of Free Pascal. If you install
developer tools. You can download these tools from the Apple to the default locations these will be /usr/local/bin/fpc and
Developer website (http://developer.apple.com). You will /usr/local/share/fpcsrc/ respectively.
have to create a developer account which is free - unless you
select one of the paid account types. I signed up using the iPhone Features not in Delphi
developer program which gives you access to the iPhone specific As mentioned earlier, Lazarus has some features that are not
tools (SDK versions, simulator etc.) but also to the desktop available in the Delphi. It also has some of Delphi features that are
specific tools. Be warned, the downloads are not small (nor fast - not so good and then it just has some features of its own that are
at least from my side of the world). not so good.
After installing the Apple developer tools, install Free Pascal NOTE: These lists are nowhere near exhaustive.
before Lazarus. This should make things a lot easier in the long

Page 20 / 2134 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Using Free Pascal and Lazarus to create applications for OSX (continuation)

Figure 4: compiler options for the project


my Mac Book Pro. This project consisted of one form. The form
had a main menu (with some items in it – two had event handlers),
a memo and a status bar. When trying to import this project the
Good Figure 2: the options form IDE crashed. A second application I tried to import did work
Lazarus includes a DIFF viewer for comparing files. however the imported project didn't have any unit paths assigned
Although nothing could replace Beyond Compare on my to it (which is done automatically when you create a new project).
systems for that. This means you need to set these paths manually. The second
Customizable number of recent project and files. This project didn't include the status bar or the main menu.
feature is included Delphi in 2010.
The tab order dialog allows you to change a forms entire Using Free Pascal with XCode and Interface Builder
tab order within the same dialog. So you don't have to keep When you install Free Pascal the later versions include an XCode
reopening the dialog with a different parent selected like for Integration product. This product allows you to use the XCode
you do in Delphi. and Interface Builder tools to create applications using Free
Not so good Pascal. While I didn't really have a lot of time to use this product,
By default a dialog displays to tell you that you have it showed considerable promise and something that will hopefully
finished running your application. This dialog is very see regular updates in the future.
annoying. It can be switched off in the Debugger options
located in the environment options dialog shown earlier.
Uncheck the Show message on stop check box.
The Importing of Delphi projects and files didn't work very
well and was error prone. Eventually I gave up.
Lots of setting up of custom paths to compiler and units
required for projects - compounded by my importing woes
mentioned earlier.
Stability
While writing this article and generally exploring Lazarus, stabi-
lity can be an issue. Trying to create a standard action using the
component editor for the action list resulted in an Access Viol-
ation that required Lazarus to be restarted. Somehow I managed
to get a Debugger error (refer to screen capture). Clicking OK
didn't prevent me from debugging the application though.

Figure 4: a debugger error under Mac


While I had issues creating a new NIB (or XIB) file modifying the
one included when creating the template was a simple. Every
control I dropped onto the design surface worked and recompiling
the application also worked fine.
Conclusion
Figure 3: a debugger error under Mac If you want to write Pascal code on your Mac and do not want to
Target Widget Type use either a Virtual Machine or Boot Camp then Lazarus and Free
The default widget framework used by Lazarus is Carbon. Pascal is an option to keep an eye on. The Intel OSX (I tested under
Carbon is the older API although it is still used in a lot of the Leopard – Snow Leopard was released just prior to completing the
native Apple applications that come with newer versions of article) version seems a little rough around the edges. If you're a
OSX. The new widget set, Cocoa is available although it is listed developer that is interested in writing applications for the Mac in
as Pre-Alpha in the LCL Widget Type drop down. When I tried Pascal, certainly check out the Free Pascal and Lazarus
to target Cocoa a basic project failed to compile. combination. I'm sure they'd appreciate any assistance you gave
Cross Platform, not so much them with bug reports or submitting fixes to the team behind the
Cross Platform seems to be a popular phrase lately. With products. One advantage of Lazarus is, if there is something in it
Embarcadero recently announcing it will be creating Linux and that you don't like. You have the source code on your disk and a
OSX compatible compilers. While the details are sketchy at the Build Lazarus menu item in the Tools menu.
moment, it has been mentioned that there will not be a version of Next Time: We will convert some component code from Delphi
the IDE for the alternate platforms. (VCL) to Free Pascal (LCL), making sure that it runs correctly
I created a very simple application in Delphi and saved it on to on OSX as well.

October 2009 BLAISE PASCAL MAGAZINE 8 Page 21 / 2135


COMPONENTS
DEVELOPERS 4
Writing Delphi Components II:
Custom Properties and Windows Controls by Marco Cantù
starter expert DELPHI 3-7 2005..10 Win32 Note: It’s important to name fields, access methods, and
properties in a manner consistent with the standards defined by
This article is the second of a series introducing a very relevant CodeGear and originally published in the Component Writer’s
features of Delphi's architecture, namely writing your own Guide. The basic guidelines are: Use meaningful names for
custom components. The first article of this introductory series properties, add an f to the names of fields that correspond to
provided an overview of the Delphi Component Wizard and properties, and name access methods as Get or Set plus the
showed a first very simple component. Our second component, property name (as in SetStatus and SetColor).
covered here, will add some extra properties and events.
A Graphical Component with Custom As usual, the Create constructor calls the inherited version of the
Properties: The LED constructor (an important step to remember), and then sets the
values I’ve specified as property defaults:
To show you a more usable graphical component, I’ve built yet
another LED component. (LED is an acronym for Light- constructor TCntLed.Create (Owner: TComponent);
Emitting Diode, a solid-state electronic light that’s typically begin
used for indicating binary conditions such as the send/receive inherited Create (Owner);
status of a modem.) Instead of calling it TYALC (for Yet // set default values
fColor := clRed; fStatus := lsOn;
Another LED Component), I’ve called it TCntLed, using the Cnt Width := 20; Height := 20;
prefix after my name. end;

The two Set methods follow the standard form: If the new value
Here is the declaration of this simple component class. As you
is really different from the current one, change the value and
can see, there are only two custom properties, Color and Status:
update the user interface. Otherwise, do nothing:
procedure TCntLed.SetStatus (Value: TCntLedStatus);
type beg
TCntLedStatus = (lsOn, lsOff); if Value <> fStatus then begin
fStatus := Value; Invalidate;
TCntLed = class (TGraphicControl) end;
private end;
fStatus: TCntLedStatus;
fColor: TColor; procedure TCntLed.SetColor (Value: TColor);
protected begin
procedure SetStatus (Value: TCntLedStatus); if Value <> fColor then begin
procedure SetColor (Value: TColor); fColor := Value; Invalidate;
public end;
constructor Create (Owner: TComponent); override; end;
procedure Paint; override;
published The Paint method is a little more complex than the property
property Status: TCntLedStatus methods. First it draws a background circle, which I use as a
read fStatus write SetStatus default lsOn;
property Color: TColor border, and then an inner circle if the LED is on. To make sure
read fColor write SetColor default clRed; the LED has the correct appearance (they’re almost always
property Width default 20; round), I check the width and height properties to determine the
property Height default 20; actual diameter of the LED (I use the smaller of the two values).
property OnClick;
property OnDblClick; In a future example, I’ll show you how to use code to impose a
end; relationship between the width and the height of a component.
Here’s the Paint method:
For the Status property, I’ve defined an enumerated data type
(TCntLedStatus), which is more understandable and flexible than a
procedure TCntLed.Paint;
Boolean data type. By convention, you should use the initial letter var Radius, XCenter, YCenter: Integer;
of the component and property name (ls for LED Status) to build begin
the names of the enumerated values (for example, lsOn). // get the minimum between width and height
If you examine the property declarations, you notice that I’ve if Height > Width then Radius := Width div 2 - 2
applied the read and write directives to specify how to set or else Radius := Height div 2 - 2;
retrieve the property’s current value. For these directives, you can XCenter := Width div 2; // get the center
specify either a local field of the class, a function (to retrieve the YCenter := Height div 2;
property), or a procedure that accepts a single parameter of the Canvas.Brush.Color := clDkGray; // LED border color (fixed)
same type (to set the property). Canvas.Ellipse (
In the declaration above, I’ve supplied private variables for the XCenter - Radius, YCenter - Radius,
XCenter + Radius, YCenter + Radius);
Status and Color property read directives, and I’ve specified if fStatus = lsOn then begin // led surface
procedures for the corresponding write directives. I used Canvas.Brush.Color := fColor;
procedures to set the property values so that I can update the user Radius := Radius - 3;
interface when the property value changes. Canvas.Ellipse (XCenter - Radius, YCenter - Radius,
XCenter + Radius, YCenter + Radius);
end;
At the end of each property declaration, I’ve provided a default end;
value. As you might have guessed, this implies that I’m going to set
those values in the component’s constructor, which means I’ll need Instead, I’ve decided to show a similar but different
to override it. I’ve declared an overridden version of the Create case—combining several TDdhLed components into a
constructor for just this reason. TDdhSemaphore component.

Finally, you’ll notice that I’m overriding the Paint method, A Custom Windows Control: The Fonts Combo
specifying default values for some inherited properties, and that Box Many applications have a toolbar with a combo box you
I’m publishing several inherited event properties. The new Paint can use to select a font. If you often use such a customized
method will allow us to take control of the appearance of the combo box, why not turn it into a component? Doing so will
component, the new default property values represent additional probably take less than a minute.
work that I’ll need to perform in the constructor, and publishing the
inherited events gives us the opportunity to customize the
component’s behavior.

Page 22 / 2136 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Writing Delphi Components II (continuation)
To begin, start the Component Wizard, either by choosing Notice that besides giving a new value to the component’s
Component ?New Component, or by selecting File ?New ? Style property in the Create method, you redefine this property
Other to open the Object Repository and then choosing the by setting a value with the default keyword. You have to do both
component in the New page. In the Component Wizard, I've operations because adding the default keyword to a property
created a component which inherit from TComboBox. and is declaration has no direct effect on the property’s initial value. Why
called TCntFontCombo. specify a property’s default value then? Because properties that
The Component Wizard will generate the following source code: have a value equal to the default are not streamed with the form
definition (and they don’t appear in the textual description of the
unit CntFontCombo; form, the DFM file). The default keyword tells the streaming code
interface
uses
that the component initialization code will set the value of that
Windows, Messages, SysUtils, Classes, Graphics, property.
Controls, Forms, Dialogs, StdCtrls; The other redefined property, Items, is set as a property that should
type not be saved to the DFM file at all, regardless of the actual value.
TCntFontCombo = class (TComboBox)
This behavior is obtained with the stored directive followed by the
private {Private declarations }
protected {Protected declarations } value False. The component and its window will be created again
public {Public declarations } when the program starts, so it doesn’t make sense to save in the
published {Published declarations } DFM file information that will be discarded later (to be replaced
end; with the new list of fonts).
procedure Register;

implementation The third property, ChangeFormFont, is not inherited but


introduced by the component. It is used to determine whether the
procedure Register; current font selection in the combo box should specify the font of
begin the form hosting the component. Again, this property is declared
RegisterComponents('Cnt', [TCntFontCombo]);
end; with a default value, which is set in the constructor. The
end. ChangeFormFont property is used in the code of the CreateWnd
method, shown earlier, to set up the initial selection of the combo
This example doesn’t include much code. You need only copy all depending on the font of the form hosting the component. This is
the system fonts to the Items property of the combo box at startup. generally the component’s Owner, although I could also have
To do so, you might try to override the Create method in the class walked the Parent tree looking for a form component. This code
declaration, adding the statement Items := Screen.Fonts. However, isn’t perfect, but the Assigned and is tests provide some extra
this is not the correct approach. The problem is, you cannot access safety.
the combo box’s Items property before the window handle of the The ChangeFormFont property and the same if test play a key role
component is available; the component cannot have a window in the Changed method, which in the base class triggers the
handle until its Parent property is set; and that property isn’t set in OnChange event. By overriding this method, you provide a default
the constructor, but later. behavior (which can be disabled by toggling the value of the
For this reason, instead of assigning the new strings in the Create property) but also allow the execution of the OnChange event, so
constructor, you must perform this operation in the CreateWnd that users of this class can fully customize its behavior. The final
procedure, which is called to create the window control after the method, SetChangeFormFont, has been modified to refresh the
component is constructed, its Parent property is set, and its window form’s font in case the property is being turned on. The complete
handle is available. Again, you execute the default behavior, and code is as follows:
then you can write your custom code. I could have skipped the
Create constructor and written all the code in CreateWnd, but I procedure TCntFontCombo.Change;
decided to use both startup methods to demonstrate the difference begin/ assign the font to the owner form
if FChangeFormFont and Assigned (Owner)
between them. Here is the declaration of the component class: and (Owner is TForm)
then TForm (Owner).Font.Name := Text; inherited;
type end;
TCntFontCombo = class (TComboBox)
private procedure TCntFontCombo.SetChangeFormFont(const Value:
FChangeFormFont: Boolean; Boolean);
procedure SetChangeFormFont(const Value: Boolean); begin
public FChangeFormFont := Value;
constructor Create (AOwner: TComponent); override; if FChangeFormFont then Change; // refresh font
procedure CreateWnd; override; end;
procedure Change; override;
published
property Style default csDropDownList; Temporarily Conclusion
property Items stored False; We have now seen some more about components, although these
property ChangeFormFont: Boolean examples are not terribly useful, they should help you get started.
read FChangeFormFont write SetChangeFormFont In the next issue we'll go ahead and cover a few more of the many
default True;
end; advanced features of components writing in Delphi.

Author
And here is the source code of its two methods executed at
Marco Cantù is the author of several best-selling
startup:
Delphi books, including the Mastering Delphi series
and the recent Delphi 2009 Handbook. He's also an
constructor TCntFontCombo.Create (AOwner: TComponent);
begin active user and developer in the Web 2.0 world and
inherited Create (AOwner); social web, like Twitter. You can reach him on
Style := csDropDownList; FChangeFormFont := True; www.marcocantu.com, blog.marcocantu.com, and
end;
twitter.com/marcocantu or by email at
procedure TCntFontCombo.CreateWnd; [email protected].
begin
inherited CreateWnd; Items.Assign (Screen.Fonts);
// grab the default font of the owner form
if FChangeFormFont and Assigned (Owner)
and (Owner is TForm)then
ItemIndex := Items.IndexOf ((Owner as TForm).Font.Name);
end;

October 2009 BLAISE PASCAL MAGAZINE 8 Page 23 / 2137


COMPONENTS
DEVELOPERS 4
My Top Five Delphi 2010 New Features door Pawe³ G³owacki
starter expert DELPHI 2010

Delphi 2010, C++Builder 2010 and Delphi Prism 2010 have


been just released. I have put together my own top five new
features introduced in Delphi 2010.
I'm so excited! The new version of Delphi is now available.
Delphi 2010 contains plenty of new features in all areas of the
product, including installation, help system, IDE, compiler,
VCL and database development.
My top five new Delphi 2010 feature list is very subjective and
I'm sure every Delphi developer may have a different view on
this matter, but here we go… Figure 2: Press F6
to display new IDE
“Insight” dialog
for easy keyboard
access to anything.

There are a number of new usability features in the debugger. It is


now much easier to debug a multithreaded application and the
debugger now allows for stepping and debugging within selected
threads. You can selectively "freeze" and "thaw" threads so that
debugging activity can be isolated to a particular thread or threads.
When a thread is frozen, it will not actually run and no debug
events will occur in the context of that thread. You can access this
functionality in the Thread Status view by using one of the four
new context menu items: "Freeze", "Freeze All Other Threads",
Figure 1: Splash screen "Thaw" and "Thaw All Threads". You can also set a breakpoint for

5. IDE Usability
It is all about the productivity of a
Delphi programmer. If you are like me,
you spend a big part of your day inside
the IDE – Integrated Development
Environment. I still wonder if there are
any limits for creative ideas related to
developer tools productivity. Delphi
has an excellent tradition here. Turbo
Pascal invented the IDE by putting
together three formerly separate
entities – code editor, compiler and
debugger. Delphi 1 pioneered Rapid
Application Development, introducing
the concept of a component - an object
instance that can be manipulated
visually at design-time. Some of the
capabilities introduced in Delphi 1, like
live data at design time, are still
unavailable in other IDEs.

I expect one of the biggest productivity


wins is with using the brand new “IDE Figure 3: Source code formatter options
Insight”. Just press F6 and it does not
matter where you are in the IDE, you are presented with the list of a selected thread. What is even more intriguing is support for so
possible commands available in a given context. For example the called “debug visualizers”. To make debugging programs much
list of options will be different when you are in the code editor and easier, custom data viewers/data visualizers in the debugger
different when you are in the forms designer. You can also start provide a way to view data other than using the standard output
typing the name of the thing that you need and the IDE Insight from the evaluators. The Open Tools API supports the
dialog will do incremental filtering as you type. As you can see in development of custom visualizers for data types. There are
Figure 2, it is also possible to use pattern matching if you include sample visualizers for several data types in RAD Studio 2010,
“*” character in the pattern. including the TDateTime, TDate, and TTime types and the
std::string and std::wstring instances for C++.
Another very much anticipated feature is the code formatter for
Delphi and C++ source files. You can format either the whole file
or just a selection of code in the code editor. This will be a very
useful feature when you are maintaining source code formatting
standards across different projects in your organization or maybe
you have inherited some source code and you are just used to
different formatting. Select a block of code and hit Ctrl+D and
your selection will be instantly formatted according to the
preferences set in the Code Formatter Options. You can see the
code formatter options in Figure 3

Page 24 / 2138 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
My Top Five Delphi 2010 New Features (continuation 1)
Consider Figure 3, with the Delphi code has a breakpoint set at There is plenty of other IDE usability improvements, both big
line 36. and small, like the new “Search” bar which is very similar to the
procedure TForm21.Button1Click(Sender: TObject); Firefox web browser, improved “Find in Files” dialog,
var draggable bookmarks and breakpoints, an improved “Use Unit”
SL: TStringList; dt: TDateTime;
begin dialog where you can specify if you want to add a given unit to
dt := Now; SL := TStringList.Create; “interface” or “implementation” section of a unit, a new
try “Reopen Menu Properties” dialog, an option to disable code
SL.Add(TimeToStr(dt)); folding in the editor and a number of new Open Tools API for
SL.Add('Delphi');
SL.Add('C++Builder'); customizing the IDE, including possibility to embed custom tabs
ListBox1.Items.Assign(SL); // <-- set a breakpoint here inside the IDE, and many more.
finally
SL.Free; 4. Native Direct2D support
end; RAD Studio 2010 provides new “Direct2D.pas” unit where you
end;
can find a brand new “TDirect2DCanvas” class and helper
Figure 4: Consider this breakpoint classes like “TDirect2DFont”, “TDirect2DPen” and
“TDirect2DBrush”. But, what is Direct2D? It is a new Windows
The Local Variables view in Figure 4 shows both visualizers in 7 graphics API that provides high performance and high quality
action. “dt” variable, which internally is just a float, is displayed rendering for 2-D geometry, bitmaps, and text. Applications that
as human readable date/time value. The “SL” variable has a use Direct2D for graphics can deliver much higher visual quality
magnifying glass icon next to it, and the context menu “Show than can be easily achieved using GDI. Direct2D uses per-
Strings”. When clicked you can actually see strings stored inside primitive anti-aliasing to deliver smoother-looking curves and
the “SL” string list. lines in rendered content. There is also full support for
transparency and alpha-blending when rendering 2-D primitives.
Why is Direct2D so mighty? Because it is implemented in native
code and Delphi provides native VCL wrappers for
programming with Direct2D. Kenny Kerr in his “Introducing
Direct2D” MSDN Magazine article (May 2009) says that “if you
want to develop high-performance and high-quality commercial
applications, you'll still look to C++ and native code to deliver
that power.” Delphi developers could not agree more with this
statement .
The “TDirect2DCanvas” class gives Delphi and C++Builder
programmers familiar “TCanvas” abstraction for doing Direct2D
programming. Sweet!
3. Custom Attributes and new RTTI
Delphi 2010 adds custom attributes to the Delphi language. This
feature has been available in the past for the Delphi for .NET
compiler, and is now available for native Delphi programming.
Custom attributes make it possible to add arbitrary custom
metadata information to your code. You can apply custom
attributes to types, methods, arguments and even function
results.
Figure 5: Data visualizers make clearer and debugging easier If you want to define a custom attribute, you just need to derive
and faster a new class from “TCustomAttribute” type. By convention
names for custom attributes do not start with canonical Delphi
RAD Studio 2010 makes it possible to author your own “T”. Custom attributes can have constructors like other Delphi
visualizers for any custom type using new Open Tools API. You classes, however you can only pass simple types to attributes
can verify which visualizers are installed in the new “Registered constructors.
Visualizers” tab in the “Options” dialog as shown in Figure 6. Why would I want to use custom attributes? What are they good
for? That's a good question. Let's
imagine a custom Object-Relational
Mapping solution where you want to
map Delphi classes to database table
names and object properties to column
names. With custom attributes you can
just mark your class and methods with
custom attributes and store mappings as
part of a class declaration.
You could also use attributes to keep
URLs to help topics in a web-based
documentation system. Figure 6 shows
the definition of “DocAttribute” that has
“URL: string” property. Note that
“TCustomAttribute” class is defined in
the “system” unit.

Figure 6: An example of registered


debugger data visualizers

October 2009 BLAISE PASCAL MAGAZINE 8 Page 25 / 2139


COMPONENTS
DEVELOPERS 4
My Top Five Delphi 2010 New Features (continuation 2)
unit uAttributes; uses RTTI, uClasses, uAttributes;
interface
{$R *.dfm}
type
DocAttribute = class(TCustomAttribute) procedure TForm2.Button1Click(Sender: TObject);
private var
FURL: string; ctx : TRttiContext;
public t : TRttiType;
constructor Create(URL: string); m : TRttiMethod;
property URL: string read FURL write FURL; a : TCustomAttribute;
end; begin
ListBox1.Clear;
implementation ctx := TRttiContext.Create;
{DocAttribute } try
t := ctx.GetType(TMySuperClass);
constructor DocAttribute.Create(URL: string); for a in t.GetAttributes do
begin if a is DocAttribute then
FURL := URL; ListBox1.Items.Add(Format
end; ('Type = %s; Attribute = %s, URL = %s',
[TMySuperClass.ClassName, a.ClassName,
end. DocAttribute(a).URL]));
Figure 7: The definition of “DocAttribute” and class of type for m in t.GetMethods do
TCustomerAttribute for a in m.GetAttributes do
if a is DocAttribute then ListBox1.Items.Add
Figure 8 shows a hypothetical definition of “TMySuperClass” (Format('Type = %s; Method = %s;
Attribute = %s, URL = %s',
decorated with custom documentation attributes. [TMySuperClass.ClassName, m.Name,
uses uAttributes; a.ClassName, DocAttribute(a).URL]));
type finally
ctx.Free;
[Doc('http://www.xyz.com/docs/23456')] // I'm skipping end;
"...Attribute" here! end;
TMySuperClass = class
public Figure 10: Querying custom attributes in code
[DocAttribute('http://www.xyz.com/docs/12345')]
procedure DoSomething;
end;
Figure 8: TMySuperClass and DocAttribute use
OK. So, what next? How do I query for attributes in code?
Another great new feature of Delphi 2010 is support for new
generation RTTI with capabilities similar to .NET/Java Reflection.
There is brand new “rtti.pas” unit that provides types and methods
for inspecting types. As you can see in Figure 8 (upper right
corner), the starting point for using RTTI in code is creating an
instance of “TRttiContext” class.

2. Touch, Multitouch and Gesturing


Do you own iPhone? There is something natural in touching the
screen and expecting something to happen. Touch is perceived as
a natural evolution of human interactions with a computer.
Delphi 2010 introduces support for touch interfaces at the level
of the VCL library and this means that touch is supported not
only on Windows 7, but also on all other versions of Windows
supported by Delphi 2010.
“TControl” class introduces “OnGesture” event and
“DoGesture” virtual method that can be overridden in
descendant classes. The VCL contains 34 built-in simple
gestures and 5 interactive gestures. If you want to do more low
level coding, you can intercept Windows WM_TOUCH Figure 11: How Zorro would define a custom gesture
message, but it is easier to just implement event handlers for You just need to drop the “TGestureManager” component on a
gestures you are interested in. Delphi 2010 also makes it possible form, connect it via the Form's “GestureManager” property and
to define your own gestures, like my “Zorro” gesture in Figure you are up and running. Figure 12 (next page) shows the
11, and also embed in a Delphi application custom gesture editor “GestureManager” property.
to let the end-users define their gestures.

Figure 9: Attributes listing


When you click on the button you get the result

Page 26 / 2140 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
My Top Five Delphi 2010 New Features (continuation 3)

Figure 14: New DataSnap WebBroker Application Wizard

In the case of WebBroker-based application you can only use


Figure 12: Setting Gestures in the Object Inspector. HTTP transport. Hosting DataSnap servers inside a web server
It is probably the most elegant solution to use “TActionList” or has the advantage of starting server instances on demand.
“TActionManager” component and hook individual gestures to That's a completely new dimension to DataSnap. It is such a
“Action.Execute” event handlers. pleasure to observe how this technology has evolved with every
For simple gestures you do not need to have touch-enabled new release of Delphi. Delphi 2007 introduced a completely
hardware. You can imitate gestures with a mouse. rewritten new implementation of the dbExpress database driver
architecture, in pure Delphi code. Then, Delphi 2009 provided
1. Datasnap 2010 brand new support for DataSnap client/server architecture
New DataSnap 2010 features are my absolute number one. I was through extending dbExpress.
hoping to see HTTP support in the new version of Delphi, but DataSnap connectivity is implemented as a special dbExpress
there is much more. First of all there are two new DataSnap driver that unlike a normal driver, does not talk to a database, but
wizards. One to create a standalone DataSnap server application rather knows how to communicate with DataSnap servers.
packaged as “VCL Forms Application”, “Console Application” Delphi 2010 adds support for HTTP communication between
or “Service Application”, supporting TCP and/or HTTP DataSnap clients and servers. There is also new support for
communication as shown in Figure 13. server callbacks and passing data as JSON. Another interesting
new feature is support for exposing DataSnap server methods as
REST interfaces. Finally, it is now very easy to process a
communication stream between client and server via
implementing a custom filters. Delphi 2010 comes with
compression filter out of the box.

Summary
Recently released Embarcadero RAD Studio 2010 contains many
new features including IDE usability improvements, support for
touch, new Delphi language features and DataSnap 2010
architecture for component-based development of multitier
systems. In this article, I have selected my personal top five, but
there is much more in Delphi 2010, C++Builder 2010 and Delphi
Prism 2010 then described here.

Try it for yourself!


http://www.embarcadero.com/products/rad-studio

[email protected]
Figure 13: New DataSnap Server Wizard or visit his blog on
The second wizard let you create DataSnap Server WebBroker http://blogs.embarcadero.com/pawelglowacki
application as shown in Figure 13. How cool is that?

October 2009 BLAISE PASCAL MAGAZINE 8 Page 27 / 2141


COMPONENTS
DEVELOPERS 4
Fast Graphic deformation by using Scanlines
by Peter Bijlsma
The SrcRect and DestRect rectangles (type TRect) have a
Sometimes it's necessary to manipulate picture height of Ns (number of scanlines) and a width of Ls (Length of
representations, e.g. to correct the perspective. Programs like scanlines). Next, the scanlinepointers of an area to be manipulated
Photoshop have that functionality: buildings who are leaning must be copied to a dynamic array of type pPixArray, called
towards each other can be set straight in no time. How can we ScanlinSel:
accomplish such a deliberate deformation? We know, either by SetLength(ScanlinSel, Ns);
for I := 0 to Ns -1 do ScanlinSel[I] := OBM.Scanline[I];
own experience or by reading articles or books about
Now we can reach each pixel as for instance ScanlinSel[Y][X].R
programming, that routines manipulating images on pixel-
points to the Red byte of pixel number X in row number Y of the
level are very slow. Older Pascallers (like me) will remember
OBM involved. But as we will see, in most cases we don't need
the Putpixel procedure and our, sometimes desperate, attempts
access to the separate Red, Blue or Green components.
to learn enough machine language to make our routines faster
In the following sections I'll describe procedures to deform the
by using Inline code. Nowadays we do not have only faster
selected area (and consequently the adjacent areas). For this
“machines”, but also the programming possibilities developed.
purpose we use another bitmap (VirtBM) in which the
Delphi gave us a powerful property to bitmaps: Scanlines. This
scanlinepointers of the manipulated areas are stored temporarily.
article will describe the use of scanlines in connection with a
program called “Deform!”. Linear Distortion
With Linear Distortion I mean that the pixels in the original
Scanlines bitmap copy OBM are stretched or compressed only in the X and
The Bitmap.Scanline property is a the Y directions. The selected area is leading and the adjacent
pointer to a horizontal row of pixels areas are changed synchronously to warrant smooth transitions
in an image. As this property is read- between the various areas. See figure 2 for the process. The first
only, we must make a copy of the image (at left) is the original image, in the next image the mouse
scanlinepointers in order to be able cursor is used to draw a rectangle: the selected area. In the third
to control the pixels in these rows (or image the rectangle is deformed by grabbing the sides with the
lines) ourselves. In this copying- mouse cursor and moving them to other positions. The last
process we can also enhance the image at right shows us the result.
“granularity” of the pointers, so that
we can address not only the separate
pixels in a line, but also the Red,
Blue and Green components of these
pixels. This is done by defining a
new type in the header of our
program:

type
TPixCol = record //sequence is Blue, Green, Red in scanlines Figure 2 Linear Distortion Process
B : byte; G : byte; R : byte;
end; Each area (OBM[0] through OBM[8]) is in this process
TPixArray = array[0..5000] of TPixCol; //5000 lines is enough deformed in the X and the Y direction. This is done in the
for our use procedure LinearDistort, which puts the result in VirtBM. After
pPixArray = ^TPixArray; copying VirtBM back to the original bitmap (this happens nine
times), the process is completed. Now we see the need to store a
Suppose we select an area of our image in Image1 (we'll call this
copy of the original in OBM first: because the new (deformed)
“main image”) by drawing a rectangle around the part we want to
areas can overlap the original areas. The procedure LinearDistort
manipulate. We copy this area into a new bitmap, OBM[0],
needs the number of selected scanlines, the length of the selected
which then contains a copy of the original pixels of the selected
scanlines, the number of new scanlines in VirtBM and the length
part of our image. By doing the same for the adjacent areas we
of the new scanlines as parameters.
obtain 9 bitmaps, see figure 1:
The procedure is as follows:
procedure TForm1.LinearDistort(NmbSelSLs, LenSelSLs,
NmbVirtSLs, LenVirtSLs: Integer);
var Ysel, Yvirt, J, CyW: Integer; CyF, Fry, Xfact,
Yfact: Single;{sub-procedure FillXVirt is incorporated here:}
procedure FillXvirt; //stretch-shrink horizontal lines, see later
begin
||
end
begin
VirtBM.Width := LenVirtSLs; VirtBM.Height := NmbVirtSLs;
SetLength(ScanlinVirt, NmbVirtSLs);
for J := 0 to NmbVirtSLs-1 do ScanlinVirt[J] :=
VirtBM.ScanLine[J];
Yfact := NmbVirtSLs/NmbSelSLs; //factor to stretch-shrink vertically
Xfact := LenVirtSLs/LenSelSLs; //factor to stretch-shrink horizontally
Yvirt := 0; CyF := 0.5;
Figure 1: Selected area and adjacent areas in main image CyW := Trunc(Yfact); Fry := Frac(Yfact);
copied to OBM bitmaps for Ysel := 0 to NmbSelSLs-1 do begin
if CyW>0 then for J := 1 to CyW do begin
The bitmap copies are stored using the CopyRect FillXvirt; inc(Yvirt);
procedure: end;
CyF := CyF + Fry;
for I := 0 to 8 do begin
if CyF >= 1 then begin
SrcRect[I] := Rect{corner coordinates of area}; FillXvirt; inc(Yvirt);
DestRect := Rect(0,0,Ls[I],Ns[I]); CyF := CyF - 1;
OBM[I].Height := Ns[I]; end;
OBM[I].Width := Ls[I]; end;
OBM[I].Canvas.CopyRect(DestRect,Image1.Canvas,SrcRect[I]); end;
end;

Page 28 / 2142 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Fast Graphic deformation by using Scanlines (continuation 2)
In the next part of the procedure the Start point array (SPar) and The pixel positions are calculated in the sub-procedure
End point array (EPar) are filled. The lengths of these arrays are PlotPixel
both equal to the longest side. The algorithm starts always with procedure PlotPixel;
the longest side and compresses the other side in a similar way as begin
we did for Linear Distortion. This is done by storing in ScanlinImg[Ye][Xe] := ScanlinVirt[I][Xb];
if Ye+1 < Image1.Picture.Height - 2 then
subsequent array values of the shortest side equal Y values where ScanlinImg[Ye+1][Xe] := ScanlinVirt[I][Xb]; // avoid
necessary. Because the shrink-factor is always equal to or smaller empty pixel positions
than one, no CyW counter is needed: if abs(ALin)>0.9 then begin
if Ye+3 < Image1.Picture.Height - 2 then begin
NmbVirtSLs := max(BegLo.Y-BegHi.Y, EndLo.Y-EndHi.Y) + 1; ScanlinImg[Ye+2][Xe] := ScanlinVirt[I][Xb];
SetLength(SPar,NmbVirtSLs); ScanlinImg[Ye+3][Xe] := ScanlinVirt[I][Xb];
SetLength(EPar,NmbVirtSLs); end;
if NmbVirtSLs = BegLo.Y-BegHi.Y+1 then begin // begin of shape end;
is longest inc(Xe);
Fry := Frac((EndLo.Y-EndHi.Y+1)/(BegLo.Y-BegHi.Y+1)); if Xe > Image1.Picture.Width - 1 then Xe :=
CyF := 0.5; I := 0; Image1.Picture.Width - 1;
if Fry = 0 then Fry := 1; // heights are equal Ye := round(ALin * Xe + BLin);
Ye := EndHi.Y; Xe := EndHi.X; if Ye > Image1.Picture.Height - 1 then Ye :=
for Yb := BegHi.Y to BegLo.Y do begin Image1.Picture.Height - 1;
SPar[I].Y := Yb; if Ye < 0 then Ye := 0;
if ABeg=1e9 then SPar[I].X := BegHi.X end;
else SPar[I].X := round((Yb-BBeg)/ABeg);
EPar[I].Y := Ye; To avoid too many complicated calculations, I did not give any
EPar[I].X := Xe;
CyF := CyF + Fry; thoughts about anti-aliasing or the like. However, plotting the
if CyF >= 1 then begin virtual scanlines could result in “empty” places, as each X position
inc(Ye); has only one Y position. This is illustrated in figure 4:
if AEnd=1e9 then Xe := EndHi.X
else Xe := round((Ye-BEnd)/AEnd);
CyF := CyF - 1
end;
inc(I);
end;
end else begin // end of shape is longest
Fry := Frac((BegLo.Y-BegHi.Y+1)/(EndLo.Y-EndHi.Y+1));
CyF := 0.5; I := 0;
if Fry = 0 then Fry := 1;
Yb := BegHi.Y; Xb := BegHi.X;
for Ye := EndHi.Y to EndLo.Y do begin
SPar[I].Y := Yb;
SPar[I].X := Xb;
EPar[I].Y := Ye;
if AEnd=1e9 then EPar[I].X := EndHi.X Figure 4: Empty pixel positions appear when plotting
else EPar[I].X := round((Ye-BEnd)/AEnd); virtual scanlines
CyF := CyF + Fry;
if CyF >= 1 then begin
This problem is solved simply by plotting two (Ye and Ye + 1)
inc(Yb); pixels for each X position. After all, if the additional pixel is
if ABeg=1e9 then Xb := BegHi.X superfluous, the next line will overwrite this position
else Xb := round((Yb-BBeg)/ABeg); automatically. For very steep lines even more Y values are
CyF := CyF - 1
end; plotted for the same X.
inc(I);
end; A short note about the huge gain in speed when scanlines are
end; used as opposed to direct pixel addressing. Replace the code of
The final part of DynamicDistort calculates the pixel positions of the “for Xb”-loop into:
the virtual scanlines in “real” coordinates. Use is made of the //Image1.Canvas.Pen.Mode := pmCopy; must be set before
formula Y = A * X + B, where the coefficients A and B must be For Xb := 0 to NmbOrgPix-1 do begin
calculated for each virtual scanline. Next, the calculated pixel PixCol := ScanlinVirt[I][Xb].R + ScanlinVirt[I][Xb].G
positions are assigned to the real scanline pointers of the shl 8 + ScanlinVirt[I][Xb].B shl 16;
Image1.Canvas.Pen.Color := PixCol; if CxW > 0 then for
ScanlinImg array, which holds a copy of the BitmapImg scanlines J := 1 to CxW do begin
of the main picture in Image1. Image1.Canvas.Pixels[Xe,Ye] := PixCol;
for I := 0 to NmbVirtSLs-1 do begin if I < NmbVirtSLs-1 then
Image1.Canvas.Pixels[Xe,Ye+1] := PixCol;
NmbNewPix := EPar[I].X - Spar[I].X + 1; // different for each line
inc(Xe);
if SPar[I].X = EPar[I].X then begin
Ye := round(ALin * Xe + BLin);
ALin := 1e9; BLin := 0; end
end;
else begin
CxF := CxF + Frx;
ALin := (SPar[I].Y - EPar[I].Y)/(SPar[I].X - EPar[I].X);
if CxF>=1 then begin
BLin := SPar[I].Y - ALin * SPar[I].X;
Image1.Canvas.Pixels[Xe,Ye] := PixCol;
end;
if I < NmbVirtSLs-1 then
CxW := Trunc(NmbNewPix/NmbOrgPix);
Image1.Canvas.Pixels[Xe,Ye+1] := PixCol;
Frx := Frac(NmbNewPix/NmbOrgPix);
inc(Xe);
CxF := 0.5;
Ye := round(ALin * Xe + BLin);
Xe := SPar[I].X;
CxF := CxF - 1;
Ye := round(ALin * Xe + BLin);
end;
if Ye > Image1.Picture.Height - 1 then Ye :=
end;
Image1.Picture.Height - 1;
if Ye < 0 then Ye := 0;
for Xb := 0 to NmbOrgPix-1 do begin In this procedure the correct colours are directly assigned to the
if CxW > 0 then for J := 1 to CxW do PlotPixel;
CxF := CxF + Frx;
pixels of Image1. Although this direct approach seems more
if CxF>=1 then begin efficient, the routine is annoyingly slow. Try this example just to
PlotPixel; learn that one should use scanlines instead!
CxF := CxF - 1;
end;
end;
Summarized, the code to change the content of all nine areas (see
end; figure 1) in a random way is:

Page 30 / 2144 COMPONENTS


DEVELOPERS 4 October 2009 BLAISE PASCAL MAGAZINE 8
Fast Graphic deformation by using Scanlines (continuation 1)
In this procedure first the scanlinepointers to VirtBM are copied Dynamic Distortion
to the array ScanlinVirt. Like ScanlinSel, ScanlinVirt is a Where in linear distortion the sides of the selected area could
dynamic array of type pPixArray. To stretch or shrink the only be moved in the X and/or the Y direction to reshape the
pixelarrays in OBM (copy of the original, array ScanlinSel area, for dynamic distortion the corners of the selected area can
points to these pixels) to the deformed ones in VirtBM (with be moved in any direction. This means that one side of the area
pointers ScanlinVirt) the proportion-factors must be calculated can be stretched while the other (opposite) side can be
first. If for instance the height of the bitmap in VirtBM is a compressed. Although the resulting area can now have an odd
quarter bigger than the original in OBM and the width is a three shape, the adjacent areas must follow the selection to warrant
quarters of the original, factors Yfact and Xfact become 1.25 smooth transitions, see figure 3:
and 0.75 respectively. The truncated whole number (1 in this
case for Y) is stored in CyW and the fraction (0.25) in Fry. For The first image (at left) is the original image, in the next image
each Y value in the selected area the procedure determines the mouse cursor is used to draw a rectangle: the selected area.
whether and how often Ysel must be copied to the new pointer In the third image the rectangle is deformed by grabbing the
Yvirt. If counter CyW is greater than zero, CyW new lines are corners with the mouse cursor and moving them to other
generated, while counter CyF generates a new line when the positions. The last image at right shows us the result.
sum of the fractions during the loop add up to at least one. In our
example this means that each time after four loops an additional
line is generated.
To obtain a better distribution
I've preset counter CyF to 0.5.

The new lines are generated


in sub-procedure FillXvirt.
This procedure takes care that
the length (X direction) of the
new lines are calculated using
the factor Xfact. The same
algorithm is used as for the Y
direction described above, but Figure 3 Dynamic Distortion Process The random shapes of the areas make the calculations of the
now a random number deformed pixel positions rather complicated. I decided to tackle
between 0 and 1 is used as this problem in various steps:
preset for CxF to avoid loss of
information in the event of 1. Copy the selected area and the eight adjacent areas in
very thin vertical lines: OBM[0..8], see figure 1, as in linear distortion.
2. After reshaping the selected area to the desired form, call
procedure FillXvirt; //stretch-shrink horizontal lines
var Xvirt, Xsel, I, CxW: Integer; for each area the procedure LinearDistort, but stretched only
CxF, Frx: Single; in the Y direction to the height of the longest side. This is
begin done to obtain the required number of scanlines for the
Xvirt := 0; CxF := random; actual dynamic distortion process.
CxW := Trunc(Xfact); Frx := Frac(Xfact);
for Xsel := 0 to LenSelSLs-1 do begin 3. Call for each area the procedure DynamicDistort, using the
if CxW>0 then for I := 1 to CxW do begin corner points of the shape as parameters. Calculate the
ScanlinVirt[Yvirt][Xvirt] := ScanlinSel[Ysel][Xsel]; position of each pixel in a virtual scanline which starts from
inc(Xvirt); a point on the left side of the modified shape and ends at a
end;
CxF := CxF + Frx; point at the right side of the shape. The start and end points
if CxF >= 1 then begin have different Y positions and the lines have different
ScanlinVirt[Yvirt][Xvirt] := ScanlinSel[Ysel][Xsel]; lengths. As the number of scanlines is fixed to the longest
inc(Xvirt); side, some values on the other (shorter) side can be the
CxF := CxF - 1;
end; same.
end; 4. Map the calculated pixels of the virtual scanlines to the
end; original bitmap of the main image.
The pointers to ScanlinSel are now copied to the pointers of The DynamicDistort procedure starts with calculating the desired
ScanlinVirt dependent upon the size of the new bitmap VirtBM. begin and end points of the virtual scanlines. By using the formula
After looping through LinearDistort, VirtBM contains the X = (Y-B)/A an X position is calculated for each Y position on the
deformed bitmap of one area, which can subsequently be left and the right side of the modified shape. These points are
transferred to the main image through the Canvas.Draw stored in arrays SPar (start points) and EPar (end points), forming
procedure. Summarized, the code to change the content of all two lines being the left and right side of the shape. Coefficients A
nine areas (see figure 1) in a linear way is: and B can be calculated from the corner coordinates which are
for J := 0 to 8 do begin given to the procedure as parameters:
SetLength(ScanlinSel, Ns[J]); procedure TForm1.DynamicDistort(BegLo, BegHi, EndLo,
if (Lsv[J]>0) and (Nsv[J]>0) then begin EndHi: TPoint; NmbOrgPix: Integer);
for I := 0 to Ns[J]-1 do ScanlinSel[I] :=
OBM[J].ScanLine[I]; Special care must be taken when a line is exactly vertical:
LinearDistort(Ns[J], Ls[J], Nsv[J], Lsv[J]);
//result in VirtBM if BegHi.X = BegLo.X then begin ABeg := 1e9; BBeg := 0;
Image1.Canvas.Draw(SPoint[J].X, SPoint[J].Y, VirtBM); end
end; else begin
end; ABeg := (BegHi.Y-BegLo.Y)/(BegHi.X-BegLo.X);
BBeg := BegHi.Y - ABeg*BegHi.X;
Where Ns and Ls are the number and length of the original end;
if EndHi.X = EndLo.X then begin AEnd := 1e9; BEnd := 0;
scanlines, Nsv and Lsv are the number and length of the new end
(deformed) scanlines and SPoint (of type TPoint) is on the main else begin
AEnd := (EndHi.Y-EndLo.Y)/(EndHi.X-EndLo.X);
image the upper left-hand corner where the deformed bitmap BEnd := EndHi.Y - AEnd*EndHi.X;
should be placed.

October 2009 BLAISE PASCAL MAGAZINE 8 Page 29 / 2143


COMPONENTS
DEVELOPERS 4
Fast Graphic deformation by using Scanlines (continuation 3)
SetLength(ScanlinImg, Image1.Picture.Height); out, this is an easy way to reduce your X-megapixel high-
for I := 0 to Image1.Picture.Height - 1 do resolution photographs to an acceptable size for use on the
ScanlinImg[I] := BitmapImg.ScanLine[I];
for J := 0 to 8 do begin SetLength(ScanlinSel, Ns[J]); internet. The procedure takes care that the image fits best on your
if Nsv[J]>0 then begin working area:
for I := 0 to Ns[J]-1 do ScanlinSel[I] := procedure TForm1.BtScreenFitClick(Sender: TObject);
OBM[J].ScanLine[I]; var I, PH, PW, CH, CW: Integer;
LinearDistort(Ns[J], Ls[J], Nsv[J], Ls[J]); Aspect: single;
// first stretch to correct height begin
SetLength(ScanlinSel, Nsv[J]); UndoBM.Assign(BitmapImg); //save original
DynamicDistort(CornerLftlo[J], CornerLfthi[J], PH := Image1.Picture.Height;
CornerRgtlo[J], CornerRgthi[0], Ls[J]); PW := Image1.Picture.Width;
end; CH := Image1.Height;
Image1.Picture.Bitmap := BitmapImg; CW := Image1.Width;
end; if (PW<=0) or (CW<=0) then exit;
Aspect := PH/PW;
if Aspect > CH/CW then CW := Trunc(CH/Aspect) else
For Ns, Ls and Nsv see the section Linear Distortion. The Corner- CH := Trunc(CW * Aspect);
variables are of type TPoint and refer to the four corners of the SetLength(ScanlinSel, PH);
distorted area. The actual code, however, is slightly different. The for I := 0 to PH-1 do ScanlinSel[I] :=
complete source code (belonging to the program “Deform!”) can, BitmapImg.ScanLine[I];
LinearDistort(PH, PW, CH, CW);
as usual, be downloaded from the website. This brings us to: BitmapImg.Assign(VirtBM);
Image1.Picture.Bitmap := BitmapImg;
The Program “Deform!” end;
The program “Deform!” utilizes the procedures as described in The Distortion buttons are grouped together. After clicking
the previous paragraphs. The program can be used to deform one of these, an area can be selected by holding down the left
photographic or other images. Sometimes for a good reason, mouse button and dragging the cursor over the image. Upon
such as the straightening of objects or correcting the perspective, “Button Up” the area is fixed. The program contains
but also just for fun. See figure 5. obviously CursorButtonDown, Move and Up procedures, but
I will not describe them here to save space. I only tell that, as
the mouse routines are shared by all distortion modes,
Booleans are used to control the process.
LOAD IMAGE
After “Distort Linear” has been clicked, the area set can be
deformed by grabbing (mouse cursor and left button) the four
Fit To Screen
sides of the area and drag them to the desired positions. On
DISTORT
clicking “Go” the LinearDistort procedure is called nine times
LINEAIR
DISTORT (once for each sub-area, see figure 1) causing the image to
INNER AREA
DISTORT ALL reshape according to figure 2.
MIRROR R MIRROR L When “Distort Inner Area” has been clicked, a special use
CROP of the DynamicDistort procedure is made. The area is now
GO! UNDO
divided into four equal pieces. Only the centre point can be
moved and after clicking “Go” the four areas are deformed by
SAVE IMAGE

SAVE AS ICON
calling LinearDistort followed by DynamicDistort four times,
see figure 6:
CLOSE PROGRAM The first image (at left) is the original image, in the next
image the mouse cursor is used to draw a rectangle: the
selected area. In the third image the rectangle is deformed by
grabbing the centre point with the mouse cursor (plus left
button) and moving it to another position. This process is
called “Warp” in other programs. The last image at right
shows us the result after clicking “Go”. The part of the image
outside the selected area is not affected, so in this mode not
Figure 5 “Deform!” can
the whole picture is deformed.
change your images

All buttons are located at


the left-hand side, which
enables the bitmap image
in Image1 (at right) to
follow the size of the
window when it is resized
by the user. As I admire the
lady on the example image
very much, I use a black
Figure 6 Dynamic Distortion Process for a single point
bar to make her unrecog-
nizable. The user can load either a JPG or a BMP image by
clicking “Load Image”. Be careful with the “Fit to Screen”
button: this is not a zoom function, but it changes the actual
number of pixels. See for instance what happens when you load a
picture, drag the right side of the window as far as possible to the
left, click “Fit to Screen”, maximize the window and click “Fit to
Screen” again. The image will be barely recognizable. The “Fit
to Screen” process makes use of the LinearDistort procedure to
resize, so complete rows and columns of pixels
are thrown away by reducing the size. However, as you will find

October 2009 BLAISE PASCAL MAGAZINE 8 Page 31 / 2145


COMPONENTS
DEVELOPERS 4
Fast Graphic deformation by using Scanlines (continuation 4)
When “Distort All” has been clicked, the area set can be deformed Conclusion
by grabbing (mouse cursor and left button) the four corner points May be after clicking “Go” you didn't get the result you'd
of the area and drag them to the desired positions. After clicking expected. No problem, after clicking “Undo” the former image is
“Go” the LinearDistort and DynamicDistort procedures are called put back on the screen. But be careful: there is only one undo
nine times (once for each sub-area) and the image is reshaped level! Of course you can utilize several distortion modes after
according to figure 3. each other. This may result in a picture like in figure 8:
When the final result is satisfactory, you can save the image (as
When “MirrorR(ight)” or “MirrorL(eft)” has been clicked, the JPG or BPM) by clicking “Save Image”. As a special feature I
selection area is split by a vertical division line in the centre. See added a “Save as Icon” possibility. This button can be used to
figure 7, second image (as this gentleman doesn't sing as good as make your own icons without using an icon-editor. The icon
the lady of figure 5, I didn't use the black bar this time): attached to this program is made with this procedure. Before
using, crop your image to obtain an approximately square area.
However, don't set your expectations too high: as an icon has an
area of only 32 x 32 pixels, hi-res pictures or photographs can
hardly be used for this process.
Making a program like this is like eating peanuts: once you've
started it's not easy to stop. You always think of another nice
useful or funny feature to add. Be my guest, download the source
code and add anything you like. In the “Distort Inner Area” for
instance two points can be used instead of only one point, or even
four points. Anyway, have fun playing, changing or just using this
program.

See you next time...

Figure 7 The Mirror process


MirrorR causes the right side of the selection to be mirrored to
the left side (third image) and MirrrorL does the opposite (fourth
image). So this mode can be used to make faces (or objects)
symmetrical. The code is rather simple:
begin
SetLength(ScanlinSel,Ns[0]);
for I := 0 to Ns[0]-1 do ScanlinSel[I] :=
OBM[0].ScanLine[I];
for I := 0 to Ns[0]-1 do for J := 0 to (Ls[0]-2) shr 1
do Figure 8 A possible final result
if MRight then ScanlinSel[I][J] :=
ScanlinSel[I][ls[0]-J-1]
else ScanlinSel[I][ls[0]-J-1] := ScanlinSel[I][J]; Peter Bijlsma
Image1.Canvas.Draw(Sel[3].X, Sel[3].Y, OBM[0]); was born in the Netherlands in 1946. He studied electronics
end; and took a course in Algol. In 1982 he became the proud
owner of an Apple II computer, and he programmed in Basic
OBM[0] contains, as usual, a copy of the original selected area and 6502 assembly language. He learned other languages
and Sel[3] (TPoint) is the upper left-hand corner of the selected (Pascal, Perl) by self-study.
He worked as a Technical Communication specialist, writing
area.
technical manuals and acting as an instructor for military
command & control systems. Later he wrote software in
The last mode is “Crop”. If after several distortions you want to order to covert XML-based text into websites, CD-ROMs with
save the created image, the edges may be deformed in an PDF files, and 'old-fashioned' manuals. He is now retired.
undesirable way. These edges can be cut off by selecting the [email protected]
“good” area after “Crop” has been selected.
Clicking “Go” causes that the new main image will be just the
selected area:
Image1.Picture.Bitmap := OBM[0];

Page 32 / 2146 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Wide Information Bus (Introduction) by Fikret Hasovic
starter expert DELPHI 3-7 2005..10 Win32
All of the pc's and servers on this image are all nodes in the
Publish/subscribe type of information transfer has become a publish/subscribe world.
hot subject lately, and its not without reason. However some of the nodes also act as kbmMW application
servers, and some of the other nodes also act as kbmMW clients.
The great thing about publish/subscribe is that its a loosely Its easy to compare publish and subscribe communication with a
coupled event oriented setup compared to the traditional news agency publishing one or more magazines (e.g. Dr Dobbs
request/response type of setup where clients starts a request Journal (DDJ), ComputerWorld (CW), PCWorld (PCW) etc.)
and servers reply with a response. Those setups often do not and having some customers who subscribe for one, some or all
allow for any 'out of order' server transmission to the client, or of the magazines.
if it does, it does so in a relatively limited way requiring hard The publishers publish each magazine under a specific name,
coding each situation for each client. which in the publish/subscribe (from now on called p/s) world
would be called the subject. Customers would choose which
Each publisher or subscriber of information is connected to a subjects to subscribe on and each time a publication was ready
virtual bus which we call the WIB (Wide Information Bus). and sent out, the customer would receive it.

Why is it named like that? The subject


'Information Bus' because it is a virtual media of information In the computerized p/s world, the subject is a loosely formatted
transportation, and 'Wide' because the types of data transported string build of one or more parts separated by '.'.
on it can consist of any of kbmMW's already well known data The subject is used as an advanced addressing mechanism
types. Thus a wide range of data types are available from simple surpassing simple IP numbers, used by nodes to know if they
values over objects and arrays to streams which for example should receive a message or not published by another node.
could contain video, sound or images, and datasets. Since the message in theory flows all over the WIB, all nodes
All applications attached to a WIB can act both as servers and connected to it can choose to receive the message. I.e. one
clients or rather as publishers and subscribers. Hence we published message can be received by many subscribers.
generally don't distinguish between servers and clients when in a In practice there are several built in techniques to limit the flow
typical publish/subscribe setup, but rather about nodes. to only nodes who have expressed their wish to receive
messages with those specific subjects.
A node is simply an application that is able to interact as an
information publisher or subscriber, or both and that are attached The subject is loosely formatted because the number of parts and
to the WIB. the contents of the parts are not defined by the p/s protocol as
Thus any node can be generating or consuming information. such except for the first part, and thus can be freely defined by
The nodes are connected to a virtual bus which we call the WIB the developer.
(Wide Information Bus). The first part generally must be one of the following texts:
The WIB can span all from a single physical segment on a local MSG, REQ, RES, SUB, USB, CAC, THR, SRV
LAN, over multiple segments on an Intranet to the world wide We will first concentrate about MSG. Later the others will be
Internet. explained.
A sample publish/subscribe setup with the WIB spanning two Subjects starting with MSG identifies unsolicited asynchronous
Ethernet LAN's messages. Using the MSG type subject we will try to build a
subject which the newpaper
agency can publish DDJ under.
The subject to publish messages
around DDJ could be
'MSG.DDJ'. Clients would be
able to subscribe for 'MSG.DDJ'
and receive all messages related
WIB WIDE INFORMATION BUS to DDJ.
However what if another
newspaper agency have a journal
which is named DDJ (Danish
Deliveries Journal)? Then there
would be a potential conflict if
the two news agencies both
publish under the same subject.
Hence a refinement is needed of
the subject. A news agency part
should be added.

Lets say the news agency that


publish Dr. Dobbs Journal is
named CMP Media LLC, and
the Danish Deliveries Journal is
published by Berlingske, we
could add a part which identifies
WIB WIDE INFORMATION BUS
the publisher. Eg. the subject for
DrDobbs Journal would be:
'MSG.CMP.DDJ' and for Danish
Deliveries would be
'MSG.BERLINGSKE.DDJ'.
Notice the hierarchical layout of
the subject, and that the subject
is not case sensitive (all will be
Figure 1:Wide information Bus Priciple handled as uppercase).

October 2009 BLAISE PASCAL MAGAZINE 8 Page 33 / 2147


COMPONENTS
DEVELOPERS 4
Wide Information Bus (continuation 1)
Lets also say that customers doesn't subscribe forever, but only Broadcast messaging
for specific issues on a month basis. We could of course just Broadcast messages have the advantage that multiple nodes are
subscribe for all DrDobbs Journal issues, and throw out the ones able to subscribe for and receive the same messages from other
we don't want after inspecting the magazine itself, but it would nodes without the need to resend the message to each receiving
be better if we didn't receive the issues we aren't interested in. node.
Hence yet a refinement of the subject is needed. Thus only one single message travels on the physical network.
We add an issue number: 'MSG.CMP.DDJ.yyyy.nn' where yyyy is
the year the issue is published, and nn is a number from 1 to 12 Publisher Subscriber Subscriber
identifying the issue that particular year.
Then customers can choose to subscribe for DrDobbs Journal
issue 4 year 2003 by subscribing for the subject:
'MSG.CMP.DDJ.2003.04'.
What about customers who want to subscribe for all of 2003?
Well then the client suddenly need to accept anything in the
place of the issue part. That's where wildcards come handy.
A customer can subscribe on 'MSG.CMP.DDJ.2003.>' to receive all
packages regarding DDJ from CMP in 2003 when they are Figure 2: WIB
published. This simplifies lots of situations, and generally lower bandwidth
The > means, that the remaining part of the subject is not taken requirements.
into consideration when kbmMW needs to figure out if a node Each node have a local list of subscriptions which it uses to
subscribes for something or not. choose which of the incoming messages it would like to keep
If the node want to subscribe for any DDJ, regardless from and process. Its voluntary if the node would like to publish its
which newspaper agency, but only for 2003 and issue 12, the list of subscriptions to other nodes.
node needs to subscribe like this: 'MSG.*.DDJ.2003.12' Due to the typical configuration of Ethernet routers and
The * means, that specific part of the subject is not to be taken switches, broadcasting only works for nodes attached to one
into consideration. The * has to replace a complete part, and its single Ethernet segment.
not allowed to do like this: 'MSG.C*.DDJ'. In other words the * If there are multiple segments, or switches/routers in between
must be considered a placeholder for a complete part. the segments, a gateway is needed. The gateway is an
It's valid to have multiple * in a subscription on a subject. Its application which subscribes for messages on one segment and
however not allowed to have more than one > (and wouldn't be transport those messages via a point to point transport (typically
very sensible to have more anyway). TCP/IP) to a gateway on the other segment where the messages
A node can subscribe for multiple subjects at any given time. are republished, hence stretching the WIB over two or more
There is no technical limit to the number of subjects subscribed segments.
on and the length of each, but since there may arrive thousand The gateway can easily be created by having a server with a
messages/second which kbmMW needs to filter according to the registered service which a client component in the other end can
subject, its good practice to keep the number of subscriptions as send a traditional message to containing the complete messaging
low as possible (less than 100/node) and to limit the number of message. The service would then simply publish the received
subject parts to less than 20. A special negate operator '!' also message on the local LAN.
exists. Its purpose is for a subscriber to say that it definitely If a gateway is created its usually a good idea for each node to
don't want to receive a specific subject. announce its subscriptions to let the gateway know what to listen
I.e. the node could subscribe for MSG.*.DDJ.*.* which means it for on the other segment. This ensures that only traffic which is
would receive all messages related to DDJ regardless of year or really interesting for nodes on both segments will be passing the
issue. But lets say that the subscriber of some reason definitely gateway.
do not want anything from year 2001. In this case the negate
subject can be useful. Hub/Spoke messaging
Thus the node would have these two subscriptions: Where the broadcast type of messaging may be impractical over
!MSG.*.DDJ.2001.* multiple physical Ethernet segments (anyway using UDP as the
MSG.*.DDJ.*.*
transport layer), Hub/Spoke messaging often is the answer.
Since the negate subscription is first, it will overrule the next
more general subscription.
There is of course no point in adding negate subscriptions for
subjects which are not otherwise subscribed for, as the node will Publisher or Publisher or Publisher or
never receive messages it does not actively want to receive by Subscriber Subscriber Subscriber
setting its subscriptions accordingly. Its good practice to arrange
the subject parts in such way that kbmMW is able to determine
if a subject match subscriptions as soon as possible. kbmMW
starts from the left when evaluating the subject parts and from
the top of the subscription list iterating downwards until match
or all subscriptions have been evaluated. Sp
Spoke

kbmMW use a very fast hashing based algorithm for detecting ok


oke
e
subjects which a subscription has been made for but nonetheless Sp
its good practice to follow these rules of thumbs.
The subject parts should generally only contain US/UK letters HUB with gateway
and digits. Using local charactersets can have side effects if the capablilities
messages are received by computers not setup the same way.

Messaging topologies
kbmMW bundles support for UDP broadcast based messaging,
TCPIP hub/spoke and UDP/TCPIP peer to peer messaging.
Other types of messaging topologies can be supported by
kbmMW as well. One could for example create a messaging Figure 3: HUB with gateway capablilities
email transport utilizing standard emails for moving messages.

Page 34 / 2148 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Wide Information Bus (continuation 2)
The hub/spoke setup differs from the broadcast setup in that one
have to designate a specific node as a hub to which other nodes About the author:
connect versus the broadcast setup where all nodes were equally Fikret Hasovic
attached to the WIB. Started working with Delphi in 1995 (at University,
department for mathematics and computer science).
First commercial work done in 1997, using Delphi,
The hub itself usually is directly attached to the WIB, thus able to
Paradox and InterBase. 2001 joined USAID CRSP
interact with other nodes on the WIB.
(Comunity Reintegration and Stabilization) Project
(Parsons Delaware Inc), developing a complete IT
Since a hub/spoke setup requires that a message is sent multiple
system solution using Delphi and InterBase 6.0.
times to multiple subscribing nodes, a hub/spoke setup is not as In mid 2002 joined USAID TAMP (Tax Administration
bandwidth efficient as the traditional broadcast messaging setup. Modernization) Project (Development Alternatives,
To lessen the bandwidth load, spokes must inform the hub about Inc.), working as Senior Programmer and Computer
what subjects they subscribe for. On a broadcast setup, this is Systems Engineer on design and development of Tax
optional unless a filtering gateway is in place. system software for Bosnia and Herzegovina.
The System is using n-tier concepts (AstaIO and then
The spoke provides this information by announcing its migrated to kbmMW), client applications using Delphi
subscriptions: (and Kylix) and kbmMW Application Servers (Delphi
spoketransport.AnnounceSubscriptions;
and Kylix based) connecting to Firebird 1.5.2 CS on
linux.
Peer to peer messaging
One can target a message to a specific node, identified by its IP Also worked for USAID TARA (Tax Administration
address, by specifying that IP address as the target argument in the Reform Activity) Project (Bearing Point, Inc).
SendMessage method. Published an article about Firebird in Bosnian IT
Publisher Subscriber Subscriber magazine INFO (www.info.ba), and wrote a Delphi
2005 article for the same magazine. Editor of Firebird
Database Community news site:
http://www.fyracle.org/shownews.php.

Figure 4: Sendmessage
Targeting a message allows the message to cross Ethernet
segments without having a messaging gateway, provided the
switch, router or hub allow UDP packages to cross.
Using the peer to peer setup, it's a true peer to peer setup Interested in working with
where any node can communicate with any other node using the
UDP messaging transport. The node targeted should of course Delphi and Flash
still be subscribing for the subjects that the sender, choose to
send. and or Adobe Flex?
As usual any messages send to the node, for which the node does
not have a matching subscription for, will be ignored.
take a look at
http://www.components4developers.com
The WIB node
Chose: Products Video
To create a publishing or subscribing node, all what's needed is
kbmMW integration with Adobe Flex, Flash and AIR.
to add a TkbmMWxxxyyyMessagingTransport where xxx identifies
the type of transport and the yyy if its a client or server transport.
Why the distinction of a client or server transport?
There are two reasons:
- One reason is that the messaging transports also support the
traditional request/response setups using kbmMW clients and
servers. Hence the messaging server transport can be directly
connected to a TkbmMWServer and operate simultaneously
as a true asynchronous messaging transport and as a
synchronized request/response transport.
- Another reason is in case of the hub/spoke messaging
transport setup. The hub will always be a server transport, and
the spoke always a client transport.
Thus if your publishing node also contains a kbmMW
application server, you would usually put a server messaging
transport on that node.
And if you have nodes which act as clients to an application
server, and thus operate according to the request/response
principle, you would put a client messaging transport on the
node.
Its perfectly legal to create a setup of nodes who all operate
100% on the publish/subscribe bases without any requirements
for an application server. In that case you don't have to add any
TkbmMWServer components in any node, and can choose to use
just client transports on all nodes, except for those who act as
hub nodes.

October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Page 35 / 2149
Freehand Drawing - Introduction by David Dirkse
Pictured are 3 * 3 pixels.
This article describes a Delphi-7 program for freehand From center (x,y) a code
drawing. (0..7) points to the next pixel.
Pictured below is an example: (reduced size) A freehand drawing can be
defined by a list of these
codes, given the coördinates
of the starting point.

The code requires 3 bits for


each step. This is far from
ideal, because multiples of 3
bits do not fit bytes or words.
A 4 bit code would be better.
The extra 4th bit provides an
extra possibility, see figure:

Figure1: The draw program in action Figure3: The extra 4th bit provides an extra possibility

The drawing is generated by mouse-movements over a paintbox, Two successive codes of “0” may be combined to one code of “8”
connecting the (x,y) coördinates by lines. , two codes of “1” to one code of “9” etcetera.
A ColorPicker component is added to the form as well as an A 4 bits -movement- code I call a “stroke” for the moment.
ArrayButton, to allow selection of pen-color and pen-width. (see
earlier articles or visit my website) The list of strokes
Drawing is not too difficult, but we want to store the drawing as At the start of a drawing, memory space is reserved for the storage
well to be repainted later. of maximal 5000 strokes. This is accomplished by the statement
getmem( P , number_of_bytes) which reserves number_of_bytes
The program allows for storage of 9 drawings. bytes on the heap. (note: the heap is memory space outside the
To verify this storage, bitbuttons “clear” and “repaint” are added. program area and is managed by the operating system) P is a
“Clear” erases the paintbox and “repaint” draws all recorded pointer to this space. The strokes are stored in an array of words.
drawings again. Type TA = array[0..strokewords] of word;
The “backspace” button removes only the last added drawing. PA = ^TA;
Type PA points to the start of an array of (strokewords + 1) words.
The elements in this array are now addresable by statement like
Coding a drawing var p : PA;
I choosed to code a drawing by means of a step-by-step route ................
description. See figure below: P^[ index] := .................
p^[0] contains the number of strokes in the array. See figure ,
showing the data format.

Figure2: Step by step route Figure4: The list of strokes

Page 36 / 2150 October 2009 BLAISE PASCAL MAGAZINE 8


COMPONENTS
DEVELOPERS 4
Freehand Drawing - Introduction (continuation)
To define the complete drawing, also the start coördinates must be For two adjacent points (px1,py1)..(px2,py2) the stroke code
remembered together with the pen-width and pen-color. must be calculated.
This is done in array “props” , saving this data for drawings 1..9. An interim variable called “dir” is used.
But this data could as well be saved on the heap. Dir is reset to zero and then increased by
Array “buffer” contains the pointers to the stroke arrays for each
– 2 if px2 > px1 ..........binary 00000010
drawing. – 3 if px2 < px1 00000011
– 8 if py2 > py1 00001000
Generating the stroke list – 12 if py2 < py1 00001100
This is less simple then expected for the following reason:
when the mouse pointer moves slowly over the screen, the Array “dir2stroke” translates the “dir” code into the stroke code.
generated (x,y) coördinates will constitute adjacent pixels.
However, for faster mouse movements the generated (x,y) points Housekeeping
will have empty spaces between them which must be filled by the Windows has granted us memory space and keeps this space
stroke codes. reserved far after we have closed our drawing application.
It is our responsibility the free the memory space for use by
We look at the program source code: others.
Drawing starts by a mouse-down event in paintbox1. At “formcreate” the 9 pointers in he buffer are set to “nil” , no
Funtion “requestbufferspace” is called to reserve space for the space is reserved yet.
strokes. If reservation was successfull, “true” is returned. Then a At “formdestroy” the statement freemem(pointer) returns the
flag “drawing” is set true, clearing the way for coming mouse- reserved memory space to Windows.
move events. Possibly, not all pace was needed for our drawing. So, following
The starting point is stored in array props, together with the a mouse-up event at the end of the drawing, the statement
selected pen-color and pen-width. (x,y) coördinates are stored in
reAllocMem(p,((p^[0]+1) shr 1)+2)
variables (x1,y1) for start and (x2,y2) for the end of a line.
BufNr is the number of the current drawing.
(x1,y1) and (x2,y2) are outside procedures so they can be returns unused memory space to the operating system and does
addressed by all procedures in unit1. not affect the data stored already.

The line (x1,y1) ----> (x2,y2) is painted on the screen and The general format is reallocmem(pointer, bytesize) .
function “recordstrokes” is called to encode the strokes.
The expression for the bytesize : (p^[0]+1) shr 1)+2 evolved
by
Converting a line into strokes p^[0] : the number of strokes stored
“Recordstrokes” translates a line into a sequence of strokes valued (P^[0]+1) shr 1 : the number of bytes needed {rounded
0..7 (not 0..15). upwards}
+2 : bytes needed for p^[0] itself.
For each stroke generated, procedure “savestroke” is called to add
this stroke to the list. Savestroke looks at the previously stored
stroke and in case of equality the new stroke is not stored but the Please refer to the program listing for more details.
old one is increased by 8.
David Dirkse
To encode a line , it must be analysed point by point.
Born 1945 in Amsterdam, David joined Control Data
In this process it is convenient to distinguish “horizontally”- and Corporation in 1968, after studying electrical
“vertically”- oriented lines, see figure: engineering. As a hardware engineer, he was
responsible for the installation and maintenance of
mainframes at scientific data centers in the
Netherlands.
With the decline of CDC around 1990, he studied
mathematics and became a math teacher.
His hobbies are programming, in particular
educational software, math algorithms, and puzzle
solving.
http://home.hccnet.nl/david.dirkse

Figure 5: Horizontally”- and “vertically”- oriented lines


In “horizontally” oriented lines, where dx > dy is true , dx is the
number of steps and for each step the y-value changes by an
amount of dy/dx.

In case of vertical orientation, dy is the step count and for each


step, X changes by an amount of dx/dy.
Note, that in the program at first dx = (x2 – x1) , dy = (y2 – y1)
but later dx and dy are converted to the step values.(-1 or +1 ,
dx/dy or dy/dx)

October 2009 BLAISE PASCAL MAGAZINE 8 Page 37 / 2151


COMPONENTS
DEVELOPERS 4
FastReport announcement:
there is a new version that has a significant
number improvements
FastReport 4.8 released!
http://fast-report.com/en/news/4485.html
! + added support of Embarcadero Rad Studio 2010
(Delphi/C++Builder)
! + added TfrxMailExport.OnSendMail event
! + [enterprise] added Windows Authentification mode
! + adedd checksum calculating for 25 interleaved barcode
! * [enterprise] improved CGI for IIS/Apache server
! * changed PDF export: added full unicode support, improved
performance, decreased memory requirements
old PDF export engine saved in file frxExportPDF_old.pas
+ added TfrxDBDataset.BCDToCurrency property
+ added TfrxReportOptions.HiddenPassword property to set
password silently from code
+ added TfrxADOConnection.OnAfterDisconnect event
+ added TfrxDesigner.MemoParentFont property
+ added new TfrxDesignerRestriction: drDontEditReportScript
and drDontEditInternalDatasets
+ added TfrxGroupHeader.ShowChildIfDrillDown property
+ added confirmation reading for TfrxMailExport
+ added TimeOut field to TfrxMailExport form
+ added ability to use keeping (KeepTogether / KeepChild /
KeepHeader) in multi-column report
+ added ability to split big bands(biggest than page height) by
default
- changed inheritance mechanism, correct inherits of linked
objects (fixups)
- fixed bug with Mirror Mrgins in RTF, HTML, XLS, XML,
OpenOffice exports
- fixed bug when cross tab cut the text in corner, when corner
height greater than column height
- improved WatchForm TListBox changet to TCheckListBox
- improved AddFrom method - copy outline
- Improved functional of vertical bands, shows memos placed
on H-band which doesn't across VBand, also calculate
expression inside it and call events (like in FR2)
- Improved unsorted mode in crosstab(join same columns
correctly)
- Improved converter from Report Builder
- Improved TfrxDesigner.OnInsertObject, should call when
drag&drop field from data tree
- improved DrillDownd mechanism, should work correct with
master-detail- subtetail nesting
- fixed bug with DownThenAcross in Cross Tab
- fixed several bugs under CodeGear RAD Studio
(Delphi/C++Builder) 2009
- fixed bug with emf in ODT export
- fixed bug with outline when build several composite reports
in double pass mode
- fixed bug when group doesn't fit on the whole page
- fixed "Page" and "Line" variables inside vertical bands
- fixed bug with using KeepHeader in some cases
- fixed bug with displacement of subreport when use
PrintOnParent property in some cases
- fixed small memory leak in subreports
- fixed problem with PageFooter and ReportSymmary when
use PrintOnPreviousPage property
- fixed bug when designer shows commented functions in
object inspector
- fixed bug when designer place function in commented text
block
- fixed bug when Engine try to split non-stretcheable view and
gone to endless loop
- fixed bug with HTML tags in memo when use shot text and
WordWrap
- [enterprise] fixed bug with variables lost on refresh/export
- fixed bug whih PDF,ODT export in Delphi4 and CBuilder4
- fixed bug with some codepage which use two bytes for
special symbols (Japanese ans Chinese codepages)
- fixed bug when engine delete first space from text in split
Memo
- fixed bug in multi-column page when band overlap stretched
PageHeader
- fixed bug with using ReprintOnNewPage
http://www.fast-report.com
FastReport announcement:
there is a new version that has a significant
number improvements

1.2 .Net
+ added Functions in the "Data" window
+ added new report objects - CellularTextObject,
ZipCodeObject added
+ report's Email settings (see Report|Options... menu,
"Email" tab)
+ added multi-frame TIFF export added RC4 128-bit
encryption in PDF
+ export added "Visible" flag in the highlight editor.
Now the highlight
+ condition may hide the object
+ added TextObject's AutoShrink, AutoShrinkMinSize
properties added
+ DataBand's RowCount property added reportPage.
ManualBuild event added
+ PictureObject.Angle property added AfterData event to all
report
+ objects added CommandTimeout property to all
connections added export
+ of watermarks in HTML format added export of
underlined TextObject
+ (Underlines = true) in PDF format added Swedish,
Chinese
+ (Traditional), Czech, Turkish, Spanish localizations
+ added new demo reports in the "Report Objects"
category added new demo
+ projects in the Demos folder
* POSSIBLE BREAKING CHANGE! changes in the
business objects engine.
See details here: http://www.fast-report.com
/en/forum/index.php?showtopic=5695
* improved performance (loading and running reports with
lot of objects)
* you can use Anchor property of report objects when
printing hierarchical bands
* changed default extension of resulting file in
Excel(XML) export from *.xls to *.xml
* changes in Excel(XML) export - added export of
numeric values
* changes in Matrix object
* improvements in hierarchical reports (header/footers, totals)
- fixed bug in VB.Net report language
- fixed bug in Viewer.exe (exception if window is too small)
- fixed bug with selecting Report in the ReportTree in VS
design-mode
- fixed bug when using WebReport with MasterPage
- fixed bug with RTL in HTML export and WebReport
- fixed bug with RTL in RichText(rtf) export
- fixed bug in MS Chart (border width is not scaled
properly when printing)
- fixed bug with preview window's "Search" dialog
- fixed bug with Nullable column type
- fixed bug in PDF export when exporting complex fills
- fixed bug with export different frame styles in XML
and RichText formats
- fixed bug when editing prepared report
- fixed printing of CellularTextObject
- fixed bug with dialogue form
- fixed bug with Entity Framework in ASP.NET mode
- fixed bug in PageSetup dialog in preview
- fixed bug with rendering side-by-side Matrix objects
- fixed bug in Label wizard
- fixed bug with send email via MAPI
Page 40 / 2154 October 2009 BLAISE PASCAL MAGAZINE 8
COMPONENTS
DEVELOPERS 4

You might also like