November 2001, Volume 7 Number 11: On The Cover
November 2001, Volume 7 Number 11: On The Cover
November 2001, Volume 7 Number 11: On The Cover
ON THE COVER
5
On the Net
FEATURES
10
15
REVIEWS
27
Kylix Tech
30
31
Delphi at Work
19
23 At Your Fingertips
Floating Menus, Etc. Bruno Sonnino
DEPARTMENTS
2
32
35
Delphi Tools
File | New by Alan C. Moore, Ph.D.
Symposium by Jerry Coffey
Delphi
T O O L S
New Products
and Solutions
Book Picks
XML by Example,
Second Edition
Benot Marchal
QUE
ISBN: 0-7897-2504-5
Cover Price: US$29.99
(495 pages)
http://www.quepublishing.com
ISBN: 0-201-72163-5
Cover Price: US$39.99
(300 pages)
http://www.awl.com/cseng
Delphi
T O O L S
New Products
and Solutions
Book Picks
User Interface Design
for Programmers
Joel Spolsky
Apress
ISBN: 0-201-73397-8
Cover Price: US$29.99
(159 pages)
http://www.awl.com/cseng/xp
Delphi
T O O L S
New Products
and Solutions
Book Picks
Mastering Delphi 6
Marco Cant
SYBEX
ISBN: 0-7821-2874-2
Cover Price: US$59.99
(1,129 pages, CD-ROM)
http://www.sybex.com
PocketStudio is easy to
learn and use, makes creating
complex and powerful applications simple and intuitive,
helps developers get products
to market quickly, and allows
PC developers to easily migrate
to Palm OS development.
Pocket Technologies, Inc.
Price: US$499.99
Contact: [email protected]
Web Site:
http://www.pocket-technologies.com
On the Net
By Keith Wood
n the August issue of Delphi Informant Magazine, I introduced you to the Simple Object
Access Protocol (SOAP) as a way of calling methods on remote objects. I presented a
series of components that allowed your Web application to respond to requests encoded
in SOAP. Thus, you could write a SOAP application by dropping two components on the
Web module, creating an action, and writing an event handler for it.
With the advent of Delphi 6 Enterprise Edition,
creating SOAP applications is just as easy. Delphi
6 goes further to provide direct support for parameter types other than strings, including structured
types. It also automatically generates another essential part of using SOAP: the Web Services Description Language (WSDL) file that allows others to
make use of your service.
This article describes the full process of creating your
own Web Service, one that finds movies given a
certain rating, and creating a client application that
makes use of it. Since Web Services are languageand platform-neutral, you also can call on other
services to add functionality to your application. To
demonstrate, the client imports and then invokes a
service that sends out e-mails, so you can inform
friends about the results of your movie search.
On the Net
Invocation Wizard
Now, you get to use the new wizard you downloaded to create the
interface and implementing class for your Web Service. Again, in
the New Items dialog, on the WebServices tab, open the Invokable
Interface & Class Wizard (see Figure 3) and enter your details. What
youre creating is an interface that defines the functionality available
through your Web Service, and a class that implements those abilities.
By deriving from TInvokableClass, you gain a virtual constructor
that lets you initialize your objects easily. As in the previous SOAP
article, the Web Service involves finding the names of movies with a
particular rating for a nights entertainment.
The result of using this wizard is two units: one for the interface, and
one for its implementation. Its good practice to separate the interface
from the implementing class, because this lets you reuse the interface
without reference to a particular way of performing its actions. Youll
make use of the interface in the client part of this Web Service later.
Within the interface declaration the wizard has created, you just enter
functions and procedures that define the required functionality. Make
sure they all have the stdcall directive, so other processes can easily
access them.
Any types to which you refer in these methods must be encodable
within SOAP. The references to the Types and XSBuiltIns units
provide you with all the basic types (such as strings, integers, and
6 November 2001 Delphi Informant Magazine
On the Net
FindMovies Client
WSDL
You can immediately see the WSDL associated with your Web
Service by accessing the following URL from your browser
(assuming a default deployment):
http://localhost/scripts/MovieSvc.exe/wsdl
Third-party Services
This is great for Delphi Web Services, but what about other ones?
One of the big promises of Web Services is that you can write
them in any language on any platform and can access them from
anywhere. Can Delphi use these other services too? Of course.
To start, you need to locate the WSDL for the required
service. One place to look is at the XMethods site (http://
www.xmethods.com), a repository of Web Service definitions.
Looking down the list, you can see quite a few already implemented using Delphi.
On the Net
{ Retrieve array of movies matching specified rating.
Trap any exception from the Web Service and display it.
Otherwise place the movie names into the memo. }
procedure TfrmMovieServices.btnSearchClick(
Sender: TObject);
var
Results: TStringDynArray;
Index: Integer;
begin
Screen.Cursor := crHourGlass;
try
memResults.Lines.Clear;
try
Results := (rioMovies as IFindMovies).FindMovies(
cmbRating.Items[cmbRating.ItemIndex]);
for Index := 0 to High(Results) do
memResults.Lines.Add(Results[Index]);
except on e: Exception do
MessageDlg('This problem occurred:'#10#13 +
e.Message, mtError, [mbOK], 0);
end;
finally
Screen.Cursor := crDefault;
end;
end;
unit EmailIntf;
interface
uses Types, XSBuiltIns;
type
Email_cemailPortType = interface(IInvokable)
['{05D28B3D-05FA-4240-BFB7-1CDCC0415442}']
function SendAnonymousEmail(const sFrom: WideString;
const sTo: WideString; const sSubject: WideString;
const sMessage: WideString): Boolean; stdcall;
end;
implementation
uses InvokeRegistry;
initialization
InvRegistry.RegisterInterface(TypeInfo(
Email_cemailPortType), '', '', '',
'Email.cemailPortType');
end.
Conclusion
Support for SOAP and Web Services is an important new feature of
Delphi 6. Writing a service consists of invoking two wizards and writing your interface method declarations and implementations. Delphi
automatically handles the processing of the SOAP messages coming
in and going out.
For a Web Service client, you can reuse the server-side interface in
conjunction with a THTTPRIO component to access the service
remotely. Then, the rest of your code is no different from calling
something locally. You even deal with exceptions the same way you
usually do. Third-party Web Services are processed through another
wizard to generate a Pascal interface for them, which is then used
with a THTTPRIO component as before.
Delphi 6 makes it easy to write Web Services applications and their
clients, and still have the full power of the Object Pascal language
at your disposal.
References
For SOAP references, go to http://www.w3c.org/TR/SOAP/ and
http://www.w3c.org/TR/soap12/. For information about WSDL,
see http://www.w3.org/TR/wsdl. The X-Methods Web Services
repository is at http://www.xmethods.com.
The files associated with this article are available on the Delphi Informant Magazine Complete Works CD located in INFORM\2001\NOV\
DI200111KW.
Keith Wood is a system engineer with Ellora Software, based near Boston. He
started using Borlands products with Turbo Pascal on a CP/M machine. Often
working with Delphi, he has enjoyed exploring it since it first appeared. Readers
may reach him via e-mail at [email protected].
On the Net
Begin Listing One Implementing the Web Service
unit FindMoviesImpl;
initialization
InvRegistry.RegisterInvokableClass(TFindMovies);
end.
<?xml version="1.0"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
name="IFindMoviesservice"
targetNamespace="http://www.borland.com/soapServices/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="urn:Types">
<types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:Types">
<xs:complexType name="TStringDynArray">
<xs:complexContent>
<xs:restriction base="soapenc:Array">
<xs:sequence/>
<xs:attribute ref="soapenc:arrayType"
n1:arrayType="xs:string[]"
xmlns:n1="http://schemas.xmlsoap.org/wsdl/"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
</types>
<message name="FindMoviesRequest">
<part name="Rating" type="xs:string"/>
</message>
<message name="FindMoviesResponse">
<part name="return" type="ns1:TStringDynArray"/>
</message>
<portType name="IFindMovies">
<operation name="FindMovies">
<input message="FindMoviesRequest"/>
<output message="FindMoviesResponse"/>
</operation>
</portType>
<binding name="IFindMoviesbinding" type="IFindMovies">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="FindMovies">
<soap:operation
soapAction=
"http://www.the_movies.com/FindMovies#FindMovies"/>
<input>
<soap:body use="encoded"
encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/"
namespace=
"http://www.the_movies.com/FindMovies"/>
</input>
<output>
<soap:body use="encoded"
encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/"
namespace=
"http://www.the_movies.com/FindMovies"/>
</output>
</operation>
</binding>
<service name="IFindMoviesservice">
<port name="IFindMoviesPort"
binding="IFindMoviesbinding">
<soap:address
location=
"http://localhost/scripts/MovieSvc.exe/soap/IFindMovies"/>
</port>
</service>
</definitions>
interface
uses
SysUtils, Types, FindMoviesIntf, InvokeRegistry,
DB, DBTables;
type
TFindMovies = class(TInvokableClass, IFindMovies)
private
FQuery: TQuery;
public
constructor Create; override;
destructor Destroy; override;
function FindMovies(Rating: string):
TStringDynArray; stdcall;
end;
implementation
constructor TFindMovies.Create;
begin
inherited Create;
FQuery := TQuery.Create(nil);
with FQuery do begin
DatabaseName := 'Movie-watcher';
SQL.Add('SELECT Name FROM Movie');
SQL.Add('WHERE :rating = '''' OR :rating = rating');
ParamByName('rating').DataType := ftString;
Prepare;
end;
end;
destructor TFindMovies.Destroy;
begin
FQuery.Free;
inherited Destroy;
end;
function TFindMovies.FindMovies(Rating: string):
TStringDynArray;
var
Index: Integer;
begin
with FQuery do
try
ParamByName('rating').AsString := Rating;
Open;
if RecordCount = 0 then
raise Exception.Create(
'No movies found for rating ' + Rating);
SetLength(Result, RecordCount);
Index := 0;
while not EOF do begin
Result[Index] := FieldByName('name').AsString;
Inc(Index);
Next;
end;
finally
Close;
end;
end;
By Alex Fedorov
n the previous articles of this series (in the August through October 2001 issues),
we looked at basic data querying techniques that allow us to use the XML features
of Microsoft SQL Server 2000 from our Delphi applications. This months article will
concentrate on using Delphi data-aware controls with XML data sources.
As mentioned in Part I of this series, the XMLDATA
option allows you to extract XML-formatted metadata along with regular data. This month, well use
this feature to connect XML-based data with Delphi
data-aware controls.
There are two distinct parts: The first is the description of the table itself along with a column list,
and the second describes the columns. For each
column theres an <ElementType> element with four
attributes. For this example, were only interested
in the name and dt:type attributes. The name
attribute contains the name of the column, while
dt:type specifies the XML data type of the column.
The urn:schemas-microsoft-com:datatypes
namespace is used to declare the data types within
the schema document. Data type namespaces are
returns an XML document that contains the representation of metadata shown in Figure 1 (the data
part is omitted).
Data Type
Description
bin.base64
bin.hex
boolean
char
date
dateTime
dateTime.tz
fixed.14.4
float
int
number
time
time.tz
i1
i2
i4
i8
r4
r8
XML RAW, FOR XML AUTO, and FOR XML AUTO, ELEMENTS
statements. Depending on which type of the statement you choose,
youll get a different representation of metadata (representation of data
was discussed earlier in this series). For example, in RAW and AUTO
mode, you get <AttributeType> elements (see Listings One and Two
on page 13), and in AUTO, ELEMENTS mode, <ElementType>
elements. (For this example, youll use AUTO, ELEMENTS mode.)
First, place a button into an empty Delphi form, and write the OnClick
event handler shown in Figure 3.
This code creates an instance of Microsoft XML Parser and executes the SQL query against the IIS virtual directory that maps
to the Northwind database on SQL Server. The resulting XML
document is loaded into XML Parser and is ready to be processed.
Creating a client dataset. Next, prepare an empty client dataset so
it can be filled with the data extracted from SQL Server. You need
to reference the DBClient unit by adding it to the uses clause. The
following code creates and initializes a new empty client dataset,
where the DS variable is declared of TClientDataSet type:
// Create client dataset.
DS := TClientDataSet.Create(Self);
ui1
ui2
ui4
ui8
uri
uuid
SQL Server
Delphi
i4
string
int
nvarchar, varchar,
char, ntext
money
smallint
bit
image
datetime
uniqueidentifier
real
ftInteger
fixed.14.4
i2
boolean
uri
datetime
uuid
r4
ftString
ftCurrency
ftSmallInt
ftBoolean
ftString
ftDateTime
ftGUID
ftFloat
else if XD = 'string'
else if XD = 'fixed.14.4'
else if XD = 'i2'
else if XD = 'boolean'
else if XD = 'uri'
else if XD = 'datetime'
else if XD = 'uuid'
else if XD = 'r4'
else
XD2DF := ftString
end;
The Nodes variable (of IXMLDOMNodeList type) will now contain all <ElementType> nodes found in the XML document. You
can iterate this collection and extract any particular node that will
represent one field in the table. The first node contains a table
definition, so skip it:
for I := 1 to Nodes.Length-1 do begin
Node := Nodes[I];
...
end;
This will fill the Nodes collection with data that can be iterated
by your code. Use two iterations: one for iterating an individual
record (appending a new record by using the Append method of
the client dataset), and the other for iterating the fields in one
record. The entire process involved in filling your dataset with
data is shown in Figure 7.
Now run the application, and use the DBNavigator and DBGrid
to navigate the data extracted from SQL Server using its XML
features. The sample application is shown in Figure 8. Listing
Three (on page 14) shows all of the source for the main form.
Conclusion
Weve seen how to extract XML metadata from SQL Server using
XML documents, and we covered processing this metadata to use
Delphi data. Weve also observed how the powerful Delphi client
dataset component can be used as a bridge between an alien data
source and Delphi data-aware controls. Mapping XML Data data
types to Delphi field types was discussed, as well.
Next month, well complete this five-part series by learning how
to insert, update, and delete data, as well as how to process errors.
See you then.
The example project referenced in this article is available on the
Delphi Informant Magazine Complete Works CD located in INFORM\
2001\NOV\DI200111AF.
Alex Fedorov is a Chief Technology Officer for Netface SA, based in Lausanne,
Switzerland (http://www.netface.ch). He was one of the co-authors of Professional
Active Server Pages 2.0 (Wrox, 1998) and ASP Programmers Reference (Wrox,
1998), as well as Advanced Delphi Developers Guide to ADO (Wordware, 2000).
<Schema name="Schema1"
xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:datatypes">
<ElementType name="row" content="empty" model="closed">
<AttributeType name="ProductID" dt:type="i4"/>
<AttributeType name="ProductName" dt:type="string"/>
<AttributeType name="SupplierID" dt:type="i4"/>
<AttributeType name="CategoryID" dt:type="i4"/>
<AttributeType name="QuantityPerUnit" dt:type="string"/>
<AttributeType name="UnitPrice" dt:type="fixed.14.4"/>
<AttributeType name="UnitsInStock" dt:type="i2"/>
<AttributeType name="UnitsOnOrder" dt:type="i2"/>
<AttributeType name="ReorderLevel" dt:type="i2"/>
<AttributeType name="Discontinued" dt:type="boolean"/>
<AttributeType name="Photo" dt:type="bin.base64"/>
<attribute type="ProductID"/>
<attribute type="ProductName"/>
<attribute type="SupplierID"/>
<attribute type="CategoryID"/>
<attribute type="QuantityPerUnit"/>
<attribute type="UnitPrice"/>
<attribute type="UnitsInStock"/>
<attribute type="UnitsOnOrder"/>
<attribute type="ReorderLevel"/>
<attribute type="Discontinued"/>
<attribute type="Photo"/>
</ElementType>
</Schema>
ftInteger
ftString
ftCurrency
ftSmallInt
ftBoolean
ftString
ftDateTime
ftGUID
ftFloat
ftString
Delphi at Work
By Ron Nibbelink
User-modifiable DBGrids
Setting Column Appearance, Order,
and Width at Run Time
ere was my problem: Some of my customers like to resize the screens, and others
like to be able to specify the order and widths of the columns. But I hate to see
unfilled space at the edge of the grid, and whenever possible Id rather avoid a
horizontal scroll bar across the bottom of the grid.
At first, I just didnt make resizing available to users.
I carefully set the column widths, and there they
stayed. In the end, however, the customers won,
and I began to develop the techniques described
in this article techniques for adding, sizing, and
otherwise modifying a DBGrids columns at run
time. It also contains a way of saving and restoring
user selections, so you can make them persistent.
Delphi at Work
const
EmplGridCols: array[TEmplGridCols] of TGridColDesc =
{ egcEmpNo } ((FldName: 'EmpNo';
Alignmt: taRightJustify; ColCapt: 'Emp #';
CaptAlign: taCenter; MinWidth: 0; VarWidth: 0),
{ egcLastName } (FldName: 'LastName';
Alignmt: taLeftJustify; ColCapt: 'Last Name';
CaptAlign: taCenter; MinWidth: 135; VarWidth: 6),
{ egcFirstName } (FldName: 'FirstName';
Alignmt: taLeftJustify; ColCapt: 'First Name';
CaptAlign: taCenter; MinWidth: 117; VarWidth: 4),
{ egcPhoneExt } (FldName: 'PhoneExt';
Alignmt: taCenter; ColCapt: 'Phone Number';
CaptAlign: taCenter; MinWidth: 97; VarWidth: 2),
{ egcHireDate } (FldName: 'HireDate';
Alignmt: taCenter; ColCapt: 'Hired';
CaptAlign: taCenter; MinWidth: 75; VarWidth: 0),
{ egcSalary } (FldName: 'Salary';
Alignmt: taRightJustify; ColCapt: 'Salary';
CaptAlign: taCenter; MinWidth: 75; VarWidth: 2));
width of the columns. It adds the MinWidth values, plus the width of
separator lines between the columns. The remaining width is available
for distribution among the columns.
The routine then uses the VarWidth values to give each column its
proportion of the remaining space. For example, suppose a grid has
four columns and the VarWidth values are 0, 3, 1, and 6, for a total
of 10. The first column gets no extra space, because its VarWidth is
0. The second column gets three-tenths of the remaining width, the
third one-tenth, and the fourth six-tenths. Any extra pixels left from
rounding are given to the last column. Conversely, if rounding takes a
few too many pixels, they are taken from the last column.
To use the TGridColDesc records, add the VCL_Util unit to your
project and include it in the uses clause of each unit that contains
a DBGrid. Then add an enumerated type for each grid, listing
all its columns that you may want to display in the grid. (This
can include calculated fields as well as normal data fields.) Create
the enumerated type value names by adding a common prefix of
lowercase characters to each database field name. At least the first
character of the field name part of the type value name must
be capitalized. (This naming convention becomes crucial if you
want to save and restore user column settings.) For the sample
employee.db table that ships with Delphi, the enumerated type
declaration might look like this:
type
TEmplGridCols = (egcEmpNo, egcLastName, egcFirstName,
egcPhoneExt, egcHireDate, egcSalary);
Delphi at Work
according to the values in EmplGridCols. Now your grid
columns fit your grid, and your application looks professional.
The net effect of this effort is that you or your user can set
the form width at will, and the columns will shrink or widen
to take up the available space, all with very little effort on your
part. Figure 2 shows the default column layout for the sample
database. In Figure 3, the column widths have been specified
and the program has called procedure SetGridCols to rebuild
the columns list.
How It Works
The VCL_Util unit contains the two routines that retrieve and
set column information. The first one is a function that returns a
string containing the names, and optionally widths of the
columns. The second routine uses a string in the same format to
set the columns: which fields, in what order, and how wide.
The GetGridColList function starts by capturing the lowercase letters that prefix the enumerated type value names. In the example
above, the prefix is egc. The routine then extracts the database
field name from each column in the grid. It concatenates the
prefix and the field name, and adds it to the function result string.
17 November 2001 Delphi Informant Magazine
Figure 4: The example SetCols form provides a visual way for the
user to select the columns to be displayed in a grid. It also allows
the user to change the order in the Visible Columns list box.
Delphi at Work
Other Goodies
The SplitStr function, a utility in the VCL_Util unit, was mentioned earlier in this article. It accepts a string and a delimiter
character as parameters and returns a TStringList. The routine
breaks the string at each delimiter character, and adds the substrings to the list. If two delimiter characters are adjacent, the
list gets an empty string for that element. Similarly, if the first or
last character is the delimiter, the list begins, or ends, respectively,
with an empty string.
This routine has proven very useful in numerous situations. For
example, I frequently store the location and size of a form so
the program can put it back there the next time the user starts
the application. In the users INI file (or in the user database),
I store a string containing the forms Left, Top, Width, and
Height properties as numbers separated by commas, for example,
120,86,450,275. When I retrieve the string, I pass it to the
SplitStr function. I can then call the forms SetBounds method with
Strings[0], Strings[1], etc. as the parameters.
Another use for SplitStr has been in passing a short list of IDs,
codes, or other values as a parameter to a routine. I can build up
the list as a comma-delimited string, and let the called routine
separate it out and use it as needed. This is especially useful if
the program needs to present the list to the user for approval in a
MessageDlg-generated dialog box.
Also in the VCL_Util unit is the declaration of an object named
TStringObj. Its simply a descendant of TObject that holds an
integer and a TStringList. In programming, I use a lot of short
keys or codes to reference longer strings. For example, we may
have manufacturing defect codes along with full descriptions, or a
key based on a persons name along with the full name. Sometimes
Ill want to view the one, but need to have the other readily
accessible. At other times, I may need them switched around.
In these situations, its very handy to associate a TStringObj object
with each string in a TStringList. Instead of calling the Add(S1)
or Insert(S1) method, I load strings by calling AddObject(S1,
TStringObj.Create(S2)), or InsertObject(...). For every Strings[i] in
the list, I can then access the associated string by referencing
TStringObj(Objects[i]).S. For example, the SetCols unit (described
earlier) uses TStringObj objects to keep the columns database field
names associated with the visible column titles. It uses the objects
integer to store the original width of the column.
Conclusion
These techniques have allowed me to provide more powerful,
better-looking programs in less time. If nothing else, I no longer
have to carefully size and align the individual columns or work
with the Columns editor. They also provide users with the ability
to customize the grid columns to meet their needs. The capability
also helps when the same form is used to list data from various
tables. Rather than have a separate grid on each of several pages,
I just swap the column descriptions. When the user switches from
one table to the other, the program just resets the columns.
All source referenced in this article is available on the Delphi Informant Magazine Complete Works CD located in INFORM\2001\NOV\
DI200111RN.
Ron Nibbelink develops PC database applications for the Quality and Process
Improvement organization of the Wichita, Kansas Division of the Boeing Commercial Airplane Group. He has developed applications on a variety of platforms
and in several languages since 1983.
Kylix Tech
Kylix Open Edition
By Ray Lischner
An Open Invitation
An Introduction to Kylix Open Edition
s a Delphi programmer, you probably have been deluged with information about
Kylix. But your main focus as a programmer has always been Windows, and may
remain Windows for some time to come. Nonetheless, you owe it to yourself and your
career to keep abreast of developments in the Linux world. Kylix is a natural next step,
and Borland has made Kylix Open Edition available as a free download, so theres no
reason not to take a closer look. This article guides you through the steps necessary
to install and run Kylix OE.
Installing Kylix OE
Kylix Tech
Of course, the biggest difference
between Kylix and Delphi is CLX.
Instead of the VCL, Kylix has a
new component library, CLX (pronounced clicks). The main system
and utility units also have been
reorganized to accommodate CLX
and the Linux environment. As you
might expect, theres no Windows
unit on Linux. Instead, there is libc.
(Irrelevant aside: Linux is written in
C, so the C run-time library is the
Linux run-time library. In Linux, as
with all flavors of UNIX, libraries
are named with an initial lib followed by the rest of the name.
By convention, all names are lowercase. Thus, the C library is called
libc.) The Windows unit held
some useful type declarations, so
the portable types were extracted
into the Types unit. Support for
the Variant type was moved into its
own unit, Variants. These changes
also took place in Delphi 6, which
makes it easier to port code between
Kylix and Delphi 6.
Running Kylix
Once youve installed Kylix, run startkylix as your self (not root).
The first time you run Kylix, it asks for your serial number and
authorization key. Borland sends them to the e-mail address you supplied when you downloaded Kylix. You need these to continue. Once
youve entered your key, Kylix asks for a Borland Community name
and password. If you arent a member, you can create a username on
the fly. If you skip this step, Kylix exits immediately.
Once youre actually running Kylix, youll see a dialog box telling you
its generating a Font Matrix. It should show a percent progress. Once
it reaches 100 percent, the dialog box disappears, and you can see
the normal Kylix splash screen. If you dont see the percent progress,
dont worry. Just wait about a minute, and then close the dialog box.
Finally, youll see the familiar Delphi interface, except this is Kylix
running on Linux (see Figure 1).
Kylix 1 is a port of Delphi 5, so you can apply your Delphi experience
to customize the Kylix environment. Choose a different editor font or
editor colors. For example, I always turn on hints and warnings in the
default project options, and the options are in the same options dialog
box in Kylix 1 as in Delphi 5. Almost everything works the same as
it does in Delphi 5. Some things are missing, such as Delphi Direct
(raise your hand if you think this is an improvement). Some Delphi 6
features found their way into Kylix, such as the new, improved Code
Insight and support for environment variables.
20 November 2001 Delphi Informant Magazine
Kylix Tech
Next, build dclindy.dpk. You can choose to install it from the Indy
source directory, or you can copy it to the Kylix bin directory
and install it from there. Lets say you copied (using cp -d) the
dclindy.so.* files to the Kylix bin directory. To install the package,
choose Component | Install Packages from the menu bar, click the
Add button, and find the Kylix bin/dclindy.so.6 file. Click OK, and
you should see three new tabs on the Component palette: Indy
Clients, Indy Servers, and Indy Misc. Indy comes with demos for a
variety of Internet utilities, from e-mail clients to Web servers.
FreeCLX
Borland has released the source code for BaseCLX (the core runtime library, such as System.pas and Classes.pas) and VisualCLX
(the basic visual components), plus the database components and
data-aware visual components. They call this collection of code
FreeCLX. Anyone may download the sources from SourceForge
(http://freeclx.sourceforge.net) under the GNU General Public
License. If you own a commercial edition of Kylix, you may download and use FreeCLX under your commercial Kylix license.
By downloading FreeCLX, you can take advantage of the latest
bug fixes without waiting for the official Kylix 1.01 update. The
downside is that the only way you can use FreeCLX is to link
statically with your application. You cannot build new packages
for use in the IDE, nor can you take advantage of the database
components that are included in FreeCLX. Despite the limitations,
you might find that you need one of the bug fixes in FreeCLX. (See
the Web site for a list of bug fixes and patches.)
To download FreeCLX, start at the main FreeCLX page on SourceForge, and click the CVS link. Read and follow the directions. The
files are downloaded into a directory named freeclx. You also will
need to download or build the latest libqtintf.so library (which is
version 2.2.4.3 as I write this article). You can download it from the
main FreeCLX page. Copy it into the Kylix bin directory. Fix the
symbolic links as follows (change /opt/kylix to the actual directory
where you installed Kylix):
cd /opt/kylix/bin
mv libqtintf.so.2.4.4{,.0}
ln -s libqtintf.2.4.4{.3,}
These links ensure that any Kylix application that tries to load
version 2.4.4 will find the new version 2.4.4.3. To make sure you
got it right, type ls -lL libqtintf.so. It should show you the
details of the newly downloaded file.
You can enter the paths as they appear, in which case you must
define the FREECLX environment variable to the absolute path
where you downloaded the FreeCLX files, or you can substitute the
actual path in place of $(FREECLX).
The next time you compile your application, Kylix will compile the
FreeCLX source files and link them into your application. Note that
the IDE is still using the original source code, so the components
might behave differently at design time than at run time. If that
causes problems for you, the only solution is to get rid of FreeCLX.
Building dbExpress
FreeCLX comes with the dbExpress driver for MySQL. Its not much
use without any database components, but if you have a project you
wrote with a commercial edition of Kylix, and you give the source
code to a friend who has only the Open Edition, and your application uses MySQL, your friend might want to build the MySQL
dbExpress library. To build it, change to the dbExpress directory,
and type:
make FREECLX=`pwd` -k
The easiest way to install the FreeCLX files is to add the FreeCLX
source directories to the library and browsing paths under the
Environment options. Be sure to move the FreeCLX directories so
they appear first in the list. Include the following directories in the
search path:
$(FREECLX)/clx
$(FREECLX)/rtl/linux
$(FREECLX)/rtl/sys
Kylix Tech
ln -s libsqlmy.so.1.0 libsqlmy.so.1
ln -s dbxres.en.1.0 dbxres.en.1
Applications
The main reason to use Kylix OE is to write applications, or to
compile applications others have released under the GPL. Thats
easy; just open the project and compile it, the same way you do
in Delphi.
Every application built with Kylix OE automatically includes a
splash screen that displays the text: This application was built
with Borland Kylix Open Edition(tm). The application must be
distributed under the terms of the GNU General Public License
(GPL), version 2. A copy of this license can be found at: http://
www.borland.com/kylix/gpl.html.
To skip the splash screen, use the -ns switch. You cannot change
the text of the splash screen or translate that text to another language. You may customize the splash screen with two bitmaps.
A title bitmap may appear across the top of the splash screen,
and an icon bitmap may appear to the left of the text, under
the title. To include the bitmaps in your application, put them in
a resource file with the resource names OSB_TITLEIMAGE and
OSB_ICONIMAGE.
If you have Delphi, you can use Delphis image editor on Windows
(or Borlands Resource Workshop) to create the resource files. Alternatively, you can use any bitmap editor (such as the GNU Image
Manipulation Program, or GIMP, which comes with all major
Linux distributions) to create bitmap files, and compile a resource
script into a binary resource file. A sample resource script is:
OSB_ICONIMAGE BITMAP "icon.bmp"
OSB_TITLEIMAGE BITMAP "title.bmp"
Conclusion
Kylix Open Edition is a unique product. For Borlands other products, the company offers a Personal edition as a free download. The
Personal edition, as the name suggests, is for personal use only. No
distribution is allowed. With Kylix OE, Borland acknowledges the
importance of open source in the Linux community, and permits
distribution under the license. The companion project, FreeCLX,
also is distributed under the license. Now, any Linux user can start
taking advantage of Delphi-style rapid application development,
and distribute the source code under the license.
To take full advantage of Kylix OE, you need some additional tools,
especially a resource compiler. Such tools are readily available, and
it doesnt take much work to use them productively with Kylix. In
time, I hope Borland will work out the glitches that prevent the full
use of FreeCLX in Kylix Open Edition.
Ray Lischner is the author of Delphi in a Nutshell and other books. His current
project is a book about Kylix, to be published next year by OReilly. When
he isnt writing, he often speaks at conferences and user-group meetings
across the country.
At Your Fingertips
By Bruno Sonnino
sually, a main menu is positioned at the top of a form, fixed above the toolbar. But
there are some applications that put the menu in a toolbar, so it can be detached
and moved around. Delphi is one of these applications. Delphi is written in Delphi, so
there must be a way to put a menu in a detachable toolbar. Lets see how.
Initially, we must know something about the
ToolBar and ControlBar components (introduced in Delphi 4). These two components
encapsulate their namesake Windows common
controls. To use them fully, you must have the
Windows DLL, COMCTL32.DLL, updated to
version 4.72 or greater.
The ControlBar component (on the Additional tab
of the Component palette) acts as a container for
other controls just drop them into it. Each
contained control gets a small handle to drag it,
represented by two vertical bars. If you wish to
drop many controls into a ControlBar, but want
just one handle, you must drop another container,
such as a ToolBar or another ControlBar, and drop
the controls there.
We can drop other controls in the ToolBar or
create new buttons in it. These buttons are of
the TToolButton class. The first step to make a
ToolBar dockable is to drop a ControlBar on a
form and align it by changing its Align property.
You can align to the side of the form where
you wish to dock the toolbar. If you want to
allow the toolbar to dock on every side of the
form, you must drop four ControlBars, one for
each side of the form. Then you can change
the ControlBars AutoSize property to True. This
way, when the ToolBar is not docked, the ControlBar will shrink, leaving space for the rest of
the controls in the form. To make a ToolBar
dockable, change the properties DragMode to
dmAutomatic, and DragKind to dkDock.
23 November 2001 Delphi Informant Magazine
At Your Fingertips
TNewToolDockForm = class(TToolDockForm)
public
constructor Create(AOwner: TComponent); override;
end;
This new class only redefines the Create constructor. In this new
constructor we remove the system menu from the BorderIcons
property, removing the close button:
constructor TNewToolDockForm.Create(AOwner: TComponent);
begin
inherited;
BorderIcons := BorderIcons - [biSystemMenu];
end;
Finally, we must tell Delphi that the class that will house the
toolbar when undocked is a TNewToolDockForm. This is done in
the OnCreate method of the main form:
procedure TForm1.FormCreate(Sender: TObject);
begin
ToolBar1.FloatingDockSiteClass := TNewToolDockForm;
end;
At Your Fingertips
procedure TForm1.FormCreate(Sender: TObject);
const
TestStr = 'abcdefghijklmnopqrstuvwxyz' +
'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var
i : Integer;
Size : TSize;
begin
// Get average width of character.
GetTextExtentPoint32(Canvas.Handle, TestStr, 52, Size);
BaseUnits := Size.cx div 52;
// Fill memo.
for i := 1 to 100 do
Memo1.Lines.Add('C1'#9'C2'#9'C3'#9'C4'#9'C5'#9'C6');
end;
procedure TForm1.HeaderControl1SectionResize(
HeaderControl: THeaderControl; Section: THeaderSection);
var
Tabs : array[0..4] of DWord;
i : Integer;
begin
// Calculate tab stops.
for i := 0 to 4 do
Tabs[i] :=
HeaderControl.Sections[i+1].Left * 4 div BaseUnits;
// Set tab stops.
Memo1.Perform(EM_SETTABSTOPS, 5, Integer(@Tabs));
end;
and may have their relative position moved. Well use one as a guide to
the tab settings in the Memo. If the sections are resized, the tabs will be
changed. To reset all tabs to the original 32 dialog units, use the code
shown here:
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Perform(EM_SETTABSTOPS, 0, 0);
SetHeaders(32);
end;
The SetHeaders procedure sets all header sections to the same width. This
is necessary when you change the tab settings, so the header control aligns
with the tabs:
paragraph; the settings apply to all of the text. The default tab
setting in a Memo is 32 dialog units. To convert a dialog unit to
pixels, you can use the formula shown in these statements:
Pixelsx := (Dialogx * BaseUnitX) div 4;
Pixelsy := (Dialogy * BaseUnitY) div 8;
Usually, the base units are retrieved with the API function,
GetDialogBaseUnits, but this doesnt work with forms that have
variable-pitch fonts. In this case, the base units are obtained using
the average width and height in pixels of the characters in the
Memo font. To get the average width, we can measure a string
made of all characters in uppercase and lowercase in pixels with
the GetTextExtentPoint32 function, and divide the result by 52,
the number of characters in the string. To alter the standard tab
setting, you must send the message EM_SETTABSTOPS to the
Memo handle. This is done with something like this:
Memo1.Perform(EM_SETTABSTOPS, WParam, LParam);
where WParam has the number of tab stops that will be set. If
it is 0, then the tab stops will be reset to the default 32 units.
If it is 1, all tab stops will be set to the spacing set by LParam.
LParam must be set to an array of DWord with the tab stop values. These
values must be in dialog units.
As an example, well put a Memo and a HeaderControl component on
the form. The HeaderControl component acts as a header for controls
that dont have one. Its like the header in a ListView in report mode, but
can be positioned at the top of other controls. Its divided into sections,
which have individual captions and widths. The sections can be dragged
25 November 2001 Delphi Informant Magazine
At Your Fingertips
tab stops for the whole text at once. Paragraph formatting is done
using the Paragraph property of TParaAttributes class. With this
property you can set the tab stops, alignment, indents, or bullets.
The TParaAttributes class has two members, TabCount and Tabs,
that are used when setting the tab stops. TabCount has the number
of tab stops set for the current paragraph, and Tabs is an indexed
property pointing to the tabs positions.
The tab stops of the underlying Windows control encapsulated by
the TRichEdit component are measured in twips (1/1440), but
Delphi multiplies the value thats set in the Tabs property by 20,
perhaps to make the values closer to the tab stops of the TMemo.
The result is that you dont get the same thing and must calculate
to get the correct result. To convert pixels to the units used to set
the RichEdit tabs, use the formula in this statement:
TabUnits :=
Pixels * 1440 div (Screen.PixelsPerInch * 20);
To set the first tab to 50 pixels, you can use this statement:
procedure TForm1.HeaderControl1SectionResize(
HeaderControl: THeaderControl; Section: THeaderSection);
var
i, OldStart, OldLen : Integer;
begin
with RichEdit1 do begin
// Store old selection.
OldStart := SelStart;
OldLen := SelLength;
// Prevent flickering.
LockWindowUpdate(Handle);
try
// Select all the text.
SelStart := 0;
SelLength := -1;
// Calculate and set tab stops.
RichEdit1.Paragraph.TabCount := 5;
for i := 0 to 4 do
RichEdit1.Paragraph.Tab[i] :=
HeaderControl.Sections[i+1].Left * 1440 div
(Screen.PixelsPerInch * 20);
finally
// Restore selection.
SelStart := OldStart;
SelLength := OldLen;
// Restore window update.
LockWindowUpdate(0);
end;
end;
end;
Paragraph.Tab[0] :=
50 * 1440 div (Screen.PixelsPerInch * 20);
A Brazilian, Bruno Sonnino has been developing with Delphi since its first
version in 1995. He has written the books 365 Delphi Tips and Developing
Applications in Delphi 5, published in Portuguese. He can be reached at
[email protected].
Figure 8: RichEdit with tab stops set.
or nearly a decade, TurboPowers low-level Windows development libraries, SysTools and the earlier WinSys, have provided outstanding support for Borlands
Windows development tools. Now the award-winning SysTools Library has been ported
to the Linux platform to aid Kylix developers. Like the SysTools 3 library I recently
reviewed (in the July 2001 issue of Delphi Informant Magazine), the Kylix incarnation
can also be divided into three general groups: data manipulation classes, container and
streaming classes, and system support classes. Well examine each of the three groups.
Then well examine other factors such as documentation and support.
Having run most of the sample programs, I can
affirm that the vast majority of the routines perform
well with Kylix. A few example programs and one
or two units showed minor problems, but I was able
to easily fix most of them. TurboPower provides free
update patches on their Internet site whenever the
number and/or severity of outstanding fixes reaches
a certain level. Before that, they post a manual fix
text file that lists fixes that users can apply to the
source code included with their libraries.
TStDQueue is a descendant of TStList that extends it, implementing a double-ended queue (and also a stack and a queue).
TStPQueue is an implementation of a priority queue in which the
elements are stored as pointers. Typically these point to a record
or class of your own, holding fields that describe the priority and
any other data needed by the application. In the classic operating
system example, a process identifier would be needed to start the
highest-priority process once it was identified.
TStHashTable is very similar to the string dictionary but differs
in various ways. For example, the keys in the internal hash table
are not limited to strings, but are passed as untyped parameters,
allowing the use of many data types.
TStLArray and TStLMatrix support two large array classes, similar to Delphis array type but capable of holding many more
elements. One is a large array in one dimension (the TStLArray
class), the other a large array in two dimensions, also known as a
matrix (the TStLMatrix class).
TStList is an implementation of a doubly-linked list manager
with TStListNode nodes that hold the data objects.
TStSortedCollection is a TStCollection descendant that adds the
functionality of automatically ordering data objects in the collection as they are inserted.
TStTree is a binary search tree data structure storing a sorted
collection of data objects in memory. There are no preset limits.
TStVMatrix is a virtual matrix that differs from TStLMatrix by
providing the programmer with more control over swapping data
to and from the hard disk.
System Support
From the beginning, SysTools has provided strong support for working
with the operating system and low-level data. The StUtils unit includes
routines for setting, filling, clearing, testing, or exchanging values in
various data types, including SetLongFlag (sets one or more bits in the
parameter Flags) and FillStruct (fills a given region of memory with values
of a specified size, i.e. not just byte-size as in FillChar). Others include
ClearByteFlag, LongFlagIsSet, SwapNibble, and SetFlag. There are lowlevel file-handling routines to retrieve all kinds of information about files
and directories and perform various operations. The Regular Expression
class and component allow you to perform search and replace operations
on text files using a powerful Regular Expression engine. If you need
to convert text to an HTML-compatible file with embedded HTML
commands you can use the SourceToHTML component.
As you might expect, not everything from the Delphi version is included,
particularly those features that are Windows-specific, such as support for
the Windows registry. And you wont find those powerful new Windows
Shell components. But the core SysTools classes are all here, including
some we havent discussed in this review (such as Bar Code support).
Alan Moore is Professor of Music at Kentucky State University, teaching music theory
and humanities; he was named Distinguished Professor for 2001-2002. He has been
developing education-related applications with the Borland languages for more than 15
years. He 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 [email protected].
TextFile
TextFile
File | New
Directions / Commentary
riginally pursuing a career in journalism, Charlie Calvert developed an interest in computing while attending college.
He learned Turbo Pascal in the mid-1980s, then went to work for Borland, his favorite company, in tech support. In
less than a year, he was asked to write his first book, on Turbo Pascal. A decade later, after writing several editions of
Delphi Unleashed, Calvert became one of the best known and most widely respected people at Borland. Hes also helped
a number of other aspiring Delphi authors, and was instrumental in strengthening the ties between Borland and Project
JEDI. Since leaving Borland, Calvert has done much development in Delphi, JBuilder, JavaScript, and Perl all related to
Internet programming with lots of emphasis on streaming. His Kylix book will be released soon.
Delphi Informant: Could you share with us how you became involved
with development, and how you came to join Borland?
Calvert: Two things happened when I started computing. I was in
school in the mid-1980s, learning how to be a journalist. One of
my teachers took us down to the computer lab and showed us a
PC. He had us type in a few words. Ho hum. Then he said, Hit
the backspace key. I reached out one Wite-Out speckled finger and
pushed backspace, and miracle of miracles the character I had
just typed disappeared. That was it. I was hooked!
I actually became a journalist and practiced journalism for a while. I
decided on a career change when the editor came into the office one
day and found I had spent the whole morning writing WordPerfect
macros instead of writing articles for him. Im not sure you are in the
right profession, he said. I was a good journalist, but I could see his
point. I sure was spending a lot of time writing WordPerfect macros.
I found a little community college where nobody knew me.
Sneaking about with my head down and collar up around my face,
I signed up for a programming course. The first day, I sat in the
back. Once I was sure there was no one there who knew me, I
decided I could risk falling flat on my face around a bunch of total
strangers, so I stuck with it. Fortunately, the teacher was using
Turbo Pascal, so I got off on the right foot. There were some other
programming projects I had been working on for some time. I
translated them into Pascal and had them all up and running in
no time. Id found my computer language. After getting through
the programming course at the community college, I signed up
for a second degree from Evergreen State College, this time in
computer programming. I had a great time getting a computer
science degree. I never wanted to graduate; I was having too much
fun hacking all night in the computer lab.
After graduating, I sent rsums everywhere. On a lark, I even
responded to Borland via my CompuServe account. They had
posted an ad for jobs on a CompuServe forum, and I thought,
What the heck? It cant hurt to apply. Then I promptly forgot
the whole thing, figuring I could never get to work at my dream
company. Low and behold, about a month later, David Wilhelm,
who is still on Borland Delphi R&D, called me up and asked if
I was really interested in a job. Yes, I said, not trusting myself
32 November 2001 Delphi Informant Magazine
to say more. He said, Okay, well send you a plane ticket and set
you up in a hotel here during the interview. Somehow, I managed
not to drop the phone on the floor. About three weeks later, I was
working in Borland tech support.
DI: Youve been involved with Delphi since the very beginning I
suspect even during its earliest development. Please share with readers
some of the highlights of Delphis genesis.
Calvert: No one who was present at the inception can ever forget
the role Anders Hejlsberg played in Delphis development. A lot of
the crunch in the development of Delphi came about because of the
struggle to add database support to the product. Most sources agree
that Zack Urlocker, the product manager at the time, was the guy who
really sold the company and developers on the need to add database
support to this new visual version of Turbo Pascal. Zack saw the success
of other products, such as PowerBuilder, and he was sure Borland
needed a similar product. The only problem was how to create it. The
Turbo Pascal team knew nothing about databases.
Initially, a programmer who wasnt on the Delphi team was assigned the
task. Im not sure how, but I had a chance to sit in on some of the
R&D meetings when the Delphi team conversed with that programmer.
Anyone who knows the key figures on the Delphi team can easily
believe most of them are not inclined to extravagant displays of temper.
Nonetheless, I can remember Anders and other members of the team
shouting during these discussions. I dont really want to pass judgment,
but the months were rolling by, and the database tools werent falling
into place.
The situation reached a crisis, when finally Anders went into
hiding with the database source code. He was gone for a month, perhaps
two. It was during the summer, and we all sat around chewing our nails,
wondering if the product would ever have database support. We also
hoped that it wouldnt have the dreaded word builder in its name.
Meanwhile, Zack was trying to promote the product. Somehow, he
reached down into the lower and most disreputable rungs of David
Intersimones developer-relations group and got me involved in the
process. We were going to go to PC Magazine and show them that
Delphi was the product for database development. This was back in the
days when PC Magazine was still important to developers.
File | New
About a week before we were to leave, Anders strolled back onto the
scene with the fruits of his labor. Someone gave me the first Delphi
build that included the database tools and told me to get the demo
ready for PC Magazine. There was only one problem: Absolutely
nothing worked! That first build with Anders database tools was
one of those builds where trying to do much more than open the
File menu was courting disaster.
I labored deep into the night, certain I had seen, at last, the dark
side of the great Anders Hejlsberg. He, too, could not solve the
database quandary, and who knew what was to be the fate of our
favorite product?
Then, of course, came build two of Anders code. I was one of the
first people to get that build, and so I was one of the first people
to understand the glory that is Delphi. In the end, I probably had
less than 48 hours to put the whole demo together. Zack and I
took it to PC Magazine, where I stared at the wonders of big-time
journalism while our fearless product manager did all the talking.
In short, I sweated, and he talked. In the long run, we prevailed;
PC Magazine gave Delphi a thumbs up. The real hero, of course,
was Anders.
DI: Lets examine the flip side of that last question. If you could add
any feature to the next version of Delphi, what would it be?
Calvert: That ones easy: better support for graphics. Where are
the good DirectX, multimedia, and OpenGL wrappers? Objectoriented databases also sound like a natural for Delphi, as would
something like Javadoc. Finally, I was a big supporter of the shelved
attempts to get Delphi to run on top of the Java virtual machine.
On a related note, Ive spent the last several years tearing my hair
out watching Macromedia develop tools for Web developers. Every
time I see a bit of Flash on a Web site, or whenever I hear people
talking about Dreamweaver, Fireworks, or even HomeSite (which
was built in Delphi), I cant help but believe all that money belongs
in the Borland coffers. No one at Borland wrote a line of code for
those products, but they were such natural Borland products that
I still feel that having the name Macromedia on them was some
kind of mistake.
Its not too late, Borland! As I write, Flash is taking the world by
storm. Borland could make a better version of Flash with one hand
tied behind its back.
DI: There have been many new features and enhancements in each
succeeding version of Delphi, beginning with 32-bit support in
Delphi 2. Besides this obvious one, what do you feel was the most
important feature added to Delphi since the original version?
Calvert: The great languages are Object Pascal, Java, and C++.
These are the only real programming languages that are in wide use
today. My favorite is Object Pascal, but if Java could overcome its
performance problems, it would provide very stiff competition.
Someone defines the interface for a COM object, and then we can
go out and find an implementation of the interface, whether its
on the local machine, or on a remote machine. Its paradise for
programmers who are looking for scalability and a way to reuse
code. Find an interface and then just plug in the implementation.
Its a beautiful way to build software.
The wrappers around COM in Delphi were brilliantly designed
and surpassed anything that Microsoft had on the table before
.NET. The only fly in the ointment was COM itself, which I dont
believe really delivers on the promise of a robust and easily reusable,
distributed architecture. A lot of people like to put down Remote
Method Invocation (RMI), perhaps because its free. But I believe
its much more robust than COM, and much easier to use at
least as it stands now. The security model in COM is a particularly
nasty rats nest. Lets hope SOAP will turn out to be a better
solution to this kind of problem.
Another important development in the history of Delphi has been
the emergence of open-source communities such as Project JEDI
and the Indy Project. They have made huge contributions to the
product.
33 November 2001 Delphi Informant Magazine
File | New
DI: Weve seen some encouraging developments at Borland profitability, for example. Whats your perspective on the companys health?
to enter into the discussions in good faith. If one side has resentment,
or if one side has a secret agenda, they wont make any progress.
Fortunately, a lot of the nonsense appears to be in the past. Management appears to understand, finally, that Delphi and JBuilder
are the heart of the company. If progress is going to be made, it
can only happen if R&D sits down with management and works
out solutions everyone can believe in.
In saying this, I dont mean to rule out the possibility that Borland
could make successful commercial software. The Borland name
still carries a lot of weight, and a well-made consumer product
from Borland could be a serious force in the market.
Alan Moore is Professor of Music at Kentucky State University, where he teaches music
theory and humanities. He was named Distinguished Professor for 2001-2002. He
has developed education-related applications with the Borland languages for more
than 15 years. He is the author of The Tomes of Delphi: Win32 Multimedia API
[Wordware Publishing, 2000] and co-author (with John Penman) of an upcoming
book in the Tomes series on Communications APIs. 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 on the Internet at [email protected].
Symposium
Directions / Commentary
to flush out the kooks. If George W. and Hillary can get along, if Gephardt
and Armey can find unity, then those who still want to play the blame game
must be of the lunatic fringe.
The United States has its own purveyors of hate. Theres a memorial
where once a building stood in Oklahoma, because of the hatred of one
Timothy McVeigh. Jerry Falwell and Pat Robertson are home-grown haters as
well (http://www.nytimes.com/2001/09/18/national/18FALW.html). Theyre
trying to distance themselves from their statements now, but they spoke
clearly enough when they blamed the September 11th attacks on gays, the
ACLU, abortion, etc. Creator of TVs The Awful Truth, Michael Moore is
repelling even his fans with his particular stripe of hate. He hates American
business and the Bush Administration so much that he cant see straight
(http://www.michaelmoore.com/2001_0917.html).
People who claim to know the truth make me very nervous. Pravda means
truth, and Hitler spoke the absolute truth as he saw it. Those on the far
right and the far left are both far too certain about the way things should
be. And they hate too much.
If we must hate something, let us hate hatred itself. And lets also hate its
bedfellows of ignorance, intolerance, and close-mindedness. Theres a better
world on the other side of this: a world with less hate.