Vous êtes sur la page 1sur 25

August

2004

Volume 10 Number 8

INSIDE
ON THE COVER
Active Delphi

Product Review: RemObjects SDK 3.0

Your First ASP.NET App

Last month, Nick Hodges showed us the 10,000-foot view of ASP.NET


the concepts, the major elements, etc. In this issue, he takes us
down in the weeds for a closer look as he shows us how to create
a Hello World style ASP.NET project with Delphi. And as you might
expect, Delphi 8 makes it easy.

The Complete Monthly Guide to Delphi Development

Your First

ASP.NET App

ADO.NET:

Columns & Rows

Where Have All the


Cursors Gone?

ADO.NET Data Access Components: Part VII

Adventures in

Continuing his exploration of ADO.NET, Bill Todd explains that the new
architectures lack of a cursor in the DataTable object is a good
thing. As usual, Bills example project demonstrates his key points,
including that the ability to refer to any row at any time using its
index number saves a lot of code.

Refactoring
Do-It-Yourself 3D
The Results Are In!

2004 Readers
Choice Awards

Cover Art by Arthur A. Dugoni Jr.

Sound+Vision

11

August 2004 vol.10, no. 8

www.DelphiZine.com

Delphi 8 Makes It Easy

FEATURES
7

Delphi Informant

Do-It-Yourself 3D

Continuing the topic of stereo vision, Alexander Gofen explains


how you can shoot 3D stereo photos with a conventional camera
for viewing on a home PC through Red/Blue glasses. Downloadable
software allows readers to create anaglyphic images via a new class
derived from TBitmap.

Informant Spotlight

16

Readers Choice Awards 2004

Editor-in-Chief Jerry Coffey shares the results of the 2004 Delphi


Informant Magazine Readers Choice Awards. Many of the results echo
last years awards, but there are enough new products and surprises
to keep you guessing. Theres even a tie for Product of the Year.

REVIEWS
20 RemObjects SDK 3.0

Product Review by Mike Riley

23

Refactoring: Improving the


Design of Existing Code
Book Review by Alan C. Moore, Ph.D.

D E PA R T M E N T S
2 Toolbox
24 File | New by Alan C. Moore, Ph.D.

DELPHI INFORMANT MAGAZINE | August 2004

T O O L B O X

New Course for ASP.NET Development with Delphi


InfoCan Management announced a
new course in Web-based development training: ASP.NET Development
with Borland Delphi 8 for Microsoft
.NET Framework. This five-day,
hands-on course showcases the power
of Delphi and ASP.NET development.
This course targets Delphi developers intending to develop Web applications using ASP.NET. Whether you
are a seasoned ASP developer or new
to ASP.NET, this course is designed to
fast-track your knowledge and show
you how to harness the power from

ASP.NET. A working knowledge of


the .NET Framework with Delphi, or
equivalent working knowledge, is recommended. This course is available
onsite or in cities throughout Canada
and the US.
This course provides practical information and in-depth coverage on
key topics for Delphi 8 and ASP.NET
development, such as the architecture behind ASP.NET, working with
server controls, data connectivity via
ADO.NET, and XML Web services.
Advanced topics include exception

handling, session management, performance tuning with smart output


caching, asynchronous Web services,
handling deployment, and mobile
development.
The accompanying courseware also
contains detailed background information to serve as a comprehensive
reference guide after the course.
InfoCan Management Consultants Group
(Canada) Inc.
Price: CDN$2,750 or US$2,150
Contact: info@infocan.com
Web Site: www.infocan.com

Atozed Releases Web Application Development Framework

Atozed announced IntraWeb, a Web


application development framework
for Delphi, C++Builder, Kylix,
Visual Studio.NET, and Java. Using
these languages, applications built
with IntraWeb can be deployed on
.NET, Windows, Linux, or any JDKbased platform. Using IntraWeb you
can build applications for the Web
(HTML 4.0 browsers or 3.2 browsers),
PDAs, and mobile phones (WAP).
Based on an HTML rendering

engine, IntraWeb allows developers


to design Web applications in the
same way they would design normal
WinForms applications. Using a
drag and drop approach, developers
can drop controls on forms (which
can be thought of as a combination
between HTML pages and forms),
hook up events, and set properties.
The code behind the application is
pure .NET code that is executed on
the server. However, IntraWeb does

ModelMaker Code Explorer 2.15 Available


ModelMaker Tools released ModelMaker Code Explorer 2.15. This class
browser and restructuring tool integrates natively with Delphi 5-8. As a
browser it improves navigating classes
and members (fields, methods, and
properties). Use it as an editor to create and modify classes and members
through drag and drop or by selecting
options in dedicated dialog boxes.
Cut, copy, and paste support lets
you pick up any class, property, or
method and duplicate it or move it to
another class.
ModelMaker Code Explorer 2.15
integrates with the Delphi 8 for .NET
IDE and supports the new language
syntax. Also new to this version is
the ability to move comments and
attributes with entities. Whenever
an entity, such as a class member, is
modified, copied, or moved, the preceding comments and attributes are
moved with it.

DELPHI INFORMANT MAGAZINE | August 2004

There are also new wizards in this


upgraded version. The Add Event
wizard allows adding an event
property and creating an Event Dispatch Method at the same time. The
Embrace With Template wizard acts
like a dual code template. That is,
it inserts a code snippet before and
after selected code and (optionally)
indents the selection. The Attribute wizard inserts an attribute to
selected classes or members. The
wizard lets you select an Attribute
preset and/or enter plain text. New
attribute presets are created from
the wizard dialog box text and can
be parameterized using macros.
A free fully functional demo is available at the ModelMaker Tools Web site.
ModelMaker Tools BV
Price: Single-user license, 99; multi-user license
discounts available.
Contact: info@modelmakertools.com
Web Site: www.modelmakertools.com

not require any knowledge of HTML


or JavaScript.
The result is an application server
that resides on a server machine and
can be accessed by clients using a
browser. No ActiveX or client-side
Java is required. All the output is
a combination of HTML, CSS, and
JavaScript. IntraWeb produces a
servlet that is deployed to a Web
server, and the browser receives a
standard Web page.
Atozed
Price: See Web site.
Contact: (412) 291-1035
Web Site: www.atozed.com/IntraWeb/

ComponentOne DevKits
for Delphi 8 and Visual
Studio.NET
ComponentOne released ComponentOne
DevKit for Delphi 8 and ComponentOne
DevKit for Visual Studio.NET.
ComponentOne DevKit for Delphi
8 includes Delphi 8 for the Microsoft
.NET Framework and ComponentOne
Studio Enterprise. ComponentOne
DevKit for Visual Studio.NET combines
ComponentOne Studio Enterprise with
Visual Studio.NET Professional.
ComponentOnes Studio Enterprise is a
component subscription that targets all
run-time environments. This integrated
framework delivers over 100 grid,
reporting, charting, data, user-interface,
and eCommerce components.
ComponentOne LLC
Price: See Web site.
Contact: sales@componentone.com
Web Site: www.componentone.com

A C T I V E
ASP.NET

D E L P H I

DELPHI 8

By Nick Hodges

Your First ASP.NET App


Part II: A Simple ASP.NET Application

n Part I we looked at the big picture of an


ASP.NET project the 10,000-foot view, as
it were. We examined the major elements, as

well as how they link together to create a Web


site. This time around were going to get down
in the weeds and look very closely at everything
that makes up a Delphi-based ASP.NET project.

To do that, of course, we need to create an ASP.NET project,


which, as you might expect, is quite easy. Once youve fired
up Delphi 8, you need only select File | New | Other | ASP.NET
Web Application, and youll see the New ASP.NET Application
wizard, as shown in Figure 1.
From here you can enter the information for your new application. In the Name edit box, enter a name for the application. This is the name that will be given to the virtual directory on the Web server that the server will use to reference
your application. Its probably best to enter an alphanumeric
name with no spaces. The Location edit box defines the physical directory where the Delphi code and ASPX pages for the
application will reside. This directory should be accessible
to the server, and most commonly will be a directory on the
server machine itself. The Server control allows you to select
the server you want for your application.
Cassini Web Server
For starters, you can probably leave the defaults in the first
two controls, but I recommend that you develop and test your
applications using the Cassini Web Server. Cassini is a small,
simple Web server that is analogous to the Web App Debug3

DELPHI INFORMANT MAGAZINE | August 2004

ger from the WebSnap/WebBroker days. Its included with


your Delphi installation, but requires a bit of work on your
part to get it compiled and running. Its actually a C# application that takes advantage of the Web server capabilities of
the .NET Framework. You can read about how to set it up
on my blog at www.lemanix.com/nick/archive/2004/02/15/
153.aspx. Or if you prefer, you can download and install Cassini from www.asp.net/Projects/Cassini/Download.
Once youve done that, select Cassini Web Server in the Server
dropdown in the wizard. Press the OK button when you
have all the settings selected, and the IDE will create a simple, one-page ASP.NET application. The project will consist
of two main modules: the global.asax/.pas module and the
WebForm1.aspx/.pas module. The IDE will also display the
ASP.NET form Designer with WebForm1.aspx loaded into
it. The Designer will have three tabs on the bottom, allowing you to view either the text for the WebForm1.aspx file,
the code in the WebForm1.pas file, or the Designer which
displays a visual representation of the WebForm1.aspx file.

Figure 1: The New ASP.NET Application wizard.

Active

Delphi

Your First ASP.NET App

In addition, you should see the Tool Palette, which displays


only those components that make sense in the context of
an ASP.NET application (for instance, the Tool Palette wont
show any WinForms controls, only WebForms and HTMLbased controls).

So, if you want to position your controls at specific points


on the page, choose GridLayout. If you want your controls
to flow like normal HTML, select FlowLayout.

Personally, I recommend FlowLayout. I like it because its what


we as HTML coders expect and understand. In addition, HTML
A Delphi-based ASP.NET application is a collection of
that flows is handled pretty much the same by all browsers. If
pages, and each page in the application consists of an ASPX you use the absolute positioning of the CSS tags, your results
file and a corresponding PAS file that is the code behind
will probably vary quite a bit between browsers. The issue of
the ASPX page. The Delphi Preview compiler released with
page layout and Web standards is somewhat contentious. I
Delphi 7 had the ability to
prefer to use <table> tags
do Delphi scripting; that is,
to do the most basic layouts
Were going to get down in
putting Delphi code right in
on my pages, and use CSS
an ASPX page. However, for
for everything else. Thats a
the weeds and look very closely at
reasons that Borland doesnt
everything that makes up a Delphi- personal preference, however,
want to disclose, that funcand you can, of course, lay
based ASP.NET project.
tionality wasnt included in
out your pages as you please.
Delphi 8. All the associated
PAS files in your application get compiled into a .NET
To change the Designer to work in FlowLayout, make sure
assembly, and the resulting DLL plus the ASPX pages, along the Designer has focus and go to the Object Inspector and
with a couple of configuration files that well talk about
drop down the combobox at the top. From there, select
later, make up your application.
DOCUMENT, and the Object Inspector will display all the
properties for the document itself. In the Object Inspector,
Because there are a number of different parts to our very
go to the PageLayout property and set it to FlowLayout. Now
simple application, lets take them one at a time, and give
your page will behave more like a normal HTML page,
each a very close look.
and your ASPX page wont have the absolute positioning
code within the style tags of all the ASP.NET controls. Take
The Designer
a look at the ASPX page; youll note that your <body> tag
First, lets look at the Designer. The Designer starts out
now looks like this:
with a somewhat dimly lit notification message in the
middle that reads The page you are working on is in grid <body ms_positioning="FlowLayout">
layout mode, and objects will be arranged using absolute
(x and y) coordinates. To use flow layout (top to bottom,
This attribute has no meaning to a browser and is only presas in a word processing document), change the pageent to inform the Designer (at design time, of course) how
Layout of the DOCUMENT to FlowLayout. Thats pretty
to do layout.
self-explanatory, but the decision to go with grid vs. flow
layout is important. The default is GridLayout (hence all
Dropping a Button
the little dots on the Designer), but this isnt necessarily
Once youve selected your layout positioning, go ahead
the way you want to go. Because youre a Web develand drop a button on the form. To do that, go to the Tool
oper, I think I can assume that you know the basics of
Palette, open the Web Controls tab, and select Button. You
HTML, and by default, HTML uses flow control. If you
can then place a button on the design surface. Note that
put a bunch of HTML tags next to each other in an HTML if you have GridLayout selected, the button will be placed
document, each item flows to the next; i.e. they are laid wherever you drop it, but if you have FlowLayout selectout one next to the other in the browser. If you want a
ed, the button will go to the upper-left corner no matter
specific tag to be placed at a specific location on the page, where it is dropped. (Ill be using FlowLayout throughout
you must use Cascading Style Sheet (CSS) tags to place it
this article; if you are using GridLayout, your ASPX code
there. For instance, if I go to the Tool Palette, select Butwill look somewhat different).
ton from the Web Controls tab, and drop in somewhere on
the Designer, a button will appear at that spot, and the
Several things should have happened. Most obviously, you
Designer will create a tag that looks something like this:
should see the button sitting there on the form Designer.
Also, the WebForm1.aspx file should have some new code in
<asp:button id="Button1"
it. Your <body> tag should now look something like this:

style="Z-INDEX:1;LEFT:350px;POSITION:absolute;TOP:238px"
runat="server" text="Button">
</asp:button>

Note that the style tag includes CSS elements to position


the button at a specific spot on the page. If you select
FlowLayout and add a button to the page, the resulting
code is simply:
<asp:button id="Button1" runat="server" text=Button">
</asp:button>

DELPHI INFORMANT MAGAZINE | August 2004

<body ms_positioning="FlowLayout">
<form runat="server">
<asp:button id="Button1" runat="server" text="Button">
</asp:button>
</form>
</body>

Here we can note a couple of things. First, that the entire


page is wrapped in a <form> tag, and the <form> tag
has a single attribute, runat="server". Normally, almost

Active

Delphi

Your First ASP.NET App

all of an ASP.NET page will be contained inside such a


<form> tag. The attribute tells the ASP.NET engine that
everything within the <form> tag should be parsed and
analyzed by the server. The ASP.NET engine will then
take all the custom tags (in this case, the custom tag is
prefaced with asp) and convert those tags into HTML
for delivery to the client. In this particular case, for example, <asp:button> will be converted into a simple HTML
<input> control that has Button as its caption and an
ID attribute or Button1.

This code should be unfamiliar to Delphi developers


just coming to .NET. In .NET, events are multi-cast, and
a class can connect multiple event handlers to a single
event. In this case, the code above takes the Page_Load
event and attaches it to the Load event. Thus, when the
page is loaded, the Page_Load event is called. Any code
you want to add to initialize the page should be put in
the Page_Load method. The Include call is used to add an
event handler to the event list, taking the event name as
the first parameter, and the method itself as the second.

In other words, the runat="server" tag instructs ASP.NET


In addition, you have an overridden OnInit method that calls
to process the given tag on the server side, and produce
the InitializeComponent method within it. The OnInit method
HTML that the client can display. <asp:button> in turn
is basically the equivalent to the Create constructor in Delphi
can have attributes attached
(although it isnt a constructo it that will determine what
tor, per se), i.e. it gets called
Theres a little magic going
HTML is produced. Notice
as the class is instantiated.
on in the background ... you might
that if you select the button
The Load event would therein the Designer, the Object
fore be analogous to the
think its black magic.
Inspector gives you a set of
Loaded method; it gets called
published properties that you can set, and those settings
after the Page class is created and fully-loaded after processing
will be reflected in the ASPX page. For instance, set the
the ASPX page similar to how the Loaded method is called
buttons Text property to Press Me! and the Width propafter the VCL is done streaming in the DFM file information.
erty to 200 and youll see those changes reflected in the
Designer. In addition, your <asp:button> tag will look
All in all, however, the PAS file is pretty straightforward.
something like this:
Of course, it is like that because the application doesnt
actually do anything yet. Lets change that.

<asp:button id="Button1" runat="server"


text="Press Me!" width="200px">
</asp:button>

Dont Forget the Delphi Code


While all this has been going on, there have been things
going on over in your WebForm1.pas file, as well. (We
cant have a Delphi project without a *.pas file, now, can
we?) The WebForm1.pas file contains the class that wraps
up the page. Each page in your application will have a
class associated with it that encapsulates the functionality
of the page. This class descends from System.Web.UI.Page.
After youve dropped your button in the Designer, the
class should have, as a strict protected field, the following:
Button1: System.Web.UI.WebControls.Button;

In addition, if you unfold all the code on the page (rightclick, select Unfold | All), you should see ... well, nothing
else related to Button1. Interesting, eh? You might have
expected to see some code in the InitializeComponents
method that creates and initializes Button1, as you would
in a WebForms application. There is no such code, however, because all the information that the application needs
to create and initialize the button is in the ASPX file, and
the ASP.NET engine uses that information right from the
file to create and initialize the button. In that way, the
ASPX file acts sort of like a DFM file from the VCL.

Lets Make It Do Something


Go back to the Designer, open the Web Controls tab in
the Tool Palette, and drop a Label on the form. Note that
because we are using FlowLayout, the label aligns itself
next to the button. That wont really look that good, so
select the button with the mouse, and press the left arrow
key. Note that as you do that, the cursor (which may be a
bit tough to see, but trust me, its there) will move from
between the two controls to outside the right control. You
can move the cursor back and forth from between the
controls to either side of the controls. Use the arrow key
to place the cursor between the two, then press R.
You should then see the Label and the Button, one above
the other. What happened? The Designer placed a <br>
tag in between the two controls, thus breaking them up
into a more pleasing layout.
Now that we have the form looking pretty, select the button and double-click it. What happens is exactly what you
would expect; the IDE has created an OnClick event handler for your button. It should look something like this:
procedure TWebForm1.Button1_Click(Sender: System.Object;
e: System.EventArgs);
begin
end;

Add the following line of code to the event handler:


The InitializeComponent method does include an interesting call:

Label1.Text := 'Now we are cooking with gas!';

procedure TWebForm1.InitializeComponent;
begin
Include(Self.Load, Self.Page_Load);
end;

And suddenly, we have a working application. But before


we run this thing, theres something important that must
be covered.

DELPHI INFORMANT MAGAZINE | August 2004

Active

Delphi

Your First ASP.NET App

Figure 2: The HTML Tidy Options page.

Figure 4: The ASP.NET application running, after the button has been pushed.

formatter has a few options you can set via the Tools |
Options | HTML Formatting page. However, if you go to the
Tools | Options menu item and select HTML Tidy Options (see
Figure 2), you can use the open source HTML Tidy
formatter, which gives you much more control over how
your HTML is formatted. (You can find out more about
HTML Tidy at http://tidy.sourceforge.net.) Note that to
use HTML Tidy you must check the checkbox at the top
of the dialog box.
Figure 3: The Project Options dialog box for an ASP.NET application allows you to
set the server host for your application.

HTML Code Formatting


The Designer and code in your ASP.NET application
dont work as it might first appear. Theres a little magic
going on in the background (after you see what, you
might think its black magic). The Designer uses the
MSHTML ActiveX control to render and manage the
dragging, dropping, and moving of controls. As you use
the Designer, it manages and manipulates the controls on
your form, keeping track of the HTML needed to do so.
When you use the Designer, and then switch to the ASPX
page, the HTML from the Designer is passed back, and
the IDE displays it for you.
But heres the catch: The Designer passes the code
back totally unformatted. Thats right all that careful
formatting you did to your HTML is lost. The Designer
ignores it and simply passes back a big string of HTML
with no formatting to it whatsoever. All those carefully
lined up tabs, spaces, and hard returns are gone. What
this means, of course, is that the IDE must format
the HTML for you to make it look at least somewhat
presentable. So theres no point in trying to manually
format the HTML yourself. If you do, the Designer will
just reformat it for you.
The IDE gives you two choices for reformatting. By
default, the IDE uses Borlands built-in formatter. This
6

DELPHI INFORMANT MAGAZINE | August 2004

Finally! We Get to Run It


At this point, we should have a very simple application,
one that merely changes the text of the label at the push of
a button. So lets run it. Its no tougher than hitting 9.
Well, it might be, if you havent set up IIS or Cassini to be
the server. If you dont have either of these servers set up
properly, you can do it from the Project Options dialog box,
as shown in Figure 3. (Again, note that to get the Cassini
server to work, you must compile and install it.)
Once you have the server host properly set up, and the
start page for the application defined, you can hit 9.
Press the button that shows up in the browser, and you
should see something like that shown in Figure 4.
Until Next Time
Thats about as basic as it gets. Weve looked at the
fundamentals of a Delphi-based ASP.NET application, and
seen how the different sections the ASPX file, the PAS
file, and the Designer work together to build a simple
Web application. The results of this application are very
simple, but there is a lot of infrastructure churning away
beneath the surface. In Part III well dig a little deeper
into this simple application.

Nick Hodges is the Chief Technology Officer for Lemanix Corporation


(www.lemanix.com), a Borland Solutions Partner in the Twin Cities of
Minnesota. Nick is a member of TeamB (www.teamb.com) and a frequent
speaker at the annual Borland Conference. Nick lives in St. Paul with his
wife and three children. He can be reached at nickhodges@yahoo.com.

C O L U M N S
ADO.NET

&

R O W S

DELPHI 8 FOR THE MICROSOFT .NET FRAMEWORK

By Bill Todd

ADO.NET Data Access


Components
Part VII: Where Have All the Cursors Gone?

mentioned in Part VI that the DataTable object


has no concept of a cursor. Instead, it implements
a collection of DataRow objects by which you can

access any row at any time using its index number.


This is great when working with data in code,
because you can access any column in any row in the
DataTable at any time; you arent limited to accessing
the row the cursor is on, as you are with the Delphi
for Win32 dataset components.

However, this approach does not work when you are


trying to access data with which the user is working in
the user interface. There is a current row if the user is
looking at data in a DataGrid on a form. Its the row
the highlighted cell is in, or if you prefer the row
to which the DataGrids selected row indicator points.
With no cursor, how can you access the row the user has
selected in the DataGrid?
The answer to that question should be simple but it
isnt. The answer isnt really complex, either. Its just
very different from the cursor-based model to which
youre accustomed. This article extends the sample
application used in Part VI. Figure 1 shows the modified
form for the sample application. Notice that the form
contains a StatusBar at the bottom that displays the four
values described in Figure 2.
Add a StatusBar to last months sample application to create
the form shown in Figure 1. Select the StatusBar and find
its Panels property in the Object Inspector. Click the ellipsis
button to open the StatusBar Panel Collection Editor. Add
four panels named StatuBarPositionPanel, StatusBarRowPanel,
StatusBarColumnPanel, and StatusBarCountryPanel. Set the
AutoSize property of each panel to Spring so the four panels
will share the available space on the StatusBar.
7

DELPHI INFORMANT MAGAZINE | August 2004

Getting the Binding Manager


When you bind a user interface object, for example
a DataGrid or TextBox, to a data source by setting its
DataSource property, the .NET Framework creates a
binding manager and assigns a reference to the binding
manager to the UI objects BindingContext property.
There are two binding manager classes, both of which
descend from the abstract class BindingManagerBase.
The first, PropertyManager, is used if the data source
can only return a single value. Its typically used to
bind a control to a property of an object. The second
BindingManagerBase descendant is the CurrencyManager
class, which is used when the data source can return a list
of objects. When you bind to a DataTable or DataView the
binding manager
will always be a
CurrencyManager.
The CurrencyManager can be
compared to the
DataSource component in Delphi
for Win32 applications. It connects
the data source
to the UI control
and keeps current

Figure 1: The modified sample application form.

StatusBar Panel

Description

Position

The index of the selected row in the underlying


data source. In this case, the position in the
DataView to which the DataGrid is bound.

Row

The number of the selected row in the DataGrid.

Column

The number of the column that contains the


selected cell.

Country

The name of the country from the selected row.

Figure 2: The StatusBar values.

Columns

&

Rows

ADO.NET Data Access Components

procedure TCountryForm.InitGridCurrencyManager;
begin
CountryGridCurrencyMgr := CountryGrid.BindingContext[
EmpDataSet.Tables['Country'].DefaultView] as
CurrencyManager;
end;

Figure 3: The InitGridCurrencyManager method.


procedure TCountryForm.ShowCurrentRow;
var
CurrentDrv: DataRowView;
begin
StatusBarPositionPanel.Text := 'Position: ' +
CountryGridCurrencyMgr.Position.ToString;
// Get a reference to the current object and display
// the Country name.
CurrentDrv :=
CountryGridCurrencyMgr.Current as DataRowView;
StatusBarCountryPanel.Text :=
CurrentDrv['Country'].ToString;
end;

Figure 4: Display the current row number in the StatusBar.

procedure TCountryForm.
CountryGridCurrencyMgr_PositionChanged(
Sender: System.Object; e: System.EventArgs);
begin
ShowCurrentRow;
end;

Figure 5: The PositionChanged event handler.

the value displayed by the UI control. To gain access to


the DataGrids CurrencyManager in the sample application, start by adding a private member variable named
CountryGridCurrencyMgr of type CurrencyManager to the
forms type declaration.
Next, add the InitGridCurrencyManager method shown in
Figure 3. When you access the BindingContext property,
its critical that you supply the exact data source that you
assigned to the UI controls DataSource property as the index.
The BindingContext property returns a reference to an object
of type BindingManagerBase. The code in Figure 3 casts
the returned value to the CurrencyManager type to provide
access to the properties, methods, and events unique to that
type. Finally, add a call to InitGridCurrencyManager to the
OpenCountry method that is called from the File | Open Country
menu items Click event handler.
Tracking the Current Row
To display the number of the current row in the StatusBar
you need a way to get the current rows index number,
and an event that fires when the number changes. The
CurrencyManager provides both. Start by creating the
ShowCurrentRow method shown in Figure 4. This method
displays the CurrencyManager.Position property as a string
in the StatusBarPositionPanel of the StatusBar. The Position
property is the index of the current row in the data source.
The next line uses the CurrencyManager.Current
property to get a reference to the current object.
Because this CurrencyManager manages a binding to
a DataView, the current object is a DataRowView so
8

DELPHI INFORMANT MAGAZINE | August 2004

procedure TCountryForm.InitGridCurrencyManager;
begin
CountryGridCurrencyMgr := CountryGrid.BindingContext[
EmpDataSet.Tables['Country'].DefaultView] as
CurrencyManager;
Include(Self.CountryGridCurrencyMgr.PositionChanged,
Self.CountryGridCurrencyMgr_PositionChanged);
ShowCurrentRow;
end;

Figure 6: The modified InitGridCurrencyManager method.


procedure TCountryForm.CountryGrid_CurrentCellChanged(
Sender: System.Object; e: System.EventArgs);
begin
ShowGridPosition;
end;
procedure TCountryForm.ShowGridPosition;
begin
StatusBarRowPanel.Text :=
'Row: ' + CountryGrid.CurrentCell.RowNumber.ToString;
StatusBarColumnPanel.Text := 'Column: ' +
CountryGrid.CurrentCell.ColumnNumber.ToString;
end;

Figure 7: Displaying the DataGrid row and column.

the method casts the returned value to a DataRowView


and assigns it to the CurrentDrv variable. The third line
uses the DataRowView syntax described in Part VI to get
the value of the Country field and assign it to the
StatusBarCountryPanel.Text property.
The CurrencyManagers PositionChanged event fires each
time the current row changes, so an event handler for this
event is the perfect place to call the ShowCurrentRow method.
Start by creating the event handler shown in Figure 5. Next,
change the InitGridCurrencyManager method from Figure 3 so
it looks like Figure 6. The call to the Include method attaches
the event handler to the event. The only problem with the
PositionChanged event is that it doesnt fire when the Country
table is opened and the DataGrid is first populated with data.
The solution is the call to ShowCurrentRow at the end of
Figure 6, which displays the initial value in the StatusBar.
Showing the DataGrids
Current Row and Column
The two middle panels in the StatusBar show the row and
column of the selected cell in the DataGrid. The DataGrids
CurrentCellChanged event fires each time the current cell in
the DataGrid changes. Figure 7 shows the CurrentCellChanged
event handler, which calls the ShowGridPosition method.
The DataGrid has a CurrentCell property, which points to the
DataGridCell that has the focus. The DataGridCell object has
a ColumnNumber property and a RowNumber property that
return the column and row numbers of the current cell, respectively. These are read/write properties, so you can also use
them to change the current cell.
Navigating and Editing Using the
CurrencyManager
The sample applications form shown in Figure 1 also has a
Navigate menu with the following choices:

Columns

&

Rows

ADO.NET Data Access Components

procedure TCountryForm.FirstItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
CountryGridCurrencyMgr.Position := 0;
end;

procedure TCountryForm.InsertItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
CountryGridCurrencyMgr.AddNew;
end;

procedure TCountryForm.LastItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
CountryGridCurrencyMgr.Position :=
CountryGridCurrencyMgr.Count - 1;
end;

procedure TCountryForm.DeleteItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
if CountryGridCurrencyMgr.Count > 0 then
CountryGridCurrencyMgr.RemoveAt(
CountryGridCurrencyMgr.Position);
end;

Figure 8: Moving to the first or last row.


Figure 10: Inserting and deleting using the CurrencyManager.
procedure TCountryForm.NextItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
if CountryGridCurrencyMgr.Position <
CountryGridCurrencyMgr.Count - 1 then
CountryGridCurrencyMgr.Position :=
CountryGridCurrencyMgr.Position + 1
else
MessageBox.Show('On last record.', 'Warning');
end;
procedure TCountryForm.PriorItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
if CountryGridCurrencyMgr.Position > 0 then
CountryGridCurrencyMgr.Position :=
CountryGridCurrencyMgr.Position - 1
else
MessageBox.Show('On first record.', 'Warning');
end;

Figure 9: Moving to the next and prior rows.

procedure TCountryForm.DeleteDataViewItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
DataView(CountryGridCurrencyMgr.List).Delete(
CountryGridCurrencyMgr.Position);
end;

Figure 11: Inserting and deleting with DataView methods.

method. Delete checks CurrencyManager.Count to


make sure the DataGrid isnt empty, then calls the
CurrencyManager.RemoveAt method. RemoveAt takes
a single parameter, which is the number of the row to
delete. In this case, the current row should be deleted, so
CurrencyManager.Position is passed as the parameter.

First
Last
Next
Prior
Insert
Delete
Insert with DataView
Delete with DataView
Cancel Edit

For reasons that are not stated, the .NET Framework


online help says that you should not edit using the
CurrencyManager methods. Instead, you should use
the corresponding methods of the data source, in this
case a DataView object. I havent encountered or read
of any problems using the CurrencyManager methods,
but theres an important disadvantage to using the
DataView.AddNew method to insert a new row.

End Edit

Figure 8 shows the Click event handlers for the First and
Last menu items. Both of these event handlers work by
setting the CurrencyManager.Position property. To go to
the first row, Position is set to zero. To go to the last row,
Position is set to CurrencyManager Count -1 because the
row numbers are zero based.
Figure 9 shows the code for the Next and Prior menu items
Click event handlers. The code for the Next menu item checks
to see if the current row is less than the last row. If so, it adds
one to the Position property. The event handler displays a
warning message if the current row is the last row. The code
for the Prior menu items event handler is almost identical,
except that it checks to see if the current position is zero and,
if not, subtracts one from the Position property.
Figure 10 shows the event handlers for the Insert and Delete
menu items. Insert calls the CurrencyManager.AddNew
9

procedure TCountryForm.InsertDataViewItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
DataView(CountryGridCurrencyMgr.List).AddNew;
end;

DELPHI INFORMANT MAGAZINE | August 2004

Figure 11 shows the event handlers for the Insert with


DataView and Delete with DataView menu items. The
CurrencyManager.List property returns the IList interface
of the data source, and can be cast to any object type that
implements IList. The Insert with DataView menu item casts the
CurrencyManagers List property to a DataView, and calls
the DataView.AddNew method to insert a new row. However, if you run the sample application youll see a big difference from the behavior of the Insert menu choice.
Calling the CurrencyManager.AddNew method inserts a new
row and makes it the current row. Calling the DataViews
AddNew method inserts a new row, but leaves the current
row unchanged. You have to scroll the DataGrid to the end
to find the new row. Figure 12 shows the sample application after inserting a new row with DataView.AddNew. Note
that the new row appears at the bottom of the grid, but the
current row indicator still points to the row for France, just
as it did before inserting the new row. The DataView.Delete

Columns

&

Rows

ADO.NET Data Access Components

method, on the
other hand, works
as expected.
Figure 13 shows
the event handlers
for the Cancel
Edit and End Edit
menu items.
The Cancel Edit
handler calls the
CurrencyManagers
CancelCurrentEdit Figure 12: The sample application after inserting a
new row with DataView.AddNew.
method to undo
the changes you
made to the current record. The End Edit handler calls
the CurrencyManager.EndCurrentEdit method. When
you change a record in the DataGrid, or any other
user interface control, the change isnt written to the
underlying DataTable until one of two things happens:
1) You change the CurrencyManager.Position property, either
in code, or by moving to another row in the DataGrid.
2) You call the CurrencyManager.EndCurrentEdit method.
If you try to apply your changes to the database before you
move to a new row or call EndCurrentEdit, your change
wont be made in the database, because it hasnt been made
to the DataTable.
Conclusion
When you understand how to work with the current row in
the user interface using the CurrencyManager, the lack of a
cursor in the DataTable object is really a blessing. The ability to refer to any row at any time using its index number
saves a lot of code. In Delphi for Win32 if you want to copy

10

DELPHI INFORMANT MAGAZINE | August 2004

procedure TCountryForm.CancelEditItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
CountryGridCurrencyMgr.CancelCurrentEdit;
end;
procedure TCountryForm.EndEditItem_Click(
Sender: System.Object; e: System.EventArgs);
begin
CountryGridCurrencyMgr.EndCurrentEdit;
end;

Figure 13: Canceling changes to the current row.

values from the fields in one row to the fields in another row
in the same table, you must use two dataset components. In
ADO.NET all you need to know is the index number of each
row and you can do the job with a simple for loop. If you
need to work with the DataRowView or the entire DataView
behind the current row in the user interface, you can do so
easily and generically using the CurrencyManagers Current
and List properties. Its a very powerful architecture.
Click here for Part 8 and Part 9.
The example project referenced in this article is available for
download on the Delphi Informant Magazine Complete
Works CD located in INFORM\2004\AUG\DI200408BT.

Bill Todd is president of The Database Group, Inc., a database consulting


and development firm based near Phoenix. He is co-author of four database
programming books, author of more than 100 articles, a contributing editor to
Delphi Informant Magazine, and a member of Team B, which provides technical
support on the Borland Internet newsgroups. Bill is also an internationally known
trainer and frequent speaker at Borland Developer Conferences in the United
States and Europe. Readers may reach him at btarticle@dbginc.com.

S O U N D + V I S I O N
ANAGLYPHIC STEREO IMAGES

DELPHI 4-7

By Alexander Gofen

Do-It-Yourself 3D
Creating Anaglyphic Images at Home

his article continues the topic of stereo


vision introduced in the January issue of
Delphi Informant, and explains how you

can shoot 3D stereo photos with a conventional


camera for viewing on your home PC through
anaglyphic Red/Blue (or Red/Cyan) glasses.

The accompanying application makes it possible to create


anaglyphic images by compensating for certain shooting errors
(see end of article for download details). In addition, the application introduces a new class derived from TBitmap, providing
the fastest access to the separate pixels and their color components. It also provides a couple of methods, such as bitmap
rotation, capitalizing on this efficient access mechanism.
Why Anaglyphic Photos?
Stereo vision is a wonderful gift. Those who have experienced it whether in modern 3D stereo movie theaters,
in museums or shops through special equipment, or when
looking at holograms are often astonished by the realistic and powerful effect.
However, you dont necessarily need to invest in fancy equipment to create stereo photos. Well learn how to create stereo
photos simply by using a conventional camera (either film
or digital), a home PC, and one of the simplest and cheapest pieces of equipment youll ever buy: a pair of Red/Blue or
Red/Cyan cardboard glasses.
In the January article we considered only computer-generated
images, which were non-planar mathematical curves displayed
in full Red and Blue colors. However, the same approach
allows displaying half-tone monochromatic, and even color,
photos as anaglyphic stereo pairs (although the perception of
colors through anaglyphic glasses would be compromised).
Using a conventional camera instead of a special doublelens model provides certain advantages over the double
lens models with only one drawback. You must shoot
11

DELPHI INFORMANT MAGAZINE | August 2004

two shots of the same scene sequentially; therefore, the


scene must be motionless. However, unlike the doublelens cameras, the distance between the shooting points,
called the base (the distance between the two lenses),
is not fixed. Varying the base, you enjoy full freedom of
shooting scenes that can be very different in scale. It may
be your favorite diamond ring (with a shooting base of
1-2 cm), or your macro surroundings, such as an office
or backyard (with a base of 6-7 cm, i.e. the distance
between human eyes), a mountain landscape (the base
is several meters), or even the rings of Saturn (in which
case the base would be the diameter of the earths orbit
and the shots made at six-month intervals).
First we need a pair of source bitmap images obtained either
directly from a digital camera or scanned from photos shot by
film cameras. Then we must perform certain adjustments and
overlap the images with the supplied software. This involves
several operations on bitmaps, performed applying a fast access
method to the bitmap pixels, discussed in the next section.
Fast Access to Bitmap Pixels
Certain numeric-intensive bitmap methods are implemented efficiently in the VCL, and work really fast, for
example, on horizontal or vertical stretching of bitmaps.
However, the VCL doesnt offer rotation of bitmaps. In
applications there are plenty of other algorithms requiring
massive pixel-by-pixel processing.
Accessing pixels via the TBitmap.Canvas.Pixels property is inefficient, and the documentation warns about that. Instead, it
offers the TBitmap.ScanLine property intended to provide efficient access to the pixels of one horizontal line of bitmaps. Yet,
its not enough for typical 2D processing algorithms demanding
the access to pixels as to a 2D array of color vectors. The solution comes as a descendant class:
TFastMap24 = class(TBitMap)

whose main goal is to introduce a new index property:


property PixelRGB[const i,j: Integer; const n: Byte]

Sound+Vision

Do-It-Yourself 3D

TFastMap24 = class(TBitMap)
private
// Scan lines for each line.
Lines : array of PByteArray;
function IsValid(const i,j: Integer): Boolean;
function GetClrComp(const i,j: Integer;
const n: Byte): Byte;
procedure SetClrComp(const i,j: Integer;
const n, ClrComp: Byte);
public
property PixelRGB[const i,j: Integer; const n: Byte]:
Byte read GetClrComp write SetClrComp; default;
destructor Destroy; override;
procedure SetLines;
procedure LoadFromFile(const FileName: string); override;
procedure Assign(Source: TPersistent); override;
procedure AssignTurned(const Source: TFastMap24;
const ang: Single);
end;

Figure 1: The mechanism for fast addressing the pixels as elements of a 2D array is
based on the introduction of a dynamic array, Lines, of the same type PByteArray as
the ScanLine property for each line of the bitmap.

procedure TFastMap24.SetLines;
var
j: Integer;
begin
SetLength(Lines, Height);
for j := 0 to Pred(Height) do
Lines[j] := ScanLine[j]
end;

Figure 2: The SetLines method.

function TFastMap24.GetClrComp(const i, j: Integer;


const n: Byte): Byte; { n = 0,1,2 only }
begin
if IsValid(i,j) then
Result := Lines[j, 3*i + n]
else
Result := 0
end;
procedure TFastMap24.SetClrComp(const i, j: Integer;
const n, ClrComp: Byte); { ClrComp = 0,1,2 only }
begin
if IsValid(i,j) then
Lines[j, 3*i + n] := ClrComp
end;

// Real type color vector - static array.


RGBSingle = array[0..2] of Single;
TSingleMap24 = array of array of RGBSingle;
procedure Map24ToArray(const Map: TFastMap24;
out MapArray: TSingleMap24);
var
i, j, k: Integer;
begin
with Map do begin
SetLength(MapArray, Width, Height);
for i := 0 to Pred(Width) do
for j := 0 to Pred(Height) do
for k := 0 to 2 do
MapArray[i,j,k] := Map[i,j,k]
end
end;
procedure ArrayToMap24(const MapArray: TSingleMap24;
out Map: TFastMap24);
var
i, j, k: Integer;
begin
with Map do begin
Width := Length(MapArray);
Height := Length(MapArray[0]);
Map.SetLines;
for i := 0 to Pred(Width) do
for j := 0 to Pred(Height) do
for k := 0 to 2 do
Map[i,j,k] := Round(MapArray[i,j,k])
end
end;

Figure 4: Convert the bitmap into a 3D array of Single then reconvert it back.

1) Obtaining fractional coordinates [i',j'] of the source


bitmap corresponding to [i,j] according to the rotation
transform:
i' = Ox + (i - Ox)*cosa - (j - Oy)*sina
j' = Oy + (i - Ox)*sina + (j - Oy)*cosa

2) Obtaining the four nearest Integer pixels [i0',j0'],


[i0'+1,j0'] , [i0',j0'+1] , [i0'+1,j0'+1] denoting the
square containing fractional point [i',j']:
i0' = Floor(i');
j0' = Floor(j');
{ Required for bi-linear interpolation }
di = Fraction(i'); dj = Fraction(j');

Figure 3: The GetClrComp and SetClrComp methods.

3) Performing the bi-linear interpolation for each of the


three color components (see the source text of the
FastBMapUnit).

In this application the derived bitmap class implements


24-bit color bitmaps only. The mechanism for fast
addressing the pixels as elements of a 2D array is based
on the introduction of a dynamic array, Lines, of the same
type PByteArray as the ScanLine property for each line of
the bitmap (see Figure 1).

The unit also offers another fast algorithm for massive computations with the color bitmap pixels. Its idea is to convert the
bitmap into a 3D array of Single (to perform massive computation of any complexity over it), and then convert it back.

The SetLines method should be called to initialize Lines


when the bitmap size changes (see Figure 2). The default
index property providing the desired fast pixel access
to the bitmap is implemented by the routines shown in
Figure 3.
Rotation of a given source bitmap (around its center)
requires the following computations performed for every
pixel [i,j] of the target bitmap:
12

DELPHI INFORMANT MAGAZINE | August 2004

Both conversions are performed using the fast access process previously described (see Figure 4). This unit opens
the door for many possible massive computations over
bitmaps required in applications. The stereo-photo application in the next section uses it, as well.
Combining Anaglyphic Pictures
The application accompanying this article makes possible the
creation of anaglyphic stereo images of two types. Both types
are overlapped left and right images in different colors.

Sound+Vision

Do-It-Yourself 3D

What Youll Need to Play


Along at Home
To watch the effects described in this article and displayed
by the software, you will you need a pair of Red/Blue glasses,
which are easily obtainable at very low cost, e.g. one source
is www.reel3d.com for 50 cents. The recommended Red/Blue
glasses are of type 7001: they are the best match to screen
Red/Blue colors. Also, you must have relatively healthy eyes
capable of stereopsis, i.e. the ability to naturally fuse two
plane images comprising a stereo pair into a 3D scene. Most
people do (this is not to be confused with fusing so called
auto-stereograms). If you have ever watched a stereo movie
through polarized or electronic shutter glasses, or have seen
a hologram pop out into space, your stereopsis is okay.
Alex Gofen

same procedure, so
that both images
are consistently
converted into gray
scale with optimal
contrast; any image
editor does it).

Figure 5: The horizontal shift between the left and right images determines the convergence point of the eyes: point A (1a) or point C (1b)
shown in Magenta as a result of overlapping Red and Blue. Black points ABCD represent how they are perceived in 3D space: all in front of
the screen (1a) or in front and behind the screen (1b). The whole set CBAD (1a) was rigidly shifted up so that C coincide with C (1b). Such a
shift affects disparities of all pairs. The convergence point (zero disparity) is perceived as lying on the screen. Pairs with disparities of opposite signs correspond to points perceived at the opposite sides of the screen. Therefore the horizontal shift affects the perceived position of
the 3D scene: whether it appears completely in front of the screen, partially, or completely behind the screen.

The two-color anaglyph consists of the overlapped left


and right images in Red and Blue, to be viewed through
the Red/Blue glasses. Red and Blue are easily separated;
either eye sees only the image intended for it, and the
viewer perceives the stereo scene as monochromatic.
In addition to what the two-color anaglyph does, the
three-color anaglyph attempts to reproduce the colors
of the original scene. In so doing, one of the images in
the stereo pair must be represented with only its Red
color component, while the other one only with the
Green and Blue components the result to be viewed
through the Red/Cyan glasses (the Cyan filter is permeable to both Green and Blue).
As a result, the two eyes together receive the full-colored
scene, although each of them gets the incompletely
colored image. The brain can fuse even these two colordistorted images into the full-color stereo scene. The
drawback is that the separation between the left and right
becomes compromised (either eye may be distracted by a
weak image intended for the other one). Also, the photos
must possess high contrast and be well lighted so that the
image represented by the Red-only component doesnt
appear much darker and with less contrast than the other
one in Green and Blue.
For the two-color scheme the source images must be either
originally black and white photos, or the color photos must
be saved as the monochromatic gray bitmaps (saved in the
13

DELPHI INFORMANT MAGAZINE | August 2004

The source images


for the sample
application must
be only in bitmap
format: 8-bit monochromatic or 24-bit color. The 24-bit color depth for the
resulting image is crucial: small color depth will compromise the color separation.
The sample application allows opening the corresponding files
and viewing the images: one in Red, the other in Blue (and
Green). As the images were not shot simultaneously, they may
require corrections compensating for undesired rotation, translations, or leaning. (The latter occurs if you tilt the camera so
much that it caused a visible perspective distortion).
First, correct the undesired rotation. Draw a vertical or
horizontal line along an edge of certain detail of the
image (you can also specify the angle for the rotation
numerically). When both images of the pair are correct
with regard to the rotational distortions, you are ready to
perform the most important correction, which compensates for the almost inevitable translational error. (The
leaning correction is not available here).
Theoretically, both eyeballs can turn, hence perform translation and rotation of the incoming images in any direction.
However, since birth we are trained to always maintain convergence of both eye axes at one certain point of interest.
That means the eye axes are crossed (or parallel) never
skewed. Therefore, there must be neither vertical shift nor
rotational difference between the images of the pair.
The application allows you to overlap the images (each in its
own color) so that you can distinguish sharp contours in both.

Sound+Vision

Do-It-Yourself 3D

Figure 6: Disparity and depth. Point A is a convergence point, hence its disparity is zero. For a nearer point B the image B would appear to the left of A, while
image B to the right of A. Disparity of point B then is BRA+ALB=2BRA.
Denoting half-base RC=SA=b, CB=d1 and CA=d, the disparity of B would be
= 2BRA=2(BRS-ARS)=2(arctan(b/d1) - arctan(b/d)).

By dragging the mouse you can draw a correction vector: first


to compensate the vertical error. When both images are vertically aligned properly, you must find the optimal horizontal
shift between them.
When two images of a stereo pair are processed in the brain,
they are compared (as though over-imposed) in order to figure
out angular differences (disparities) between the corresponding
points (see Figure 5). The point with zero disparity is the convergence point; this is usually in the plane of the screen. Points
with disparities of opposite signs are perceived as though situated in front and behind the screen in depth, depending on the
disparity values.
The disparities of a 3D scene are encoded in the images
when the images were shot at two different points. The horizontal translation of the displayed images adds a constant
component to the encoded disparities (again, see Figure 5).
The effect of the horizontal translation is as if we were to vary
the convergence angle of our eyes (again, see Figure 5). We
dont want it to be negative (when the axes cross behind our
head). The axes must cross in front of us in a point of interest
in the 3D scene.
Analyzing the scene, we determine the background and the
extreme foreground. If we want the whole scene to pop out
of the screen, we assume the background lying on the screen,
i.e. the disparities of the background being zero. To achieve
that, align the corresponding points of the background so that
they coincide (colored Magenta). Then all the others would
not coincide, and for all stereo pairs a point intended for the
left eye would appear to the left of the corresponding right one
(case 1a in Figure 5).
If you want the scene to pop out of the screen only partially,
align points situating in the middle of the depth of your scene.
Then the background would be perceived behind the screen,
and the foreground in the front of it (case 1b in the Figure 5).
Scale and Parameters of a 3D Scene
The proper shooting distance, angular size, and stereo base for
your pictures are very important to facilitate fusing and stereo perception. The optimal viewing distance for any images,
whether mono or stereo, photo or paintings, must be such
that you view it at the same angle as it was shot (or viewed
by the artist). Only then can we properly perceive the perspective information encoded in the image (although the tolerance
for this error is high enough). In some pictures (single pic14

DELPHI INFORMANT MAGAZINE | August 2004

Figure 7: Black and white 3D pair: left (left top), right (right top), and
overlapped (bottom).

tures, not stereo pairs), if you view it with your one eye (the
other one closed), the perspective hints may appear so strong
(streets, straight edges, obviously different layers of depth), that
with a little brain effort you can suddenly perceive it as though
real 3D stereo. This is known as monocular stereopsis.
Thus, paying attention to the angular setting of your lenses
(focus or zoom factor) vs. the expected conditions for viewing
the hard copy (or the screen image), is always important in
photography.
The comfortable viewing angle for us is something between
40 and 60 degrees. Therefore, the fish-eye lenses or tele-lenses
would be an improper choice for shooting a scene with rich
perspective. Another important limitation is that the brain fuses
stereo pairs only for disparities not exceeding approximately 2
(120). Front images situated too close to the viewer (disparity
overflow) would not fuse, and only hinder the perception.
The limitation from below is that of our visual acuity (about
1). Therefore, disparity of less than 1 is not perceived and
always translates into a plane background in the far (disparity underflow). For example, while viewing naturally at a
real-world scene (eye base 6-7 cm) we can perceive stereopsis
for objects between 0.8 and 200 meters: everything farther is
perceived as a plane background. Shifting the fixation (convergence) point closer, say at 50 cm, and allowing disparity
between -1and 1, we can place the nearest objects at 38 cm,
and the farthest at 70 cm (see the formula in Figure 6).

Sound+Vision

Do-It-Yourself 3D
Same zoom. You must apply exactly the same zoom
for both shots (if your zoom is variable).
No internal flash. You should not use the internal flash
on your camera; it would create confusing non-matching
shadows. Instead, shoot in natural light, possibly with
low-speed exposition (the camera is fixated anyway).
Left/Right not interchangeable. Both images are
intended for the proper eye only, therefore name the
files correspondingly. If you later confuse their order,
you will probably still perceive the stereo effect, albeit
inversely in depth. Generally speaking, this inversion
is not geometrically consistent with the perspective
hints in the image, which may hinder the fusing and
perception. (Only if the perspective hints are purposely minimized by shooting with tele-lenses, the inversion of depth doesnt cause fusing difficulties).

Figure 8: Overlapped 3D color image.

Hints for Sequential Shooting


To begin with, you can use several pairs of stereo photos
downloaded together with the software. Some of them are
black/white/gray (Figure 7), others are full color pairs
(Figure 8). You can use the latter either as color images
for creating the three-color anaglyph pairs, or transform
them into black/white/gray before further processing.
You may want to shoot your own 3D stereo photos. Here are
several important hints (I borrowed some of them from Stereo Photography by Fritz G. Waack, self published, 1985):
Still images only. The double-shot method applies
only to shooting still scenes. You can shoot with an
arbitrary small or large base distance between the left
and right shooting points.
Base size. A good approximation for the base size is
1/30 of the distance to the nearest object in the scene.
Sharpness and high contrast. For easy and comfortable fusing, its important that both images be sharp
and of high contrast for all objects in the scene. That
means that the depth of focusing must be large (hence
the aperture is small, which is achievable for a welllighted scene and high-speed film).
Correct translation. To make good sequential double
shots, it may be desirable to fixate the camera on a
tripod, or something similar. While moving it from the
left to the right shooting position (or vice versa), be
careful to preserve approximately its horizontal and
vertical orientation. Certain translation and rotation
error between the pairs is allowed and may be compensated for later. Ideally, both shots should be made
at the same horizontal level, preserving the parallelism of the frames and optical axes.
Shifting scene vs. shifting camera. Instead of shifting
the camera between the two shooting points, you may
want to carefully shift the 3D scene if it is a small set
of objects placed onto a tray. Thus, you must shift the
whole tray, not touching the things on it.
No date/time stamp. You may want to switch off the
date/time stamp on your camera (otherwise, the two
text lines would corrupt the stereo image).
15

DELPHI INFORMANT MAGAZINE | August 2004

Conclusion
The anaglyphic display is the simplest, yet most efficient
approach to implementing the stereo vision on conventional PCs. Its the best choice for displaying monochromatic stereo images; however, it does compromise color
perception of full-color stereo pictures.
For stereo viewing with uncompromised colors, more
sophisticated gadgets are needed. For example, color stereo
pairs may be displayed next to each other on the left and
right halves of the same screen. To view them, you would
need a viewer with a pair of mirrors (or prisms) inside,
which comfortably helps converging your eyes at each of the
images properly. The ultimate device would be goggles with
small, high-quality monitors for each eye. Then the viewer
enjoys not only the highest quality color stereo vision, but
also full freedom from maintaining the correct place and
position of the head. This freedom is achievable also while
viewing stereo on a big screen through shuttered or polarizes glasses, and through the anaglyph glasses, as well.
Meanwhile, Sharp Inc. (www.sharpsystems.com) introduced the latest Sharp 3D Stereo Notebook computer that
requires no glasses or goggles, but provides plenty of
stunning stereo images and the software to assist in their
creation. However, this model does require the viewer to
always maintain the correct place and position of the head.
We are now at the doorstep of the next stage in the evolution of computer displays, stereo vision, and the 3D Stereo Notebook marks the beginning of this evolution and a
general reawakening of the interest in stereo vision.
The files referenced in this article are available
for download on the Delphi Informant Magazine Complete
Works CD located in INFORM\2004\AUG\DI200408AG.

Alexander Gofen is a programmer at the Smith-Kettlewell Eye Research Institute


in San Francisco, CA (www.ski.org), where he has worked since 1995. Previously,
he was a senior researcher for the Institute of Computer Science (Academy of
Sciences, Russia) and Hydro-Meteorological Center in Moscow, Russia. Gofen has
been developing scientific applications in all versions of Delphi and Borlands
Pascal, varying from the Numeric Weather Forecast and the Taylor Solver to the
Macula Mapping Test (Eye Research Institute). You can reach him by phone at
(415) 345-2119, by e-mail at galex@ski.org, or by visiting www.ski.org/gofen.

INFORMA NT

SPOTL IG HT

By Jerry Coffey

Readers Choice Awards 2004


Changes at the Margins

o be honest, last years awards were a lot


more dramatic. Coming as they did after
TurboPower Software (then a major player)

decided to leave the Delphi arena, there were new


winners to announce in many new categories;
it was a genuine sea change. The opposite is
true this time around; with no new big players
entering or exiting the stage, this years awards
resemble last years in many categories. Happily,
there are enough new products and place changes

count topped out at 339, so Delphi-related books seem to


be the exception rather than the rule when it comes to
Delphi-related products. So lets get to it...

Best Accounting Package


Trading places. This
years first- and secondplace finishers are the
mirror image of last years,
with BS/1 (from Davis Business Systems Ltd.) taking
top honors with 25% of the
vote, and ColumbuSofts
Accounting for Delphi taking runner-up with 21%.

to keep things interesting, so read on.


There are two modifications to the balloting this year.
Theres one new category: Best Build Tool. And sadly,
there werent enough books in the past year to justify
a Best Book category. Its the first year without it. Until
quite recently there was only one book that qualified:
Advantage Database Server: The Official Guide by
Cary Jensen and Loy Anderson (published by McGrawHill Osborne Media). Cary and Loy are well-known,
world-class writers and the book has received sterling
reviews in these pages and on Amazon.com. Once the
balloting ended, we received our first copies of Delphi
for .NET Developers Guide, by Xavier Pacheco, et al. Its
the latest installment of one of the most respected series
in Delphi history, and is also receiving stellar reviews on
Amazon.com. Well be reviewing it soon in DI.
In contrast, there are more third-party tools than ever.
There were 228 in 2002, and 299 in 2003. This year the
16

DELPHI INFORMANT MAGAZINE | August 2004

BS/1 (25%)
Accounting for Delphi (21%)
BSS Business Systems (10%)
Express Spreadsheet (9%)
other (35%)

Best Add-in
Its a rush. It was a
closer finish, but Developer
Express CodeRush took
first place for the sixth
straight year with 27% of
the vote (last year it took
36%). This years runner-up
brings us our first tie with
Athlant (from Devrace) and
TMS Plugin Framework
(from TMS Software) each
garnering 18%. Last years
runner-up, ModelMaker
Code Explorer, drops to
fourth place with 16%.

CodeRush (27%)
Athlant (18%)
TMS Plugin Framework (18%)
ModelMaker
Code Explorer (16%)
Castalia (12%)
other (9%)

Informant

Spotlight

Readers Choice Awards 2004

Best Build Tool

Best Database Engine

No competition. This is a
brand new category, so no
one knew what to expect.
What happened was a blowout, with Atozed Softwares
FinalBuilder taking 79% of the
vote. Quality Software Components came in a distant
FinalBuilder (79%)
runner-up with 12% for their
TC Builder (12%)
TC Builder.
Visual Build Professional (7%)
other (2%)

Best Charting/Mapping Tool


Steemarolla (again). Steema Softwares TeeChartPro
dominates Best Charting/
Mapping Tool again, with
45% of the vote its seventh
consecutive first-place finish!
Runner-up is a tie between
TMS Diagram Studio (from
TMS Software) and EasyMap VCL (from microOLAP
Technologies), each with
13%. Last years runner-up,
ExpressOrgChart Suite (from
Developer Express), dropped
to fourth place.

TeeChartPro (45%)
TMS Diagram Studio (13%)
EasyMap VCL (13%)
ExpressOrgChart Suite
(11%)
Chart FX (5%)
other (13%)

Indy Plus (36%)


RemObjects SDK (17%)
TMS Async32 (14%)
Network Investigation Suite (12%)
IP*Works! Delphi Edition (5%)
other (16%)

Best Database Connectivity


Volatile connections.
FIBPlus (from Devrace)
moves up to first place
to take the category
easily with nearly a
quarter of the votes
(last year it finished second). Runner-up goes to
newcomer Direct Access
Components for MySQL
(from microOLAP Technologies) with 12% of
the votes.
17

DBISAM Database
System (27%)
Advantage Database Server (21%)
NexusDB (21%)
Apollo (6%)
TurboDB (6%)
other (19%)P

Best Database Tool

Best Communications Tool


New champ (again). Last
years winner, RemObjects
SDK (from RemObjects
Software) has to be happy
with runner-up status
this time around. Since
then, Atozed Software has
released a commercial

edition of their popular

open-source Indy product.


Its called Indy Plus and it
took first place with 36%
of the vote.

Muscling in. This category has featured close


competition between
DBISAM Database System (Elevate Software)
and Advantage Database
Server (Extended Systems) for four years running. This year, DBISAM
takes first place again,
while Advantage ties for
runner-up with new player, NexusDB (from Nexus
Database Systems).

FIBPlus (24%)
Direct Access
Components for
MySQL (12%)
IB Objects (10%)
Oracle Data Access
Components (9%)
Advantage TDataSet
Decendant (9%)
other (36%)

DELPHI INFORMANT MAGAZINE | August 2004

Pulling away. After


last years close finish,
IB Expert (HK-Software)
wins again, this time
in convincing fashion
with 25% of the votes.
Woll2Wolls InfoPower
takes runner-up (again)
with 13%, edging out
Developer Express
ExpressQuantumTreeList (again) with 11%.

IB Expert (25%)
InfoPower (13%)
ExpressQuantumTreeList (11%)
EhLib (10%)
other (41%)

Best Debugging Tool


Role reversal. Transposing last years order, AutomatedQAs AQtime steps
up to finish first with 25%,
while Raize Softwares
CodeSite drops to runner-up status with 22% of
your votes. Interestingly,
newcomer EurekaLog
(from Fabio DellAria) finishes a respectable third
with 17%.

AQtime (25%)
CodeSite (22%)
EurekaLog (17%)
madExcept (14%)
other (22%)

Best Globalization Tool


Another switcharoo. This
is getting kinda weird. First
and second place swap
out in this category as well,
with TsiLang Components
Suite (SiComponents) taking Best with 31%, and
MULTILIZER VCL Edition
(MULTILIZER) following
closely with 29%. For the
second year running, Localizer (Korzh.com) takes a
close third with 24%.

TsiLang Components Suite (31%)


MULTILIZER VCL Edition (29%)
Localizer (24%)
QuickLocalizer Component
Suite (9%)
other (7%)

Informant

Spotlight

Readers Choice Awards 2004

Best Help-authoring Package


Help yourself to more.
For the third year in a
row, Help & Manual (EC
Software) dominates this
category and with a
higher percentage than
ever (59% this year, 51%
in 2003, 29% in 2002).
HelpScribble (JGsoft)
and last years runner-up
RoboHelp Office (eHelp
Corp.) tie for second this
year with 12% apiece.

Nothing new here. ModelMaker, Rational Rose,


and CDK (Developer Express) finished one, two,
and three, just as they did last year, and by very
nearly the same
ModelMaker (53%)
percentages.
Rational Rose (16%)

Help & Manual (59%)


HelpScribble (12%)
RoboHelp Office (12%)
Doc-O-Matic (6%)
other (11%)

Best Imaging Tool


A new look. Things got
tossed about a bit in this
category, with last years
third-place product, ImageEn (HiComponents) taking Best with 29%. Meanwhile, last years winners
(it was a tie for first),
ImageLib Corporate Suite
(from SkyLine Tools) and
LEADTOOLS Imaging Toolkit (LEAD Technologies),
now tie for runner-up with
20% apiece.

ImageEn (29%)
LEADTOOLS
Imaging Toolkit (20%)
ImageLib
CORPORATE SUITE (20%)
Billenium Effects (13%)
ImagXpress (6%)
other (12%)

InstallShield (60%)
Wise for Windows Installer (25%)
Ghost Installer Studio (10%)
other (5%)

18

Best Reporting Tool


Race to the swift.
Its been a long time
coming, but FastReport (FastReports)
has finally taken first
place (42%), from
Digital Metaphors
ReportBuilder (33%).

FastReport (42%)
ReportBuilder (33%)
QuickReport
Professional (7%)
Rav BEX (Borland
Edition Extended) (7%)
other (11%)

The same, just more so. This category is three


years old, and has had the same winner and
runner-up for all three years. TMS TPlanner/
TDBPlanner (TMS Software) took first place
with 72% (last year it was 63%), and Jazmine
Calendar/PIM Widgets (Jazmine Components)
took second place with TMS TPlanner/TDBPlanner (72%)
11% (down from last Jazmine Calendar/PIM Widgets (11%)
years 17%).
other (17%)

Best Security Tool


All new lineup. This is the second year for this category, and its
proving to be volatile with a new
cast of characters in first and second place. TMS Security System
(TMS Software) wins with 36%.
StreamSec Tools (StreamSec) and
ICE License (Ionworx Technology)
tie for runner-up with 15% apiece.
Interestingly, none of these products made a ripple last year.

TMS Security
System (36%)
StreamSec Tools (15%)
ICE License (15%)
other (34%)

Best Team/Project Tool

Best Library
Check this out. ExpressBars Suite (Developer
Express) wins again with
a convincing 34% of your
votes. The big story in this
category is that FastScript
(FastReports) has come
out of nowhere to take
19% and second place.

CDK (13%)
other (18%)

Best Scheduling/Calendar

Best Installation Package


Dominance. InstallShield
places first again with an
even wider margin than
last year over runner-up
Wise for Windows Installer.
InstallShield won last year
by 19%; this year the margin is 35%.

Best Modeling/CASE Tool

ExpressBars Suite (34%)


FastScript (19%)
eDocEngine + PDFtoolkit (6%)
ElPack (6%)
other (35%)

DELPHI INFORMANT MAGAZINE | August 2004

Make room! Make room! Also


in its second year, this category
must suddenly make room for
Borlands StarTeam (it wasnt
commercially available as a standalone product last year). Even so,
Team Coherence (Quality Software
Components) managed a tie (at
34%) for first place. AQdevTeam
(AutomatedQA) places third again
with 19%, while last years runner-up PVCS Professional (Merant)
drops to fourth place.

StarTeam (34%)
Team Coherence (34%)
AQdevTeam (19%)
PVCS Professional (9%)
other (4%)

Informant

Spotlight

Readers Choice Awards 2004

Best Testing/QA Tool


Test results. AutomatedQAs
TestComplete dominates
the category with 71% of
the votes (last year it was
60%), while Rational Robot
(IBM Rational) has runnerup to itself with 16%. Last
year Rational Robot shared
runner-up with DevPartnerStudio (Compuware), which
drops to third.

Best VCL Component

TestComplete (71%)
Rational Robot (16%)
DevPartner Studio (10%)
other (3%)

Best Training
Theyre back! After
falling to third place last
year, InfoCan is back on
top with 28%. And after
winning two years in a row,
Jensen Data Systems slips
to runner-up status with
23% of the vote. Dropping
from the runner-up status
they enjoyed last year,
Falafel Software is still a
player with third place
and 16%.

InfoCan Management (28%)


Delphi Developer Days (23%)
Falafel Software (16%)
Keystone Learning
Systems (6%)
other (27%)

Best Utility
Retied. This is a first.
Just as they did last year,
ASPack (from ASPack
Software) and VMware
Workstation (VMware) tied
for first place and with
near identical percentages
(each with 24% as compared to last years 23%).
Beyond Compare in third
place is also an exact repetition of last year.

Victory Express. Your pick for Best VCL


Component is ExpressQuantumGrid (Developer Express) for the fourth year running,
with 40% of the votes (down slightly from
last years 43%), while TAdvStringGrid (TMS
Software) repeats as runner-up in even
more convincing fashion
ExpressQuantumGrid (40%)
(besting last years 16%
TAdvStringGrid (22%)
by six percentage points).
other (38%)

Best VCL Component Set


Consolidation duo. Developer Express wins
in this category too, with its ExpressQuantumPack, for the third year running, this time
with 31% as opposed to the previous years
28% and 22% respectively. TMS Component
Pack (TMS Software) firmed up its runner-up
status with 26% (up from last
ExpressQuantumPack (31%)
years 20%), while Raize Com- TMS Component Pack (26%)
ponents (Raize Software)
Raize Components (13%)
repeats its third-place finish.
other (30%)

Best Web Development Tool


Ditto that. No change in this category either, with last years
winner and runner-up repeating, and by nearly the same percentages. IntraWeb (Atozed Software) takes first easily with just
2 percentage points
less than last year, while
IntraWeb (60%)
ExpressWeb Framework
ExpressWeb
(Developer Express)
Framework (26%)
takes runner-up by one
other (14%)
additional point.

Best Web Host

VMware Workstation (24%)


ASPack (24%)
Beyond Compare (16%)
NexusDB Memory Manager (9%)
other (27%)

Some change. Last years


winner, Defined Systems,
must share first place this
year with 1&1 Hosting (runner-up last year), each with
27% of the votes.

1&1 WebHosting
(27%)
Defined
Systems (27%)
Kylix Host (14%)
other (32%)

Product of the Year

Company of the Year

Surprise! Its another repeat and another tie. Product of


the Year goes to Help & Manual (EC Software) for the second
year in a row. This time however, it must share the honor with
FastReport (FastReports). For historys sake, here are the winners and runners-up for POY since the award began in 1996:
1996 InfoPower, (unknown)
1997 InfoPower, Orpheus
1998 InfoPower, Apollo
1999 ReportBuilder, Orpheus
2000 ReportBuilder, Apollo
2001 ReportBuilder, Advantage Database Server
2002 ReportBuilder, Advantage Database Server
2003 Help & Manual, ExpressQuantumGrid
2004 FastReport and Help & Manual (tie for POY)

No tie! Company of the Year goes to the organization with the


most first-place finishes for the year, and that honor goes to
Developer Express with four. And it wasnt a tie! It was fairly
close however, with Atozed Software right behind with three
first-place wins. And honorable mentions need to go to AutomatedQA and TMS Software with two first-place finishes apiece.

19

DELPHI INFORMANT MAGAZINE | August 2004

Until Next Year


As always, I would like to thank the multitude of Delphi
third-party vendors who create the products that make Delphi development easier and more productive. And, thank
you, gentle reader, for participating in the awards process.
Jerry Coffey is Editor-in-Chief of Delphi Informant Magazine. You can reach
him at jcoffey@DelphiZine.com.

N E W

&

U S E D

By Mike Riley

RemObjects SDK 3.0


The Best Just Got Better

jumped on the opportunity when Delphi


Informant Managing Editor David Riggs asked
if I would be interested in reviewing the latest

release of RemObjects SDK. There is a reason this


toolkit won the 2003 Delphi Informant Readers
Choice Award for Best Communication Tool, and
I wanted to know if this update would keep this
product in the running for 2004. The answer
is a resounding Yes! RemObjects SDK 3.0 is
a stunning piece of technology, one that any
serious Delphi developer designing sophisticated

via this plug-in architecture, as well as enhancements


made to the library editors, validators, and views.
Complementing Service Builder 3 is the brand new Service
Tester, an invaluable benchmarking and load-testing tool
that current RemObjects SDK users will wonder how they
ever lived without (see Figure 2). Test configurations are
established via the six-step New Test Wizard that requires
a running RemObjects-enabled server with which to
connect and interrogate. The Service Tester can then be
easily configured to fire off as many incremental or random
threads and requests (with fixed or random delays) as
necessary to simulate real-world loads.
In addition to SOAP and RemObjects proprietary, yet highly
efficient binary Smart Services, RemObjects-authored

remote object access environments must have.


The product has evolved considerably since Ron Loewy
reviewed the initial release in the July, 2003 issue
of Delphi Informant (Loewys review is available at
www.delphizine.com/productreviews/2003/07/di200307rl_
p/di200307rl_p.asp). Because Loewys evaluation provides
a good foundation of the RemObjects SDK, my appraisal
will focus on the features new to this version.
New and Improved
The most visible change is the SDKs centerpiece for
defining remote services, Service Builder 3, which has
been completely rewritten for this release (see Figure 1).
The redesigned application now sports a consistent UI
and can run outside the Delphi IDE. Its also instrumental
in generating remote code stubs. The plug-in architecture
provides advanced developers ways to further expand the
products capabilities. For example, code generators for
other language syntax, such as C# and Java, can be added
20

DELPHI INFORMANT MAGAZINE | August 2004

Figure 1: One of the more visibly notable improvements from previous versions is
the completely rewritten Service Builder 3.

New

&

Used

RemObjects SDK 3.0

Figure 2: The Service Tester performance measurement application is an


invaluable addition to the RemObjects toolkit.

servers can now be accessed from any COM-consuming


languages and Windows scripting languages, such as VBA
and ASP. The RemObjects Server options have also been
dramatically improved via integrated load-balancing and failover support. Developers also now have the ability to create
a Combo Server, a single executable that can be registered
as an NT service or executed instead as a standalone
application. This feature is probably most effective during
debugging so as not to have to cycle through service
register/un-register configurations to test the build. It also
provides flexibility to system administrators concerned about
installing a green NT service in a production environment.
And because RemObjects servers have these new distributed
server features, a new Master Server monitor application has
been provided to synchronize session data across multiple
RemObjects servers on the same or different machines.
Enhancements to the client components have also been
made in the form of a PostMessage messaging type
component, server-client callback and event messages,
Variant type support, and a Dynamic Request component
that allows server calls to be dynamically generated in
real-time (see Figure 3). It also supports the Synapse
library of synchronous (blocking) TCP/IP communications

Just the Facts


RemObjects SDK 3.0 is a multi-tiered remoting framework
that builds on an award-winning toolkit designed to
develop, test, and deliver distributed network application
solutions. It can be used to construct services running as
Windows or Linux clients and servers and provide SOAPbased and other network standard protocols such as UDP,
SMTP, and POP3 to service a wide range of languages and
architectures.
RemObjects Software, Inc.
Contact: info@remobjects.com
Web Site: www.remobjects.com
Price: Visit the RemObjects Web site for complete details.

21

DELPHI INFORMANT MAGAZINE | August 2004

Figure 3: More than 35 RemObjects SDK components are exposed on the


Delphi IDE palette.

New

&

Used

RemObjects SDK 3.0

Figure 4: The MegaDemo client/server project provides an effective


advertisement for the power and flexibility that the RemObjects SDK provides.

mode (visit www.ararat.cz/synapse/about.htm for more


information about this slick Delphi freeware library). Given
the numerous methods by which RemObjects allows for
message connectivity, Delphi developers will rarely be at
a loss for developing a cross-platform, standards-based,
language-neutral distributed application messaging solution.
Comprehensive and Complex
RemObjects is a sophisticated product. As such, the
learning curve is steep and will require many hours
to dedicate to tinkering with and understanding the
30+ installed sample projects. The MegaDemo project
should be the first one executed, as it introduces new
users to the wide array of data types and messaging that
RemObjects can support (see Figure 4). Recognizing
the depth, complexity, and power that the product
provides, RemObjects Software offers a healthy list
of technical articles on their Web site, available at
www.remobjects.com/articles.
Conclusion
RemObjects SDK 3.0 is a sophisticated toolkit that elevates
Delphi developers to a higher level of distributed computing
complexity. It offers one of the most comprehensive
compilations of remote function call libraries available for
the Delphi programming community today. The products
learning curve is steep, but the rewards and the flexibility
of protocols are worth the investment. This latest release
has further solidified RemObjects leadership position in
the Delphi communications and distributed object market,
and I highly recommend it for advanced remote application
messaging needs.

Mike Riley is an advanced computing professional specializing in emerging


technologies and new development trends. Readers may contact him at
mike@mikeriley.com.
22

DELPHI INFORMANT MAGAZINE | August 2004

T E X T F I L E

Refactoring: Improving the Design


of Existing Code
S

ome readers may recall that in


my December 2003 File | New
column, titled Extreme Reading, I
promised a more detailed review of
Martin Fowlers Refactoring: Improving
the Design of Existing Code. I stated
that I considered this book to be in
a class by itself ... an essential reference for any developers library along
with works like Steve McConnells
Code Complete. Fowlers writing style
is superb. Its always clear, includes
excellent examples, and features an
abundance of humor.
The book is divided into two parts.
The first half discusses general principles and is worth reading in its
entirety. The second half is a catalogue
of specific refactoring techniques. But
if youre expecting examples in Delphi,
youll be disappointed: Fowler uses
Java for his refactoring examples. However, there is a section at the end that
discusses refactoring using C++.
From the outset, Fowler demonstrates
an approach he much prefers: using real
code examples to present refactoring
principles that would otherwise be quite
abstract. This approach works very well.
Throughout the first half of the book he
develops a business application, using
both code and UML diagrams. Throughout the book Fowler also emphasizes
another vital XP practice: testing. In
23

DELPHI INFORMANT MAGAZINE | August 2004

fact, after a careful examination of


statements, conditional logic, and other
issues, the section concludes with a
small chapter on using JUnit (the predecessor of DUnit) to build tests.
The remaining three-quarters of the
book presents a detailed catalogue of
refactoring techniques, again with specific before and after code fragments.
Fowler organizes these approaches into
groups, such as those related to methods, features, data, and so on. I was
especially intrigued with the relationships between the refactoring methods,
with some of them arranged in pairs.
Each member of a particular pair
performs the opposite task as its companion, such as Extract Method and
Inline Method. The point that Fowler
makes is important: Dont get fixated
on one particular approach, but, rather,
refactor intelligently.
This is one book that will benefit any
developer who has the responsibility
for writing and/or maintaining code.
The refactoring catalog alone, or even
the short chapter titled Bad Smells
in Code co-written by Kent Beck,
makes this an essential reference. I
highly recommend it.
Alan C. Moore, Ph.D.

Refactoring: Improving the


Design of Existing Code
by Martin Fowler,
Addison-Wesley, 1999,
www.aw-bc.com.
ISBN: 0-201-48567-2
Cover Price: US$44.95
(431 pages)

F I L E

N E W

Adventures in Refactoring

By Alan C. Moore, Ph.D.

his is an account of a project in which I have been


involved for several years. Let me admit at the outset however, that it doesnt show this humble columnist
in the best possible light. Rather, it could easily serve as
my application for entry into Procrastinators Anonymous.
But at least it has a good ending.
Bob Swart has been a friend and supporter of Project JEDI
from the beginning. He was one of the first in the Delphi
community to provide a link to the JEDI site, and early on
made his popular header converter tool, HeadConv, available
to those working in the Project to translate header files. Over
the years Bob produced a number of versions of the tool,
improving its functionality and effectiveness. But around the
time of the Borland Conference in Philadelphia, he came to
the realization that he was simply too busy with other matters to devote further time to updating HeadConv.
I forget who initiated the conversation Bob or me but
I do remember requesting that he release the source code to
Project JEDI. He was certainly open to the possibility, but
he had a major reservation. He said he considered the code
something of a hack in need of cleaning up. Knowing
Bob as one of the recognized gurus in the community, and
having seen his considerable expertise in various venues,
I took his remark as too modest. But I immediately volunteered to do whatever I could to help clean up the code.
Only after Bob sent me the code did I finally understand his
concerns. HeadConv consisted of a single file. The largest
portion of that file was a single routine that went on for pages
and pages of code. And that routine consisted of a complex
series of nested conditional (if..else) statements. However, the
code was well-formatted and not that hard to read.
I immediately came up with a plan that proved to be
successful at least to a point. That approach would
eventually lead to the release of the source code to Project JEDI and the greater Delphi community at the time of
the release of Delphi 7. The first part of my plan involved
dividing the large unit into three units: a main parsing
unit, a unit of global variables, and a unit containing
utilities. I presented the plan to Bob. Not only did he
agree with me, but he went ahead and did this first part
himself, sending the new version back to me!
24

DELPHI INFORMANT MAGAZINE | August 2004

Greatly inspired, I devoted myself to refactoring the huge


parsing unit, HeadPars. That unit consisted of a large number of conditional if..then and if..then..else statements
nested five or six levels deep. I began with the outermost
levels, transforming the if..then statements themselves into
Boolean functions and the remainder into procedures. Bobs
comments were very helpful in suggesting names for these
routines. If this discussion strikes you as rather abstract up
to this point, let me provide a specific example. Heres the
original code fragment:
if (Pos('#ifndef', Str) = com) and (com = com1) then
begin
Delete(Str, 1, com + 6);
SkipSpaces(Str);
Writeln(tmp, '{$IFNDEF ', Str, '}')
end

The refactored fragment is as follows, first creating the


routines:
function IfNDefFound: Boolean;
begin
IfNDefFound :=
(Pos('#ifndef',Str) = com) and (com = com1);
end; { IfNDefFound }
procedure ProcessIfNDef;
begin
Delete(Str, 1 , com+6);
SkipSpaces(Str);
Writeln(tmp, '{$IFNDEF ',Str,'}')
end; { ProcessIfNDef }

and then calling those routines in the following context:


begin { ProcessCompilerDirective }
if IncludeFound then ProcessInclude
else
if TypeFound then
if IfDefFound then ProcessIfDef
else
if IfNDefFound then ProcessIfNDef
else
if IfDefinedFound then ProcessIfDefined
else
if IfNotDefinedFound then ProcessIfNotDefined
else WriteIfDef
else ProcessConditional;
end; { ProcessCompilerDirective }

File

New

Adventures in Refactoring

This example is from my most recent, and finally


successful, efforts. But those efforts before the release
of Delphi 7 were not successful. Although I was able to
compile that first refactored HeadPars unit, it did not
produce output as good as Bobs original code. And Bob
will be (and has been) the first to admit that the output
from HeadConv is not perfect and that some handiwork
is often needed. But the refactored code should be much
easier to maintain and modify, so there is hope that the
tool will become more reliable in the future.
We took one additional step with the initial Project JEDI
release that greatly increased the friendliness of the tool:
We created a Windows graphical user interface (GUI) for
the tool. Thats right! It had lived as a command-line tool
up to that point. Among other things, the GUI displayed
both the original C header file and the resulting Pascal
file. Not only did this new structure make it easier for
users, it made it much easier for me to finally complete
the refactoring. I didnt try to find the bugs in the earlier
attempt, but rather, started over. With each revision
(which usually involved the creation of no more than
two or three routines at a time), I ran the program with
Bobs test header file and made certain that the output
remained consistent.
I am hopeful that the new version of HeadConv will be
available when this column is published. I heard from
Bob as I was writing this article; he indicated that he
was very satisfied. I also shared the revised code with
Project JEDIs DARTH team. Once that team approves it,
well release a new version of HeadConv. That release
will probably include a number of other changes beyond
the ones Ive written, and could be another story itself
(managing an open source project). Regardless of the
nature of the next release, I expect there will continue
to be additional refactoring in the future. After all, this
is the approach that people in the Extreme Programming
community recommend. But I think the major emphasis
will shift to improving the effectiveness of the code.

Alan Moore is a professor at Kentucky State University, where he teaches


music theory and humanities. He was named Distinguished Professor for
2001-2002. He has been named the Project JEDI Director for 2002-2005. He
has developed education-related applications with the Borland languages
for more than 15 years. Hes the author of The Tomes of Delphi: Win32
Multimedia API (Wordware Publishing, 2000) and co-author (with John
C. Penman) of The Tomes of Delphi: Basic 32-Bit Communications
Programming (Wordware Publishing, 2003). He also has published
a number of articles in various technical journals. Using Delphi, he
specializes in writing custom components and implementing multimedia
capabilities in applications, particularly sound and music. You can reach
Alan at acmdoc@aol.com.

25

DELPHI INFORMANT MAGAZINE | August 2004

Vous aimerez peut-être aussi