On The Cover: December 2000, Volume 6, Number 12
On The Cover: December 2000, Volume 6, Number 12
On The Cover: December 2000, Volume 6, Number 12
ON THE COVER
7 In Development
Implementing COM+ Events — Binh Ly
Binh Ly introduces the COM+ loosely-coupled event (LCE) system, and
demonstrates its three core concepts: the event class, the event publisher,
and the event subscriber.
FEATURES
13 On Language
New List Objects — Jeremy Merrill
Jeremy Merrill demonstrates classes from the new Contnrs unit, such
as TObjectList and TComponentList which can manipulate objects and REVIEWS
components without additional code. 31 LEADTOOLS Raster Imaging 12
Product Review by Bill Todd
18 Greater Delphi
Two Office Web Components — Alex Fedorov
Alex Fedorov puts two of the Office Web Components (OWC) through 34 Wireless Web Development
their paces, to easily add — for example — a bit of Microsoft Excel Book Review by Mike Riley
functionality to your Delphi applications.
36 Advanced Delphi Developer’s Guide to ADO
24 At Your Fingertips Book Review by Alan C. Moore, Ph.D.
Fancy Menus, etc. — Bruno Sonnino
Bruno Sonnino begins his new tips column by showing us how to
rotate text, create special lines, and customize menus with various fonts,
bitmaps, shapes, and colors. DEPARTMENTS
2 Symposium Guest Editorial by Michael Pence
29 Case Study 3 Delphi Tools
ASSESS — Denis Perrotti 6 Newsline
Denis Perrotti explains how Delphi was the perfect tool for developing
ASSESS, in contrast to the experience with Visual Basic and its requisite 37 Best Practices by Clay Shannon
tours of DLL hell and VBX purgatory. 38 File | New by Alan C. Moore, Ph.D.
1 December 2000 Delphi Informant Magazine
Symposium
L et’s create a development environment that combines the ease-of-use of VB with the power of OOP and C++.
i Let’s make it component based, but still able to statically compile for maximum performance and minimal DLL
conflicts. We’ll have it support Microsoft technologies better and sooner than VB, and we’ll even create a Linux version
for cross-platform development.
Then let’s keep it a secret. Cordes, a Delphi and Java consultant and editor of The BDE Alter-
natives Guide at http://kylecordes.com/bag. Anthony DiAngelus, a
Sound familiar? If you’re a long-time Delphi developer, as I am, senior architect and consultant from Tampa, Florida concurs. “Unfor-
you recognize this truth-is-stranger-than-fiction scenario all too well. tunately, I’ve had to rely on my other skills as an Oracle DBA, rather
Through several management upheavals, countless premature obitu- than be a full-time Delphi developer. The work just isn’t there, and I
aries by industry pundits, and dizzying swings in business strategy, can only point the finger at the marketing group. Delphi is the best
there’s been one constant: pathetic marketing. development tool I have, but corporate America just doesn’t know
about it.”
We all slept through the “On Time, On Budget” campaign, carefully
synchronized with the “Inprise” branding fiasco. Now, as the Inprise Is it just a case of Borland being another aim-impaired David against
emblem has slowly crept into the shadow of the Borland name, we the Goliath of Redmond? Certainly, it’s not easy to market against
have the “Webvolutionaries” campaign, seemingly inspired by Elmer Microsoft’s tools division, which is heavily stocked with ex-Borland-
Fudd. Brilliant. ers, and has very deep pockets. However, companies like WebGain
(http://www.webgain.com) are successfully bundling top-quality tools
Borland makes better development tools than Microsoft, or anyone — and getting noticed. Just try to get through an InfoWorld or
else. They make the best application server out there, but who other trade magazine and not see them. Where is Borland’s bundling
would know? They are the Mercedes of developer tools, with the mar- strategy and marketing presence? Aiming to be Switzerland doesn’t get
keting strength of a Daewoo. Allaire, Embarcadero, Scour.com, and you on many people’s maps.
countless others leverage Delphi as their “secret weapon,” producing
top-notch software in record time, because they know The Secret. In their defense, Borland has begun, finally, to target the VB
Unfortunately, they’re in the minority. community with their latest campaign, featuring the promise of a
Linux-based RAD tool in Kylix (http://www.vbforlinux.com) and
On this late August day, Dice.com is trumpeting some 153,752 open aggressively distributing functional demonstration versions of Delphi
positions. Of those, only 627 are matches for jobs requiring Delphi. in publications like Visual Basic Programmer’s Journal. But is it too
That’s one in every 245 jobs, or 0.4%. Compare that to 14,950 Visual little, too late?
Basic jobs, approximately one in every 10, or 9.7%. And Java? Java
(not JavaScript) weighs in with 29,073 — one in every 5 jobs — or Kylix may be a reality by the time you read this, but the Linux market
18.9%! So our admittedly unscientific, but still relevant, search shows is still an emerging one. The Windows market will continue to
that, for every 200 IT jobs across the US, approximately 38 will be flourish for many years, and Delphi — the most powerful Windows
Java jobs, 20 will be Visual Basic jobs, and less than one will be a development environment available — will go the way of FoxPro
Delphi job. unless someone turns the lights on at Borland marketing.
The persistent lack of exposure of Delphi and other Borland tools — Michael Pence
has left those who have invested their time and talents in Borland
technologies scrambling to diversify. “Borland continues to make Michael Pence ([email protected]) lives in Phoenix with his wife, Denise, and
great solutions, but to attract desirable business I have added better- children, Ryan and Becca, and Sammy the puppy. He’s been an analyst and program-
marketed solutions from other vendors. Personally, I find myself mer for 10 years, using Java, Delphi, Visual Basic, and other tools. He is also founder
having to weigh the market presence of competing solutions as much, of The Delphi Advocacy Group (http://www.egroups.com/group/tdag), a mailing list
or more than, the technical aspects. Marketing matters,” notes Kyle for Delphi users.
4Tier Software
Price: Free for development and deployment
with up to three computers connected.
Phone: (33) 1 39 76 80 20
Web Site: http://www.4tier.com
ISBN: 1-56592-627-7
Advanced Software Technologies Unveils GDPro 5.0
Price: US$34.95 Advanced Software Tech- sive visual blueprints of Java, mance enhancements, context-
Web Site: http://www. nologies, Inc. announced the C++, and IDL. sensitive pop-up Windows to
ComputerBookstore.com release of GDPro 5.0, an New features include a speed diagram population, and
upgrade to the company’s Web System Browser Report, a Rational Rose diagram import
UML visual modeling solution with functionality that allows feature.
for accelerating software design developers to produce and
and collaborative development. share comprehensive diagrams Advanced Software Technologies, Inc.
This new version allows appli- of their software designs over Price: US$2,995 for Windows; US$4,795
cation developers to create and the Internet. for Unix.
communicate across the enter- Other new features include Phone: (800) 811-2784
prise using simple, comprehen- Java Reverse Engineering perfor- Web Site: http://www.advancedsw.com
By Binh Ly
O ne of the more interesting features of COM+ (the new version of COM for Microsoft
Windows 2000) is the introduction of a new event mechanism for developing
scalable distributed systems. To appreciate the COM+ event system, it’s important to first
understand how events were implemented in the pre-COM+ era.
Pre-COM+ events fall into two main categories: between the event source and receiver. For
§ COM connection points are a standard instance, it can take an effort to implement
way of negotiating event interfaces between multiple event receivers (particularly as sepa-
the source and the receiver of the events. rate applications) to receive events from a
This structured negotiation is dictated by single event source.
the architecture of some standard COM
interfaces, such as IConnectionPoint and Because of these behaviors, the pre-COM+ event
IConnectionPointContainer. infrastructure is often referred to as a tightly cou-
§ COM callbacks are a low-level, application- pled event (TCE) system. The term “tightly cou-
specific way of negotiating event interfaces pled” denotes the strong and intimate dependency
between the source and the receiver of the between the event source and receiver objects.
events. This negotiation usually requires a
custom architecture, specific to an application A tightly coupled event system has its place, and
or part of an application. has been used successfully over the years, e.g. for
implementing the ActiveX controls event mecha-
I won’t go into the technical details of COM connec- nism. Unfortunately, with today’s applications rap-
tion points and COM callbacks; that’s not the goal idly moving toward high-speed, enterprise-scale
of this article. (For more information on these two environments, such as Web applications, new event
techniques, refer to my two-part series in the June requirements have surfaced that are difficult to sat-
and July 1998 issues of Delphi Informant Magazine.) isfy with a TCE solution.
Let’s assume our business requirements are as follows: An important thing to understand about event classes is that we
1) Every time an order transaction is placed, an e-mail message must never implement the methods of the event class interface. We
be sent to a known back-end mail server, where another routine simply define the interface, and then install it into the COM+
will take control and start the process of filling the order. environment (see Figure 1).
2) Every time an order transaction is placed for a particular product
(ProductID), we’ll need to log that into the system. This log is To further understand what I mean, let’s take a look at the
used by other statistical applications that will analyze purchase Delphi implementation of an event class. Figure 2 illustrates the
patterns of customers and experimental products. Experimental OrderEvents event class (TheBestEvents.dpr). This module was
products change regularly, so it would be nice to have an imple- created using Delphi’s Automation Object Wizard (File | New
mentation for this that isn’t unduly impacted by product changes. | ActiveX | Automation Object) and using “OrderEvents” as the
CoClass name.
Obviously, a brute-force way to implement these requirements is to
hard-code the business processes into the IOrder.PlaceOrder imple-
mentation. However, we can look at these requirements from a
different angle, and conclude that we may want to trigger some kind
of event every time an order is placed. Other business processes or
components can then “listen in” on this event to perform the desired
operation, based on our current (and future) business requirements.
uses uses
TheBestEvents_TLB; TheBestEvents_TLB;
// Step 2:
To put that in context, let’s trigger this event from within the PlaceOrder // Trigger OrderEvents.
method of the Order business component, as shown in Figure 3. // Create OrderEvents event class.
OrderEvents := CoOrderEvents.Create;
The process of triggering a COM+ event works only if we properly // Execute OrderEvents.OrderPlaced event.
OrderEvents.OrderPlaced(CustomerID, ProductID, Quantity);
install the OrderEvents event class into the COM+ environment. The
end;
process of installing an event class for everybody to see is known as
publishing the event. The party that publishes an event is called the Figure 3: Triggering the event from the PlaceOrder method of
event publisher. In our case, the publisher of the OrderEvents event the TOrder class.
class is our retail application, The Best.
Publishing Events
An event class can be published administratively (interactively) or
programmatically. I will only demonstrate administrative publishing;
programmatic publishing requires knowledge of programmatic access
to the COM+ administration APIs that is beyond the scope of
this article. Before we can publish an event class, we first need to
build the COM server that defines the event class. This is contained
in the project, TheBestEvents.dpr. Building this project produces
TheBestEvents.dll, which we’ll install into the COM+ environment.
We’ve learned what an event class is, how it’s installed, and how it’s
called to trigger events. The next step is to understand how we can
listen in on an event. Figure 5: The COM Component Install Wizard.
Now we need to associate the IOrderEvents interface with the EMailer Figure 7: The EMailer CoClass in the Type Library editor.
CoClass. To do this, click on the EMailer CoClass (while still in the
Type Library editor), and select the Implements page. Right-click to unit OrderLogger;
interface uses
ComObj, ActiveX, TheBestSubscribers_TLB,
uses TheBestEvents_TLB, StdVcl;
ComObj, ActiveX, TheBestSubscribers_TLB,
TheBestEvents_TLB, StdVcl; // Order Log subscriber.
type
// EMailer subscriber. TOrderLogger = class(TAutoObject, IOrderLogger,
type IOrderEvents)
TEMailer = class(TAutoObject, IEMailer, IOrderEvents) protected
protected procedure OrderPlaced(
procedure OrderPlaced( const CustomerID, ProductID: WideString;
const CustomerID, ProductID: WideString; Quantity: Integer); safecall;
Quantity: Integer); safecall; procedure LogOrder;
procedure SendEMail; end;
end;
implementation
implementation
uses
uses ComServ, Dialogs, SysUtils;
ComServ, Dialogs, SysUtils;
// IOrderEvents.OrderPlaced subscription implementation.
// IOrderEvents.OrderPlaced subscription implementation. procedure TOrderLogger.OrderPlaced(
procedure TEMailer.OrderPlaced(const CustomerID, const CustomerID, ProductID: WideString;
ProductID: WideString; Quantity: Integer); Quantity: Integer);
begin begin
SendEMail; LogOrder;
ShowMessage('EMail Processing completed!' + #13 + ShowMessage('Order logging completed!' + #13 +
'Customer: ' + CustomerID + ', Product: ' + ProductID + 'Customer: ' + CustomerID + ', Product: ' + ProductID +
', Quantity: ' + IntToStr(Quantity)); ', Quantity: ' + IntToStr(Quantity));
end; end;
initialization initialization
TAutoObjectFactory.Create(ComServer, TEMailer, TAutoObjectFactory.Create(ComServer, TOrderLogger,
Class_EMailer, ciMultiInstance, tmApartment); Class_OrderLogger, ciMultiInstance, tmApartment);
end. end.
Figure 11: Invoking the COM New Subscription Wizard. Figure 13: Configuring OrderLogger’s subscription filter.
Note that Filter criteria uses the ProductID taken from the specified Binh Ly is an independent consultant who specializes in developing
parameter name in the IOrderEvents.OrderPlaced method. The filter distributed systems using COM technologies. He also maintains a Web site
criteria consists of a string Boolean expression. The expression is evalu- (http://www.techvanguards.com) that educates people on how to effectively
ated by the COM+ event system before instantiation of the subscriber use COM technologies using Borland products. You can reach Binh at
component. This provides for an efficient filtering mechanism in [email protected].
which subscribers aren’t unnecessarily instantiated if they aren’t “inter-
ested” in an event, based on certain conditions. The filter criteria can
also include Boolean operators, such as OR, AND, and NOT.
A Sample Application
Now that we’ve installed both subscriber business components,
we can then test their functionality. Before we do this, however,
let’s install the Order business component (discussed earlier) that
triggers the events. To do this, build the TheBest.dpr project and
install TheBest.dll into the COM+ environment. On my machine, I
simply added this into The Best.
Assuming you’ve
installed the event
classes and
subscriptions correctly,
executing the
Order.PlaceOrder oper-
ation should produce
a message box from
the EMailer subscriber.
Figure 14: A simple purchase-order
And changing the
client application.
Product edit box con-
uses
TheBest_TLB;
By Jeremy Merrill
D elphi 5 introduced a new Contnrs unit that defines eight new classes, all based on
the standard TList class. In this article, we’ll provide an overview of the TList class,
then explore these eight new classes in detail. We’ll also look at how to create custom list
classes, ending with the creation of a new TList descendant class, TIntList.
Figure 5: Class declaration for TComponentList. Figure 6: TOrderedList, TStack, and TQueue.
{ TMyObjectStack } end;
function TMyObjectStack.Peek: TMyObject;
begin function TIntList.First: Integer;
Result := TMyObject(inherited Peek); begin
end; Result := Integer(inherited First);
end;
function TMyObjectStack.Pop: TMyObject;
begin function TIntList.GetItem(Index: Integer): Integer;
Result := TMyObject(inherited Pop); begin
end; Result := Integer(inherited Items[Index]);
end;
procedure TMyObjectStack.Push(AMyObject: TMyObject);
begin function TIntList.IndexOf(Item: Integer): Integer;
inherited Push(AMyObject); begin
end; Result := inherited IndexOf(Pointer(Item));
end;
{ TMyObjectQueue }
function TMyObjectQueue.Peek: TMyObject; procedure TIntList.Insert(Index, Item: Integer);
begin begin
Result := TMyObject(inherited Peek); inherited Insert(Index, Pointer(Item));
end; end;
implementation
{ TIntList }
function TIntList.Add(Item: Integer): Integer;
begin
Result := inherited Add(Pointer(Item));
end;
By Alex Fedorov
O ne of the new and exciting features of Microsoft Office 2000 is its Office Web
Components (OWC), a set of ActiveX components intended for use from HTML
pages to create “active” Web documents. Since these components are simply ActiveX
components, however, we can also use them in non-Web applications built with Delphi.
This article shows you how.
The six ActiveX components that comprise the select Microsoft Office Web Components 9.0 (Version
OWC implement some of the functionality 1.0) from the list of available type libraries.
of Microsoft Excel, and provide database
access. The components are named ChartSpace, Since we’re dealing with ActiveX components,
Spreadsheet, DataSourceControl, RecordNaviga- we need to check the Generate Component Wrap-
tionControl, ExpandControl, and PivotTable. per option, select the Palette page where Delphi
DataSourceControl and RecordNavigationCon- will put the components wrappers (the default is
trol can be replaced with ADOExpress VCL ActiveX), and click Install. The six components
components (as we’ll see in this article), so will be added to the Component palette. As
they’re of no particular interest to Delphi devel- already mentioned, we’ll discuss only the Chart-
opers. ExpandControl is also outside the scope Space and Spreadsheet components.
of this article.
The type library file for the OWC is named
This leaves ChartSpace, Spreadsheet, and Pivot- MSOWC.DLL, and lives by default in \Program
Table. Unfortunately, I haven’t found a direct Files\Microsoft Office 2000\Office. The help file
way to make the PivotTable component work for the OWC is named MSOWCVBA.CHM,
in Delphi 5; it cannot be activated correctly for and lives in \Program Files\Microsoft Office
some reason. We can use still the component in 2000\Office\1033 by default.
Delphi, however, and in a future issue of this
magazine we’ll see the PivotTable component at The ChartSpace Component
work, and discuss accessing the Microsoft Excel As its name denotes, ChartSpace is used to
Pivot Table services. create charts. ChartSpace supports 46 types of
charts, from Line to Doughnut Exploded. See
As with many programming services available the ChartChartTypeEnum constants in OWC
through a type library — ActiveX components, help for the complete list. It can also draw charts
Automation servers, etc. — we need to create a from other members of the OWC (the Spread-
wrapper unit to use them. (This step is unneces- sheet component in our case), from ADO data
sary if you’re using late binding. In that case, sources, or from static data. In this article, we’ll
you can use Windows COM API functions to demonstrate how to do all three. (The demon-
create objects and variants to use the methods stration projects are available for download; see
and properties implemented in them. However, end of article for details.)
the easier way to deal with ActiveX components is
to create a wrapper unit.) To do so, select Project Charts Based on Static Data
| Import Type Library from the Delphi menu, and Static data is supplied by the application, i.e. it’s
A dynamic variant array is created with the VarArrayOf function, XValues := VarArrayCreate([0,7], varVariant);
and isn’t associated with a particular variable. In the following XValues[0] := 'Beverages';
XValues[1] := 'Condiments';
example, the VarArrayOf function returns a one-dimensional array
XValues[2] := 'Confections';
of items of type Variant: XValues[3] := 'Dairy Products';
XValues[4] := 'Grains & Cereals';
VarArrayOf([104737, 50952, 78128, 117797, XValues[5] := 'Meat & Poultry';
52902, 80160, 47491, 62435])); XValues[6] := 'Produce';
XValues[7] := 'Seafood';
Charts Based on Data from a Database Then, we clear the chart, and indicate the source of data:
When we need to build a chart based on data stored in a database,
we have two options. We can use DataSource from the OWC, or with ChartSpace1 do begin
we can use some ADO-compatible data source. As we will see later Clear;
Refresh;
in this article, the main sequence of actions is the same; the only
DataSource := DataSourceControl1.DefaultInterface as
difference is how the data sources are defined. MSDATASRC_TLB.DataSource;
DataMember := RSD.Name;
end;
var
// Set the horizontal layout for the chart. RS : _Recordset; // ADO RecordSet
ChartSpace1.ChartLayout := chChartLayoutHorizontal;
// Add new Chart.
BarChart := ChartSpace1.Charts.Add(0); Then, the following code executes the SQL query, and associates the
with BarChart do begin returned data with the Chart:
// Set the type of Chart, a bar chart.
Type_ := chChartTypeBarClustered;
RS := ADOCommand1.Execute;
// The first field is categories.
with ChartSpace1 do begin
SetData(chDimCategories, 0, 0);
Clear;
// The second field is values.
Refresh;
SetData(chDimValues, 0, 1);
DataSource := RS as MSDATASRC_TLB.DataSource;
// Format the axes.
DataMember := '';
with Axes[chAxisPositionBottom] do begin
end;
NumberFormat := '0,';
MajorUnit := 25000;
HasMajorGridlines := False; Creating the Chart
end; After the source of the data is specified — with the OWC Data-
end;
Source, or through an ADO recordset — we can create our chart. To
Figure 5: Creating a bar chart. do so, we must add a new chart to the Charts collection, specify the
Figure 6: Adding a pie chart to the collection. Figure 8: Using a Spreadsheet component as the data source.
After specifying the data, we can set properties for the cells. This
example changes the font of the first row:
Figure 10: A Spreadsheet component, and a chart using its data.
with Spreadsheet1.Range[Spreadsheet1.Cells.Item[1, 1],
The Spreadsheet Spreadsheet1.Cells.Item[1, RS.Fields.Count]].Font do
Component begin
Set_Name('Arial Narrow');
Spreadsheet The Spreadsheet component Set_Bold(True);
provides us with a programma- Set_Size(11);
ble kernel, which can be used end;
Pane
to perform various calculations
with a huge library of func- Here, we specify that the cells automatically adjust their size to their
Range tions. It also comes with an contents, and to left-align the contents of the cells:
easy-to-use graphical interface
for manipulating the cells of with Spreadsheet1.Range[Spreadsheet1.Cells.Item[1, 1],
TitleBar the spreadsheet. Spreadsheet1.Cells.Item[NumRecs, RS.Fields.Count]] do
begin
AutoFitColumns;
Worksheet The object model of the Set_HAlignment(ssHAlignLeft);
Spreadsheet component (see end;
Figure 11: Simplified object
Figure 11) contains the
model for the Spreadsheet
ActiveSheet property, which
component.
gives us access to an individual The resulting spreadsheet is shown in Figure 13.
sheet within the component;
and such objects as Pane (the work area of the spreadsheet), Range Setting Colors
(for a range of cells), TitleBar ( the title bar for the spreadsheet), and Before we end our discussion of Microsoft Office Web Compo-
Worksheet (for the spreadsheet itself ). Again, see OWC Help for the nents, let’s briefly talk about setting colors. If you try to change the
complete diagram. color of an element of a Chart or Spreadsheet component, you’ll
find that the Color property is read-only. This is due to a bug in the
There are many ways to insert data into the Spreadsheet compo- Delphi type-library parser.
nent. For example, we can enter it manually, use copy and paste
(the Clipboard), load data from Microsoft Excel or Word, load To solve this problem, we must use the more round-about Set_Color
data stored in text file or Web site, etc. method. Another nuisance is that this method takes an argument of
type POleVariant1. A closer inspection of the type-library interface
To load data from a text file, we can use the Spreadsheet’s LoadText code shows that this type is defined as a pointer to OLEVariant. The
method, which takes the following arguments: following code shows how to use the Set_Color method:
Conclusion The files referenced in this article are available on the Delphi Informant
So there you have it. We’ve seen how to use two Microsoft Office Magazine Complete Works CD in INFORM\00\DEC\DI200012AF.
Web Components in Delphi applications, so you can add two more
ActiveX components to your bag of tricks.
By Bruno Sonnino
B efore Delphi 4, it was difficult to customize a menu (add a bitmap, change a font,
ietc.), because owner drawing (i.e. custom drawing) — although implemented by
Windows — was not exposed by the TMainMenu class. Since Delphi 4, however, this
situation has been rectified, and we can have our way with menus.
This article will highlight some techniques property of the menu component — TMainMenu
you can use to customize the appearance of or TPopupMenu — to True, and provide event
menus in your Delphi applications. We’ll discuss handlers for its OnDrawItem and OnMeasureItem
text placement, menu sizing, font assignment, events. For example, an OnMeasureItem event
and using bitmaps and shapes to enhance a handler is declared like this:
menu’s appearance.
procedure TForm1.Option1MeasureItem(
Sender: TObject; ACanvas: TCanvas;
Just for fun, this article also features techniques
var Width, Height: Integer);
for creating rotated text and custom lines. All
of the techniques discussed in this article are
demonstrated in projects available for download; Set the Width and Height variables to adjust the
see end of article for details. size of the menu item. The OnDrawItem event
handler is where all the hard work is done; it’s
Custom Fonts and Sizes where you draw your menu and make any special
To create a custom menu, set the OwnerDraw settings. To draw the menu option with Times
New Roman font, for example, you should do
procedure TForm1.Times2DrawItem(Sender: TObject;
something like this:
ACanvas: TCanvas; ARect: TRect; Selected: Boolean);
var
dwCheck : Integer; procedure TForm1.Times1DrawItem(
MenuCaption : string; Sender: TObject; ACanvas: TCanvas;
begin ARect: TRect; Selected: Boolean);
// Get the checkmark dimensions. begin
dwCheck := GetSystemMetrics(SM_CXMENUCHECK); ACanvas.Font.Name := 'Times New Roman';
// Adjust left position. ACanvas.TextOut(ARect.Left+1, ARect.Top+1,
ARect.Left := ARect.Left + LoWord(dwCheck) + 1; (Sender as TMenuItem).Caption);
MenuCaption := (Sender as TMenuItem).Caption; end;
// The font name is the menu caption.
ACanvas.Font.Name := 'Times New Roman';
// Draw the text. This code is flawed, however. If it’s run, the
DrawText(ACanvas.Handle, PChar(MenuCaption), menu caption will be drawn aligned with the
Length(MenuCaption), ARect, 0); left border of the menu. This isn’t default Win-
end; dows behavior; usually, there’s a space to put
Figure 1: This OnDrawItem event handler places menu item bitmaps and checkmarks in the menu. There-
text correctly. fore, you should calculate the space needed for a
function LineDDA(
// x-coordinate of line's starting point.
nXStart,
// y-coordinate of line's starting point.
nYStart,
// x-coordinate of line's ending point.
nXEnd,
// y-coordinate of line's ending point.
YEnd : Integer;
// Address of application-defined callback function.
lpLineFunc : TFNLineDDAProc;
lpData : LPARAM // Address of application-defined data.
): BOOL; stdcall;
Figure 13: Object Pascal declaration for the Windows API func-
tion, LineDDA.
Figure 11: Text rotated 360 degrees.
type
TForm1 = class(TForm)
procedure TForm1.Info1Click(Sender: TObject); ImageList1: TImageList;
var procedure FormPaint(Sender: TObject);
LogFont : TLogFont; procedure FormResize(Sender: TObject);
begin end;
// Fill LogFont structure with information
// from current font. var
GetObject(Canvas.Font.Handle, Form1: TForm1;
Sizeof(LogFont), @LogFont);
// Display font information. procedure CallDDA(x, y: Integer; Form: TForm1); stdcall;
with LogFont do
ShowMessage( implementation
'lfHeight: ' + IntToStr(lfHeight) + #13 +
'lfWidth: ' + IntToStr(lfWidth) + #13 + { $R *.DFM }
'lfEscapement: ' +
IntToStr(lfEscapement) + #13 + procedure CallDDA(x, y: Integer; Form: TForm1);
'lfOrientation: ' + begin
IntToStr(lfOrientation) + #13 + if x mod 13 = 0 then
'lfWeight: ' + IntToStr(lfWeight) + #13 + Form.ImageList1.Draw(Form.Canvas, x, y, 0);
'lfItalic: ' + IntToStr(lfItalic) + #13 + end;
'lfUnderline: ' +
IntToStr(lfUnderline) + #13 + procedure TForm1.FormPaint(Sender: TObject);
'lfStrikeOut: ' + begin
IntToStr(lfStrikeOut) + #13 + LineDDA(0, 0, ClientWidth, ClientHeight,
'lfCharSet: ' + IntToStr(lfCharSet) + #13 + @CallDDA, Integer(Self));
'lfOutPrecision: ' + end;
IntToStr(lfOutPrecision) + #13 +
'lfClipPrecision: ' + procedure TForm1.FormResize(Sender: TObject);
IntToStr(lfClipPrecision) + #13 + begin
'lfQuality: ' + IntToStr(lfQuality) + #13 + Invalidate;
'lfPitchAndFamily: ' + end;
IntToStr(lfPitchAndFamily) + #13 +
'lfFaceName: ' + string(lfFaceName)); Figure 14: Code to draw a line of bitmaps.
end;
with CreateFontIndirect. Before using this new font, it must be selected
Figure 12: Getting and displaying font attributes. with SelectObject. Another way is to assign the handle of this new
font to the handle of the canvas’ font, before drawing the text. After
member, a number between 0 and 1000. 400 is normal text, values drawing the text, this work must be reversed; the old font must be
above this draw bold text, and values below it draw light text. selected, and the new font deleted. If the new font isn’t deleted, there
will be a memory leak, and — if the routine is executed many times
The code in Figure 10 draws text at angles ranging from 0 degrees — Windows (especially 95/98) will run out of resources, and crash.
to 360 degrees, at 20-degree intervals. It’s the form’s OnPaint event
handler, so the text is redrawn each time the form is painted. Figure Stylish Lines
11 shows the result. When you draw lines, the individual pixels usually don’t matter; you
simply set the line style, and it’s drawn by Windows. Sometimes
The form’s font is set to Arial, a TrueType font. This code works only however, you need to do something special and draw a line style
with TrueType fonts; other kinds of fonts don’t support text rotation. not provided by Windows. This can be done using a Windows API
To get current font settings and fill the TLogFont structure, you must function named LineDDA, defined in Figure 13.
use the GetObject API function. The code in Figure 12 shows how to
fill and display the TLogFont settings for the form’s font. The first four parameters are the starting and ending points of the
line. The fifth parameter is a callback function that will be called
Once you have the settings in a TLogFont structure, the only change every time a pixel should be drawn. You put your drawing routines
left is to set lfEscapement to the desired angle and create a new font there. The last parameter is a user parameter that will be passed to
the callback function. You can pass any Integer or pointer to the
function, because it is an LParam (in Win32, it is translated to a
Longint). The callback function must take the form shown here:
where x and y are the coordinates of the drawn point, and UserParam
is a parameter that is passed to the function. This function must be
declared as stdcall. The routine in Figure 14 draws a line of bitmaps,
and Figure 15 shows the result.
Conclusion
Since owner drawing was exposed in TMainMenu in Delphi 4, there
have been many ways to augment your menus. Using the techniques
we’ve discussed here, you can easily enhance your Delphi application’s
menus with custom text, bitmaps, and colors. ∆
The files referenced in this article are available on the Delphi Informant
Magazine Complete Works CD in INFORM\00\DEC\DI200012BS.
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].
By Denis Perrotti
ASSESS
Delphi Helps American Skandia Compete
By Bill Todd
I f you need a powerful professional imaging toolkit that you can use as the foundation
for any graphics application, look no further than LEADTOOLS Raster Imaging 12 from
LEAD Technologies, Inc. LEADTOOLS includes support for more than 60 graphics file
formats, including JPEG, GIF, TIFF (including G3/G4, LZW, CMYK, and JTIF), PNG, BMP,
MODCA/IOCA, PCX, and TGA.
You can manipulate all or part of an image using the document imaging product, the royalty varies
more than 70 digital filters and transforms, includ- from US$75 per unit for quantities less than 50, to
ing smooth; sharpen; edge detect and enhance; US$1.50 per unit for quantities of 10,000 or more.
change brightness, contrast, and gamma; change hue
and saturation; add noise; resize and rotate images; Although all of the functionality of LEADTOOLS
and change color depth. All standard image com- is implemented in a collection of DLLs, you have
pression techniques, including JPEG, CMP, LZW, your choice of two high-level interfaces to make
G3/G4, Huffman, and run-length, are available, programming your graphics application easier. If
as is LEADTOOLS’ high-performance proprietary you’re working in Delphi or C++Builder, you’ll
compression algorithm. You can also apply 2,000 want to use the VCL components. For other lan-
display effects to modify the appearance of an image. guages, use the ActiveX control.
Delphi and C++Builder developers are used to going to the help index,
entering a class name, and being taken to a topic that provides a descrip-
tion of the class and a list of all of the properties, methods, and events
for the class with each property, method, and event providing a link
to its own topic. If you search either the LEADTOOLS online help
or the manual for a component class name, such as TLeadImage, you
will find nothing. There is no way to find a topic that will give you a
list of the properties, methods, and events of any of the LEADTOOLS
components. If you know the name of a property, method, or event, you
Figure 1: The LeadImage control with a pan window displayed. can find its help topic, but the only way to find the names is to use the
A ll developers are in R&D — or should be. Personal research (books, magazines, newsgroups, Web sites, and source
lcode) and development (hacking and side projects) are necessary if you’re to grow as a developer and adapt
to changing needs. In contrast, developers who concentrate only on their assigned tasks often harm themselves and
their employers.
It’s self-defeating to subscribe to the “begin coding as soon as tion from scratch, using the preferred method. I finished in approxi-
possible to finish the project as soon as possible” mindset. It’s mately 15 minutes. Yes, what you don’t know can come back to
specious reasoning. Although it sounds sensible on the surface, chomp you on the gluteus maximus!
it often leads to chaos and project cancellation. It’s the same as
thinking that devoting all your time to a project (and thereby When you get a new version of Delphi, do you simply kick the tires
neglecting research and development) is selfless and valorous. and take it for a spin, or do you also look under the hood? As Danny
Such self-sacrifice is deleterious to you and your employer or Thorpe said: “Use the source, Luke!” Read it. Seek out the changes
client. Not opening up to better ways means you’re not doing from the last version. What do the new components do? What classes
your best work. have been added that don’t show up on the Component palette? What
functions are new to this version? It would be a shame to rewrite code
Failing to aerate the brain and rejuvenate the creative juices that has already been written, tested, and debugged for you. In Delphi
leads to an atrophy of spirit and an inbreeding of thought. To 6 take a look at the new declaration of TComponent, the new utilities
quote Charlie Calvert on the importance of hacking from Delphi in the Math unit, new units such as StrUtils, ConvUtils, DateUtils,
Unleashed: “Most good programmers spend a large percentage of VarUtils, Bands, etc. Check out the IfThen, AnsiIndexText, Soundex,
their time hacking. If you run a programming shop and you and Metaphone functions. You won’t know they’re available if you don’t
arrange things so that none of your programmers have time to look for them. Be curious; become a Delphi expert!
hack, you will end up with a group of very mediocre program-
mers. The best will either lose their skills, or more likely, head Expand your knowledge: Pick your colleagues’ brains, explore, and
for greener pastures.” experiment. Reading, sharing with others, and scouring OPC (other
people’s code), should give you countless ideas for utilities. Side
If we rely only on personal prior knowledge (been there, done that) projects and hacking, and using technology or components differ-
and hard work (I don’t have time to stop and sharpen the saw, I’ll just ent from your usual group will expand your horizons. Write a
work harder/faster), we are limiting our productivity. database application using a different DBMS and/or engine. Write
components that answer tricky programming challenges or Delphi
What you don’t know can hurt you. An example of this is my FAQs, so you can say: “Just use this component; the functionality
first program in Delphi 1. Its sole purpose was to return the day you’re after is automatically provided.” The possibilities for personal
of the week for a date entered by the user. I labored over this advancement and self-expression are virtually endless. Grab them
little application, and wrote so much complex code, that I got before they grab you. Innovate or stagnate! ∆
a run-time error for using up too much stack space. Finally, the
happy moment came when the code was broken up into smaller — Clay Shannon
methods, the stack space was increased, and the program was
debugged. It worked like a charm. No papa was prouder as I Clay Shannon is an independent Delphi consultant based in northern Idaho. He is
showed off my baby. available for Delphi consulting work in the greater Spokane/Coeur d’Alene areas,
remote development (no job too small!), and short-term or part-time assignments
Not much later, though, I discovered the standard Delphi DayOfWeek in other locales. Clay is a certified Delphi 5 developer, and is the author of Develop-
function. I could have saved myself hours using this function and er’s Guide to Delphi Troubleshooting [Wordware, 1999]. You can reach him at
writing just one line of code! To punish myself I re-wrote the applica- [email protected].
I iwrote the first in this series of columns a year or so ago to concentrate on third-party tools, components, and libraries,
iproviding mini reviews along with tips and techniques. Recently I realized that there are a number of hidden gems —
useful but little-known utilities — that come with Delphi. All of these can be found in the Delphi\Bin folder, and many
go back to early versions of Turbo Pascal.
Command-line utilities. To learn the syntax and options for com- TDump.exe is well named. This utility will literally dump a ton
mand-line utilities, you can usually either type the name alone, or the of information about an executable file to the screen. It lists the
name with a question mark (?) at the command prompt. One of the DOS file size, load-image size, header size, minimum and maximum
veterans of Turbo Pascal is TPC.EXE, the command-line compiler, memory requirement, program entry point, CPU type, O/S version,
with its new name DCC32.EXE. Its long list of available switches various flags and offsets, code and data sizes, and base locations. It
provides you with the many compilation options available in the provides information about exports and imports, resources, object
Delphi IDE. You may be wondering, “Why use such a cumbersome tables, imports from Windows DLLs, and much more.
tool when you have the IDE available and can simply click with the
mouse?” In the old days, one motivation was memory — more was One final command-line tool might be helpful in certain circum-
available at the command prompt than in an IDE. That’s not such an stances. Convert.exe provides a quick and easy way to convert one
issue in compiling large programs today. Another reason for using this or more Delphi form files to either text or binary formats. You
fast compiler is to automate compilation of multiple units in a batch have the option of converting the file in-place, overwriting the
or “make” file, a technique used by third parties when they distribute input file.
patches to their libraries.
Wizards. In addition to the command-line tools we’ve been dis-
Let’s make it. Another venerable utility, MAKE.EXE, is a program cussing, there are many useful Wizards in the \Bin subdirectory.
manager for compiling programs with specific options. Those options Some are integrated into the Delphi IDE; others can be easily
are listed in a text file that generally has a *.mak extension. added to the Tools menu. There are several tools for managing
databases (not available in all editions), including the BDE Admin-
Make files, which are similar to batch files, can be used to automate many istrator, which lets you configure the Borland Database Engine
processes: from building large complex projects, to compiling resource (BDE) among other tasks; Database Explorer, for browsing and
files. Delphi comes with a large make file called, of all things, Makefile! editing database objects; and tools for working with SQL. The
If you have Turbo Assembler and other required files, you can run this Image Editor is a useful tool that provides an easy way to work
with a recent version of MAKE.EXE to rebuild the entire VCL from with graphic files you use in your applications, e.g. icons, cursors,
the command line. You can also edit the file to create either a debug or and bitmaps. Finally, WinSight is a debugging tool that provides
non-debug version of the library. On the command line you can specify information about window classes, windows, and messages. For
options (including the make file to use), and one or more target files. more information on these and other tools, look under Delphi
Productivity Tools in the Delphi Help file.
Other options include specifying whether to conduct auto-dependency
checks, providing the name of an include directory, and indicating Remember, before you go looking for a solution from a third-party
whether to ignore encountered errors. You can do a lot in the main source, check out what’s available with Delphi. You just might discover
make file, such as defining macros. These can serve as shortcuts to exe- the solution to your problem “in the bin.” Until next time... ∆
cutable files (usually compilers), including their full path and options.
You can also define explicit rules and implicit rules. Implicit rules are — Alan C. Moore, Ph.D.
generalizations of the explicit rules and help to simplify a make file.
Alan Moore is a Professor of Music at Kentucky State University, specializing in music
Get a grep or dump it. What’s this grep thing all about? Consider composition and music theory. He has been developing education-related applications
this scenario: Months ago you wrote a wonderful utility that with the Borland languages for more than 15 years. He is the author of The Tomes
accomplished its task perfectly, but now you’ve forgotten which of Delphi: Win 32 Multimedia API [Wordware Publishing, 2000] and co-author (with
programs it’s in. You do remember the name of the routine, so John Penman) of an upcoming book in the Tomes series on Communications APIs. He
it’s grep.exe to the rescue! This fast file-searching utility provides has also published a number of articles in various technical journals. Using Delphi, he
a plethora of options, including word search, regular expression specializes in writing custom components and implementing multimedia capabilities
search, inclusion or exclusion character set searches, and more. Best in applications, particularly sound and music. You can reach Alan on the Internet at
of all, it’s freely available with every version of Delphi. [email protected].