Delphi 7 - Developers Guide
Delphi 7 - Developers Guide
Borland®
™
Delphi 7
for Windows™
Borland Software Corporation
100 Enterprise Way, Scotts Valley, CA 95066-3249
www.borland.com
Refer to the DEPLOY document located in the root directory of your Delphi 7 product for a complete list of files that
you can distribute in accordance with the Delphi 7 License Statement and Limited Warranty.
Borland Software Corporation may have patents and/or pending patent applications covering subject matter in this
document. Please refer to the product CD or the About dialog box for the list of applicable patents. The furnishing of
this document does not give you any license to these patents.
COPYRIGHT © 1983–2002 Borland Software Corporation. All rights reserved. All Borland brand and product names
are trademarks or registered trademarks of Borland Software Corporation in the United States and other countries.
All other marks are the property of their respective owners.
Printed in the U.S.A.
HDE1370WW21001 7E5R0802
0203040506-9 8 7 6 5 4 3 2 1
D3
Contents
Chapter 1 Using object variables . . . . . . . . . . . . . . 4-7
Creating, instantiating, and destroying
Introduction 1-1 objects . . . . . . . . . . . . . . . . . . . . . . 4-8
What’s in this manual? . . . . . . . . . . . . . . 1-1
Components and ownership . . . . . . . . . 4-9
Manual conventions . . . . . . . . . . . . . . . . 1-2
Defining new classes . . . . . . . . . . . . . . . 4-9
Developer support services . . . . . . . . . . . . 1-3
Using interfaces . . . . . . . . . . . . . . . . . . 4-12
Part I Using interfaces across the hierarchy . . . . 4-13
Using interfaces with procedures . . . . . . 4-14
Programming with Delphi Implementing IInterface . . . . . . . . . . . 4-14
TInterfacedObject . . . . . . . . . . . . . . . 4-15
Chapter 2 Using the as operator with interfaces . . . . 4-16
Developing applications with Delphi 2-1 Reusing code and delegation. . . . . . . . . 4-16
Integrated development environment . . . . . . 2-1 Using implements for delegation . . . . 4-17
Designing applications . . . . . . . . . . . . . . 2-2 Aggregation . . . . . . . . . . . . . . . . 4-18
Creating projects . . . . . . . . . . . . . . . . . . 2-3 Memory management of interface
Editing code . . . . . . . . . . . . . . . . . . . . 2-4 objects. . . . . . . . . . . . . . . . . . . . . 4-18
Compiling applications . . . . . . . . . . . . . . 2-4 Using reference counting . . . . . . . . 4-19
Debugging applications . . . . . . . . . . . . . . 2-5 Not using reference counting . . . . . . 4-20
Deploying applications . . . . . . . . . . . . . . 2-5 Using interfaces in distributed
applications . . . . . . . . . . . . . . . . . 4-21
Chapter 3
Using the component library 3-1 Chapter 5
Understanding the component library . . . . . 3-1 Using BaseCLX 5-1
Properties, methods, and events . . . . . . . 3-3 Using streams . . . . . . . . . . . . . . . . . . . 5-2
Properties . . . . . . . . . . . . . . . . . . 3-3 Using streams to read or write data . . . . . 5-2
Methods . . . . . . . . . . . . . . . . . . 3-4 Stream methods for reading
Events . . . . . . . . . . . . . . . . . . . . 3-4 and writing . . . . . . . . . . . . . . . 5-2
User events . . . . . . . . . . . . . . . . . 3-4 Reading and writing components . . . 5-3
System events . . . . . . . . . . . . . . . 3-4 Reading and writing strings . . . . . . . 5-3
Internal events . . . . . . . . . . . . . . . 3-4 Copying data from one stream
Objects, components, and controls . . . . . . . . 3-5 to another. . . . . . . . . . . . . . . . . . . 5-4
TObject branch . . . . . . . . . . . . . . . . . 3-6 Specifying the stream position and size. . . 5-4
TPersistent branch . . . . . . . . . . . . . . . 3-7 Seeking to a specific position . . . . . . 5-4
TComponent branch . . . . . . . . . . . . . . 3-7 Using Position and Size properties . . . 5-5
TControl branch . . . . . . . . . . . . . . . . 3-9 Working with files . . . . . . . . . . . . . . . . 5-5
TWinControl/TWidgetControl branch . . . 3-10 Approaches to file I/O . . . . . . . . . . . . 5-6
Using file streams . . . . . . . . . . . . . . . 5-6
Chapter 4 Creating and opening files using
Using the object model 4-1 file streams . . . . . . . . . . . . . . . 5-7
What is an object? . . . . . . . . . . . . . . . . . 4-1 Using the file handle . . . . . . . . . . . 5-8
Examining a Delphi object . . . . . . . . . . 4-2 Manipulating files . . . . . . . . . . . . . . . 5-8
Changing the name of a component . . . . . 4-4 Deleting a file . . . . . . . . . . . . . . . 5-8
Inheriting data and code from an object. . . . . 4-5 Finding a file . . . . . . . . . . . . . . . 5-8
Scope and qualifiers . . . . . . . . . . . . . . . . 4-5 Renaming a file . . . . . . . . . . . . . . 5-10
Private, protected, public, and published File date-time routines . . . . . . . . . . 5-10
declarations . . . . . . . . . . . . . . . . . . 4-6 Copying a file . . . . . . . . . . . . . . . 5-11
iii
Working with ini files and the system Creating a simple conversion family
Registry . . . . . . . . . . . . . . . . . . . . . 5-11 and adding units. . . . . . . . . . . . . . . 5-34
Using TIniFile and TMemIniFile . . . . 5-12 Declare variables . . . . . . . . . . . . . 5-35
Using TRegistryIniFile . . . . . . . . . 5-13 Register the conversion family . . . . . 5-35
Using TRegistry . . . . . . . . . . . . . 5-13 Register measurement units . . . . . . . 5-35
Working with lists . . . . . . . . . . . . . . . . 5-14 Use the new units . . . . . . . . . . . . . 5-35
Common list operations . . . . . . . . . . . 5-15 Using a conversion function . . . . . . . . . 5-36
Adding list items . . . . . . . . . . . . 5-15 Declare variables . . . . . . . . . . . . . 5-36
Deleting list items . . . . . . . . . . . . 5-15 Register the conversion family . . . . . 5-36
Accessing list items . . . . . . . . . . . 5-16 Register the base unit . . . . . . . . . . 5-36
Rearranging list items . . . . . . . . . . 5-16 Write methods to convert to and
Persistent lists. . . . . . . . . . . . . . . . . 5-16 from the base unit . . . . . . . . . . . . 5-36
Working with string lists . . . . . . . . . . . . 5-17 Register the other units . . . . . . . . . 5-37
Loading and saving string lists . . . . . . . 5-17 Use the new units . . . . . . . . . . . . . 5-37
Creating a new string list . . . . . . . . . . 5-18 Using a class to manage conversions . . . . 5-37
Short-term string lists . . . . . . . . . . 5-18 Creating the conversion class . . . . . . 5-38
Long-term string lists . . . . . . . . . . 5-18 Declare variables . . . . . . . . . . . . . 5-39
Manipulating strings in a list . . . . . . . . 5-20 Register the conversion family and
Counting the strings in a list . . . . . . 5-20 the other units . . . . . . . . . . . . . . 5-39
Accessing a particular string . . . . . . 5-20 Use the new units . . . . . . . . . . . . . 5-40
Locating items in a string list . . . . . . 5-20 Defining custom variants . . . . . . . . . . . . 5-40
Iterating through strings in a list . . . . 5-20 Storing a custom variant type’s data . . . . 5-41
Adding a string to a list . . . . . . . . . 5-21 Creating a class to enable the
Moving a string within a list . . . . . . 5-21 custom variant type . . . . . . . . . . . . . 5-42
Deleting a string from a list . . . . . . . 5-21 Enabling casting . . . . . . . . . . . . . 5-42
Associating objects with a Implementing binary operations . . . . 5-44
string list . . . . . . . . . . . . . . . . 5-22 Implementing comparison
Working with strings . . . . . . . . . . . . . . 5-22 operations . . . . . . . . . . . . . . . . 5-46
Wide character routines . . . . . . . . . . . 5-22 Implementing unary operations . . . . 5-47
Commonly used long string routines . . . 5-23 Copying and clearing custom variants . . . 5-48
Commonly used routines for Loading and saving custom
null-terminated strings. . . . . . . . . . . 5-26 variant values . . . . . . . . . . . . . . 5-49
Declaring and initializing strings . . . . . . 5-27 Using the TCustomVariantType
Mixing and converting string types . . . . 5-28 descendant . . . . . . . . . . . . . . . . 5-50
String to PChar conversions. . . . . . . . . 5-28 Writing utilities to work with a
String dependencies . . . . . . . . . . . 5-29 custom variant type . . . . . . . . . . . . . 5-50
Returning a PChar local variable . . . 5-29 Supporting properties and methods
Passing a local variable as in custom variants . . . . . . . . . . . . . . 5-51
a PChar . . . . . . . . . . . . . . . . . 5-29 Using TInvokeableVariantType . . . . . 5-51
Compiler directives for strings . . . . . . . 5-30 Using TPublishableVariantType . . . . 5-53
Creating drawing spaces . . . . . . . . . . . . 5-31
Printing . . . . . . . . . . . . . . . . . . . . . . 5-32 Chapter 6
Converting measurements . . . . . . . . . . . 5-33 Working with components 6-1
Performing conversions . . . . . . . . . . . 5-33 Setting component properties . . . . . . . . . . 6-2
Performing simple conversions . . . . 5-33 Setting properties at design time . . . . . . 6-2
Performing complex conversions . . . 5-33 Using property editors . . . . . . . . . . 6-3
Adding new measurement types . . . . . . 5-34 Setting properties at runtime. . . . . . . . . 6-3
Calling methods. . . . . . . . . . . . . . . . . . 6-3
iv
Working with events and event handlers . . . . 6-3 Adding graphics to controls . . . . . . . . . . . 7-13
Generating a new event handler . . . . . . . 6-4 Indicating that a control is
Generating a handler for a owner-drawn. . . . . . . . . . . . . . . . . 7-13
component’s default event . . . . . . . . . 6-4 Adding graphical objects to
Locating event handlers . . . . . . . . . . . . 6-4 a string list . . . . . . . . . . . . . . . . . . 7-14
Associating an event with an existing Adding images to an application . . . . 7-14
event handler . . . . . . . . . . . . . . . . . 6-5 Adding images to a string list . . . . . . 7-14
Using the Sender parameter . . . . . . . 6-5 Drawing owner-drawn items . . . . . . 7-15
Displaying and coding shared Sizing owner-draw items . . . . . . . . . . . 7-16
events . . . . . . . . . . . . . . . . . . . 6-5 Drawing owner-draw items . . . . . . . . . 7-17
Associating menu events with
event handlers . . . . . . . . . . . . . . . . 6-6 Chapter 8
Deleting event handlers . . . . . . . . . . . . 6-6 Building applications, components,
Cross-platform and non-cross-platform
components . . . . . . . . . . . . . . . . . . . . 6-7
and libraries 8-1
Creating applications . . . . . . . . . . . . . . . 8-1
Adding custom components to the
GUI applications. . . . . . . . . . . . . . . . 8-2
Component palette . . . . . . . . . . . . . . 6-9
User interface models . . . . . . . . . . 8-2
SDI applications . . . . . . . . . . . . . 8-2
Chapter 7 MDI applications . . . . . . . . . . . . . 8-2
Working with controls 7-1 Setting IDE, project, and compiler
Implementing drag and drop in controls . . . . 7-1 options . . . . . . . . . . . . . . . . . . 8-3
Starting a drag operation . . . . . . . . . . . 7-1 Programming templates . . . . . . . . . . . 8-3
Accepting dragged items . . . . . . . . . . . 7-2 Console applications . . . . . . . . . . . . . 8-4
Dropping items . . . . . . . . . . . . . . . . . 7-3 Service applications . . . . . . . . . . . . . . 8-5
Ending a drag operation. . . . . . . . . . . . 7-3 Service threads . . . . . . . . . . . . . . 8-8
Customizing drag and drop with Service name properties . . . . . . . . . 8-9
a drag object. . . . . . . . . . . . . . . . . . 7-3 Debugging service applications . . . . . 8-10
Changing the drag mouse pointer . . . . . . 7-4 Creating packages and DLLs . . . . . . . . . . 8-11
Implementing drag and dock in controls . . . . 7-4 When to use packages and DLLs . . . . . . 8-11
Making a windowed control a Writing database applications . . . . . . . . . . 8-12
docking site . . . . . . . . . . . . . . . . . . 7-4 Distributing database applications . . . . . 8-13
Making a control a dockable child . . . . . . 7-5 Creating Web server applications . . . . . . . . 8-13
Controlling how child controls Creating Web Broker applications . . . . . . 8-14
are docked . . . . . . . . . . . . . . . . . . . 7-5 Creating WebSnap applications . . . . . . . 8-15
Controlling how child controls Creating Web Services applications . . . . . 8-15
are undocked . . . . . . . . . . . . . . . . . 7-6 Writing applications using COM . . . . . . . . 8-16
Controlling how child controls respond Using COM and DCOM . . . . . . . . . . . 8-16
to drag-and-dock operations . . . . . . . . 7-6 Using MTS and COM+ . . . . . . . . . . . . 8-16
Working with text in controls. . . . . . . . . . . 7-6 Using data modules . . . . . . . . . . . . . . . 8-17
Setting text alignment . . . . . . . . . . . . . 7-7 Creating and editing standard data
Adding scroll bars at runtime . . . . . . . . . 7-7 modules. . . . . . . . . . . . . . . . . . . . 8-17
Adding the clipboard object. . . . . . . . . . 7-8 Naming a data module and
Selecting text . . . . . . . . . . . . . . . . . . 7-9 its unit file . . . . . . . . . . . . . . . . 8-18
Selecting all text . . . . . . . . . . . . . . . . 7-9 Placing and naming components . . . . 8-19
Cutting, copying, and pasting text . . . . . 7-10 Using component properties and
Deleting selected text . . . . . . . . . . . . 7-10 events in a data module . . . . . . . . 8-19
Disabling menu items . . . . . . . . . . . . 7-11 Creating business rules in a
Providing a pop-up menu . . . . . . . . . . 7-11 data module . . . . . . . . . . . . . . . 8-20
Handling the OnPopup event. . . . . . . . 7-12
v
Accessing a data module from a form . . . 8-20 Chapter 9
Adding a remote data module to an
application server project . . . . . . . . . 8-21
Developing the application
Using the Object Repository . . . . . . . . . . 8-21 user interface 9-1
Sharing items within a project . . . . . . . 8-21 Controlling application behavior . . . . . . . . 9-1
Adding items to the Object Working at the application level . . . . . . . 9-2
Repository . . . . . . . . . . . . . . . . . . 8-22 Handling the screen . . . . . . . . . . . . . . 9-2
Sharing objects in a team Setting up forms. . . . . . . . . . . . . . . . . . 9-3
environment. . . . . . . . . . . . . . . . . 8-22 Using the main form . . . . . . . . . . . . . 9-3
Using an Object Repository item in Hiding the main form. . . . . . . . . . . . . 9-3
a project . . . . . . . . . . . . . . . . . . . 8-22 Adding forms . . . . . . . . . . . . . . . . . 9-4
Copying an item . . . . . . . . . . . . . 8-22 Linking forms . . . . . . . . . . . . . . . 9-4
Inheriting an item . . . . . . . . . . . . 8-23 Avoiding circular unit references . . . . 9-4
Using an item . . . . . . . . . . . . . . 8-23 Managing layout . . . . . . . . . . . . . . . 9-5
Using project templates . . . . . . . . . . . 8-23 Using forms . . . . . . . . . . . . . . . . . . . . 9-6
Modifying shared items . . . . . . . . . . . 8-23 Controlling when forms reside
Specifying a default project, new form, in memory . . . . . . . . . . . . . . . . . . 9-6
and main form . . . . . . . . . . . . . . . 8-24 Displaying an auto-created form . . . . 9-6
Enabling Help in applications . . . . . . . . . 8-24 Creating forms dynamically . . . . . . . 9-7
Help system interfaces . . . . . . . . . . . . 8-25 Creating modeless forms such
Implementing ICustomHelpViewer . . . . 8-25 as windows . . . . . . . . . . . . . . . 9-8
Communicating with the Help Creating a form instance using
Manager . . . . . . . . . . . . . . . . . . . 8-26 a local variable . . . . . . . . . . . . . 9-8
Asking the Help Manager for Passing additional arguments to forms . . . 9-8
information . . . . . . . . . . . . . . . . . 8-26 Retrieving data from forms. . . . . . . . . . 9-9
Displaying keyword-based Help . . . . . . 8-27 Retrieving data from modeless
Displaying tables of contents . . . . . . . . 8-28 forms . . . . . . . . . . . . . . . . . . . 9-9
Implementing IExtendedHelpViewer . . . 8-28 Retrieving data from modal forms . . . 9-11
Implementing IHelpSelector . . . . . . . . 8-29 Reusing components and groups of
Registering Help system objects . . . . . . 8-30 components . . . . . . . . . . . . . . . . . . . 9-13
Registering Help viewers . . . . . . . . 8-30 Creating and using component
Registering Help selectors . . . . . . . 8-30 templates . . . . . . . . . . . . . . . . . . . . . 9-13
Using Help in a VCL application. . . . . . . . 8-31 Working with frames . . . . . . . . . . . . . . . 9-14
How TApplication processes Creating frames . . . . . . . . . . . . . . . . 9-14
VCL Help . . . . . . . . . . . . . . . . . . 8-31 Adding frames to the Component
How VCL controls process Help . . . . . . 8-31 palette . . . . . . . . . . . . . . . . . . . . . 9-15
Using Help in a CLX application. . . . . . . . 8-32 Using and modifying frames. . . . . . . . . 9-15
How TApplication processes Sharing frames. . . . . . . . . . . . . . . . . 9-16
CLX Help . . . . . . . . . . . . . . . . . . 8-32 Developing dialog boxes . . . . . . . . . . . . . 9-17
How CLX controls process Help . . . . . . 8-32 Using open dialog boxes . . . . . . . . . . . 9-17
Calling a Help system directly . . . . . . . . . 8-33 Organizing actions for toolbars
Using IHelpSystem . . . . . . . . . . . . . . . 8-33 and menus . . . . . . . . . . . . . . . . . . . . 9-18
Customizing the IDE Help system . . . . . . . 8-34 What is an action? . . . . . . . . . . . . . . . 9-19
Setting up action bands . . . . . . . . . . . . 9-20
vi
Creating toolbars and menus . . . . . . . . 9-20 Manipulating menu items at runtime . . . . 9-44
Adding color, patterns, or pictures Merging menus . . . . . . . . . . . . . . . . 9-44
to menus, buttons, and toolbars . . . 9-22 Specifying the active menu: Menu
Adding icons to menus and property . . . . . . . . . . . . . . . . . 9-45
toolbars . . . . . . . . . . . . . . . . . 9-22 Determining the order of merged menu
Selecting menu and toolbar styles . . . 9-23 items: GroupIndex property . . . . . . 9-45
Creating dynamic menus . . . . . . . . 9-24 Importing resource files . . . . . . . . . . . 9-45
Creating toolbars and menus that Designing toolbars and cool bars . . . . . . . . 9-46
users can customize . . . . . . . . . . 9-24 Adding a toolbar using a panel
Hiding unused items and categories component . . . . . . . . . . . . . . . . . . 9-47
in action bands . . . . . . . . . . . . . 9-24 Adding a speed button to a panel . . . 9-47
Creating most recently used Assigning a speed button’s glyph . . . 9-48
(MRU) lists . . . . . . . . . . . . . . . 9-25 Setting the initial condition of a
Using action lists . . . . . . . . . . . . . . . . . 9-26 speed button . . . . . . . . . . . . . . . 9-48
Setting up action lists . . . . . . . . . . . . 9-26 Creating a group of speed buttons . . . 9-48
What happens when an action fires . . . . 9-27 Allowing toggle buttons . . . . . . . . . 9-49
Responding with events . . . . . . . . 9-27 Adding a toolbar using the toolbar
How actions find their targets . . . . . 9-29 component . . . . . . . . . . . . . . . . . . 9-49
Updating actions . . . . . . . . . . . . . . . 9-29 Adding a tool button . . . . . . . . . . . 9-49
Predefined action classes . . . . . . . . . . 9-30 Assigning images to tool buttons . . . . 9-50
Writing action components . . . . . . . . . 9-31 Setting tool button appearance and
Registering actions . . . . . . . . . . . . . . 9-31 initial conditions . . . . . . . . . . . . 9-50
Creating and managing menus. . . . . . . . . 9-32 Creating groups of tool buttons . . . . . 9-51
Opening the Menu Designer . . . . . . . . 9-33 Allowing toggled tool buttons . . . . . 9-51
Building menus . . . . . . . . . . . . . . . . 9-34 Adding a cool bar component . . . . . . . . 9-51
Naming menus . . . . . . . . . . . . . 9-34 Setting the appearance of the
Naming the menu items . . . . . . . . 9-34 cool bar . . . . . . . . . . . . . . . . . . 9-52
Adding, inserting, and deleting Responding to clicks . . . . . . . . . . . . . 9-52
menu items . . . . . . . . . . . . . . . 9-35 Assigning a menu to a tool button . . . 9-52
Adding separator bars . . . . . . . . . 9-36 Adding hidden toolbars . . . . . . . . . . . 9-53
Specifying accelerator keys and Hiding and showing toolbars . . . . . . . . 9-53
keyboard shortcuts . . . . . . . . . . 9-36 Demo programs . . . . . . . . . . . . . . . . 9-53
Creating submenus. . . . . . . . . . . . . . 9-37 Common controls and XP themes. . . . . . . . 9-54
Creating submenus by demoting
existing menus . . . . . . . . . . . . . 9-37 Chapter 10
Moving menu items . . . . . . . . . . . 9-38 Types of controls 10-1
Adding images to menu items . . . . . 9-38 Text controls . . . . . . . . . . . . . . . . . . . . 10-1
Viewing the menu . . . . . . . . . . . . 9-39 Edit controls . . . . . . . . . . . . . . . . . . 10-1
Editing menu items in the Object Memo and rich edit controls . . . . . . 10-2
Inspector . . . . . . . . . . . . . . . . . . . 9-39 Text viewing controls . . . . . . . . . . . . . 10-3
Using the Menu Designer context Labels . . . . . . . . . . . . . . . . . . . . . . 10-3
menu . . . . . . . . . . . . . . . . . . . . . 9-40 Specialized input controls . . . . . . . . . . . . 10-4
Commands on the context menu . . . 9-40 Scroll bars . . . . . . . . . . . . . . . . . . . 10-4
Switching between menus at Track bars. . . . . . . . . . . . . . . . . . . . 10-5
design time . . . . . . . . . . . . . . . 9-41 Up-down controls . . . . . . . . . . . . . . . 10-5
Using menu templates . . . . . . . . . . . . 9-41 Spin edit controls (CLX only) . . . . . . . . 10-5
Saving a menu as a template . . . . . . . . 9-43 Hot key controls (VCL only) . . . . . . . . . 10-6
Naming conventions for template Splitter controls . . . . . . . . . . . . . . . . 10-6
menu items and event handlers . . . 9-44
vii
Buttons and similar controls . . . . . . . . . . 10-6 Using ModelMaker views . . . . . . . . . . . . 11-4
Button controls . . . . . . . . . . . . . . . . 10-7 Collections pane . . . . . . . . . . . . . . . . 11-5
Bitmap buttons . . . . . . . . . . . . . . . . 10-7 Classes view . . . . . . . . . . . . . . . . 11-5
Speed buttons. . . . . . . . . . . . . . . . . 10-8 Units view . . . . . . . . . . . . . . . . . 11-5
Check boxes . . . . . . . . . . . . . . . . . . 10-8 Diagrams view . . . . . . . . . . . . . . 11-6
Radio buttons . . . . . . . . . . . . . . . . . 10-8 Members pane . . . . . . . . . . . . . . . . . 11-7
Toolbars . . . . . . . . . . . . . . . . . . . . 10-9 Editors pane . . . . . . . . . . . . . . . . . . 11-7
Cool bars (VCL only). . . . . . . . . . . . . 10-9 Implementation Editor . . . . . . . . . . 11-7
List controls. . . . . . . . . . . . . . . . . . . . 10-9 Unit Code Editor . . . . . . . . . . . . . 11-8
List boxes and check-list boxes . . . . . . . 10-10 Diagram Editor . . . . . . . . . . . . . . 11-9
Combo boxes . . . . . . . . . . . . . . . . . 10-11 Other Editors . . . . . . . . . . . . . . . 11-9
Tree views . . . . . . . . . . . . . . . . . . . 10-11 For more information. . . . . . . . . . . . . . 11-10
List views . . . . . . . . . . . . . . . . . . . 10-12
Icon views (CLX only) . . . . . . . . . . . . 10-12 Chapter 12
Date-time pickers and month Working with graphics and
calendars. . . . . . . . . . . . . . . . . . . 10-12
Grouping controls . . . . . . . . . . . . . . . . 10-12
multimedia 12-1
Overview of graphics programming . . . . . . 12-1
Group boxes and radio groups . . . . . . . 10-13
Refreshing the screen . . . . . . . . . . . . . 12-2
Panels . . . . . . . . . . . . . . . . . . . . . 10-13
Types of graphic objects . . . . . . . . . . . 12-3
Scroll boxes . . . . . . . . . . . . . . . . . . 10-13
Common properties and methods
Tab controls . . . . . . . . . . . . . . . . . . 10-14
of Canvas . . . . . . . . . . . . . . . . . . . 12-4
Page controls . . . . . . . . . . . . . . . . . 10-14
Using the properties of the Canvas
Header controls. . . . . . . . . . . . . . . . 10-14
object . . . . . . . . . . . . . . . . . . . . . 12-5
Display controls . . . . . . . . . . . . . . . . . 10-15
Using pens . . . . . . . . . . . . . . . . 12-5
Status bars. . . . . . . . . . . . . . . . . . . 10-15
Using brushes . . . . . . . . . . . . . . . 12-8
Progress bars . . . . . . . . . . . . . . . . . 10-15
Reading and setting pixels . . . . . . . 12-9
Help and hint properties . . . . . . . . . . 10-16
Using Canvas methods to draw
Grids. . . . . . . . . . . . . . . . . . . . . . . . 10-16
graphic objects . . . . . . . . . . . . . . . 12-10
Draw grids . . . . . . . . . . . . . . . . . . 10-16
Drawing lines and polylines . . . . . 12-10
String grids . . . . . . . . . . . . . . . . . . 10-16
Drawing shapes . . . . . . . . . . . . . 12-11
Value list editors (VCL only) . . . . . . . . . . 10-17
Handling multiple drawing objects
Graphic controls . . . . . . . . . . . . . . . . . 10-18
in your application . . . . . . . . . . . . 12-12
Images . . . . . . . . . . . . . . . . . . . . . 10-18
Keeping track of which drawing
Shapes . . . . . . . . . . . . . . . . . . . . . 10-18
tool to use . . . . . . . . . . . . . . . 12-12
Bevels . . . . . . . . . . . . . . . . . . . . . 10-18
Changing the tool with speed
Paint boxes . . . . . . . . . . . . . . . . . . 10-19
buttons . . . . . . . . . . . . . . . . . 12-13
Animation control . . . . . . . . . . . . . . 10-19
Using drawing tools . . . . . . . . . . 12-14
Drawing on a graphic . . . . . . . . . . . . 12-16
Chapter 11 Making scrollable graphics . . . . . . 12-17
Designing classes and Adding an image control . . . . . . . 12-17
components with ModelMaker 11-1 Loading and saving graphics files . . . . . 12-19
ModelMaker fundamentals . . . . . . . . . . . 11-2 Loading a picture from a file . . . . . 12-19
ModelMaker models . . . . . . . . . . . . . 11-2 Saving a picture to a file . . . . . . . . 12-20
Using ModelMaker with the IDE . . . . . . 11-2 Replacing the picture . . . . . . . . . . 12-20
Creating models . . . . . . . . . . . . . . . 11-3
viii
Using the clipboard with graphics . . . . . 12-21 Executing thread objects . . . . . . . . . . . . 13-12
Copying graphics to the Overriding the default priority . . . . . . 13-12
clipboard . . . . . . . . . . . . . . . . 12-22 Starting and stopping threads . . . . . . . 13-12
Cutting graphics to the clipboard . . . 12-22 Debugging multi-threaded applications . . . 13-13
Pasting graphics from the Naming a thread. . . . . . . . . . . . . . . 13-13
clipboard . . . . . . . . . . . . . . . . 12-23 Converting an unnamed thread
Rubber banding example . . . . . . . . . . 12-24 to a named thread . . . . . . . . . . 13-13
Responding to the mouse . . . . . . . . 12-24 Assigning separate names to
Responding to a mouse-down similar threads . . . . . . . . . . . . 13-15
action . . . . . . . . . . . . . . . . . . 12-25
Adding a field to a form object to Chapter 14
track mouse actions . . . . . . . . . . 12-27 Exception handling 14-1
Refining line drawing . . . . . . . . . . 12-28 Defining protected blocks . . . . . . . . . . . . 14-2
Working with multimedia . . . . . . . . . . . 12-30 Writing the try block . . . . . . . . . . . . . 14-2
Adding silent video clips to an Raising an exception . . . . . . . . . . . 14-3
application. . . . . . . . . . . . . . . . . . 12-30 Writing exception handlers. . . . . . . . . . 14-4
Example of adding silent Exception-handling statements . . . . . 14-4
video clips . . . . . . . . . . . . . . . 12-31 Handling classes of exceptions . . . . . 14-6
Adding audio and/or video clips to Scope of exception handlers . . . . . . . 14-6
an application . . . . . . . . . . . . . . . . 12-32 Reraising exceptions . . . . . . . . . . . 14-7
Example of adding audio and/or Writing finally blocks . . . . . . . . . . . . . 14-8
video clips (VCL only) . . . . . . . . 12-33 Writing a finally block . . . . . . . . . . 14-9
Handling exceptions in VCL
Chapter 13 applications . . . . . . . . . . . . . . . . . . . 14-9
Writing multi-threaded applications 13-1 VCL exception classes . . . . . . . . . . . 14-10
Defining thread objects . . . . . . . . . . . . . 13-2 Default exception handling in VCL . . . . 14-11
Initializing the thread . . . . . . . . . . . . 13-3 Silent exceptions. . . . . . . . . . . . . . . 14-12
Assigning a default priority . . . . . . 13-3 Defining your own VCL exceptions. . . . 14-13
Indicating when threads are freed . . . 13-4
Writing the thread function . . . . . . . . . 13-4 Chapter 15
Using the main VCL/CLX thread . . . 13-4 Developing cross-platform
Using thread-local variables . . . . . . 13-6
Checking for termination by other
applications 15-1
Creating CLX applications . . . . . . . . . . . . 15-2
threads . . . . . . . . . . . . . . . . . 13-6
Porting VCL applications . . . . . . . . . . . . 15-2
Handling exceptions in the thread
Porting techniques . . . . . . . . . . . . . . 15-2
function . . . . . . . . . . . . . . . . . 13-6
Platform-specific ports . . . . . . . . . . 15-3
Writing clean-up code . . . . . . . . . . . . 13-7
Cross-platform ports . . . . . . . . . . . 15-3
Coordinating threads . . . . . . . . . . . . . . 13-7
Windows emulation ports . . . . . . . . 15-3
Avoiding simultaneous access . . . . . . . 13-7
Modifying VCL applications . . . . . . . . . 15-4
Locking objects . . . . . . . . . . . . . 13-8
WinCLX versus VisualCLX. . . . . . . . . . 15-5
Using critical sections . . . . . . . . . . 13-8
What VisualCLX does differently . . . . 15-6
Using the multi-read exclusive-write
Features that do not port directly
synchronizer . . . . . . . . . . . . . . 13-8
or are missing . . . . . . . . . . . . . . . . 15-7
Other techniques for sharing
Comparing WinCLX and
memory . . . . . . . . . . . . . . . . . 13-9
VisualCLX units . . . . . . . . . . . . . . . 15-8
Waiting for other threads . . . . . . . . . . 13-9
Differences in CLX object constructors . . 15-11
Waiting for a thread to finish
Handling system and widget events . . . 15-12
executing . . . . . . . . . . . . . . . . 13-10
Waiting for a task to be
completed . . . . . . . . . . . . . . . 13-10
ix
Writing portable code . . . . . . . . . . . . 15-12 Editing package source files
Using conditional directives . . . . . . 15-13 manually . . . . . . . . . . . . . . . . . . 16-10
Terminating conditional Compiling packages . . . . . . . . . . . . 16-10
directives . . . . . . . . . . . . . . . . 15-14 Package-specific compiler
Including inline assembler code . . . . 15-15 directives . . . . . . . . . . . . . . . . 16-11
Programming differences on Linux . . . . 15-16 Compiling and linking from the
Transferring applications between command line . . . . . . . . . . . . . 16-13
Windows and Linux . . . . . . . . . . . . . . 15-17 Package files created when
Sharing source files between compiling . . . . . . . . . . . . . . . 16-13
Windows and Linux . . . . . . . . . . . . 15-17 Deploying packages . . . . . . . . . . . . . . 16-14
Environmental differences between Deploying applications that use
Windows and Linux . . . . . . . . . . . . 15-18 packages . . . . . . . . . . . . . . . . . . 16-14
Registry . . . . . . . . . . . . . . . . . . 15-20 Distributing packages to other
Look and feel . . . . . . . . . . . . . . . 15-20 developers . . . . . . . . . . . . . . . . . 16-14
Directory structure on Linux . . . . . . . . 15-20 Package collection files . . . . . . . . . . . 16-14
Cross-platform database applications . . . . . 15-21
dbExpress differences . . . . . . . . . . . . 15-22 Chapter 17
Component-level differences . . . . . . . . 15-22 Creating international applications 17-1
User interface-level differences . . . . . . . 15-23 Internationalization and localization . . . . . . 17-1
Porting database applications Internationalization . . . . . . . . . . . . . . 17-1
to Linux . . . . . . . . . . . . . . . . . . . 15-24 Localization . . . . . . . . . . . . . . . . . . 17-2
Updating data in dbExpress Internationalizing applications . . . . . . . . . 17-2
applications . . . . . . . . . . . . . . . . . 15-26 Enabling application code . . . . . . . . . . 17-2
Cross-platform Internet applications . . . . . 15-28 ~Character sets . . . . . . . . . . . . . . 17-2
Porting Internet applications OEM and ANSI character sets . . . . . 17-3
to Linux . . . . . . . . . . . . . . . . . . . 15-28 Multibyte character sets . . . . . . . . . 17-3
Wide characters . . . . . . . . . . . . . . 17-4
Chapter 16 Including bi-directional functionality
Working with packages and in applications . . . . . . . . . . . . . . 17-4
components 16-1 BiDiMode property . . . . . . . . . . . . 17-4
Why use packages? . . . . . . . . . . . . . . . 16-2 Locale-specific features . . . . . . . . . 17-7
Packages and standard DLLs . . . . . . . . 16-2 Designing the user interface . . . . . . . . . 17-7
Runtime packages . . . . . . . . . . . . . . . . 16-3 Text . . . . . . . . . . . . . . . . . . . . . 17-7
Loading packages in an application . . . . 16-3 Graphic images . . . . . . . . . . . . . . 17-8
Loading packages with the Formats and sort order . . . . . . . . . . 17-8
LoadPackage function . . . . . . . . . . 16-4 Keyboard mappings . . . . . . . . . . . 17-8
Deciding which runtime packages Isolating resources. . . . . . . . . . . . . . . 17-8
to use . . . . . . . . . . . . . . . . . . . . . 16-4 Creating resource DLLs. . . . . . . . . . . . 17-9
Custom packages . . . . . . . . . . . . . . . 16-5 Using resource DLLs . . . . . . . . . . . . 17-10
Design-time packages . . . . . . . . . . . . . . 16-5 Dynamic switching of resource DLLs . . . 17-11
Installing component packages . . . . . . . 16-6 Localizing applications . . . . . . . . . . . . . 17-12
Creating and editing packages . . . . . . . . . 16-7 Localizing resources. . . . . . . . . . . . . 17-12
Creating a package . . . . . . . . . . . . . . 16-7
Editing an existing package . . . . . . . . . 16-8
Understanding the structure of
a package . . . . . . . . . . . . . . . . . . 16-8
Naming packages . . . . . . . . . . . . 16-8
Requires clause . . . . . . . . . . . . . 16-9
Contains clause . . . . . . . . . . . . . 16-9
x
Chapter 18 Transactions . . . . . . . . . . . . . . . . . . 19-4
Referential integrity, stored procedures,
Deploying applications 18-1 and triggers. . . . . . . . . . . . . . . . . . 19-5
Deploying general applications . . . . . . . . 18-1
Database architecture. . . . . . . . . . . . . . . 19-6
Using installation programs. . . . . . . . . 18-2
General structure . . . . . . . . . . . . . . . 19-6
Identifying application files . . . . . . 18-2
The user interface form . . . . . . . . . 19-6
Application files . . . . . . . . . . . . . 18-3
The data module . . . . . . . . . . . . . 19-6
Package files . . . . . . . . . . . . . . . 18-3
Connecting directly to a database
Merge modules . . . . . . . . . . . . . 18-3
server . . . . . . . . . . . . . . . . . . . . . 19-8
ActiveX controls . . . . . . . . . . . . . 18-5
Using a dedicated file on disk . . . . . . . . 19-9
Helper applications . . . . . . . . . . . 18-5
Connecting to another dataset . . . . . . . 19-10
DLL locations . . . . . . . . . . . . . . 18-6
Connecting a client dataset to another
Deploying CLX applications . . . . . . . . . . 18-6
dataset in the same application . . . 19-12
Deploying database applications. . . . . . . . 18-6
Using a multi-tiered architecture . . . 19-13
Deploying dbExpress database
Combining approaches . . . . . . . . . . . 19-14
applications . . . . . . . . . . . . . . . . . 18-7
Designing the user interface . . . . . . . . . . 19-15
Deploying BDE applications . . . . . . . . 18-8
Analyzing data . . . . . . . . . . . . . . . 19-15
Borland Database Engine . . . . . . . . 18-8
Writing reports. . . . . . . . . . . . . . . . 19-16
Deploying multi-tiered database
applications (DataSnap) . . . . . . . . . . 18-9
Deploying Web applications . . . . . . . . . . 18-9
Chapter 20
Deploying on Apache servers . . . . . . . 18-10 Using data controls 20-1
Enabling modules . . . . . . . . . . . . 18-10 Using common data control features . . . . . . 20-2
CGI applications . . . . . . . . . . . . . 18-11 Associating a data control with
Programming for varying host a dataset . . . . . . . . . . . . . . . . . . . 20-3
environments . . . . . . . . . . . . . . . . . . 18-12 Changing the associated dataset
Screen resolutions and color depths . . . . 18-12 at runtime . . . . . . . . . . . . . . . . 20-4
Considerations when not Enabling and disabling the data
dynamically resizing . . . . . . . . . 18-12 source . . . . . . . . . . . . . . . . . . 20-4
Considerations when dynamically Responding to changes mediated
resizing forms and controls . . . . . . 18-13 by the data source . . . . . . . . . . . 20-4
Accommodating varying Editing and updating data . . . . . . . . . . 20-5
color depths . . . . . . . . . . . . . . 18-14 Enabling editing in controls on
Fonts . . . . . . . . . . . . . . . . . . . . . . 18-14 user entry . . . . . . . . . . . . . . . . 20-5
Operating systems versions . . . . . . . . . 18-15 Editing data in a control . . . . . . . . . 20-5
Software license requirements . . . . . . . . . 18-15 Disabling and enabling data display . . . . 20-6
DEPLOY . . . . . . . . . . . . . . . . . . . . 18-15 Refreshing data display. . . . . . . . . . . . 20-7
README . . . . . . . . . . . . . . . . . . . 18-16 Enabling mouse, keyboard, and
No-nonsense license agreement . . . . . . 18-16 timer events . . . . . . . . . . . . . . . . . 20-7
Third-party product documentation . . . . 18-16 Choosing how to organize the data . . . . . . . 20-7
Displaying a single record . . . . . . . . . . 20-7
Part II Displaying data as labels . . . . . . . . 20-8
Displaying and editing fields in
Developing database applications an edit box . . . . . . . . . . . . . . . . 20-8
Displaying and editing text in a
Chapter 19 memo control . . . . . . . . . . . . . . 20-9
Designing database applications 19-1 Displaying and editing text in a rich
Using databases . . . . . . . . . . . . . . . . . 19-1 edit memo control . . . . . . . . . . . 20-9
Types of databases . . . . . . . . . . . . . . 19-2 Displaying and editing graphics
Database security. . . . . . . . . . . . . . . 19-4 fields in an image control . . . . . . 20-10
xi
Displaying and editing data in list Component overview . . . . . . . . . . . . . . 21-4
and combo boxes . . . . . . . . . . . 20-10 VCL/CLX components . . . . . . . . . . . . 21-4
Handling Boolean field values Engine components . . . . . . . . . . . 21-4
with check boxes . . . . . . . . . . . . 20-13 Render components . . . . . . . . . . . 21-4
Restricting field values with Data connection components . . . . . . 21-4
radio controls . . . . . . . . . . . . . . 20-14 Rave project component . . . . . . . . . 21-5
Displaying multiple records. . . . . . . . . 20-14 Reporting components . . . . . . . . . . . . 21-5
Viewing and editing data with TDBGrid . . . 20-15 Project components . . . . . . . . . . . . 21-5
Using a grid control in its default Data objects . . . . . . . . . . . . . . . . 21-5
state . . . . . . . . . . . . . . . . . . . . . 20-16 Standard components . . . . . . . . . . 21-5
Creating a customized grid . . . . . . . . . 20-17 Drawing components . . . . . . . . . . 21-5
Understanding persistent Report components . . . . . . . . . . . . 21-6
columns . . . . . . . . . . . . . . . . . 20-17 Bar code components . . . . . . . . . . 21-6
Creating persistent columns . . . . . . 20-18 Getting more information . . . . . . . . . . . . 21-6
Deleting persistent columns . . . . . . 20-19
Arranging the order of persistent Chapter 22
columns . . . . . . . . . . . . . . . . . 20-19 Using decision support
Setting column properties at
design time . . . . . . . . . . . . . . . 20-20
components 22-1
Overview . . . . . . . . . . . . . . . . . . . . . 22-1
Defining a lookup list column . . . . . 20-21
About crosstabs . . . . . . . . . . . . . . . . . . 22-2
Putting a button in a column . . . . . . 20-22
One-dimensional crosstabs. . . . . . . . . . 22-3
Restoring default values to
Multidimensional crosstabs . . . . . . . . . 22-3
a column . . . . . . . . . . . . . . . . 20-22
Guidelines for using decision support
Displaying ADT and array fields . . . . . . 20-22
components . . . . . . . . . . . . . . . . . . . 22-4
Setting grid options . . . . . . . . . . . . . 20-24
Using datasets with decision support
Editing in the grid . . . . . . . . . . . . . . 20-26
components . . . . . . . . . . . . . . . . . . . 22-5
Controlling grid drawing . . . . . . . . . . 20-26
Creating decision datasets with
Responding to user actions
TQuery or TTable . . . . . . . . . . . . . . 22-6
at runtime . . . . . . . . . . . . . . . . . . 20-27
Creating decision datasets with the
Creating a grid that contains other
Decision Query editor. . . . . . . . . . . . 22-6
data-aware controls . . . . . . . . . . . . . . 20-28
Using decision cubes . . . . . . . . . . . . . . . 22-7
Navigating and manipulating records. . . . . 20-29
Decision cube properties and events . . . . 22-7
Choosing navigator buttons to
Using the Decision Cube editor . . . . . . . 22-8
display . . . . . . . . . . . . . . . . . . . . 20-30
Viewing and changing dimension
Hiding and showing navigator
settings . . . . . . . . . . . . . . . . . . 22-8
buttons at design time . . . . . . . . . 20-30
Setting the maximum available
Hiding and showing navigator
dimensions and summaries . . . . . . 22-9
buttons at runtime . . . . . . . . . . . 20-31
Viewing and changing design
Displaying fly-over help. . . . . . . . . . . 20-31
options . . . . . . . . . . . . . . . . . . 22-9
Using a single navigator for multiple
Using decision sources . . . . . . . . . . . . . . 22-9
datasets . . . . . . . . . . . . . . . . . . . 20-32
Properties and events . . . . . . . . . . . . . 22-9
Using decision pivots. . . . . . . . . . . . . . 22-10
Chapter 21 Decision pivot properties. . . . . . . . . . 22-10
Creating reports with Rave Reports 21-1 Creating and using decision grids . . . . . . 22-11
Overview . . . . . . . . . . . . . . . . . . . . . 21-1 Creating decision grids . . . . . . . . . . . 22-11
Getting started . . . . . . . . . . . . . . . . . . 21-2 Using decision grids . . . . . . . . . . . . 22-11
The Rave Visual Designer. . . . . . . . . . . . 21-3 Opening and closing decision
grid fields . . . . . . . . . . . . . . . 22-11
xii
Reorganizing rows and columns in Obtaining metadata. . . . . . . . . . . . . . . 23-13
decision grids . . . . . . . . . . . . . 22-12 Listing available tables . . . . . . . . . . . 23-14
Drilling down for detail in Listing the fields in a table . . . . . . . . . 23-14
decision grids . . . . . . . . . . . . . 22-12 Listing available stored procedures . . . . 23-14
Limiting dimension selection in Listing available indexes . . . . . . . . . . 23-14
decision grids . . . . . . . . . . . . . 22-12 Listing stored procedure parameters . . . 23-15
Decision grid properties . . . . . . . . . . . 22-12
Creating and using decision graphs . . . . . . 22-13 Chapter 24
Creating decision graphs . . . . . . . . . . 22-13 Understanding datasets 24-1
Using decision graphs . . . . . . . . . . . . 22-14 Using TDataSet descendants . . . . . . . . . . 24-2
The decision graph display . . . . . . . . . 22-15 Determining dataset states. . . . . . . . . . . . 24-3
Customizing decision graphs . . . . . . . . 22-16 Opening and closing datasets . . . . . . . . . . 24-4
Setting decision graph template Navigating datasets. . . . . . . . . . . . . . . . 24-5
defaults . . . . . . . . . . . . . . . . . 22-17 Using the First and Last methods . . . . . . 24-6
Customizing decision graph Using the Next and Prior methods . . . . . 24-7
series . . . . . . . . . . . . . . . . . . 22-18 Using the MoveBy method . . . . . . . . . . 24-7
Decision support components at Using the Eof and Bof properties . . . . . . 24-8
runtime . . . . . . . . . . . . . . . . . . . . . 22-19 Eof . . . . . . . . . . . . . . . . . . . . . 24-8
Decision pivots at runtime . . . . . . . . . 22-19 Bof . . . . . . . . . . . . . . . . . . . . . 24-9
Decision grids at runtime . . . . . . . . . . 22-19 Marking and returning to records . . . . . . 24-9
Decision graphs at runtime . . . . . . . . . 22-20 The Bookmark property . . . . . . . . . 24-9
Decision support components and The GetBookmark method . . . . . . 24-10
memory control . . . . . . . . . . . . . . . . 22-20 The GotoBookmark and
Setting maximum dimensions, BookmarkValid methods . . . . . . . 24-10
summaries, and cells . . . . . . . . . . . . 22-20 The CompareBookmarks method . . 24-10
Setting dimension state . . . . . . . . . . . 22-21 The FreeBookmark method . . . . . . 24-10
Using paged dimensions . . . . . . . . . . 22-21 A bookmarking example . . . . . . . 24-10
Searching datasets . . . . . . . . . . . . . . . 24-11
Chapter 23 Using Locate . . . . . . . . . . . . . . . . . 24-11
Connecting to databases 23-1 Using Lookup . . . . . . . . . . . . . . . . 24-12
Using implicit connections . . . . . . . . . . . 23-2 Displaying and editing a subset of data
Controlling connections . . . . . . . . . . . . . 23-3 using filters . . . . . . . . . . . . . . . . . . 24-13
Connecting to a database server . . . . . . 23-3 Enabling and disabling filtering . . . . . . 24-13
Disconnecting from a database server . . . 23-4 Creating filters . . . . . . . . . . . . . . . . 24-13
Controlling server login . . . . . . . . . . . . . 23-4 Setting the Filter property . . . . . . . 24-14
Managing transactions . . . . . . . . . . . . . 23-6 Writing an OnFilterRecord
Starting a transaction . . . . . . . . . . . . 23-7 event handler . . . . . . . . . . . . . 24-15
Ending a transaction . . . . . . . . . . . . . 23-8 Switching filter event handlers
Ending a successful transaction . . . . 23-8 at runtime . . . . . . . . . . . . . . . 24-16
Ending an unsuccessful Setting filter options. . . . . . . . . . . . . 24-16
transaction . . . . . . . . . . . . . . . 23-9 Navigating records in a filtered
Specifying the transaction dataset . . . . . . . . . . . . . . . . . . . 24-16
isolation level . . . . . . . . . . . . . . . . 23-9 Modifying data . . . . . . . . . . . . . . . . . 24-17
Sending commands to the server . . . . . . . 23-10 Editing records. . . . . . . . . . . . . . . . 24-18
Working with associated datasets . . . . . . . 23-12 Adding new records . . . . . . . . . . . . 24-19
Closing all datasets without Inserting records . . . . . . . . . . . . 24-19
disconnecting from the server. . . . . . . 23-12 Appending records . . . . . . . . . . . 24-20
Iterating through the associated Deleting records . . . . . . . . . . . . . . . 24-20
datasets . . . . . . . . . . . . . . . . . . . 23-13 Posting data . . . . . . . . . . . . . . . . . 24-21
xiii
Canceling changes . . . . . . . . . . . . . . 24-21 Using parameters in queries . . . . . . . . 24-45
Modifying entire records . . . . . . . . . . 24-22 Supplying parameters at design
Calculating fields . . . . . . . . . . . . . . . . 24-23 time . . . . . . . . . . . . . . . . . . . 24-45
Types of datasets . . . . . . . . . . . . . . . . . 24-24 Supplying parameters at runtime . . 24-47
Using table type datasets . . . . . . . . . . . . 24-25 Establishing master/detail relationships
Advantages of using table type using parameters . . . . . . . . . . . . . 24-47
datasets . . . . . . . . . . . . . . . . . . . 24-26 Preparing queries . . . . . . . . . . . . . . 24-48
Sorting records with indexes . . . . . . . . 24-26 Executing queries that don’t return
Obtaining information about a result set . . . . . . . . . . . . . . . . . 24-49
indexes . . . . . . . . . . . . . . . . . 24-27 Using unidirectional result sets . . . . . . 24-49
Specifying an index with Using stored procedure-type datasets . . . . 24-50
IndexName . . . . . . . . . . . . . . . 24-27 Working with stored procedure
Creating an index with parameters . . . . . . . . . . . . . . . . . 24-51
IndexFieldNames . . . . . . . . . . . 24-28 Setting up parameters at
Using Indexes to search for records . . . . 24-28 design time . . . . . . . . . . . . . . 24-52
Executing a search with Goto Using parameters at runtime . . . . . 24-54
methods . . . . . . . . . . . . . . . . . 24-29 Preparing stored procedures . . . . . . . . 24-55
Executing a search with Find Executing stored procedures that don’t
methods . . . . . . . . . . . . . . . . . 24-30 return a result set . . . . . . . . . . . . . 24-55
Specifying the current record after Fetching multiple result sets . . . . . . . . 24-56
a successful search . . . . . . . . . . . 24-30
Searching on partial keys . . . . . . . . 24-30 Chapter 25
Repeating or extending a search . . . . 24-30 Working with field components 25-1
Limiting records with ranges . . . . . . . . 24-31 Dynamic field components . . . . . . . . . . . 25-2
Understanding the differences Persistent field components . . . . . . . . . . . 25-3
between ranges and filters . . . . . . 24-31 Creating persistent fields . . . . . . . . . . . 25-4
Specifying ranges . . . . . . . . . . . . 24-31 Arranging persistent fields . . . . . . . . . . 25-5
Modifying a range . . . . . . . . . . . . 24-34 Defining new persistent fields . . . . . . . . 25-5
Applying or canceling a range . . . . . 24-34 Defining a data field . . . . . . . . . . . 25-6
Creating master/detail relationships. . . . 24-35 Defining a calculated field . . . . . . . . 25-7
Making the table a detail of Programming a calculated field . . . . . 25-8
another dataset . . . . . . . . . . . . . 24-35 Defining a lookup field . . . . . . . . . 25-9
Using nested detail tables . . . . . . . 24-37 Defining an aggregate field . . . . . . 25-10
Controlling Read/write access Deleting persistent field components . . . 25-11
to tables . . . . . . . . . . . . . . . . . . . 24-38 Setting persistent field properties
Creating and deleting tables . . . . . . . . 24-38 and events . . . . . . . . . . . . . . . . . 25-11
Creating tables . . . . . . . . . . . . . . 24-38 Setting display and edit properties
Deleting tables . . . . . . . . . . . . . . 24-41 at design time . . . . . . . . . . . . . 25-11
Emptying tables . . . . . . . . . . . . . . . 24-41 Setting field component properties
Synchronizing tables . . . . . . . . . . . . . 24-42 at runtime . . . . . . . . . . . . . . . 25-13
Using query-type datasets . . . . . . . . . . . 24-42 Creating attribute sets for field
Specifying the query . . . . . . . . . . . . . 24-43 components . . . . . . . . . . . . . . 25-13
Specifying a query using the Associating attribute sets with field
SQL property . . . . . . . . . . . . . . 24-44 components . . . . . . . . . . . . . . 25-14
Specifying a query using the Removing attribute associations . . . 25-14
CommandText property . . . . . . . 24-44 Controlling and masking
user input . . . . . . . . . . . . . . . 25-15
xiv
Using default formatting for numeric, Chapter 26
date, and time fields . . . . . . . . . . 25-15
Handling events . . . . . . . . . . . . . 25-16
Using the Borland Database Engine 26-1
BDE-based architecture. . . . . . . . . . . . . . 26-1
Working with field component methods
Using BDE-enabled datasets . . . . . . . . . 26-2
at runtime . . . . . . . . . . . . . . . . . . . . 25-17
Associating a dataset with database
Displaying, converting, and accessing
and session connections . . . . . . . . 26-3
field values . . . . . . . . . . . . . . . . . . . 25-18
Caching BLOBs . . . . . . . . . . . . . . 26-4
Displaying field component values in
Obtaining a BDE handle . . . . . . . . . 26-4
standard controls . . . . . . . . . . . . . . 25-18
Using TTable . . . . . . . . . . . . . . . . . . 26-5
Converting field values . . . . . . . . . . . 25-19
Specifying the table type for local
Accessing field values with the default
tables . . . . . . . . . . . . . . . . . . . 26-5
dataset property . . . . . . . . . . . . . . 25-20
Controlling read/write access to
Accessing field values with a dataset’s
local tables . . . . . . . . . . . . . . . . 26-6
Fields property . . . . . . . . . . . . . . . 25-21
Specifying a dBASE index file . . . . . . 26-6
Accessing field values with a dataset’s
Renaming local tables . . . . . . . . . . 26-8
FieldByName method . . . . . . . . . . . 25-21
Importing data from another table . . . 26-8
Setting a default value for a field. . . . . . . . 25-22
Using TQuery . . . . . . . . . . . . . . . . . 26-9
Working with constraints . . . . . . . . . . . . 25-22
Creating heterogeneous queries . . . . 26-9
Creating a custom constraint . . . . . . . . 25-22
Obtaining an editable result set . . . . 26-10
Using server constraints . . . . . . . . . . . 25-23
Updating read-only result sets . . . . 26-11
Using object fields . . . . . . . . . . . . . . . . 25-23
Using TStoredProc . . . . . . . . . . . . . 26-11
Displaying ADT and array fields . . . . . . 25-24
Binding parameters . . . . . . . . . . 26-12
Working with ADT fields . . . . . . . . . . 25-25
Working with Oracle overloaded
Using persistent field
stored procedures . . . . . . . . . . . 26-12
components . . . . . . . . . . . . . . 25-25
Connecting to databases with
Using the dataset’s FieldByName
TDatabase . . . . . . . . . . . . . . . . . 26-12
method . . . . . . . . . . . . . . . . . 25-25
Associating a database component
Using the dateset’s FieldValues
with a session . . . . . . . . . . . . . 26-13
property . . . . . . . . . . . . . . . . . 25-25
Understanding database and session
Using the ADT field’s FieldValues
component interactions . . . . . . . 26-13
property . . . . . . . . . . . . . . . . . 25-26
Identifying the database . . . . . . . . 26-14
Using the ADT field’s Fields
Opening a connection using
property . . . . . . . . . . . . . . . . . 25-26
TDatabase . . . . . . . . . . . . . . . 26-15
Working with array fields . . . . . . . . . . 25-26
Using database components in data
Using persistent fields . . . . . . . . . 25-26
modules . . . . . . . . . . . . . . . . 26-16
Using the array field’s FieldValues
Managing database sessions . . . . . . . . 26-16
property . . . . . . . . . . . . . . . . . 25-27
Activating a session . . . . . . . . . . 26-18
Using the array field’s Fields
Specifying default database
property . . . . . . . . . . . . . . . . . 25-27
connection behavior . . . . . . . . . 26-18
Working with dataset fields . . . . . . . . . 25-27
Managing database connections . . . 26-19
Displaying dataset fields . . . . . . . . 25-27
Working with password-protected
Accessing data in a nested dataset . . . 25-28
Paradox and dBASE tables . . . . . 26-21
Working with reference fields. . . . . . . . 25-28
Specifying Paradox directory
Displaying reference fields . . . . . . . 25-28
locations . . . . . . . . . . . . . . . . 26-24
Accessing data in a reference field . . . 25-29
Working with BDE aliases . . . . . . . 26-25
Retrieving information about
a session . . . . . . . . . . . . . . . . 26-27
xv
Creating additional sessions . . . . . . 26-28 Indicating the types of operations
Naming a session . . . . . . . . . . . . 26-29 the connection supports . . . . . . . . 27-6
Managing multiple sessions . . . . . . 26-29 Specifying whether the connection
Using transactions with the BDE . . . . . . . . 26-31 automatically initiates
Using passthrough SQL . . . . . . . . . . . 26-32 transactions . . . . . . . . . . . . . . . 27-7
Using local transactions . . . . . . . . . . . 26-32 Accessing the connection’s
Using the BDE to cache updates . . . . . . . . 26-33 commands . . . . . . . . . . . . . . . . . . 27-7
Enabling BDE-based cached updates . . . 26-34 ADO connection events. . . . . . . . . . . . 27-8
Applying BDE-based cached updates . . . 26-35 Events when establishing a
Applying cached updates using connection . . . . . . . . . . . . . . . . 27-8
a database . . . . . . . . . . . . . . . . 26-36 Events when disconnecting . . . . . . . 27-8
Applying cached updates with dataset Events when managing
component methods . . . . . . . . . . 26-36 transactions . . . . . . . . . . . . . . . 27-9
Creating an OnUpdateRecord Other events . . . . . . . . . . . . . . . . 27-9
event handler . . . . . . . . . . . . . . 26-37 Using ADO datasets . . . . . . . . . . . . . . . 27-9
Handling cached update errors . . . . 26-38 Connecting an ADO dataset to
Using update objects to update a data store . . . . . . . . . . . . . . 27-10
a dataset . . . . . . . . . . . . . . . . . . . 26-40 Working with record sets . . . . . . . 27-11
Creating SQL statements for update Filtering records based on
components . . . . . . . . . . . . . . 26-41 bookmarks . . . . . . . . . . . . . . . 27-11
Using multiple update objects . . . . . 26-45 Fetching records asynchronously . . . 27-12
Executing the SQL statements . . . . . 26-46 Using batch updates . . . . . . . . . . 27-13
Using TBatchMove. . . . . . . . . . . . . . . . 26-49 Loading data from and saving
Creating a batch move component . . . . . 26-49 data to files . . . . . . . . . . . . . . 27-15
Specifying a batch move mode . . . . . . . 26-50 Using TADODataSet . . . . . . . . . . . . 27-16
Appending records . . . . . . . . . . . 26-50 Using Command objects . . . . . . . . . . . . 27-18
Updating records . . . . . . . . . . . . 26-50 Specifying the command . . . . . . . . . . 27-18
Appending and updating Using the Execute method . . . . . . . . . 27-19
records . . . . . . . . . . . . . . . . . 26-51 Canceling commands . . . . . . . . . . . . 27-19
Copying datasets . . . . . . . . . . . . 26-51 Retrieving result sets with commands . . 27-20
Deleting records . . . . . . . . . . . . . 26-51 Handling command parameters . . . . . . 27-20
Mapping data types . . . . . . . . . . . . . 26-51
Executing a batch move . . . . . . . . . . . 26-52 Chapter 28
Handling batch move errors . . . . . . . . 26-52 Using unidirectional datasets 28-1
The Data Dictionary . . . . . . . . . . . . . . . 26-53 Types of unidirectional datasets . . . . . . . . . 28-2
Tools for working with the BDE . . . . . . . . 26-55 Connecting to the database server . . . . . . . 28-2
Setting up TSQLConnection . . . . . . . . . 28-3
Chapter 27 Identifying the driver . . . . . . . . . . 28-3
Working with ADO components 27-1 Specifying connection parameters . . . 28-4
Overview of ADO components . . . . . . . . 27-2 Naming a connection description . . . . 28-4
Connecting to ADO data stores . . . . . . . . 27-3 Using the Connection Editor . . . . . . 28-5
Connecting to a data store using Specifying what data to display . . . . . . . . . 28-6
TADOConnection. . . . . . . . . . . . . . 27-3 Representing the results of a query . . . . . 28-6
Accessing the connection object . . . . 27-5 Representing the records in a table . . . . . 28-7
Fine-tuning a connection . . . . . . . . . . 27-5 Representing a table using
Forcing asynchronous TSQLDataSet . . . . . . . . . . . . . . 28-7
connections . . . . . . . . . . . . . . . 27-5 Representing a table using
Controlling time-outs . . . . . . . . . . 27-6 TSQLTable . . . . . . . . . . . . . . . . 28-7
xvi
Representing the results of a Copying data from another dataset . . . . 29-14
stored procedure . . . . . . . . . . . . . . 28-8 Assigning data directly . . . . . . . . 29-14
Fetching the data. . . . . . . . . . . . . . . . . 28-8 Cloning a client dataset cursor . . . . 29-15
Preparing the dataset . . . . . . . . . . . . 28-9 Adding application-specific information
Fetching multiple datasets . . . . . . . . . 28-9 to the data . . . . . . . . . . . . . . . . . 29-15
Executing commands that do not Using a client dataset to cache updates. . . . 29-16
return records. . . . . . . . . . . . . . . . . . 28-10 Overview of using cached updates . . . . 29-17
Specifying the command to execute . . . . 28-10 Choosing the type of dataset for caching
Executing the command . . . . . . . . . . . 28-11 updates . . . . . . . . . . . . . . . . . . . 29-18
Creating and modifying server Indicating what records are modified . . . 29-19
metadata . . . . . . . . . . . . . . . . . . . 28-11 Updating records . . . . . . . . . . . . . . 29-20
Setting up master/detail linked cursors. . . . 28-12 Applying updates . . . . . . . . . . . 29-20
Accessing schema information . . . . . . . . . 28-13 Intervening as updates are
Fetching metadata into a unidirectional applied . . . . . . . . . . . . . . . . . 29-21
dataset . . . . . . . . . . . . . . . . . . . . 28-13 Reconciling update errors . . . . . . . 29-23
Fetching data after using the dataset Using a client dataset with a provider . . . . 29-24
for metadata . . . . . . . . . . . . . . 28-14 Specifying a provider . . . . . . . . . . . . 29-25
The structure of metadata Requesting data from the source dataset
datasets . . . . . . . . . . . . . . . . . 28-14 or document . . . . . . . . . . . . . . . . 29-26
Debugging dbExpress applications . . . . . . 28-19 Incremental fetching . . . . . . . . . . 29-26
Using TSQLMonitor to monitor Fetch-on-demand . . . . . . . . . . . . 29-27
SQL commands . . . . . . . . . . . . . . . 28-19 Getting parameters from the source
Using a callback to monitor dataset . . . . . . . . . . . . . . . . . . . 29-27
SQL commands . . . . . . . . . . . . . . . 28-20 Passing parameters to the source
dataset . . . . . . . . . . . . . . . . . . . 29-28
Chapter 29 Sending query or stored procedure
Using client datasets 29-1 parameters . . . . . . . . . . . . . . . 29-29
Working with data using a client dataset . . . 29-2 Limiting records with parameters . . 29-29
Navigating data in client datasets . . . . . 29-2 Handling constraints from the server . . . 29-30
Limiting what records appear. . . . . . . . 29-2 Refreshing records. . . . . . . . . . . . . . 29-31
Editing data . . . . . . . . . . . . . . . . . . 29-5 Communicating with providers using
Undoing changes . . . . . . . . . . . . 29-5 custom events . . . . . . . . . . . . . . . 29-31
Saving changes . . . . . . . . . . . . . 29-6 Overriding the source dataset . . . . . . . 29-32
Constraining data values . . . . . . . . . . 29-7 Using a client dataset with file-based
Specifying custom constraints . . . . . 29-7 data . . . . . . . . . . . . . . . . . . . . . . . 29-33
Sorting and indexing. . . . . . . . . . . . . 29-8 Creating a new dataset . . . . . . . . . . . 29-33
Adding a new index . . . . . . . . . . . 29-8 Loading data from a file or stream . . . . 29-34
Deleting and switching indexes . . . . 29-9 Merging changes into data . . . . . . . . . 29-34
Using indexes to group data . . . . . . 29-9 Saving data to a file or stream . . . . . . . 29-35
Representing calculated values . . . . . . . 29-10 Using a simple dataset . . . . . . . . . . . . . 29-35
Using internally calculated fields When to use TSimpleDataSet . . . . . . . 29-36
in client datasets . . . . . . . . . . . . 29-11 Setting up a simple dataset . . . . . . . . . 29-36
Using maintained aggregates . . . . . . . . 29-11
Specifying aggregates . . . . . . . . . 29-12
Aggregating over groups of
records . . . . . . . . . . . . . . . . . 29-13
Obtaining aggregate values . . . . . . 29-14
xvii
Chapter 30 Building a multi-tiered application . . . . . . 31-11
Creating the application server . . . . . . . . 31-12
Using provider components 30-1 Setting up the remote data module . . . . 31-13
Determining the source of data. . . . . . . . . 30-2
Configuring
Using a dataset as the source
TRemoteDataModule . . . . . . . . 31-13
of the data . . . . . . . . . . . . . . . . . . 30-2
Configuring TMTSDataModule . . . 31-15
Using an XML document as the source
Configuring TSoapDataModule . . . 31-16
of the data . . . . . . . . . . . . . . . . . . 30-2
Extending the application server’s
Communicating with the client dataset . . . . 30-3
interface. . . . . . . . . . . . . . . . . . . 31-16
Choosing how to apply updates using
Adding callbacks to the application
a dataset provider . . . . . . . . . . . . . . . 30-4
server’s interface . . . . . . . . . . . 31-17
Controlling what information is included
Extending a transactional application
in data packets . . . . . . . . . . . . . . . . . 30-4
server’s interface . . . . . . . . . . . 31-17
Specifying what fields appear in
Managing transactions in multi-tiered
data packets . . . . . . . . . . . . . . . . . 30-4
applications . . . . . . . . . . . . . . . . 31-17
Setting options that influence the
Supporting master/detail
data packets . . . . . . . . . . . . . . . . . 30-5
relationships . . . . . . . . . . . . . . . . 31-18
Adding custom information to
Supporting state information in remote
data packets . . . . . . . . . . . . . . . . . 30-6
data modules. . . . . . . . . . . . . . . . 31-19
Responding to client data requests. . . . . . . 30-7
Using multiple remote data modules . . . 31-21
Responding to client update requests . . . . . 30-8
Registering the application server . . . . . . 31-22
Editing delta packets before updating
Creating the client application. . . . . . . . . 31-22
the database . . . . . . . . . . . . . . . . . 30-9
Connecting to the application server . . . 31-23
Influencing how updates are applied . . . 30-10
Specifying a connection
Screening individual updates . . . . . . . . 30-11
using DCOM . . . . . . . . . . . . . 31-24
Resolving update errors on
Specifying a connection
the provider . . . . . . . . . . . . . . . . . 30-11
using sockets . . . . . . . . . . . . . 31-24
Applying updates to datasets that do
Specifying a connection
not represent a single table . . . . . . . . 30-12
using HTTP . . . . . . . . . . . . . . 31-25
Responding to client-generated events . . . . 30-12
Specifying a connection
Handling server constraints . . . . . . . . . . 30-13
using SOAP . . . . . . . . . . . . . . 31-26
Chapter 31 Brokering connections . . . . . . . . . 31-27
Managing server connections . . . . . . . 31-27
Creating multi-tiered applications 31-1 Connecting to the server . . . . . . . . 31-27
Advantages of the multi-tiered Dropping or changing a server
database model . . . . . . . . . . . . . . . . . 31-2 connection . . . . . . . . . . . . . . . 31-28
Understanding multi-tiered database Calling server interfaces . . . . . . . . . . 31-28
applications . . . . . . . . . . . . . . . . . . . 31-2 Using early binding with DCOM . . . 31-29
Overview of a three-tiered application. . . 31-3 Using dispatch interfaces with
The structure of the client application . . . 31-4 TCP/IP or HTTP . . . . . . . . . . . 31-29
The structure of the application server. . . 31-5 Calling the interface of a SOAP-based
The contents of the remote server . . . . . . . . . . . . . . . . . . 31-30
data module . . . . . . . . . . . . . . 31-6 Connecting to an application server that
Using transactional data modules . . . 31-7 uses multiple data modules . . . . . . . 31-30
Pooling remote data modules . . . . . 31-8 Writing Web-based client applications . . . . 31-31
Choosing a connection protocol . . . . . . 31-9 Distributing a client application as an
Using DCOM connections . . . . . . . 31-9 ActiveX control . . . . . . . . . . . . . . 31-32
Using Socket connections . . . . . . . . 31-9 Creating an Active Form for the client
Using Web connections . . . . . . . . . 31-10 application . . . . . . . . . . . . . . . 31-33
Using SOAP connections . . . . . . . . 31-11
xviii
Building Web applications using Part III
InternetExpress . . . . . . . . . . . . . . . 31-33
Building an InternetExpress
Writing Internet applications
application. . . . . . . . . . . . . . . . . . 31-34
Using the javascript libraries . . . . . . 31-35 Chapter 33
Granting permission to access and Creating Internet server
launch the application server . . . . . 31-36 applications 33-1
Using an XML broker . . . . . . . . . . . . 31-36 About Web Broker and WebSnap . . . . . . . . 33-1
Fetching XML data packets . . . . . . . 31-36 Terminology and standards . . . . . . . . . . . 33-3
Applying updates from XML Parts of a Uniform Resource Locator . . . . 33-3
delta packets . . . . . . . . . . . . . . 31-37 URI vs. URL . . . . . . . . . . . . . . . . 33-4
Creating Web pages with an HTTP request header information. . . . . . 33-4
InternetExpress page producer . . . . . . 31-39 HTTP server activity . . . . . . . . . . . . . . . 33-5
Using the Web page editor . . . . . . . 31-39 Composing client requests . . . . . . . . . . 33-5
Setting Web item properties . . . . . . 31-40 Serving client requests . . . . . . . . . . . . 33-5
Customizing the InternetExpress Responding to client requests . . . . . . . . 33-6
page producer template . . . . . . . . 31-41 Types of Web server applications . . . . . . . . 33-6
ISAPI and NSAPI . . . . . . . . . . . . . 33-6
Chapter 32 CGI stand-alone . . . . . . . . . . . . . 33-6
Using XML in database Apache . . . . . . . . . . . . . . . . . . . 33-7
applications 32-1 Web App Debugger . . . . . . . . . . . 33-7
Defining transformations . . . . . . . . . . . . 32-1 Converting Web server application
Mapping between XML nodes and target types . . . . . . . . . . . . . . . . . . 33-8
data packet fields . . . . . . . . . . . . . . 32-2 Debugging server applications . . . . . . . . . 33-9
Using XMLMapper. . . . . . . . . . . . . . 32-4 Using the Web Application Debugger . . . 33-9
Loading an XML schema or Launching your application with
data packet . . . . . . . . . . . . . . . 32-4 the Web Application Debugger . . . . 33-9
Defining mappings . . . . . . . . . . . 32-5 Converting your application to
Generating transformation files . . . . 32-6 another type of Web server
Converting XML documents into application . . . . . . . . . . . . . . . 33-10
data packets. . . . . . . . . . . . . . . . . . . 32-6 Debugging Web applications
Specifying the source XML document . . . 32-6 that are DLLs. . . . . . . . . . . . . . . . 33-10
Specifying the transformation . . . . . . . 32-7 User rights necessary for
Obtaining the resulting data packet . . . . 32-7 DLL debugging . . . . . . . . . . . . 33-10
Converting user-defined nodes . . . . . . . 32-7
Using an XML document as the source Chapter 34
for a provider . . . . . . . . . . . . . . . . . . 32-8 Using Web Broker 34-1
Using an XML document as the client Creating Web server applications with
of a provider . . . . . . . . . . . . . . . . . . 32-9 Web Broker. . . . . . . . . . . . . . . . . . . . 34-1
Fetching an XML document from The Web module. . . . . . . . . . . . . . . . 34-2
a provider . . . . . . . . . . . . . . . . . . 32-9 The Web Application object . . . . . . . . . 34-3
Applying updates from an XML The structure of a Web Broker
document to a provider . . . . . . . . . . 32-11 application . . . . . . . . . . . . . . . . . . . . 34-3
The Web dispatcher. . . . . . . . . . . . . . . . 34-5
Adding actions to the dispatcher . . . . . . 34-5
Dispatching request messages . . . . . . . . 34-5
xix
Action items . . . . . . . . . . . . . . . . . . . 34-6 Representing database information
Determining when action items fire . . . . 34-6 in HTML . . . . . . . . . . . . . . . . . . 34-19
The target URL . . . . . . . . . . . . . . 34-6 Using dataset page producers . . . . . 34-19
The request method type . . . . . . . . 34-7 Using table producers . . . . . . . . . 34-20
Enabling and disabling action Specifying the table attributes . . . . . 34-20
items . . . . . . . . . . . . . . . . . . . 34-7 Specifying the row attributes . . . . . 34-20
Choosing a default action item . . . . . 34-7 Specifying the columns . . . . . . . . 34-20
Responding to request messages with Embedding tables in HTML
action items . . . . . . . . . . . . . . . . . 34-8 documents . . . . . . . . . . . . . . . 34-21
Sending the response . . . . . . . . . . 34-8 Setting up a dataset table
Using multiple action items . . . . . . 34-9 producer . . . . . . . . . . . . . . . . 34-21
Accessing client request information . . . . . 34-9 Setting up a query table
Properties that contain request header producer . . . . . . . . . . . . . . . . 34-21
information . . . . . . . . . . . . . . . . . 34-9
Properties that identify the target . . . 34-9 Chapter 35
Properties that describe the Creating Web Server applications
Web client . . . . . . . . . . . . . . . . 34-10
Properties that identify the purpose
using WebSnap 35-1
Fundamental WebSnap components . . . . . . 35-2
of the request . . . . . . . . . . . . . . 34-10
Web modules. . . . . . . . . . . . . . . . . . 35-2
Properties that describe the expected
Web application module types . . . . . 35-3
response . . . . . . . . . . . . . . . . 34-10
Web page modules . . . . . . . . . . . . 35-4
Properties that describe the
Web data modules . . . . . . . . . . . . 35-5
content . . . . . . . . . . . . . . . . . 34-11
Adapters . . . . . . . . . . . . . . . . . . . . 35-5
The content of HTTP request
Fields . . . . . . . . . . . . . . . . . . . . 35-6
messages. . . . . . . . . . . . . . . . . . . 34-11
Actions . . . . . . . . . . . . . . . . . . . 35-6
Creating HTTP response messages . . . . . . 34-11
Errors . . . . . . . . . . . . . . . . . . . 35-6
Filling in the response header. . . . . . . . 34-11
Records . . . . . . . . . . . . . . . . . . 35-6
Indicating the response status . . . . . 34-12
Page producers . . . . . . . . . . . . . . . . 35-6
Indicating the need for client
Creating Web server applications
action . . . . . . . . . . . . . . . . . . 34-12
with WebSnap . . . . . . . . . . . . . . . . . . 35-7
Describing the server application . . . 34-12
Selecting a server type . . . . . . . . . . . . 35-8
Describing the content . . . . . . . . . 34-12
Specifying application module
Setting the response content . . . . . . . . 34-13
components . . . . . . . . . . . . . . . . . 35-9
Sending the response . . . . . . . . . . . . 34-13
Selecting Web application module
Generating the content of response
options . . . . . . . . . . . . . . . . . . . 35-10
messages . . . . . . . . . . . . . . . . . . . . 34-13
Advanced HTML design. . . . . . . . . . . . 35-11
Using page producer components . . . . . 34-14
Manipulating server-side script in
HTML templates . . . . . . . . . . . . . 34-14
HTML files . . . . . . . . . . . . . . . . . 35-12
Specifying the HTML template . . . . 34-15
Login support . . . . . . . . . . . . . . . . . . 35-13
Converting HTML-transparent
Adding login support. . . . . . . . . . . . 35-13
tags . . . . . . . . . . . . . . . . . . . 34-16
Using the sessions service . . . . . . . . . 35-14
Using page producers from an
Login pages . . . . . . . . . . . . . . . . . 35-15
action item . . . . . . . . . . . . . . . 34-16
Setting pages to require logins . . . . . . . 35-17
Chaining page producers
User access rights . . . . . . . . . . . . . . 35-17
together . . . . . . . . . . . . . . . . . 34-17
Dynamically displaying fields as
Using database information in
edit or text boxes . . . . . . . . . . . 35-18
responses . . . . . . . . . . . . . . . . . . . . 34-18
Hiding fields and their contents . . . 35-18
Adding a session to the Web module . . . 34-18
Preventing page access . . . . . . . . . 35-19
xx
Server-side scripting in WebSnap . . . . . . . 35-19 Abstracting XML documents with the
Active scripting . . . . . . . . . . . . . . . . 35-20 Data Binding wizard . . . . . . . . . . . . . . 37-6
Script engine . . . . . . . . . . . . . . . . . 35-20 Using the XML Data Binding wizard . . . . 37-8
Script blocks. . . . . . . . . . . . . . . . . . 35-20 Using code that the XML Data
Creating script . . . . . . . . . . . . . . . . 35-21 Binding wizard generates. . . . . . . . . . 37-9
Wizard templates . . . . . . . . . . . . 35-21
TAdapterPageProducer . . . . . . . . . 35-21 Chapter 38
Editing and viewing script . . . . . . . . . 35-21 Using Web Services 38-1
Including script in a page . . . . . . . . . . 35-21 Understanding invokable interfaces . . . . . . 38-2
Script objects . . . . . . . . . . . . . . . . . 35-22 Using nonscalar types in invokable
Dispatching requests and responses . . . . . . 35-22 interfaces . . . . . . . . . . . . . . . . . . . 38-4
Dispatcher components . . . . . . . . . . . 35-23 Registering nonscalar types . . . . . . . 38-5
Adapter dispatcher operation. . . . . . . . 35-23 Using remotable objects . . . . . . . . . 38-6
Using adapter components to Representing attachments . . . . . . . . 38-7
generate content . . . . . . . . . . . . 35-23 Managing the lifetime of remotable
Receiving adapter requests and objects . . . . . . . . . . . . . . . . . . 38-7
generating responses . . . . . . . . . 35-25 Remotable object example . . . . . . . . 38-7
Image request . . . . . . . . . . . . . . 35-26 Writing servers that support Web Services. . . 38-9
Image response . . . . . . . . . . . . . 35-27 Building a Web Service server . . . . . . . . 38-9
Dispatching action items . . . . . . . . . . 35-27 Using the SOAP application wizard . . . 38-10
Page dispatcher operation . . . . . . . . . . 35-28 Adding new Web Services . . . . . . . . . 38-11
Editing the generated code . . . . . . 38-12
Chapter 36 Using a different base class . . . . . . 38-12
Creating Web server applications Using the WSDL importer . . . . . . . . . 38-13
using IntraWeb 36-1 Browsing for Business services . . . . . . 38-14
Using IntraWeb components . . . . . . . . . . 36-2 Understanding UDDI . . . . . . . . . 38-15
Getting started with IntraWeb . . . . . . . . . 36-3 Using the UDDI browser . . . . . . . 38-15
Creating a new IntraWeb application . . . 36-4 Defining and using SOAP headers . . . . 38-16
Editing the main form . . . . . . . . . . . . 36-4 Defining header classes . . . . . . . . 38-16
Writing an event handler for Sending and receiving headers . . . . 38-16
the button . . . . . . . . . . . . . . . . . . 36-5 Handling scalar-type headers . . . . . 38-17
Running the completed application . . . . 36-6 Communicating the structure of your
Using IntraWeb with Web Broker headers to other applications . . . . 38-18
and WebSnap . . . . . . . . . . . . . . . . . . 36-7 Creating custom exception classes for
For more information . . . . . . . . . . . . . . 36-8 Web Services . . . . . . . . . . . . . . . . 38-18
Generating WSDL documents for
Chapter 37 a Web Service application. . . . . . . . . 38-19
Writing clients for Web Services. . . . . . . . 38-20
Working with XML documents 37-1 Importing WSDL documents . . . . . . . 38-20
Using the Document Object Model . . . . . . 37-2
Calling invokable interfaces . . . . . . . . 38-20
Working with XML components . . . . . . . . 37-4
Obtaining an invokable interface
Using TXMLDocument . . . . . . . . . . . 37-4
from the generated function . . . . . 38-21
Working with XML nodes . . . . . . . . . . 37-4
Using a remote interfaced object . . . 38-21
Working with a node’s value . . . . . . 37-5
Processing headers in client
Working with a node’s attributes . . . 37-5
applications . . . . . . . . . . . . . . . . 38-23
Adding and deleting child nodes . . . 37-6
xxi
Chapter 39 Part IV
Working with sockets 39-1 Developing COM-based applications
Implementing services . . . . . . . . . . . . . 39-1
Understanding service protocols . . . . . . 39-2 Chapter 40
Communicating with
applications . . . . . . . . . . . . . . . 39-2
Overview of COM technologies 40-1
COM as a specification and
Services and ports . . . . . . . . . . . . . . 39-2
implementation . . . . . . . . . . . . . 40-2
Types of socket connections. . . . . . . . . . . 39-3
COM extensions . . . . . . . . . . . . . 40-2
Client connections . . . . . . . . . . . . . . 39-3
Parts of a COM application . . . . . . . . . . . 40-3
Listening connections . . . . . . . . . . . . 39-3
COM interfaces . . . . . . . . . . . . . . . . 40-3
Server connections . . . . . . . . . . . . . . 39-3
The fundamental COM interface,
Describing sockets . . . . . . . . . . . . . . . . 39-4
IUnknown . . . . . . . . . . . . . . . . 40-4
Describing the host . . . . . . . . . . . . . . 39-4
COM interface pointers . . . . . . . . . 40-5
Choosing between a host name
COM servers . . . . . . . . . . . . . . . . . . 40-5
and an IP address . . . . . . . . . . . 39-5
CoClasses and class factories . . . . . . 40-6
Using ports . . . . . . . . . . . . . . . . . . 39-5
In-process, out-of-process, and
Using socket components . . . . . . . . . . . . 39-6
remote servers . . . . . . . . . . . . . . 40-7
Getting information about the
The marshaling mechanism . . . . . . . 40-8
connection . . . . . . . . . . . . . . . . . . 39-6
Aggregation . . . . . . . . . . . . . . . . 40-9
Using client sockets . . . . . . . . . . . . . 39-6
COM clients . . . . . . . . . . . . . . . . . 40-10
Specifying the desired server . . . . . . 39-7
COM extensions. . . . . . . . . . . . . . . . . 40-10
Forming the connection . . . . . . . . . 39-7
Automation servers . . . . . . . . . . . . . 40-12
Getting information about the
Active Server Pages . . . . . . . . . . . . . 40-13
connection . . . . . . . . . . . . . . . 39-7
ActiveX controls . . . . . . . . . . . . . . . 40-13
Closing the connection . . . . . . . . . 39-7
Active Documents. . . . . . . . . . . . . . 40-14
Using server sockets . . . . . . . . . . . . . 39-7
Transactional objects . . . . . . . . . . . . 40-15
Specifying the port . . . . . . . . . . . 39-8
Type libraries. . . . . . . . . . . . . . . . . 40-16
Listening for client requests . . . . . . 39-8
The content of type libraries . . . . . . 40-16
Connecting to clients . . . . . . . . . . 39-8
Creating type libraries . . . . . . . . . 40-17
Closing server connections . . . . . . . 39-8
When to use type libraries . . . . . . . 40-17
Responding to socket events . . . . . . . . . . 39-8
Accessing type libraries . . . . . . . . 40-18
Error events . . . . . . . . . . . . . . . . . . 39-9
Benefits of using type libraries . . . . 40-18
Client events . . . . . . . . . . . . . . . . . 39-9
Using type library tools . . . . . . . . 40-19
Server events . . . . . . . . . . . . . . . . . 39-9
Implementing COM objects
Events when listening . . . . . . . . . . 39-9
with wizards . . . . . . . . . . . . . . . . . . 40-19
Events with client connections . . . . . 39-10
Code generated by wizards . . . . . . . . 40-22
Reading and writing over socket
connections . . . . . . . . . . . . . . . . . . . 39-10
Non-blocking connections. . . . . . . . . . 39-10
Reading and writing events . . . . . . 39-11
Blocking connections. . . . . . . . . . . . . 39-11
xxii
Chapter 41 Chapter 42
Working with type libraries 41-1 Creating COM clients 42-1
Type Library editor . . . . . . . . . . . . . . . 41-2 Importing type library information . . . . . . . 42-2
Parts of the Type Library editor. . . . . . . 41-3 Using the Import Type Library dialog . . . 42-3
Toolbar . . . . . . . . . . . . . . . . . . 41-3 Using the Import ActiveX dialog . . . . . . 42-4
Object list pane . . . . . . . . . . . . . . 41-5 Code generated when you import
Status bar . . . . . . . . . . . . . . . . . 41-5 type library information . . . . . . . . . . 42-5
Pages of type information . . . . . . . 41-6 Controlling an imported object . . . . . . . . . 42-6
Type library elements . . . . . . . . . . . . 41-8 Using component wrappers . . . . . . . . . 42-6
Interfaces . . . . . . . . . . . . . . . . . 41-9 ActiveX wrappers . . . . . . . . . . . . 42-6
Dispinterfaces . . . . . . . . . . . . . . 41-9 Automation object wrappers . . . . . . 42-7
CoClasses . . . . . . . . . . . . . . . . . 41-10 Using data-aware ActiveX controls . . . . . 42-8
Type definitions . . . . . . . . . . . . . 41-10 Example: Printing a document with
Modules . . . . . . . . . . . . . . . . . 41-11 Microsoft Word . . . . . . . . . . . . . . . 42-9
Using the Type Library editor. . . . . . . . 41-11 Preparing Delphi for this example . . 42-10
Valid types . . . . . . . . . . . . . . . . 41-12 Importing the Word type library . . . 42-10
Using Delphi or IDL syntax . . . . . . 41-13 Using a VTable or dispatch
Creating a new type library . . . . . . 41-19 interface object to control
Opening an existing type library . . . 41-20 Microsoft Word . . . . . . . . . . . . 42-11
Adding an interface to the type Cleaning up the example . . . . . . . 42-12
library . . . . . . . . . . . . . . . . . . 41-21 Writing client code based on type
Modifying an interface using the library definitions . . . . . . . . . . . . . 42-13
type library . . . . . . . . . . . . . . . 41-21 Connecting to a server . . . . . . . . . 42-13
Adding properties and methods to Controlling an Automation server
an interface or dispinterface . . . . . 41-22 using a dual interface . . . . . . . . 42-13
Adding a CoClass to the type Controlling an Automation server
library . . . . . . . . . . . . . . . . . . 41-23 using a dispatch interface . . . . . . 42-14
Adding an interface to a CoClass . . . 41-23 Handling events in an automation
Adding an enumeration to the controller . . . . . . . . . . . . . . . . 42-14
type library . . . . . . . . . . . . . . . 41-24 Creating clients for servers that do not
Adding an alias to the type have a type library . . . . . . . . . . . . . . 42-16
library . . . . . . . . . . . . . . . . . . 41-24 Using .NET assemblies with Delphi . . . . . 42-17
Adding a record or union to the Requirements for COM
type library . . . . . . . . . . . . . . . 41-24 interoperability . . . . . . . . . . . . . . 42-17
Adding a module to the type .NET components and type libraries . . . 42-18
library . . . . . . . . . . . . . . . . . . 41-25 Accessing user-defined .NET
Saving and registering type library components . . . . . . . . . . . . . . . . 42-20
information . . . . . . . . . . . . . . . 41-25
Apply Updates dialog . . . . . . . . . 41-26
Saving a type library . . . . . . . . . . 41-26
Refreshing the type library . . . . . . . 41-26
Registering the type library . . . . . . 41-27
Exporting an IDL file . . . . . . . . . . 41-27
Deploying type libraries . . . . . . . . . . . . 41-27
xxiii
Chapter 43 Registering an Active Server Object . . . . . . 44-8
Registering an in-process server . . . . . . . 44-8
Creating simple COM servers 43-1 Registering an out-of-process server . . . . 44-8
Overview of creating a COM object . . . . . . 43-2
Testing and debugging the Active Server
Designing a COM object . . . . . . . . . . . . 43-2
Page application. . . . . . . . . . . . . . . . . 44-8
Using the COM object wizard . . . . . . . . . 43-3
Using the Automation object wizard . . . . . 43-5
COM object instancing types . . . . . . . . 43-6
Chapter 45
Choosing a threading model . . . . . . . . 43-6 Creating an ActiveX control 45-1
Writing an object that supports the Overview of ActiveX control creation . . . . . 45-2
free threading model . . . . . . . . . 43-8 Elements of an ActiveX control . . . . . . . 45-2
Writing an object that supports the VCL control . . . . . . . . . . . . . . . . 45-3
apartment threading model . . . . . 43-9 ActiveX wrapper . . . . . . . . . . . . . 45-3
Writing an object that supports the Type library . . . . . . . . . . . . . . . . 45-3
neutral threading model . . . . . . . 43-9 Property page . . . . . . . . . . . . . . . 45-3
Defining a COM object’s interface . . . . . . . 43-9 Designing an ActiveX control . . . . . . . . . . 45-4
Adding a property to the object’s Generating an ActiveX control from a
interface . . . . . . . . . . . . . . . . . . . 43-10 VCL control . . . . . . . . . . . . . . . . . . . 45-4
Adding a method to the object’s Generating an ActiveX control based on
interface . . . . . . . . . . . . . . . . . . . 43-10 a VCL form. . . . . . . . . . . . . . . . . . . . 45-6
Exposing events to clients . . . . . . . . . . 43-11 Licensing ActiveX controls. . . . . . . . . . . . 45-7
Managing events in your Customizing the ActiveX control’s
Automation object . . . . . . . . . . . 43-12 interface . . . . . . . . . . . . . . . . . . . . . 45-8
Automation interfaces . . . . . . . . . . . . . . 43-13 Adding additional properties,
Dual interfaces . . . . . . . . . . . . . . . . 43-13 methods, and events . . . . . . . . . . . . 45-9
Dispatch interfaces . . . . . . . . . . . . . . 43-14 Adding properties and methods . . . . 45-9
Custom interfaces . . . . . . . . . . . . . . 43-15 Adding events . . . . . . . . . . . . . 45-10
Marshaling data . . . . . . . . . . . . . . . . . 43-15 Enabling simple data binding with
Automation compatible types . . . . . . . 43-16 the type library. . . . . . . . . . . . . . . 45-11
Type restrictions for automatic Creating a property page for an
marshaling . . . . . . . . . . . . . . . . . 43-16 ActiveX control . . . . . . . . . . . . . . . . 45-12
Custom marshaling . . . . . . . . . . . . . 43-17 Creating a new property page . . . . . . . 45-13
Registering a COM object . . . . . . . . . . . . 43-17 Adding controls to a property page . . . . 45-13
Registering an in-process server . . . . . . 43-17 Associating property page controls
Registering an out-of-process server . . . . 43-17 with ActiveX control properties . . . . . 45-13
Testing and debugging the application . . . . 43-18 Updating the property page . . . . . . 45-13
Updating the object . . . . . . . . . . 45-14
Chapter 44 Connecting a property page to an
ActiveX control . . . . . . . . . . . . . . 45-14
Creating an Active Server Page 44-1 Registering an ActiveX control . . . . . . . . 45-15
Creating an Active Server Object. . . . . . . . 44-2
Testing an ActiveX control . . . . . . . . . . . 45-15
Using the ASP intrinsics . . . . . . . . . . . 44-3
Deploying an ActiveX control
Application . . . . . . . . . . . . . . . . 44-4
on the Web . . . . . . . . . . . . . . . . . . . 45-15
Request . . . . . . . . . . . . . . . . . . 44-4
Setting options . . . . . . . . . . . . . . . . 45-16
Response . . . . . . . . . . . . . . . . . 44-5
Session . . . . . . . . . . . . . . . . . . 44-6
Server . . . . . . . . . . . . . . . . . . . 44-6
Creating ASPs for in-process or
out-of-process servers . . . . . . . . . . . 44-7
xxiv
Chapter 46 Role-based security . . . . . . . . . . . . . . . 46-15
Overview of creating transactional
Creating MTS or COM+ objects 46-1 objects . . . . . . . . . . . . . . . . . . . . . 46-15
Understanding transactional objects. . . . . . 46-2
Using the Transactional Object wizard . . . . 46-16
Requirements for a transactional
Choosing a threading model for a
object . . . . . . . . . . . . . . . . . . . . . 46-3
transactional object . . . . . . . . . . . . 46-17
Managing resources . . . . . . . . . . . . . . . 46-3
Activities . . . . . . . . . . . . . . . . 46-18
Accessing the object context. . . . . . . . . 46-4
Generating events under COM+ . . . . . . . 46-19
Just-in-time activation . . . . . . . . . . . . 46-4
Using the Event Object wizard. . . . . . . 46-21
Resource pooling . . . . . . . . . . . . . . . 46-5
Using the COM+ Event Subscription
Database resource dispensers . . . . . 46-6
object wizard . . . . . . . . . . . . . . . . 46-22
Shared property manager . . . . . . . 46-6
Firing events using a COM+ event
Releasing resources . . . . . . . . . . . 46-8
object . . . . . . . . . . . . . . . . . . . . 46-23
Object pooling . . . . . . . . . . . . . . . . 46-8
Passing object references . . . . . . . . . . . . 46-23
MTS and COM+ transaction support . . . . . 46-9
Using the SafeRef method . . . . . . . 46-24
Transaction attributes . . . . . . . . . . . . 46-10
Callbacks . . . . . . . . . . . . . . . . 46-25
Setting the transaction attribute . . . . 46-11
Debugging and testing transactional
Stateful and stateless objects . . . . . . . . 46-11
objects . . . . . . . . . . . . . . . . . . . . . 46-25
Influencing how transactions end . . . . . 46-12
Installing transactional objects . . . . . . . . 46-26
Initiating transactions . . . . . . . . . . . . 46-12
Administering transactional objects . . . . . 46-27
Setting up a transaction object
on the client side . . . . . . . . . . . . 46-13
Setting up a transaction object on
Index I-1
the server side . . . . . . . . . . . . . 46-14
Transaction time-out . . . . . . . . . . . . . 46-14
xxv
Tables
1.1 Typefaces and symbols . . . . . . . . . . . 1-2 10.1 Edit control properties . . . . . . . . . . . 10-2
3.1 Component sublibraries . . . . . . . . . . 3-1 12.1 Graphic object types . . . . . . . . . . . . 12-3
3.2 Important base classes . . . . . . . . . . . 3-5 12.2 Common properties of the Canvas
5.1 Values for the Origin parameter . . . . . . 5-5 object . . . . . . . . . . . . . . . . . . . . . 12-4
5.2 Open modes . . . . . . . . . . . . . . . . . 5-7 12.3 Common methods of the Canvas
5.3 Share modes . . . . . . . . . . . . . . . . . 5-7 object . . . . . . . . . . . . . . . . . . . . . 12-4
5.4 Shared modes available for each 12.4 CLX MIME types and constants . . . . 12-22
open mode . . . . . . . . . . . . . . . . . . 5-7 12.5 Mouse events . . . . . . . . . . . . . . . 12-24
5.5 Attribute constants and values . . . . . . . 5-9 12.6 Mouse-event parameters. . . . . . . . . 12-25
5.6 Classes for managing lists . . . . . . . . . 5-14 12.7 Multimedia device types and their
5.7 String comparison routines . . . . . . . . . 5-24 functions . . . . . . . . . . . . . . . . . . 12-33
5.8 Case conversion routines . . . . . . . . . . 5-25 13.1 Thread priorities . . . . . . . . . . . . . . 13-3
5.9 String modification routines . . . . . . . . 5-25 13.2 WaitFor return values . . . . . . . . . . .13-11
5.10 Sub-string routines . . . . . . . . . . . . . 5-25 14.1 Selected exception classes . . . . . . . . 14-10
5.11 Null-terminated string comparison 15.1 Porting techniques . . . . . . . . . . . . . 15-2
routines . . . . . . . . . . . . . . . . . . . . 5-26 15.2 Changed or different features . . . . . . . 15-7
5.12 Case conversion routines for 15.3 WinCLX-only and equivalent
null-terminated strings . . . . . . . . . . . 5-26 VisualCLX units. . . . . . . . . . . . . . . 15-8
5.13 String modification routines . . . . . . . . 5-26 15.4 VisualCLX-only units . . . . . . . . . . . 15-9
5.14 Sub-string routines . . . . . . . . . . . . . 5-26 15.5 WinCLX-only units . . . . . . . . . . . . . 15-9
5.15 String copying routines . . . . . . . . . . . 5-27 15.6 Differences in the Linux and Windows
5.16 Compiler directives for strings . . . . . . . 5-30 operating environments . . . . . . . . . 15-18
6.1 Component palette pages . . . . . . . . . 6-7 15.7 Common Linux directories . . . . . . . 15-20
7.1 Properties of selected text. . . . . . . . . . 7-9 15.8 Comparable data-access
7.2 Fixed vs. variable owner-draw styles . . . 7-13 components . . . . . . . . . . . . . . . . 15-23
8.1 Compiler directives for libraries . . . . . . 8-11 15.9 Properties, methods, and events
8.2 Database pages on the Component for cached updates . . . . . . . . . . . . 15-27
palette . . . . . . . . . . . . . . . . . . . . . 8-12 16.1 Package files. . . . . . . . . . . . . . . . . 16-2
8.3 Web server applications. . . . . . . . . . . 8-14 16.2 Package-specific compiler directives . . .16-11
8.4 Context menu options for data 16.3 Package-specific command-line
modules. . . . . . . . . . . . . . . . . . . . 8-18 compiler switches. . . . . . . . . . . . . 16-13
8.5 Help methods in TApplication . . . . . . . 8-31 17.1 Runtime library functions . . . . . . . . . 17-3
9.1 Action setup terminology. . . . . . . . . . 9-18 17.2 VCL methods that support BiDi . . . . . 17-6
9.2 Default values of the action manager’s 17.3 Estimating string lengths . . . . . . . . . 17-7
PrioritySchedule property . . . . . . . . . 9-25 18.1 Application files . . . . . . . . . . . . . . 18-3
9.3 Action classes . . . . . . . . . . . . . . . . 9-30 18.2 Merge modules and their
9.4 Methods overriden by base classes dependencies . . . . . . . . . . . . . . . . 18-4
of specific actions . . . . . . . . . . . . . . 9-31 18.3 dbExpress deployment as stand-alone
9.5 Sample captions and their derived executable . . . . . . . . . . . . . . . . . . 18-7
names . . . . . . . . . . . . . . . . . . . . . 9-34 18.4 dbExpress deployment with
9.6 Menu Designer context menu driver DLLs . . . . . . . . . . . . . . . . . 18-8
commands . . . . . . . . . . . . . . . . . . 9-40 20.1 Data controls . . . . . . . . . . . . . . . . 20-2
9.7 Setting speed buttons’ appearance. . . . . 9-48 20.2 Column properties . . . . . . . . . . . . 20-20
9.8 Setting tool buttons’ appearance . . . . . . 9-50 20.3 Expanded TColumn Title
9.9 Setting a cool button’s appearance. . . . . 9-52 properties . . . . . . . . . . . . . . . . . 20-21
xxvi
20.4 Properties that affect the way 27.1 ADO components. . . . . . . . . . . . . . 27-2
composite fields appear . . . . . . . . . . 20-24 27.2 Connection parameters . . . . . . . . . . 27-4
20.5 Expanded TDBGrid Options 27.3 ADO connection modes . . . . . . . . . . 27-6
properties . . . . . . . . . . . . . . . . . . 20-25 27.4 Execution options for ADO
20.6 Grid control events . . . . . . . . . . . . 20-27 datasets . . . . . . . . . . . . . . . . . . 27-12
20.7 Selected database control grid 27.5 Comparison of ADO and client dataset
properties . . . . . . . . . . . . . . . . . . 20-29 cached updates . . . . . . . . . . . . . . 27-13
20.8 TDBNavigator buttons . . . . . . . . . . 20-30 28.1 Columns in tables of metadata
21.1 Rave Reports documentation. . . . . . . . 21-6 listing tables . . . . . . . . . . . . . . . . 28-15
23.1 Database connection components . . . . . 23-1 28.2 Columns in tables of metadata
24.1 Values for the dataset State property . . . 24-3 listing stored procedures. . . . . . . . . 28-15
24.2 Navigational methods of datasets . . . . . 24-5 28.3 Columns in tables of metadata
24.3 Navigational properties of datasets . . . . 24-6 listing fields . . . . . . . . . . . . . . . . 28-16
24.4 Comparison and logical operators 28.4 Columns in tables of metadata
that can appear in a filter . . . . . . . . . 24-14 listing indexes . . . . . . . . . . . . . . . 28-17
24.5 FilterOptions values . . . . . . . . . . . . 24-16 28.5 Columns in tables of metadata listing
24.6 Filtered dataset navigational parameters. . . . . . . . . . . . . . . . . 28-18
methods. . . . . . . . . . . . . . . . . . . 24-16 29.1 Filter support in client datasets . . . . . . 29-3
24.7 Dataset methods for inserting, 29.2 Summary operators for maintained
updating, and deleting data . . . . . . . 24-17 aggregates . . . . . . . . . . . . . . . . . 29-12
24.8 Methods that work with entire 29.3 Specialized client datasets for
records . . . . . . . . . . . . . . . . . . . 24-22 caching updates. . . . . . . . . . . . . . 29-18
24.9 Index-based search methods . . . . . . . 24-28 30.1 AppServer interface members. . . . . . . 30-3
25.1 TFloatField properties that affect 30.2 Provider options . . . . . . . . . . . . . . 30-5
data display . . . . . . . . . . . . . . . . . 25-1 30.3 UpdateStatus values . . . . . . . . . . . . 30-9
25.2 Special persistent field kinds . . . . . . . . 25-6 30.4 UpdateMode values . . . . . . . . . . . 30-10
25.3 Field component properties . . . . . . . 25-11 30.5 ProviderFlags values . . . . . . . . . . . 30-10
25.4 Field component formatting 31.1 Components used in multi-tiered
routines . . . . . . . . . . . . . . . . . . . 25-15 applications . . . . . . . . . . . . . . . . . 31-3
25.5 Field component events. . . . . . . . . . 25-16 31.2 Connection components . . . . . . . . . . 31-5
25.6 Selected field component methods . . . 25-17 31.3 Javascript libraries . . . . . . . . . . . . 31-35
25.7 Special conversion results . . . . . . . . 25-20 33.1 Web Broker versus WebSnap . . . . . . . 33-2
25.8 Types of object field components . . . . 25-24 34.1 MethodType values. . . . . . . . . . . . . 34-7
25.9 Common object field descendant 34.2 Predefined tag names . . . . . . . . . . 34-10
properties . . . . . . . . . . . . . . . . . . 25-24 35.1 Web application module types . . . . . . 35-3
26.1 Table types recognized by the BDE 35.2 Web server application types . . . . . . . 35-8
based on file extension . . . . . . . . . . . 26-5 35.3 Web application components . . . . . . . 35-9
26.2 TableType values. . . . . . . . . . . . . . . 26-6 35.4 Script objects . . . . . . . . . . . . . . . 35-22
26.3 BatchMove import modes . . . . . . . . . 26-8 35.5 Request information found in
26.4 Database-related informational action requests . . . . . . . . . . . . . . 35-25
methods for session components . . . . 26-27 36.1 VCL/CLX and IntraWeb
26.5 TSessionList properties and components . . . . . . . . . . . . . . . . . 36-2
methods. . . . . . . . . . . . . . . . . . . 26-30 38.1 Remotable classes. . . . . . . . . . . . . . 38-6
26.6 Properties, methods, and events 40.1 COM object requirements . . . . . . . . 40-12
for cached updates. . . . . . . . . . . . . 26-33 40.2 Delphi wizards for implementing COM,
26.7 UpdateKind values . . . . . . . . . . . . 26-39 Automation, and ActiveX objects . . . . 40-21
26.8 Batch move modes. . . . . . . . . . . . . 26-50 40.3 DAX Base classes for generated
26.9 Data Dictionary interface . . . . . . . . . 26-54 implementation classes . . . . . . . . . 40-23
xxvii
41.1 Type Library editor files . . . . . . . . . . 41-2 44.4 ISessionObject interface members . . . . 44-6
41.2 Type Library editor parts . . . . . . . . . . 41-3 44.5 IServer interface members . . . . . . . . . 44-6
41.3 Attribute syntax . . . . . . . . . . . . . . 41-14 46.1 IObjectContext methods for
43.1 Threading models for COM objects . . . . 43-7 transaction support . . . . . . . . . . . . 46-12
44.1 IApplicationObject interface 46.2 Threading models for transactional
members . . . . . . . . . . . . . . . . . . . 44-4 objects . . . . . . . . . . . . . . . . . . . 46-17
44.2 IRequest interface members . . . . . . . . 44-4 46.3 Call synchronization options . . . . . . 46-19
44.3 IResponse interface members . . . . . . . 44-5 46.4 Event publisher return codes . . . . . . 46-23
xxviii
Figures
3.1 A simplified hierarchy diagram . . . . . . 3-5 20.5 TDBCtrlGrid at design time . . . . . . . 20-28
4.1 A simple form . . . . . . . . . . . . . . . . 4-3 20.6 Buttons on the TDBNavigator
9.1 A frame with data-aware controls control . . . . . . . . . . . . . . . . . . . 20-29
and a data source component . . . . . . . 9-16 22.1 Decision support components
9.3 Menu terminology. . . . . . . . . . . . . . 9-32 at design time . . . . . . . . . . . . . . . . 22-2
9.4 MainMenu and PopupMenu 22.2 One-dimensional crosstab . . . . . . . . . 22-3
components . . . . . . . . . . . . . . . . . 9-33 22.3 Three-dimensional crosstab . . . . . . . . 22-3
9.6 Adding menu items to a main menu . . . 9-36 22.4 Decision graphs bound to different
9.7 Nested menu structures. . . . . . . . . . . 9-37 decision sources. . . . . . . . . . . . . . 22-15
10.2 A progress bar . . . . . . . . . . . . . . . 10-15 26.1 Components in a BDE-based
11.1 Part of the ModelMaker toolbar . . . . . . 11-3 application. . . . . . . . . . . . . . . . . . 26-2
11.2 ModelMaker showing a sample 31.1 Web-based multi-tiered database
model . . . . . . . . . . . . . . . . . . . . . 11-4 application. . . . . . . . . . . . . . . . . 31-31
11.3 The Classes view. . . . . . . . . . . . . . . 11-5 33.1 Parts of a Uniform Resource Locator . . . 33-3
11.4 The Units view . . . . . . . . . . . . . . . . 11-5 34.1 Structure of a Server Application . . . . . 34-4
11.5 The Diagrams view . . . . . . . . . . . . . 11-6 35.2 Web App Components dialog . . . . . . . 35-9
11.6 The Members view . . . . . . . . . . . . . 11-7 35.3 Web App Components dialog with
11.7 The Implementation Editor view . . . . . 11-8 options for login support selected . . . 35-14
11.8 The Unit Code Editor . . . . . . . . . . . . 11-8 35.4 An example of a login page as seen
11.9 The Diagram Editor . . . . . . . . . . . . . 11-9 from a Web page editor . . . . . . . . . 35-16
12.1 Bitmap-dimension dialog box from 35.5 Generating content flow . . . . . . . . . 35-24
the BMPDlg unit . . . . . . . . . . . . . . 12-21 35.6 Action request and response . . . . . . 35-26
17.1 TListBox set to bdLeftToRight . . . . . . . 17-5 35.7 Image response to a request . . . . . . . 35-27
17.2 TListBox set to bdRightToLeft . . . . . . . 17-5 35.8 Dispatching a page . . . . . . . . . . . . 35-28
17.3 TListBox set to 36.2 The main form of the IntraWeb
bdRightToLeftNoAlign . . . . . . . . . . . 17-5 application. . . . . . . . . . . . . . . . . . 36-5
17.4 TListBox set to 40.1 A COM interface . . . . . . . . . . . . . . 40-3
bdRightToLeftReadingOnly . . . . . . . . 17-5 40.2 Interface vtable . . . . . . . . . . . . . . . 40-5
19.1 Generic Database Architecture . . . . . . . 19-6 40.3 In-process server . . . . . . . . . . . . . . 40-7
19.2 Connecting directly to the 40.4 Out-of-process and remote servers . . . . 40-8
database server. . . . . . . . . . . . . . . . 19-8 40.5 COM-based technologies . . . . . . . . .40-11
19.3 A file-based database application . . . . . 19-9 40.6 Simple COM object interface . . . . . . 40-20
19.4 Architecture combining a client 40.7 Automation object interface . . . . . . . 40-20
dataset and another dataset . . . . . . . 19-12 40.8 ActiveX object interface . . . . . . . . . 40-20
19.5 Multi-tiered database architecture . . . . 19-13 40.9 Delphi ActiveX framework . . . . . . . 40-23
20.1 TDBGrid control . . . . . . . . . . . . . . 20-15 41.1 Type Library editor . . . . . . . . . . . . . 41-3
20.2 TDBGrid control with ObjectView 41.2 Object list pane . . . . . . . . . . . . . . . 41-5
set to False . . . . . . . . . . . . . . . . . 20-23 43.1 Dual interface VTable . . . . . . . . . . 43-14
20.3 TDBGrid control with Expanded 45.1 Mask Edit property page in
set to False . . . . . . . . . . . . . . . . . 20-23 design mode. . . . . . . . . . . . . . . . 45-13
20.4 TDBGrid control with Expanded 46.1 The COM+ Events system . . . . . . . . 46-21
set to True. . . . . . . . . . . . . . . . . . 20-24
xxix
xxx
Chapter
1
Introduction
Chapter1
The Developer’s Guide describes intermediate and advanced development topics, such
as building client/server database applications, creating Internet Web server
applications, and writing custom components. It allows you to build applications
that meet many industry-standard specifications such as SOAP, TCP/IP, COM+, and
ActiveX. Many of the advanced features that support Web development, advanced
XML technologies, and database development require components or wizards that
are not available in all editions of Delphi.
The Developer’s Guide assumes you are familiar with using Delphi and understand
fundamental Delphi programming techniques. For an introduction to Delphi
programming and the integrated development environment (IDE), see the Quick
Start manual or the online Help.
Introduction 1-1
Manual conventions
to determine which packages, DLLs, and other libraries to use when building the
production-quality version of your application.
• Part II, “Developing database applications,” describes how to build database
applications using database tools and components. You can access several types of
databases, including local databases such as Paradox and dBASE, and network
SQL server databases such as InterBase, Oracle, and Sybase. You can choose from
a variety of data access mechanisms, including dbExpress, InterbaseExpress, and
ADO. To implement the more advanced database applications, you need the
features that are not available in all editions.
• Part III, “Writing Internet applications,” describes how to create applications that
are distributed over the Internet. Delphi includes a wide array of tools for writing
Web server applications, including: the Web Broker architecture, with which you
can create cross-platform server applications; WebSnap, with which you can
design Web pages in a GUI environment; support for working with XML
documents; and BizSnap, an architecture for using SOAP-based Web Services. For
lower-level support that underlies much of the messaging in Internet applications,
this section also describes how to work with socket components. The components
that implement many of these features are not available in all editions.
• Part IV, “Developing COM-based applications,” describes how to build
applications that can interoperate with other COM-based API objects on the
system such as Windows Shell extensions or multimedia applications. Delphi
contains components that support the ActiveX, COM+, and a COM-based library
for COM controls that can be used for general-purpose and Web-based
applications. A Type Library editor simplifies the development of COM servers.
Support for COM controls and ActiveX controls is not available in all editions of
Delphi.
Manual conventions
This manual uses the typefaces and symbols described in Table 1.1 to indicate special
text.
Introduction 1-3
1-4 Developer’s Guide
Part
I
Programming with Delphi
Part I
The chapters in “Programming with Delphi” introduce concepts and skills necessary
for creating applications using any edition of Delphi.
• Object Inspector for examining and changing an object’s properties and events.
• Object TreeView for displaying and changing a components’ logical relationships.
• Code editor for writing and editing the underlying program logic.
• Project Manager for managing the files that make up one or more projects.
• Integrated debugger for finding and fixing errors in your code.
• Many other tools such as property editors to change the values for an object’s
property.
• Command-line tools including compilers, linkers, and other utilities.
• Extensive class libraries with many reusable objects. Many of the objects provided
in the class library are accessible in the IDE from the Component palette. By
convention, the names of objects in the class library begin with a T, such as
TStatusBar. Names of objects that begin with a Q are based on the Qt library and
are used for cross-platform applications.
Some tools may not be included in all editions of the product.
A more complete overview of the development environment is presented in the
Quick Start manual included with the product. In addition, the online Help system
provides help on all menus, dialog boxes, and windows.
Designing applications
You can design any kind of 32-bit application—from general-purpose utilities to
sophisticated data access programs or distributed applications.
As you visually design the user interface for your application, the Form Designer
generates the underlying Delphi code to support the application. As you select and
modify the properties of components and forms, the results of those changes appear
automatically in the source code, and vice versa. You can modify the source files
directly with any text editor, including the built-in Code editor. The changes you
make are immediately reflected in the visual environment.
You can create your own components using the Delphi language. Most of the
components provided are written in Delphi. You can add components that you write
to the Component palette and customize the palette for your use by including new
tabs if needed.
You can also design applications that run on both Linux and Windows by using CLX
components. CLX contains a set of classes that, if used instead of those in the VCL,
allows your program to port between Windows and Linux. Refer to Chapter 15,
“Developing cross-platform applications” for details about cross-platform
programming and the differences between the Windows and Linux environments. If
you are using Kylix while developing cross-platform applications, Kylix also
includes a Developer’s Guide that is tailored for the Linux environment. You can refer
to the manual both in the Kylix online Help or the printed manual provided with the
Kylix product.
Chapter 8, “Building applications, components, and libraries,” introduces support
for different types of applications.
Creating projects
All application development revolves around projects. When you create an
application in Delphi you are creating a project. A project is a collection of files that
make up an application. Some of these files are created at design time. Others are
generated automatically when you compile the project source code.
You can view the contents of a project in a project management tool called the Project
Manager. The Project Manager lists, in a hierarchical view, the unit names, the forms
contained in the unit (if there is one), and shows the paths to the files in the project.
Although you can edit many of these files directly, it is often easier and more reliable
to use the visual tools.
At the top of the project hierarchy is a group file. You can combine multiple projects
into a project group. This allows you to open more than one project at a time in the
Project Manager. Project groups let you organize and work on related projects, such
as applications that function together or parts of a multi-tiered application. If you are
only working on one project, you do not need a project group file to create an
application.
Project files, which describe individual projects, files, and associated options, have a
.dpr extension. Project files contain directions for building an application or shared
object. When you add and remove files using the Project Manager, the project file is
updated. You specify project options using a Project Options dialog which has tabs
for various aspects of your project such as forms, application, and compiler. These
project options are stored in the project file with the project.
Units and forms are the basic building blocks of an application. A project can share
any existing form and unit file including those that reside outside the project
directory tree. This includes custom procedures and functions that have been written
as standalone routines.
If you add a shared file to a project, realize that the file is not copied into the current
project directory; it remains in its current location. Adding the shared file to the
current project registers the file name and path in the uses clause of the project file.
Delphi automatically handles this as you add units to a project.
When you compile a project, it does not matter where the files that make up the
project reside. The compiler treats shared files the same as those created by the
project itself.
Editing code
The Code editor is a full-featured ASCII editor. If using the visual programming
environment, a form is automatically displayed as part of a new project. You can start
designing your application interface by placing objects on the form and modifying
how they work in the Object Inspector. But other programming tasks, such as writing
event handlers for objects, must be done by typing the code.
The contents of the form, all of its properties, its components, and their properties
can be viewed and edited as text in the Code editor. You can adjust the generated
code in the Code editor and add more components within the editor by typing code.
As you type code into the editor, the compiler is constantly scanning for changes and
updating the form with the new layout. You can then go back to the form, view and
test the changes you made in the editor, and continue adjusting the form from there.
The code generation and property streaming systems are completely open to
inspection. The source code for everything that is included in your final executable
file—all of the VCL objects, CLX objects, RTL sources, and project files—can be
viewed and edited in the Code editor.
Compiling applications
When you have finished designing your application interface on the form and
writing additional code so it does what you want, you can compile the project from
the IDE or from the command line.
All projects have as a target a single distributable executable file. You can view or test
your application at various stages of development by compiling, building, or
running it:
• When you compile, only units that have changed since the last compile are
recompiled.
• When you build, all units in the project are compiled, regardless of whether they
have changed since the last compile. This technique is useful when you are unsure
of exactly which files have or have not been changed, or when you simply want to
ensure that all files are current and synchronized. It's also important to build when
you've changed global compiler directives to ensure that all code compiles in the
proper state.You can also test the validity of your source code without attempting
to compile the project.
• When you run, you compile and then execute your application. If you modified
the source code since the last compilation, the compiler recompiles those changed
modules and relinks your application.
If you have grouped several projects together, you can compile or build all projects in
a single project group at once. Choose Project|Compile All Projects or Project|Build
All Projects with the project group selected in the Project Manager.
Note To compile a CLX application on Linux, you need Kylix.
Debugging applications
With the integrated debugger, you can find and fix errors in your applications. The
integrated debugger lets you control program execution, monitor variable values and
items in data structures, and modify data values while debugging.
The integrated debugger can track down both runtime errors and logic errors. By
running to specific program locations and viewing the variable values, the functions
on the call stack, and the program output, you can monitor how your program
behaves and find the areas where it is not behaving as designed. The debugger is
described in online Help.
You can also use exception handling to recognize, locate, and deal with errors.
Exceptions are classes, like other classes in Delphi, except, by convention, they begin
with an initial E rather than a T.
Deploying applications
Delphi includes add-on tools to help with application deployment. For example,
InstallShield Express (not available in all editions) helps you to create an installation
package for your application that includes all of the files needed for running a
distributed application. TeamSource software (not available in all editions) is also
available for tracking application updates.
To deploy a CLX application on Linux, you need Kylix.
Note Not all editions have deployment capabilities.
Refer to Chapter 18, “Deploying applications,” for specific information on
deployment.
The VCL and CLX contain many of the same sublibraries. They both include
BaseCLX, DataCLX, NetCLX. The VCL also includes WinCLX while CLX includes
VisualCLX instead. Use the VCL when you want to use native Windows controls,
Windows-specific features, or extend an existing VCL application. Use CLX when
you want to write a cross-platform application or use controls that are available in
CLX applications, such as TLCDNumber. For more information on writing cross-
platform applications, see Chapter 15, “Developing cross-platform applications.”
All classes descend from TObject. TObject introduces methods that implement
fundamental behavior like construction, destruction, and message handling.
Components are a subset of the component library that descend from the class
TComponent. You can place components on a form or data module and manipulate
them at design time. Using the Object Inspector, you can assign property values
without writing code. Most components are either visual or nonvisual, depending on
whether they are visible at runtime. Some components appear on the Component
palette.
Visual components, such as TForm and TSpeedButton, are called controls and descend
from TControl. Controls are used in GUI applications, and appear to the user at
runtime. TControl provides properties that specify the visual attributes of controls,
such as their height and width.
Nonvisual components are used for a variety of tasks. For example, if you are writing
an application that connects to a database, you can place a TDataSource component
on a form to connect a control and a dataset used by the control. This connection is
not visible to the user, so TDataSource is nonvisual. At design time, nonvisual
components are represented by an icon. This allows you to manipulate their
properties and events just as you would a visual control.
Classes that are not components (that is, classes that descend from TObject but not
TComponent) are also used for a variety of tasks. Typically, these classes are used for
accessing system objects (such as a file or the clipboard) or for transient tasks (such as
storing data in a list). You can’t create instances of these classes at design time,
although they are sometimes created by the components that you add in the Form
Designer.
Detailed reference material on all VCL and CLX objects is accessible through online
Help while you are programming. In the Code editor, place the cursor anywhere on
the object and press F1 to display the Help topic. Objects, properties, methods, and
events that are in the VCL are marked “VCL Reference” and those in CLX are
marked “CLX Reference.”
Properties
Properties are characteristics of an object that influence either the visible behavior or
the operations of the object. For example, the Visible property determines whether an
object can be seen in an application interface. Well-designed properties make your
components easier for others to use and easier for you to maintain.
Here are some of the useful features of properties:
• Unlike methods, which are only available at runtime, you can see and change
some properties at design time and get immediate feedback as the components
change in the IDE.
• You can access some properties in the Object Inspector, where you can modify the
values of your object visually. Setting properties at design time is easier than
writing code and makes your code easier to maintain.
• Because the data is encapsulated, it is protected and private to the actual object.
• The calls to get and set the values of properties can be methods, so special
processing can be done that is invisible to the user of the object. For example, data
could reside in a table, but could appear as a normal data member to the
programmer.
• You can implement logic that triggers events or modifies other data during the
access of a property. For example, changing the value of one property may require
you to modify another. You can change the methods created for the property.
• Properties can be virtual.
• A property is not restricted to a single object. Changing one property on one object
can affect several objects. For example, setting the Checked property on a radio
button affects all of the radio buttons in the group.
Methods
A method is a procedure that is always associated with a class. Methods define the
behavior of an object. Class methods can access all the public, protected, and
privateproperties and fields of the class and are commonly referred to as member
functions. See “Controlling access” on page 2-6 of the Component Writer’s Guide.
Although most methods belong to an instance of a class, some methods belong
instead to the class type. These are called class methods.
Events
An event is an action or occurrence detected by a program. Most modern applications
are said to be event-driven, because they are designed to respond to events. In a
program, the programmer has no way of predicting the exact sequence of actions a
user will perform. For example, the user may choose a menu item, click a button, or
mark some text. You can write code to handle the events in which you are interested,
rather than writing code that always executes in the same restricted order.
Regardless of how an event is triggered, VCL objects look to see if you have written
any code to handle that event. If you have, that code is executed; otherwise, the
default event handling behavior takes place.
The kinds of events that can occur can be divided into two main categories:
• User events
• System events
• Internal events
User events
User events are actions that the user initiates. Examples of user events are OnClick
(the user clicked the mouse), OnKeyPress (the user pressed a key on the keyboard),
and OnDblClick (the user double-clicked a mouse button).
System events
System events are events that the operating system fires for you. For example, the
OnTimer event (which the Timer component issues whenever a predefined interval
has elapsed), the OnPaint event (a component or window needs to be redrawn), and
so on. Usually, system events are not directly initiated by a user action.
Internal events
Internal events are events that are generated by the objects in your application. An
example of an internal event is the OnPost event that a dataset generates when your
application tells it to post the current record.
[Objects]
[Objects] [Objects] TGraphicControl [Objects]
[Objects]
Every object (class) inherits from TObject. Objects that can appear in the Form
Designer inherit from TPersistent or TComponent. Controls, which appear to the user
at runtime, inherit from TControl. There are two types of controls, graphic controls,
which inherit from TGraphicControl, and windowed controls, which inherit from
TWinControl or TWidgetControl. A control like TCheckBox inherits all the functionality
of TObject, TPersistent, TComponent, TControl, and TWinControl or TWidgetControl,
and adds specialized capabilities of its own.
The figure shows several important base classes, which are described in the
following table:
The next few sections present a general description of the types of classes that each
branch contains. For a complete overview of the VCL and CLX object hierarchies,
refer to the VCL Object Hierarchy and CLX Object Hierarchy wall charts included
with this product.
TObject branch
The TObject branch includes all VCL and CLX classes that descend from TObject but
not from TPersistent. Much of the powerful capability of the component library is
established by the methods that TObject introduces. TObject encapsulates the
fundamental behavior common to all classes in the component library by introducing
methods that provide:
• The ability to respond when object instances are created or destroyed.
• Class type and instance information on an object, and runtime type information
(RTTI) about its published properties.
• Support for handling messages (VCL applications) or handling notifications (CLX
applications).
TObject is the immediate ancestor of many simple classes. Classes in the TObject
branch have one common, important characteristic: they are transitory. This means
that these classes do not have a method to save the state that they are in prior to
destruction; they are not persistent.
One of the main groups of classes in this branch is the Exception class. This class
provides a large set of built-in exception classes for automatically handling divide-
by-zero errors, file I/O errors, invalid typecasts, and many other exception
conditions.
Another group in the TObject branch is classes that encapsulate data structures, such
as:
• TBits, a class that stores an “array” of Boolean values.
• TList, a linked list class.
• TStack, a class that maintains a last-in first-out array of pointers.
• TQueue, a class that maintains a first-in first-out array of pointers.
Another group in the TObject branch are wrappers for external objects like TPrinter,
which encapsulates a printer interface, and TIniFile, which lets a program read from
or write to an ini file.
TStream is a good example of another type of class in this branch. TStream is the base
class type for stream objects that can read from or write to various kinds of storage
media, such as disk files, dynamic memory, and so on (see “Using streams” on
page 5-2 for information on streams).
See Chapter 5, “Using BaseCLX,” for information on many of the classes in the
TObject branch (as well as on many global routines in the Delphi Runtime Library).
TPersistent branch
The TPersistent branch includes all VCL and CLX classes that descend from
TPersistent but not from TComponent. Persistence determines what gets saved with a
form file or data module and what gets loaded into the form or data module when it
is retrieved from memory.
Because of their persistence, objects from this branch can appear at design time.
However, they can’t exist independently. Rather, they implement properties for
components. Properties are only loaded and saved with a form if they have an
owner. The owner must be some component. TPersistent introduces the GetOwner
method, which lets the Form Designer determine the owner of the object.
Classes in this branch are also the first to include a published section where
properties can be automatically loaded and saved. A DefineProperties method lets
each class indicate how to load and save properties.
Following are some of the classes in the TPersistent branch of the hierarchy:
• Graphics such as: TBrush, TFont, and TPen.
• Classes such as TBitmap and TIcon, which store and display visual images, and
TClipboard, which contains text or graphics that have been cut or copied from an
application.
• String lists, such as TStringList, which represent text or lists of strings that can be
assigned at design time.
• Collections and collection items, which descend from TCollection or
TCollectionItem. These classes maintain indexed collections of specially defined
items that belong to a component. Examples include THeaderSections and
THeaderSection or TListColumns and TListColumn.
TComponent branch
The TComponent branch contains classes that descend from TComponent but not
TControl. Objects in this branch are components that you can manipulate on forms at
design time but which do not appear to the user at runtime. They are persistent
objects that can do the following:
• Appear on the Component palette and be changed on the form.
• Own and manage other components.
• Load and save themselves.
TControl branch
The TControl branch consists of components that descend from TControl but not
TWinControl (TWidgetControl in CLX applications). Classes in this branch are
controls: visual objects that the user can see and manipulate at runtime. All controls
have properties, methods, and events in common that relate to how the control looks,
such as its position, the cursor associated with the control’s window, methods to
paint or move the control, and events to respond to mouse actions. Controls in this
branch, however, can never receive keyboard input.
Whereas TComponent defines behavior for all components, TControl defines behavior
for all visual controls. This includes drawing routines, standard events, and
containership.
TControl introduces many visual properties that all controls inherit. These include the
Caption, Color, Font, and HelpContext or HelpKeyword. While these properties inherited
from TControl, they are only published—and hence appear in the Object Inspector—
for controls to which they are applicable. For example, TImage does not publish the
Color property, since its color is determined by the graphic it displays. TControl also
introduces the Parent property, which specifies another control that visually contains
the control.
Classes in the TControl branch often called graphic controls, because they all descend
from TGraphicControl, which is an immediate descendant of TControl. Although these
controls appear to the user at runtime, graphic controls do not have their own
underlying window or widget. Instead, they use their parent’s window or widget. It
is because of this limitation that graphic controls cant receive keyboard input or act
as a parent to other controls. However, because they do not have their own window
or widget, graphic controls use fewer system resources. For details on many of the
classes in the TControl branch, see “Graphic controls” on page 10-18.
There are two versions of TControl, one for VCL (Windows-only) applications and
one for CLX (cross-platform) applications. Most controls have two versions as well, a
Windows-only version that descends from the Windows-only version of TControl,
and a cross-platform version that descends from the cross-platform version of
TControl. The Windows-only controls use native Windows APIs in their
implementations, while the cross-platform versions sit on top of the Qt cross-
platform widget library.
See Chapter 7, “Working with controls,” for details on how to interact with controls
at runtime.
TWinControl/TWidgetControl branch
Most controls fall into the TWinControl/ TWidgetControl branch. Unlike graphic
controls, controls in this branch have their own associated window or widget.
Because of this, they are sometimes called windowed controls or widget controls.
Windowed controls all descend from TWinControl, which descends from the
windows-only version of TControl. Widget controls all descend from TWidgetControl,
which descends from the CLX version of TControl.
Controls in the TWinControl/TWidgetControl branch:
• Can receive focus while an application is running, which means they can receive
keyboard input from the application user. In comparison, graphic controls can
only display data and respond to the mouse.
• Can be the parent of one or more child controls.
• Have a handle, or unique identifier, that allows them to access the underlying
window or widget.
The TWinControl/TWidgetControl branch includes both controls that are drawn
automatically (such as TEdit, TListBox, TComboBox, TPageControl, and so on) and
custom controls that do not correspond directly to a single underlying Windows
control or widget. Controls in this latter category, which includes classes like
TStringGrid and TDBNavigator, must handle the details of painting themselves.
Because of this, they descend from TCustomControl, which introduces a Canvas
property on which they can paint themselves.
For details on many of the controls in the TWinControl/TWidgetControl branch, see
Chapter 10, “Types of controls.”
What is an object?
A class is a data type that encapsulates data and operations on data in a single unit.
Before object-oriented programming, data and operations (functions) were treated as
separate elements. An object is an instance of a class. That is, it is a value whose type
is a class. The term object is often used more loosely in this documentation and where
the distinction between a class and an instance of the class is not important, the term
“object” may also refer to a class.
You can begin to understand objects if you understand Pascal records or structures in
C. Records are made of up fields that contain data, where each field has its own type.
Records make it easy to refer to a collection of varied data elements.
Objects are also collections of data elements. But objects—unlike records—contain
procedures and functions that operate on their data. These procedures and functions
are called methods.
An object’s data elements are accessed through properties. The properties of many
Delphi objects have values that you can change at design time without writing code.
If you want a property value to change at runtime, you need to write only a small
amount of code.
The combination of data and functionality in a single unit is called encapsulation. In
addition to encapsulation, object-oriented programming is characterized by
inheritance and polymorphism. Inheritance means that objects derive functionality from
other objects (called ancestors); objects can modify their inherited behavior.
Polymorphism means that different objects derived from the same ancestor support
the same method and property interfaces, which often can be called interchangeably.
Form1 represents an instance, or object, of the class type TForm1. You can declare
more than one instance of a class type; you might want to do this, for example, to
create multiple child windows in a Multiple Document Interface (MDI) application.
Each instance maintains its own data, but all instances use the same code to execute
methods.
Although you haven’t added any components to the form or written any code, you
already have a complete GUI application that you can compile and run. All it does is
display a blank form.
Suppose you add a button component to this form and write an OnClick event
handler that changes the color of the form when the user clicks the button. The result
might look like this:
Figure 4.1 A simple form
When the user clicks the button, the form’s color changes to green. This is the event-
handler code for the button’s OnClick event:
procedure TForm1.Button1Click(Sender: TObject);
begin
Form1.Color := clGreen;
end;
Objects can contain other objects as data fields. Each time you place a component on
a form, a new field appears in the form’s type declaration. If you create the
application described above and look at the code in the Code editor, this is what you
see:
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
Button1: TButton;{ New data field }
procedure Button1Click(Sender: TObject);{ New method declaration }
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);{ The code of the new method }
begin
Form1.Color := clGreen;
end;
end.
TForm1 has a Button1 field that corresponds to the button you added to the form.
TButton is a class type, so Button1 refers to an object.
All the event handlers you write using the IDE are methods of the form object. Each
time you create an event handler, a method is declared in the form object type. The
TForm1 type now contains a new method, the Button1Click procedure, declared in the
TForm1 type declaration. The code that implements the Button1Click method appears
in the implementation part of the unit.
Note that the code in the OnClick event handler for the button hasn’t changed.
Because you wrote the code, you have to update it yourself and correct any
references to the form:
procedure TColorWindow.Button1Click(Sender: TObject);
begin
ColorWindow.Color := clGreen;
end;
• The protected section includes fields and methods with some access restrictions. A
protected member is accessible within the unit where its class is declared and by
any descendant class, regardless of the descendant class’s unit.
• The private section declares fields and methods that have rigorous access
restrictions. A private member is accessible only within the unit where it is
declared. Private members are often used in a class to implement other (public or
published) methods and properties.
• For classes that descend from TPersistent, a published section declares properties
and events that are available at design time. A published member has the same
visibility as a public member, but the compiler generates runtime type information
for published members. Published properties appear in the Object Inspector at
design time.
When you declare a field, property, or method, the new member is added to one of
these four sections, which gives it its visibility: private, protected, public, or
published.
For more information about visibility, see the Delphi Language Guide.
In addition to the fields, properties, and methods you’ve defined, TEmployee inherits
all the methods of TObject. You can place a type declaration like this one in either the
interface or implementation part of a unit, and then create instances of the new class
by calling the Create method that TEmployee inherits from TObject:
var
Employee: TEmployee;
begin
Employee := TEmployee.Create;
end;
The Create method is called a constructor. It allocates memory for a new instance
object and returns a reference to the object.
Components on a form are created and destroyed automatically. However, if you
write your own code to instantiate objects, you are responsible for disposing of them
as well. Every object inherits a Destroy method (called a destructor) from TObject. To
destroy an object, however, you should call the Free method (also inherited from
TObject), because Free checks for a nil reference before calling Destroy. For example,
Employee.Free;
destroys the Employee object and deallocates its memory.
If you do not have class completion, you need to write the code yourself,
completing property declarations and writing the methods.
Given the example above, if you have class completion, read and write specifiers
are added to your declaration, including any supporting fields or methods:
type TMyButton = class(TButton)
property Size: Integer read FSize write SetSize;
procedure DoSomething;
private
FSize: Integer;
procedure SetSize(const Value: Integer);
The following code is also added to the implementation section of the unit.
{ TMyButton }
procedure TMyButton.DoSomething;
begin
end;
procedure TMyButton.SetSize(const Value: Integer);
begin
FSize := Value;
end;
5 Fill in the methods. For example, to make it so the button beeps when you call the
DoSomething method, add the Beep between begin and end.
{ TMyButton }
procedure TMyButton.DoSomething;
begin
Beep;
end;
procedure TMyButton.SetSize(const Value: Integer);
begin
if fsize < > value then
begin
FSize := Value;
DoSomething;
end;
end;
Note that the button also beeps when you call SetSize to change the size of the
button.
For more information about the syntax, language definitions, and rules for classes,
see the Delphi Language Guide.
Using interfaces
Delphi is a single-inheritance language. That means that any class has only a single
direct ancestor. However, there are times you want a new class to inherit properties
and methods from more than one base class so that you can use it sometimes like one
and sometimes like the other. Interfaces let you achieve something like this effect.
An interface is like a class that contains only abstract methods (methods with no
implementation) and a clear definition of their functionality. Interface method
definitions include the number and types of their parameters, their return type, and
their expected behavior. By convention, interfaces are named according to their
behavior and prefaced with a capital I. For example, an IMalloc interface would
allocate, free, and manage memory. Similarly, an IPersist interface could be used as a
general base interface for descendants, each of which defines specific method
prototypes for loading and saving the state of an object to a storage, stream, or file.
An interface has the following syntax:
IMyObject = interface
procedure MyProcedure;
end;
A simple example of an interface declaration is:
type
IEdit = interface
procedure Copy;
procedure Cut;
procedure Paste;
function Undo: Boolean;
end;
Interfaces can never be instantiated. To use an interface, you need to obtain it from an
implementing class.
To implement an interface, define a class that declares the interface in its ancestor list,
indicating that it will implement all of the methods of that interface:
TEditor = class(TInterfacedObject, IEdit)
procedure Copy;
procedure Cut;
procedure Paste;
function Undo: Boolean;
end;
While interfaces define the behavior and signature of their methods, they do not
define the implementations. As long as the class’s implementation conforms to the
interface definition, the interface is fully polymorphic, meaning that accessing and
using the interface is the same for any implementation of it.
For more details about the syntax, language definitions and rules for interfaces, see
the Delphi Language Guide
Later, you could create a class TFilledCircle that implements the IRotate interface to
allow rotation of a pattern that fills the circle without having to add rotation to the
simple circle.
Note For these examples, the immediate base class or an ancestor class is assumed to have
implemented the methods of IInterface, the base interface from which all interfaces
descend. For more information on IInterface, see “Implementing IInterface” on
page 4-14 and “Memory management of interface objects” on page 4-18.
Implementing IInterface
Just as all objects descend, directly or indirectly, from TObject, all interfaces derive
from the IInterface interface. IInterface provides for dynamic querying and lifetime
management of the interface. This is established in the three IInterface methods:
• QueryInterface dynamically queries a given object to obtain interface references for
the interfaces that the object supports.
• _AddRef is a reference counting method that increments the count each time a call
to QueryInterface succeeds. While the reference count is nonzero the object must
remain in memory.
• _Release is used with _AddRef to allow an object to track its own lifetime and
determine when it is safe to delete itself. Once the reference count reaches zero, the
object is freed from memory.
Every class that implements interfaces must implement the three IInterface methods,
as well as all of the methods declared by any other ancestor interfaces, and all of the
methods declared by the interface itself. You can, however, inherit the
implementations of methods of interfaces declared in your class.
By implementing these methods yourself, you can provide an alternative means of
lifetime management, disabling reference-counting. This is a powerful technique that
lets you decouple interfaces from reference-counting.
TInterfacedObject
When defining a class that supports one or more interfaces, it is convenient to use
TInterfacedObject as a base class because it implements the methods of IInterface.
TInterfacedObject class is declared in the System unit as follows:
type
TInterfacedObject = class(TObject, IInterface)
protected
FRefCount: Integer;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
class function NewInstance: TObject; override;
property RefCount: Integer read FRefCount;
end;
Deriving directly from TInterfacedObject is straightforward. In the following example
declaration, TDerived is a direct descendant of TInterfacedObject and implements a
hypothetical IPaint interface.
type
TDerived = class(TInterfacedObject, IPaint)
ƒ
end;
Because it implements the methods of IInterface, TInterfacedObject automatically
handles reference counting and memory management of interfaced objects. For more
information, see “Memory management of interface objects” on page 4-18, which
also discusses writing your own classes that implement interfaces but that do not
follow the reference-counting mechanism inherent in TInterfacedObject.
For more information about the syntax, implementation details, and language rules
of the implements keyword, see the Delphi Language Guide.
Aggregation
Aggregation offers a modular approach to code reuse through sub-objects that make
up the functionality of a containing object, but that hide the implementation details
from that object. In aggregation, an outer object implements one or more interfaces.
At a minimum, it must implement IInterface. The inner object, or objects, also
implement one or more interfaces. However, only the outer object exposes the
interfaces. That is, the outer object exposes both the interfaces it implements and the
ones that its contained objects implement.
Clients know nothing about inner objects. While the outer object provides access to
the inner object interfaces, their implementation is completely transparent. Therefore,
the outer object class can exchange the inner object class type for any class that
implements the same interface. Correspondingly, the code for the inner object classes
can be shared by other classes that want to use it.
The aggregation model defines explicit rules for implementing IInterface using
delegation. The inner object must implement two versions of the IInterface methods.
• It must implement IInterface on itself, controlling its own reference count. This
implementation of IInterface tracks the relationship between the outer and the
inner object. For example, when an object of its type (the inner object) is created,
the creation succeeds only for a requested interface of type IInterface.
• It also implements a second IInterface for all the interfaces it implements that the
outer object exposes. This second IInterface delegates calls to QueryInterface,
_AddRef, and _Release to the outer object. The outer IInterface is referred to as the
“controlling Unknown.”
Refer to the MS online help for the rules about creating an aggregation. When writing
your own aggregation classes, you can also refer to the implementation details of
IInterface in TComObject. TComObject is a COM class that supports aggregation. If you
are writing COM applications, you can also use TComObject directly as a base class.
Using BaseCLX
Chapter5
5
There are a number of units in the component library that provide the underlying
support for most of the component libraries. These units include the global routines
that make up the runtime library, a number of utility classes such as those that
represent streams and lists, and the classes TObject, TPersistent, and TComponent.
Collectively, these units are called BaseCLX. BaseCLX does not include any of the
components that appear on the Component palette. Rather, the classes and routines
in BaseCLX are used by the components that do appear on the Component palette
and are available for you to use in application code or when you are writing your
own classes.
The following topics discuss many of the classes and routines that make up BaseCLX
and illustrate how to use them.
• Using streams
• Working with files~
• Working with .ini files
• Working with lists
• Working with string lists
• Working with strings~
• Creating drawing spaces
• Printing
• Converting measurements
• Defining custom variants
Note This list of tasks is not exhaustive. The runtime library in BaseCLX contains many
routines to perform tasks that are not mentioned here. These include a host of
mathematical functions (defined in the Math unit), routines for working with date/
time values (defined in the SysUtils and DateUtils units), and routines for working
with Variant values (defined in the Variants unit).
Using streams
Streams are classes that let you read and write data. They provide a common
interface for reading and writing to different media such as memory, strings, sockets,
and BLOB fields in databases. There are several stream classes, which all descend
from TStream. Each stream class is specific to one media type. For example,
TMemoryStream reads from or writes to a memory image; TFileStream reads from or
writes to a file.
Read and Write methods, which can return a byte count that differs from the
requested value. The prototypes for ReadBuffer and WriteBuffer are:
procedure ReadBuffer(var Buffer; Count: Longint);
procedure WriteBuffer(const Buffer; Count: Longint);
These methods call the Read and Write methods to perform the actual reading and
writing.
The Origin parameter indicates how to interpret the Offset parameter. Origin should
be one of the following values:
Seek resets the current stream position, moving it by the indicated offset. Seek returns
the new current position in the stream.
Note When writing cross-platform applications, remember that although the Delphi
language is not case sensitive, the Linux operating system is. When using objects and
routines that work with files, be attentive to the case of file names.
The share mode can be one of the following values with the restrictions listed below:
Note that which share mode you can use depends on which open mode you used.
The following table shows shared modes that are available for each open mode.
The file open and share mode constants are defined in the SysUtils unit.
Manipulating files
Several common file operations are built into the runtime library. The routines for
working with files operate at a high level. For most routines, you specify the name of
the file and the routine makes the necessary calls to the operating system for you. In
some cases, you use file handles instead.
Caution Although the Delphi language is not case sensitive, the Linux operating system is. Be
attentive to case when working with files in cross-platform applications.
Deleting a file
Deleting a file erases the file from the disk and removes the entry from the disk's
directory. There is no corresponding operation to restore a deleted file, so
applications should generally allow users to confirm before deleting files. To delete a
file, pass the name of the file to the DeleteFile function:
DeleteFile(FileName);
DeleteFile returns True if it deleted the file and False if it did not (for example, if the
file did not exist or if it was read-only). DeleteFile erases the file named by FileName
from the disk.
Finding a file
There are three routines used for finding a file: FindFirst, FindNext, and FindClose.
FindFirst searches for the first instance of a filename with a given set of attributes in a
specified directory. FindNext returns the next entry matching the name and attributes
specified in a previous call to FindFirst. FindClose releases memory allocated by
FindFirst. You should always use FindClose to terminate a FindFirst/FindNext
sequence. If you want to know if a file exists, a FileExists function returns True if the
file exists, False otherwise.
The three file find routines take a TSearchRec as one of the parameters. TSearchRec
defines the file information searched for by FindFirst or FindNext. If a file is found, the
fields of the TSearchRec type parameter are modified to describe the found file.
type
TFileName = string;
TSearchRec = record
Time: Integer;//Time contains the time stamp of the file.
Size: Integer;//Size contains the size of the file in bytes.
Attr: Integer;//Attr represents the file attributes of the file.
Name: TFileName;//Name contains the filename and extension.
ExcludeAttr: Integer;
FindHandle: THandle;
FindData: TWin32FindData;//FindData contains additional information such as
//file creation time, last access time, long and short filenames.
end;
On field of TSearchRec that is of particular interest is the Attr field. You can test Attr
against the following attribute constants or values to determine if a file has a specific
attribute:
To test for an attribute, combine the value of the Attr field with the attribute constant
using the and operator. If the file has that attribute, the result will be greater than 0.
For example, if the found file is a hidden file, the following expression will evaluate
to True:
(SearchRec.Attr and faHidden > 0).
Attributes can be combined by OR’ing their constants or values. For example, to
search for read-only and hidden files in addition to normal files, pass the following as
the Attr parameter.
(faReadOnly or faHidden).
The following example illustrates the use of the three file find routines. It uses a label,
a button named Search, and a button named Again on a form. When the user clicks the
Search button, the first file in the specified path is found, and the name and the
number of bytes in the file appear in the label's caption. Each time the user clicks the
Again button, the next matching filename and size is displayed in the label:
var
SearchRec: TSearchRec;
procedure TForm1.SearchClick(Sender: TObject);
begin
FindFirst('c:\Program Files\MyProgram\bin\*.*', faAnyFile, SearchRec);
Label1.Caption := SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) + ' bytes in size';
end;
procedure TForm1.AgainClick(Sender: TObject);
begin
if FindNext(SearchRec) = 0 then
Label1.Caption := SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) + ' bytes in size'
else
FindClose(SearchRec);
end;
Note In cross-platform applications, you should replace any hard-coded pathnames with
the correct pathname for the system or use environment variables (on the
Environment Variables page when you choose Tools|Environment Options) to
represent them.
Renaming a file
To change a file name, use the RenameFile function:
function RenameFile(const OldFileName, NewFileName: string): Boolean;
RenameFile changes a file name, identified by OldFileName, to the name specified by
NewFileName. If the operation succeeds, RenameFile returns True. If it cannot rename
the file (for example, if a file called NewFileName already exists), RenameFile returns
False. For example:
if not RenameFile('OLDNAME.TXT','NEWNAME.TXT') then
ErrorMsg('Error renaming file!');
You cannot rename (move) a file across drives using RenameFile. You would need to
first copy the file and then delete the old one.
Note RenameFile in the runtime library is a wrapper around the Windows API MoveFile
function, so MoveFile will not work across drives either.
As with most of the file manipulating routines, FileAge uses a string filename.
FileGetDate and FileSetDate, however, use a Handle type as a parameter. To get the file
handle either:
• Use the FileOpen or FileCreate function to create a new file or open an existing file.
Both FileOpen and FileCreate return the file handle.
• Instantiate TFileStream to create or open a file. Then use its Handle property. See
“Using file streams” on page 5-6 for more information.
Copying a file
FindingAFile;RenamingAFile;FileDateTimeRoutines;DeletingAFileThe runtime
library does not provide any routines for copying a file. However, if you are writing
Windows-only applications, you can directly call the Windows API CopyFile function
to copy a file. Like most of the runtime library file routines, CopyFile takes a filename
as a parameter, not a file handle. When copying a file, be aware that the file attributes
for the existing file are copied to the new file, but the security attributes are not.
CopyFile is also useful when moving files across drives because neither the RenameFile
function nor the Windows API MoveFile function can rename or move files across
drives. For more information, see the Microsoft Windows online Help.
Each of the Read routines takes three parameters. The first parameter identifies the
section of the ini file. The second parameter identifies the value you want to read,
and the third is a default value in case the section or value doesn't exist in the ini file.
Just as the Read methods gracefully handle the case when a section or value does not
exist, the Write routines create the section and/or value if they do not exist. The
example code creates an ini file the first time it is run that looks like this:
[Form]
Top=100
Left=100
Caption=Default Caption
InitMax=0
On subsequent execution of this application, the ini values are read in when the form
is created and written back out in the OnClose event.
Using TRegistryIniFile
Many 32-bit Windows applications store their information in the system Registry
instead of ini files because the Registry is hierarchical and doesn't suffer from the size
limitations of ini files. If you are accustomed to using ini files and want to move your
configuration information to the Registry instead, you can use the TRegistryIniFile
class. You may also want to use TRegistryIniFile in cross-platform applications if you
want to use the system Registry on Windows and an ini file on Linux. You can write
most of your application so that it uses the TCustomIniFile type. You need only
conditionalize the code that creates an instance of TRegistryIniFile (on Windows) or
TMemIniFile (on Linux) and assigns it to the TCustomIniFile your application uses.
TRegistryIniFile makes Registry entries look like ini file entries. All the methods from
TIniFile and TMemIniFile (read and write) exist in TRegistryIniFile.
When you construct a TRegistryIniFile object, the parameter you pass to the
constructor (corresponding to the filename for an IniFile or TMemIniFile object)
becomes a key value under the user key in the registry. All sections and values
branch from that root. TRegistryIniFile simplifies the Registry interface considerably,
so you may want to use it instead of the TRegistry component even if you aren't
porting existing code or writing a cross-platform application.
Using TRegistry
If you are writing a Windows-only application and are comfortable with the
structure of the system Registry, you can use TRegistry. Unlike TRegistryIniFile, which
uses the same properties and methods of other ini file components, the properties
and methods of TRegistry correspond more directly to the structure of the system
Registry. For example, TRegistry lets you specify both the root key and subkey, while
TRegistryIniFile assumes HKEY_CURRENT_USER as a root key. In addition to
methods for opening, closing, saving, moving, copying, and deleting keys, TRegistry
lets you specify the access level you want to use.
Note TRegistry is not available for cross-platform programming.
Persistent lists
Persistent lists can be saved to a form file. Because of this, they are often used as the
type of a published property on a component. You can add items to the list at design
time, and those items are saved with the object so that they are there when the
component that uses them is loaded into memory at runtime. There are two main
types of persistent lists: string lists and collections.
Examples of string lists include TStringList and THashedStringList. String lists, as the
name implies, contain strings. They provide special support for strings of the form
Name=Value, so that you can look up the value associated with a name. In addition,
most string lists let you associate an object with each string in the list. String lists are
described in more detail in “Working with string lists” on page 5-17.
Collections descend from the class TCollection. Each TCollection descendant is
specialized to manage a specific class of items, where that class descends from
TCollectionItem. Collections support many of the common list operations. All
collections are designed to be the type of a published property, and many can not
function independently of the object that uses them to implement on of its properties.
At design time, the property whose value is a collection can use the collection editor
to let you add, remove, and rearrange items. The collection editor provides a
common user interface for manipulating collections.
This example uses a long-term string list to record the user’s mouse clicks on the
main form, then saves the list to a file before the application terminates.
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
{For CLX apps: uses SysUtils, Variants, Classes, QGraphics, QControls, QForms, QDialogs;}
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
ClickList: TStrings;{ declare the field }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
end.
The following functions convert between standard single-byte character strings (or
MBCS strings) and Unicode strings:
• StringToWideChar
• WideCharLenToString
• WideCharLenToStrVar
• WideCharToString
• WideCharToStrVar
In addition, the following functions translate between WideStrings and other
representations:
• UCS4StringToWideString
• WideStringToUCS4String
• VarToWideStr
• VarToWideStrDef
The following routines work directly with WideStrings:
• WideCompareStr
• WideCompareText
• WideSameStr
• WideSameText
• WideSameCaption (CLX applications only)
• WideFmtStr
• WideFormat
• WideLowerCase
• WideUpperCase
Finally, some routines include overloads for working with wide strings:
• UniqueString
• Length
• Trim
• TrimLeft
• TrimRight
Where appropriate, the tables also provide columns indicating whether a routine
satisfies the following criteria.
• Uses case sensitivity: If locale settings are used, it determines the definition of case.
If the routine does not use locale settings, analyses are based upon the ordinal
values of the characters. If the routine is case-insensitive, there is a logical merging
of upper and lower case characters that is determined by a predefined pattern.
• Uses locale settings: Locale settings allow you to customize your application for
specific locales, in particular, for Asian language environments. Most locale
settings consider lowercase characters to be less than the corresponding uppercase
characters. This is in contrast to ASCII order, in which lowercase characters are
greater than uppercase characters. Routines that use the system locale are typically
prefaced with Ansi (that is, AnsiXXX).
• Supports the multi-byte character set (MBCS): MBCSs are used when writing code
for far eastern locales. Multi-byte characters are represented by one or more
character codes, so the length in bytes does not necessarily correspond to the
length of the string. The routines that support MBCS parse one- and multibyte
characters.
ByteType and StrByteType determine whether a particular byte is the lead byte of a
multibyte character. Be careful when using multibyte characters not to truncate a
string by cutting a character in half. Do not pass characters as a parameter to a
function or procedure, since the size of a character cannot be predetermined. Pass,
instead, a pointer to a to a character or string. For more information about MBCS,
see “Enabling application code” on page 17-2.
Situations in which these differences can cause subtle errors are discussed in the
following topics.
String dependencies
Sometimes you need convert a long string to a null-terminated string, for example, if
you are using a function that takes a PChar. If you must cast a string to a PChar, be
aware that you are responsible for the lifetime of the resulting PChar. Because long
strings are reference counted, typecasting a string to a PChar increases the
dependency on the string by one, without actually incrementing the reference count.
When the reference count hits zero, the string will be destroyed, even though there is
an extra dependency on it. The cast PChar will also disappear, while the routine you
passed it to may still be using it. For example:
procedure my_func(x: string);
begin
// do something with x
some_proc(PChar(x)); // cast the string to a PChar
// you now need to guarantee that the string remains
// as long as the some_proc procedure needs to use it
end;
var
i: Integer;
buf: array[0..MAX_SIZE] of char;
S: string;
begin
i := FillBuffer(0, buf, SizeOf(buf));// treats buf as a PChar
S := buf;
//statements
end;
This approach is useful if the size of the buffer is relatively small, since it is allocated
on the stack. It is also safe, since the conversion between an array of char and a string
is automatic. The Length of the string is automatically set to the right value after
assigning buf to the string.
To eliminate the overhead of copying the buffer, you can cast the string to a PChar (if
you are certain that the routine does not need the PChar to remain in memory).
However, synchronizing the length of the string does not happen automatically, as it
does when you assign an array of char to a string. You should reset the string Length
so that it reflects the actual width of the string. If you are using a function that returns
the number of bytes copied, you can do this safely with one line of code:
var
S: string;
begin
SetLength(S, MAX_SIZE;// when casting to a PChar, be sure the string is not empty
SetLength(S, GetModuleFilename( 0, PChar(S), Length(S) ) );
// statements
end;
The TCanvas object defined in the Graphics unit also protects you against common
Windows graphics errors, such as restoring device contexts, pens, brushes, and so on
to the value they had before the drawing operation. TCanvas is used everywhere in
the VCL that drawing is required or possible, and makes drawing graphics both fail-
safe and easy.
See TCanvas in the online Help reference for a complete listing of properties and
methods.
Printing
Like TCanvas, the TPrinter class does not belong to BaseCLX because there are two
separate versions, one for VCL applications (in the Printers unit) and one for CLX
applications (in the QPrinters unit). The VCL TPrinter object encapsulates details of
Windows printers. The CLX TPrinter object is a paint device that paints on a printer.
It generates postscript and sends that to lpr, lp, or another print command. Both
versions of TPrinter, however, are extremely similar.
To get a list of installed and available printers, use the Printers property. Both printer
objects use a TCanvas (which is identical to the form's TCanvas) which means that
anything that can be drawn on a form can be printed as well. To print an image, call
the BeginDoc method followed by whatever canvas graphics you want to print
(including text through the TextOut method) and send the job to the printer by calling
the EndDoc method.
This example uses a button and a memo on a form. When the user clicks the button,
the content of the memo is printed with a 200-pixel border around the page.
To run this example successfully, add Printers to your uses clause.
procedure TForm1.Button1Click(Sender: TObject);
var
r: TRect;
i: Integer;
begin
with Printer do
begin
r := Rect(200,200,(Pagewidth - 200),(PageHeight - 200));
BeginDoc;
Canvas.Brush.Style := bsClear;
for i := 0 to Memo1.Lines.Count do
Canvas.TextOut(200,200 + (i *
Canvas.TextHeight(Memo1.Lines.Strings[i])),
Memo1.Lines.Strings[i]);
Canvas.Brush.Color := clBlack;
Canvas.FrameRect(r);
EndDoc;
end;
end;
For more information on the use of the TPrinter object, look in the online help under
TPrinter.
Converting measurements
The ConvUtils unit declares a general-purpose Convert function that you can use to
convert a measurement from one set of units to another. You can perform
conversions between compatible units of measurement such as feet and inches or
days and weeks. Units that measure the same types of things are said to be in the
same conversion family. The units you’re converting must be in the same conversion
family. For information on doing conversions, see “Performing conversions” on
page 5-33 and refer to Convert in the online Help.
The StdConvs unit defines several conversion families and measurement units
within each family. In addition, you can create customized conversion families and
associated units using the RegisterConversionType and RegisterConversionFamily
functions. For information on extending conversion and conversion units, see
“Adding new measurement types” on page 5-34 and refer to Convert in the online
Help.
Performing conversions
You can use the Convert function to perform both simple and complex conversions. It
includes a simple syntax and a second syntax for performing conversions between
complex measurement types.
The StdConvs unit defines several families of TConvType values. See Conversion
family variables in the online Help for a list of the predefined families of
measurement units and the measurement units in each family.
Declare variables
First, you need to declare variables for the identifiers. The identifiers are used in the
new LongTime conversion family, and the units of measurement that are its
members:
var
cbLongTime: TConvFamily;
ltMonths: TConvType;
ltYears: TConvType;
ltDecades: TConvType;
ltCenturies: TConvType;
ltMillennia: TConvType;
Declare variables
First, declare variables for the identifiers. The identifiers are used in the cbTemperature
conversion family, and the units of measurement are its members:
var
cbTemperature: TConvFamily;
tuCelsius: TConvType;
tuKelvin: TConvType;
tuFahrenheit: TConvType;
Note The units of measurement listed here are a subset of the temperature units actually
registered in the StdConvs unit.
The problem is, this approach requires extra parameters on the conversion function,
which means you can’t simply register the same function with every European
currency. In order to avoid having to write two new conversion functions for every
European currency, you can make use of the same two functions by making them the
members of a class.
Declare variables
Now that you have a conversion class, begin as with any other conversion family, by
declaring identifiers:
var
euEUR: TConvType; { EU euro }
euBEF: TConvType; { Belgian francs }
euDEM: TConvType; { German marks }
euGRD: TConvType; { Greek drachmas }
euESP: TConvType; { Spanish pesetas }
euFFR: TConvType; { French francs }
euIEP: TConvType; { Irish pounds }
euITL: TConvType; { Italian lire }
euLUF: TConvType; { Luxembourg francs }
euNLG: TConvType; { Dutch guilders }
euATS: TConvType; { Austrian schillings }
euPTE: TConvType; { Portuguese escudos }
euFIM: TConvType; { Finnish marks }
cbEuro: TConvFamily;
If your new custom Variant type needs more than 14 bytes to store its data, you can
define a new record type that includes a pointer or object instance. For example, the
VarCmplx unit uses an instance of the class TComplexData to represent the data in a
complex-valued variant. It therefore defines a record type the same size as TVarData
that includes a reference to a TComplexData object:
TComplexVarData = packed record
VType: TVarType;
Reserved1, Reserved2, Reserved3: Word;
VComplex: TComplexData;
Reserved4: LongInt;
end;
Object references are actually pointers (two Words), so this type is the same size as
the TVarData record. As before, a complex custom variant (or its TVarData record),
can be cast to TComplexVarData, and the custom variant type works with the
TVarData record as if it were a TComplexVarData type.
Enabling casting
One of the most important features of the custom variant type for you to implement
is typecasting. The flexibility of variants arises, in part, from their implicit typecasts.
There are two methods for you to implement that enable the custom Variant type to
perform typecasts: Cast, which converts another variant type to your custom variant,
and CastTo, which converts your custom Variant type to another type of Variant.
When implementing either of these methods, it is relatively easy to perform the
logical conversions from the built-in variant types. You must consider, however, the
possibility that the variant to or from which you are casting may be another custom
Variant type. To handle this situation, you can try casting to one of the built-in
Variant types as an intermediate step.
For example, the following Cast method, from the TComplexVariantType class uses the
type Double as an intermediate type:
procedure TComplexVariantType.Cast(var Dest: TVarData; const Source: TVarData);
var
LSource, LTemp: TVarData;
begin
VarDataInit(LSource);
try
VarDataCopyNoInd(LSource, Source);
if VarDataIsStr(LSource) then
TComplexVarData(Dest).VComplex := TComplexData.Create(VarDataToStr(LSource))
else
begin
VarDataInit(LTemp);
try
VarDataCastTo(LTemp, LSource, varDouble);
TComplexVarData(Dest).VComplex := TComplexData.Create(LTemp.VDouble, 0);
finally
VarDataClear(LTemp);
end;
end;
Dest.VType := VarType;
finally
VarDataClear(LSource);
end;
end;
In addition to the use of Double as an intermediate Variant type, there are a few
things to note in this implementation:
• The last step of this method sets the VType member of the returned TVarData
record. This member gives the Variant type code. It is set to the VarType property
of TComplexVariantType, which is the Variant type code assigned to the custom
variant.
• The custom variant’s data (Dest) is typecast from TVarData to the record type that
is actually used to store its data (TComplexVarData). This makes the data easier to
work with.
• The method makes a local copy of the source variant rather than working directly
with its data. This prevents side effects that may affect the source data.
When casting from a complex variant to another type, the CastTo method also uses an
intermediate type of Double (for any destination type other than a string):
procedure TComplexVariantType.CastTo(var Dest: TVarData; const Source: TVarData;
const AVarType: TVarType);
var
LTemp: TVarData;
begin
if Source.VType = VarType then
case AVarType of
varOleStr:
VarDataFromOleStr(Dest, TComplexVarData(Source).VComplex.AsString);
varString:
VarDataFromStr(Dest, TComplexVarData(Source).VComplex.AsString);
else
VarDataInit(LTemp);
try
LTemp.VType := varDouble;
LTemp.VDouble := TComplexVarData(LTemp).VComplex.Real;
VarDataCastTo(Dest, LTemp, AVarType);
finally
VarDataClear(LTemp);
end;
end
else
RaiseCastError;
end;
Note that the CastTo method includes a case where the source variant data does not
have a type code that matches the VarType property. This case only occurs for empty
(unassigned) source variants.
If the custom type does not support the concept of “greater than” or “less than,” only
“equal” or “not equal,” however, it is difficult to implement the Compare method,
because Compare must return crLessThan, crEqual, or crGreaterThan. When the only
valid response is “not equal,” it is impossible to know whether to return crLessThan
or crGreaterThan. Thus, for types that do not support the concept of ordering, you can
override the CompareOp method instead.
CompareOp has three parameters: the value of the left-hand operand, the value of the
right-hand operand, and the comparison operator. Implement this method to
perform the operation and return a boolean that indicates whether the comparison is
True. You can then call the RaiseInvalidOp method when the comparison makes no
sense.
For example, the following CompareOp method comes from the TComplexVariantType
object in the VarCmplx unit. It supports only a test of equality or inequality:
function TComplexVariantType.CompareOp(const Left, Right: TVarData;
const Operator: Integer): Boolean;
begin
Result := False;
if (Left.VType = VarType) and (Right.VType = VarType) then
case Operator of
opCmpEQ:
Result := TComplexVarData(Left).VComplex.Equal(TComplexVarData(Right).VComplex);
opCmpNE:
Result := not TComplexVarData(Left).VComplex.Equal(TComplexVarData(Right).VComplex);
else
RaiseInvalidOp;
end
else
RaiseInvalidOp;
end;
Note that the types of operands that both these implementations support are very
limited. As with binary operations, you can use the RightPromotion and LeftPromotion
methods to limit the cases you must consider by forcing a cast before Compare or
CompareOp is called.
else
RaiseInvalidOp;
end
else
RaiseInvalidOp;
end;
Note that for the logical not operator, which does not make sense for complex values,
this method calls RaiseInvalidOp to cause a runtime error.
You will also need to implement the IsClear method. This way, you can detect any
invalid values or special values that represent “blank” data:
function TComplexVariantType.IsClear(const V: TVarData): Boolean;
begin
Result := (TComplexVarData(V).VComplex = nil) or
TComplexVarData(V).VComplex.IsZero;
end;
Two other standard utilities provided for most custom variants check whether a
given variant is of the custom type and cast an arbitrary variant to the new custom
type. Here is the implementation of those utilities from the VarCmplx unit:
function VarIsComplex(const AValue: Variant): Boolean;
begin
Result := (TVarData(AValue).VType and varTypeMask) = VarComplex;
end;
function VarAsComplex(const AValue: Variant): Variant;
begin
if not VarIsComplex(AValue) then
VarCast(Result, AValue, VarComplex)
else
Result := AValue;
end;
Note that these use standard features of all variants: the VType member of the
TVarData record and the VarCast function, which works because of the methods
implemented in the TCustomVariantType descendant for casting data.
In addition to the standard utilities mentioned above, you can write any number of
utilities specific to your new custom variant type. For example, the VarCmplx unit
defines a large number of functions that implement mathematical operations on
complex-valued variants.
Using TInvokeableVariantType
To provide support for properties and methods, the class you create to enable the
new custom variant type should descend from TInvokeableVariantType instead of
directly from TCustomVariantType.
TInvokeableVariantType defines four methods:
• DoFunction
• DoProcedure
• GetProperty
• SetProperty
that you can implement to support properties and methods on your custom variant
type.
For example, the VarConv unit uses TInvokeableVariantType as the base class for
TConvertVariantType so that the resulting custom variants can support properties.
The following example shows the property getter for these properties:
function TConvertVariantType.GetProperty(var Dest: TVarData;
const V: TVarData; const Name: String): Boolean;
var
LType: TConvType;
begin
// supports...
// 'Value'
// 'Type'
// 'TypeName'
// 'Family'
// 'FamilyName'
// 'As[Type]'
Result := True;
if Name = 'VALUE' then
Variant(Dest) := TConvertVarData(V).VValue
else if Name = 'TYPE' then
Variant(Dest) := TConvertVarData(V).VConvType
else if Name = 'TYPENAME' then
Variant(Dest) := ConvTypeToDescription(TConvertVarData(V).VConvType)
else if Name = 'FAMILY' then
Variant(Dest) := ConvTypeToFamily(TConvertVarData(V).VConvType)
else if Name = 'FAMILYNAME' then
Variant(Dest) := ConvFamilyToDescription(ConvTypeToFamily(TConvertVarData(V).VConvType))
else if System.Copy(Name, 1, 2) = 'AS' then
begin
if DescriptionToConvType(ConvTypeToFamily(TConvertVarData(V).VConvType),
System.Copy(Name, 3, MaxInt), LType) then
VarConvertCreateInto(Variant(Dest), Convert(TConvertVarData(V).VValue,
TConvertVarData(V).VConvType, LType), LType)
else
Result := False;
end
else
Result := False;
end;
The GetProperty method checks the Name parameter to determine what property is
wanted. It then retrieves the information from the TVarData record of the Variant (V),
and returns it as a Variant (Dest). Note that this method supports properties whose
names are dynamically generated at runtime (As[Type]), based on the current value
of the custom variant.
Similarly, the SetProperty, DoFunction, and DoProcedure methods are sufficiently
generic that you can dynamically generate method names, or respond to variable
numbers and types of parameters.
Using TPublishableVariantType
If the custom variant type stores its data using an object instance, then there is an
easier way to implement properties, as long as they are also properties of the object
that represents the variant’s data. If you use TPublishableVariantType as the base class
for your custom variant type, then you need only implement the GetInstance method,
and all the published properties of the object that represents the variant’s data are
automatically implemented for the custom variants.
For example, as was seen in “Storing a custom variant type’s data” on page 5-41,
TComplexVariantType stores the data of a complex-valued variant using an instance of
TComplexData. TComplexData has a number of published properties (Real, Imaginary,
Radius, Theta, and FixedTheta), that provide information about the complex value.
TComplexVariantType descends from TPublishableVariantType, and implements the
GetInstance method to return the TComplexData object (in TypInfo.pas) that is stored
in a complex-valued variant’s TVarData record:
function TComplexVariantType.GetInstance(const V: TVarData): TObject;
begin
Result := TComplexVarData(V).VComplex;
end;
TPublishableVariantType does the rest. It overrides the GetProperty and SetProperty
methods to use the runtime type information (RTTI) of the TComplexData object for
getting and setting property values.
Note For TPublishableVariantType to work, the object that holds the custom variant’s data
must be compiled with RTTI. This means it must be compiled using the {$M+}
compiler directive, or descend from TPersistent.
Most Windows messages (VCL applications) or system events (CLX applications) are
handled by Delphi components. When you want to respond to a message or system
event, you only need to provide an event handler.
Chapter 9, “Developing the application user interface,” provides details on using
forms such as creating modal forms dynamically, passing parameters to forms, and
retrieving data from forms.
Calling methods
Methods are called just like ordinary procedures and functions. For example, visual
controls have a Repaint method that refreshes the control’s image on the screen. You
could call the Repaint method in a draw-grid object like this:
DrawGrid1.Repaint;
As with properties, the scope of a method name determines the need for qualifiers. If
you want, for example, to repaint a form within an event handler of one of the form’s
child controls, you don’t have to prepend the name of the form to the method call:
procedure TForm1.Button1Click(Sender: TObject);
begin
Repaint;
end;
For more information about scope, see “Scope and qualifiers” on page 4-5.
You can add, remove, and rearrange components on the palette, and you can create
component templates and frames that group several components.
For more information about the components on the Component palette, see online
Help. You can press F1 on the Component palette, on the component itself when it is
selected, after it has been dropped onto a form, or anywhere on its name in the Code
editor. If a tab of the Component palette is selected, the Help gives a general
description for all of the components on that tab. Some of the components on the
ActiveX, Servers, and Samples pages, however, are provided as examples only and
are not documented.
For more information on the differences between VCL and CLX applications, see
Chapter 15, “Developing cross-platform applications.”
To start dragging a control manually, call the control’s BeginDrag method. BeginDrag
takes a Boolean parameter called Immediate and, optionally, an integer parameter
called Threshold. If you pass True for Immediate, dragging begins immediately. If you
pass False, dragging does not begin until the user moves the mouse the number of
pixels specified by Threshold. Calling
BeginDrag (False);
allows the control to accept mouse clicks without beginning a drag operation.
You can place other conditions on whether to begin dragging, such as checking
which mouse button the user pressed, by testing the parameters of the mouse-down
event before calling BeginDrag. The following code, for example, handles a mouse-
down event in a file list box by initiating a drag operation only if the left mouse
button was pressed.
procedure TFMForm.FileListBox1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then { drag only if left button pressed }
with Sender as TFileListBox do { treat Sender as TFileListBox }
begin
if ItemAtPos(Point(X, Y), True) >= 0 then { is there an item here? }
BeginDrag(False); { if so, drag it }
end;
end;
Dropping items
If a control indicates that it can accept a dragged item, it needs to handle the item
should it be dropped. To handle dropped items, attach an event handler to the
OnDragDrop event of the control accepting the drop. Like the drag-over event, the
drag-and-drop event indicates the source of the dragged item and the coordinates of
the mouse cursor over the accepting control. The latter parameter allows you to
monitor the path an item takes while being dragged; you might, for example, want to
use this information to change the color of components if an item is dropped.
In the following VCL example, a directory tree view, accepting items dragged from a
file list box, responds by moving files to the directory on which they are dropped.
procedure TFMForm.DirectoryOutline1DragDrop(Sender, Source: TObject; X,
Y: Integer);
begin
if Source is TFileListBox then
with DirectoryOutline1 do
ConfirmChange('Move', FileListBox1.FileName, Items[GetItem(X, Y)].FullPath);
end;
Normally, the source parameter of the drag-over and drag-and-drop events is the
control that starts the drag operation. If different kinds of control can start an
operation involving the same kind of data, the source needs to support each kind of
control. When you use a descendant of TDragObject, however, the source is the drag
object itself; if each control creates the same kind of drag object in its OnStartDrag
event, the target needs to handle only one kind of object. The drag-over and drag-
and-drop events can tell if the source is a drag object, as opposed to the control, by
calling the IsDragObject function.
TDragObjectEx descendants (VCL only) are freed automatically whereas descendants
of TDragObject are not. If you have TDragObject descendants that you are not
explicitly freeing, you can change them so they descend from TDragObjectEx instead
to prevent memory loss.
Drag objects let you drag items between a form implemented in the application’s
main executable file and a form implemented using a DLL, or between forms that are
implemented using different DLLs.
OnDockOver occurs on the docking site when the user drags a dockable child over the
control. It is analogous to the OnDragOver event in a drag-and-drop operation. Use it
to signal that the child can be released for docking, by setting the Accept parameter. If
the dockable control is rejected by the OnGetSiteInfo event handler (perhaps because
it is the wrong type of control), OnDockOver does not occur.
property OnDockDrop: TDockDropEvent;
TDockDropEvent = procedure(Sender: TObject; Source: TDragDockObject; X, Y: Integer) of
object;
OnDockDrop occurs on the docking site when the user releases the dockable child
over the control. It is analogous to the OnDragDrop event in a normal drag-and-drop
operation. Use this event to perform any necessary accommodations to accepting the
control as a child control. Access to the child control can be obtained using the
Control property of the TDockObject specified by the Source parameter.
Selecting text
For text in an edit control, before you can send any text to the clipboard, that text
must be selected. Highlighting of selected text is built into the edit components.
When the user selects text, it appears highlighted.
Table 7.1 lists properties commonly used to handle selected text.
For example, the following OnFind event handler searches a Memo component for
the text specified in the FindText property of a find dialog component. If found, the
first occurrence of the text in Memo1 is selected.
procedure TForm1.FindDialog1Find(Sender: TObject);
var
I, J, PosReturn, SkipChars: Integer;
begin
for I := 0 to Memo1.Lines.Count do
begin
PosReturn := Pos(FindDialog1.FindText,Memo1.Lines[I]);
if PosReturn <> 0 then {found!}
begin
Skipchars := 0;
for J := 0 to I - 1 do
Skipchars := Skipchars + Length(Memo1.Lines[J]);
SkipChars := SkipChars + (I*2);
SkipChars := SkipChars + PosReturn - 1;
Memo1.SetFocus;
Memo1.SelStart := SkipChars;
Memo1.SelLength := Length(FindDialog1.FindText);
Break;
end;
end;
end;
To select the entire contents of a rich edit or memo control, call the RichEdit1 control’s
SelectAll method.
For example:
procedure TMainForm.SelectAll(Sender: TObject);
begin
RichEdit1.SelectAll; { select all text in RichEdit }
end;
A form’s PopupMenu property specifies what pop-up menu to display when a user
right-clicks any item on the form. Individual controls also have PopupMenu
properties that can override the form’s property, allowing customized menus for
particular controls.
To add a pop-up menu to a form:
1 Place a pop-up menu component on the form.
2 Use the Menu Designer to define the items for the pop-up menu.
3 Set the PopupMenu property of the form or control that displays the menu to the
name of the pop-up menu component.
4 Attach handlers to the OnClick events of the pop-up menu items.
The following example shows how you might want to add images to a string list.
This is part of a file manager application where, along with a letter for each valid
drive, it adds a bitmap indicating each drive’s type. The OnCreate event handler looks
like this:
procedure TFMForm.FormCreate(Sender: TObject);
var
Drive: Char;
AddedIndex: Integer;
begin
for Drive := 'A' to 'Z' do { iterate through all possible drives }
begin
case GetDriveType(Drive + ':/') of { positive values mean valid drives }
DRIVE_REMOVABLE: { add a tab }
AddedIndex := DriveTabSet.Tabs.AddObject(Drive, Floppy.Picture.Graphic);
DRIVE_FIXED: { add a tab }
AddedIndex := DriveTabSet.Tabs.AddObject(Drive, Fixed.Picture.Graphic);
DRIVE_REMOTE: { add a tab }
AddedIndex := DriveTabSet.Tabs.AddObject(Drive, Network.Picture.Graphic);
end;
if UpCase(Drive) = UpCase(DirectoryOutline.Drive) then { current drive? }
DriveTabSet.TabIndex := AddedIndex; { then make that current tab }
end;
end;
Creating applications
The most common types of applications you can design and build are:
• GUI applications
• Console applications
• Service applications
• Packages and DLLs
GUI applications generally have an easy-to-use interface. Console applications run
from a console window. Service applications are run as Windows services. These
types of applications compile as executables with start-up code.
You can create other types of projects such as packages and DLLs that result in
creating packages or dynamically linkable libraries. These applications produce
executable code without start-up code. Refer to “Creating packages and DLLs” on
page 8-11.
GUI applications
A graphical user interface (GUI) application is one that is designed using graphical
features such as windows, menus, dialog boxes, and features that make the
application easy to use. When you compile a GUI application, an executable file with
start-up code is created. The executable usually provides the basic functionality of
your program, and simple programs often consist of only an executable file. You can
extend the application by calling DLLs, packages, and other support files from the
executable.
The IDE offers two application UI models:
• Single document interface (SDI)
• Multiple document interface (MDI)
In addition to the implementation model of your applications, the design-time
behavior of your project and the runtime behavior of your application can be
manipulated by setting project options in the IDE.
SDI applications
To create a new SDI application:
1 Choose File|New|Other to bring up the New Items dialog.
2 Click on the Projects page and double-click SDI Application.
3 Click OK.
By default, the FormStyle property of your Form object is set to fsNormal, so that the
IDE assumes that all new applications are SDI applications.
MDI applications
To create a new MDI application using a wizard:
1 Choose File|New|Other to bring up the New Items dialog.
2 Click on the Projects page and double-click MDI Application.
3 Click OK.
MDI applications require more planning and are somewhat more complex to design
than SDI applications. MDI applications spawn child windows that reside within the
client window; the main form contains child forms. Set the FormStyle property of the
TForm object to specify whether a form is a child (fsMDIChild) or main form
(fsMDIForm). It is a good idea to define a base class for your child forms and derive
each child form from this class, to avoid having to reset the child form’s properties.
MDI applications often include a Window pop-up on the main menu that has items
such as Cascade and Tile for viewing multiple windows in various styles. When a
child window is minimized, its icon is located in the MDI parent form.
To create a new MDI application without using a wizard:
1 Create the main window form or MDI parent window. Set its FormStyle property
to fsMDIForm.
2 Create a menu for the main window that includes File|Open, File|Save, and
Window which has Cascade, Tile, and Arrange All items.
3 Create the MDI child forms and set their FormStyle properties to fsMDIChild.
Programming templates
Programming templates are commonly used skeleton structures that you can add to
your source code and then fill in. You can also use standard code templates such as
those for array, class, and function declarations, and many statements.
You can also write your own templates for coding structures that you often use. For
example, if you want to use a for loop in your code, you could insert the following
template:
for := to do
begin
end;
To insert a code template in the Code editor, press Ctrl-j and select the template you
want to use. You can also add your own templates to this collection. To add a
template:
1 Choose Tools|Editor Options.
2 Click the Code Insight tab.
3 In the Templates section, click Add.
4 Type a name for the template after Shortcut name, enter a brief description of the
new template, and click OK.
5 Add the template code to the Code text box.
6 Click OK.
Console applications
Console applications are 32-bit programs that run without a graphical interface, in a
console window. These applications typically don’t require much user input and
perform a limited set of functions. Any application that contains:
{$APPTYPE CONSOLE}
in the code opens a console window of its own.
To create a new console application, choose File|New|Other and double-click
Console Application from the New Items dialog box.
The IDE then creates a project file for this type of source file and displays the Code
editor.
Console applications should make sure that no exceptions escape from the program
scope. Otherwise, when the program terminates, the Windows operating system
displays a modal dialog with exception information. For example, your application
should include exception handling such as shown in the following code:
program ConsoleExceptionHandling;
{$APPTYPE CONSOLE}
uses
SysUtils;
procedure ExecuteProgram;
begin
//Program does something
raise Exception.Create('Unforeseen exception');
end;
begin
try
ExecuteProgram;
except
//Handle error condition
WriteIn(‘Program terminated due to an exception’);
//Set ExitCode <> 0 to flag error condition (by convention)
ExitCode := 1;
end;
end.
Users can terminate console applications in one of the following ways:
• Click the Close (X) button.
• Press Ctrl+C.
• Press Ctrl+Break.
• Log off.
Depending on which way the user chooses, the application is terminated forcefully,
the process is not shut down cleanly, and the finalization section isn’t run. Use the
Windows API SetConsoleCtrlHandler function for options for handling these user
termination requests.
Service applications
Service applications take requests from client applications, process those requests,
and return information to the client applications. They typically run in the
background, without much user input. A Web, FTP, or e-mail server is an example of
a service application.
To create an application that implements a Win32 service:
1 Choose File|New|Other, and double-click Service Application in the New Items
dialog box. This adds a global variable named Application to your project, which is
of type TServiceApplication.
2 A Service window appears that corresponds to a service (TService). Implement the
service by setting its properties and event handlers in the Object Inspector.
3 You can add additional services to your service application by choosing File|
New|Other, and double-click Service in the New Items dialog box. Do not add
services to an application that is not a service application. While a TService object
can be added, the application will not generate the requisite events or make the
appropriate Windows calls on behalf of the service.
4 Once your service application is built, you can install its services with the Service
Control Manager (SCM). Other applications can then launch your services by
sending requests to the SCM.
To install your application’s services, run it using the /INSTALL option. The
application installs its services and exits, giving a confirmation message if the
services are successfully installed. You can suppress the confirmation message by
running the service application using the /SILENT option.
To uninstall the services, run it from the command line using the /UNINSTALL
option. (You can also use the /SILENT option to suppress the confirmation message
when uninstalling).
Example This service has a TServerSocket whose port is set to 80. This is the default port for
Web browsers to make requests to Web servers and for Web servers to make
responses to Web browsers. This particular example produces a text document in the
C:\Temp directory called WebLogxxx.log (where xxx is the ThreadID). There should
be only one server listening on any given port, so if you have a Web server, you
should make sure that it is not listening (the service is stopped).
To see the results: open up a Web browser on the local machine and for the address,
type 'localhost' (with no quotes). The browser will time out eventually, but you
should now have a file called Weblogxxx.log in the C:\Temp directory.
1 To create the example, choose File|New|Other and select Service Application
from the New Items dialog box. The Service1 window appears.
2 From the Internet page of the Component palette, add a ServerSocket component
to the service window (Service1).
3 Add a private data member of type TMemoryStream to the TService1 class. The
interface section of your unit should now look like this:
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
ScktComp;
type
TService1 = class(TService)
ServerSocket1: TServerSocket;
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure Service1Execute(Sender: TService);
private
{ Private declarations }
Stream: TMemoryStream; // Add this line here
public
function GetServiceController: PServiceController; override;
{ Public declarations }
end;
var
Service1: TService1;
4 Select ServerSocket1, the component you added in step 1. In the Object Inspector,
double-click the OnClientRead event and add the following event handler:
procedure TService1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
Buffer: PChar;
begin
Buffer := nil;
while Socket.ReceiveLength > 0 do begin
Buffer := AllocMem(Socket.ReceiveLength);
try
Socket.ReceiveBuf(Buffer^, Socket.ReceiveLength);
Stream.Write(Buffer^, StrLen(Buffer));
finally
FreeMem(Buffer);
end;
Stream.Seek(0, soFromBeginning);
Stream.SaveToFile('c:\Temp\Weblog' + IntToStr(ServiceThread.ThreadID) + '.log');
end;
end;
5 Finally, select Service1 by clicking in the window’s client area (but not on the
ServiceSocket). In the Object Inspector, double click the OnExecute event and add
the following event handler:
procedure TService1.Service1Execute(Sender: TService);
begin
Stream := TMemoryStream.Create;
try
ServerSocket1.Port := 80; // WWW port
ServerSocket1.Active := True;
while not Terminated do begin
ServiceThread.ProcessRequests(True);
end;
ServerSocket1.Active := False;
finally
Stream.Free;
end;
end;
When writing your service application, you should be aware of:
• Service threads
• Service name properties
• Debugging service applications
Note Service applications are not available for cross-platform applications.
Service threads
Each service has its own thread (TServiceThread), so if your service application
implements more than one service you must ensure that the implementation of your
services is thread-safe. TServiceThread is designed so that you can implement the
service in the TService OnExecute event handler. The service thread has its own
Execute method which contains a loop that calls the service’s OnStart and OnExecute
handlers before processing new requests.
Because service requests can take a long time to process and the service application
can receive simultaneous requests from more than one client, it is more efficient to
spawn a new thread (derived from TThread, not TServiceThread) for each request and
move the implementation of that service to the new thread’s Execute method. This
allows the service thread’s Execute loop to process new requests continually without
having to wait for the service’s OnExecute handler to finish. The following example
demonstrates.
Example This service beeps every 500 milliseconds from within the standard thread. It handles
pausing, continuing, and stopping of the thread when the service is told to pause,
continue, or stop.
1 Choose File|New|Other and double-click Service Application in the New Items
dialog. The Service1 window appears.
2 In the interface section of your unit, declare a new descendant of TThread named
TSparkyThread. This is the thread that does the work for your service. The
declaration should appear as follows:
TSparkyThread = class(TThread)
public
procedure Execute; override;
end;
3 In the implementation section of your unit, create a global variable for a
TSparkyThread instance:
var
SparkyThread: TSparkyThread;
4 In the implementation section for the TSparkyThread Execute method (the thread
function), add the following code:
procedure TSparkyThread.Execute;
begin
while not Terminated do
begin
Beep;
Sleep(500);
end;
end;
5 Select the Service window (Service1), and double-click the OnStart event in the
Object Inspector. Add the following OnStart event handler:
procedure TService1.Service1Start(Sender: TService; var Started: Boolean);
begin
SparkyThread := TSparkyThread.Create(False);
Started := True;
end;
6 Double-click the OnContinue event in the Object Inspector. Add the following
OnContinue event handler:
procedure TService1.Service1Continue(Sender: TService; var Continued: Boolean);
begin
SparkyThread.Resume;
Continued := True;
end;
7 Double-click the OnPause event in the Object Inspector. Add the following
OnPause event handler:
procedure TService1.Service1Pause(Sender: TService; var Paused: Boolean);
begin
SparkyThread.Suspend;
Paused := True;
end;
8 Finally, double-click the OnStop event in the Object Inspector and add the
following OnStop event handler:
procedure TService1.Service1Stop(Sender: TService; var Stopped: Boolean);
begin
SparkyThread.Terminate;
Stopped := True;
end;
When developing server applications, choosing to spawn a new thread depends on
the nature of the service being provided, the anticipated number of connections, and
the expected number of processors on the computer running the service.
TDependency properties
The TDependency DisplayName is both a display name and the actual name of the
service. It is nearly always the same as the TDependency Name property.
Packages are special DLLs used by Delphi applications, the IDE, or both. There are
two kinds of packages: runtime packages and design-time packages. Runtime
packages provide functionality to a program while that program is running. Design-
time packages extend the functionality of the IDE.
For more information on packages, see Chapter 16, “Working with packages and
components.”
You cannot pass Delphi runtime type information (RTTI) across DLLs or from a DLL
to an executable. If you pass an object from one DLL to another DLL or an executable,
you will not be able to use the is or as operators with the passed object. This is
because the is and as operators need to compare RTTI. If you need to pass objects
from a library, use packages instead, as these can share RTTI. Similarly, you should
use packages instead of DLLs in Web Services because they are rely on Delphi RTTI.
When designing a database application, you must decide which data access
mechanism to use. Each data access mechanism differs in its range of functional
support, the ease of deployment, and the availability of drivers to support different
database servers.
See Part II, “Developing database applications,” for details on how to create both
database client applications and application servers. See “Deploying database
applications” on page 18-6 for deployment information.
Note Not all editions of Delphi include database support.
CGI applications use more system resources on the server, so complex applications
are better created as ISAPI, NSAPI, or Apache DLL applications. When writing cross-
platform applications, you should select CGI stand-alone or Apache Shared Module
(DLL) for Web server development. These are also the same options you see when
creating WebSnap and Web Service applications.
For more information on building Web server applications, see Chapter 33, “Creating
Internet server applications.”
You can also right-click a module to display a context menu for it. The following
table summarizes the context menu options for a data module.
For more information about data modules, see the online Help.
You can define the data source before you drag a field to the form by adding a
TDataSource component to the data module. Set the data source’s DataSet property to
ClientDataSet1. After you drag a field to the form, the edit box appears with its
TDataSource property already set to DataSource1. This method keeps your data access
model cleaner.
Copying an item
Choose Copy to make an exact copy of the selected item and add the copy to your
project. Future changes made to the item in the Object Repository will not be
reflected in your copy, and alterations made to your copy will not affect the original
Object Repository item.
Copy is the only option available for project templates.
Inheriting an item
Choose Inherit to derive a new class from the selected item in the Object Repository
and add the new class to your project. When you recompile your project, any changes
that have been made to the item in the Object Repository will be reflected in your
derived class, in addition to changes you make to the item in your project. Changes
made to your derived class do not affect the shared item in the Object Repository.
Inherit is available for forms, dialog boxes, and data modules, but not for project
templates. It is the only option available for reusing items within the same project.
Using an item
Choose Use when you want the selected item itself to become part of your project.
Changes made to the item in your project will appear in all other projects that have
added the item with the Inherit or Use option. Select this option with caution.
The Use option is available for forms, dialog boxes, and data modules.
Implementing ICustomHelpViewer
The ICustomHelpViewer interface contains three types of methods: methods used to
communicate system-level information (for example, information not related to a
particular Help request) with the Help Manager; methods related to showing Help
based upon a keyword provided by the Help Manager; and methods for displaying a
table of contents.
is called by the Help Manager if more than one viewer can provide Help on a topic.
The viewer is expected to return a TStringList, which is freed by the Help Manager.
The strings in the returned list should map to the pages available for that keyword,
but the characteristics of that mapping can be determined by the viewer. In the case
of the WinHelp viewer on Windows and the HyperHelp viewer on Linux, the string
list always contains exactly one entry. HyperHelp provides its own indexing, and
duplicating that elsewhere would be pointless duplication. In the case of the Man
page viewer (Linux), the string list consists of multiple strings, one for each section of
the manual which contains a page for that keyword.
ICustomHelpViewer.ShowHelp(const HelpString: String)
is called by the Help Manager if it needs the Help viewer to display help for a
particular keyword. This is the last method call in the operation; it is guaranteed to
never be called unless the UnderstandsKeyword method is invoked first.
Implementing IExtendedHelpViewer
ICustomHelpViewer only provides direct support for keyword-based Help. Some
Help systems (especially WinHelp) work by associating numbers (known as context
IDs) with keywords in a fashion which is internal to the Help system and therefore
not visible to the application. Such systems require that the application support
context-based Help in which the application invokes the Help system with that
context, rather than with a string, and the Help system translates the number itself.
Implementing IHelpSelector
IHelpSelector is a companion to ICustomHelpViewer. When more than one registered
viewer claims to provide support for a given keyword, context, or topic, or provides
a table of contents, the Help Manager must choose between them. In the case of
contexts or topics, the Help Manager always selects the first Help viewer that claims
to provide support. In the case of keywords or the table of context, the Help Manager
will, by default, select the first Help viewer. This behavior can be overridden by an
application.
To override the decision of the Help Manager in such cases, an application must
register a class that provides an implementation of the IHelpSelector interface.
IHelpSelector exports two functions: SelectKeyword, and TableOfContents. Both take as
arguments a TStrings containing, one by one, either the possible keyword matches or
the names of the viewers claiming to provide a table of contents. The implementor is
required to return the index (in the TStringList) that represents the selected string; the
TStringList is then freed by the Help Manager.
Note The Help Manager may get confused if the strings are rearranged; it is recommended
that implementors of IHelpSelector refrain from doing this. The Help system only
supports one HelpSelector; when new selectors are registered, any previously
existing selectors are disconnected.
All four functions take the data passed to them and forward it through a data
member of TApplication, which represents the Help system. That data member is
directly accessible through the property HelpSystem.
Using IHelpSystem
IHelpSystem allows an application to do three things:
• Provides path information to the Help Manager.
• Provides a new Help selector.
• Asks the Help Manager to display Help.
Providing path information is important because the Help Manager is platform-
independent and Help system-independent and so is not able to ascertain the
location of Help files. If an application expects Help to be provided by an external
Help system that is not able to ascertain file locations itself, it must provide this
information through the IHelpSystem’s ProvideHelpPath method, which allows the
information to become available through the IHelpManager’s GetHelpPath method.
(This information propagates outward only if the Help viewer asks for it.)
Assigning a Help selector allows the Help Manager to delegate decision-making in
cases where multiple external Help systems can provide Help for the same keyword.
For more information, see the section “Implementing IHelpSelector” on page 8-29.
IHelpSystem exports four procedures and one function to request the Help Manager
to display Help:
• ShowHelp
• ShowContextHelp
• ShowTopicHelp
• ShowTableOfContents
• Hook
Hook is intended entirely for WinHelp compatibility and should not be used in a CLX
application; it allows processing of WM_HELP messages that cannot be mapped
directly onto requests for keyword-based, context-based, or topic-based Help. The
other methods each take two arguments: the keyword, context ID, or topic for which
help is being requested, and the Help file in which it is expected that help can be
found.
In general, unless you are asking for topic-based help, it is equally effective and more
clear to pass help requests to the Help Manager through the InvokeHelp method of
your control.
Setting up forms
TForm is the key class for creating GUI applications. When you open a default project
or create a new project, a form appears on which you can begin your UI design.
Adding forms
To add a form to your project, select File|New|Form. You can see all your project’s
forms and their associated units listed in the Project Manager (View|Project
Manager) and you can display a list of the forms alone by choosing View|Forms.
Linking forms
Adding a form to a project adds a reference to it in the project file, but not to any
other units in the project. Before you can write code that references the new form,
you need to add a reference to it in the referencing forms’ unit files. This is called form
linking.
A common reason to link forms is to provide access to the components in that form.
For example, you’ll often use form linking to enable a form that contains data-aware
components to connect to the data-access components in a data module.
To link a form to another form,
1 Select the form that needs to refer to another.
2 Choose File|Use Unit.
3 Select the name of the form unit for the form to be referenced.
4 Choose OK.
Linking a form to another just means that the uses clauses of one form unit contains a
reference to the other’s form unit, meaning that the linked form and its components
are now in scope for the linking form.
Managing layout
At its simplest, you control the layout of your user interface by where you place
controls in your forms. The placement choices you make are reflected in the control’s
Top, Left, Width, and Height properties. You can change these values at runtime to
change the position and size of the controls in your forms.
Controls have a number of other properties, however, that allow them to
automatically adjust to their contents or containers. This allows you to lay out your
forms so that the pieces fit together into a unified whole.
Two properties affect how a control is positioned and sized in relation to its parent.
The Align property lets you force a control to fit perfectly within its parent along a
specific edge or filling up the entire client area after any other controls have been
aligned. When the parent is resized, the controls aligned to it are automatically
resized and remain positioned so that they fit against a particular edge.
If you want to keep a control positioned relative to a particular edge of its parent, but
don’t want it to necessarily touch that edge or be resized so that it always runs along
the entire edge, you can use the Anchors property.
If you want to ensure that a control does not grow too big or too small, you can use
the Constraints property. Constraints lets you specify the control’s maximum height,
minimum height, maximum width, and minimum width. Set these to limit the size
(in pixels) of the control’s height and width. For example, by setting the MinWidth
and MinHeight of the constraints on a container object, you can ensure that child
objects are always visible.
The value of Constraints propagates through the parent/child hierarchy so that an
object’s size can be constrained because it contains aligned children that have size
constraints. Constraints can also prevent a control from being scaled in a particular
dimension when its ChangeScale method is called.
TControl introduces a protected event, OnConstrainedResize, of type
TConstrainedResizeEvent:
TConstrainedResizeEvent = procedure(Sender: TObject; var MinWidth, MinHeight, MaxWidth,
MaxHeight: Integer) of object;
This event allows you to override the size constraints when an attempt is made to
resize the control. The values of the constraints are passed as var parameters which
can be changed inside the event handler. OnConstrainedResize is published for
container objects (TForm, TScrollBox, TControlBar, and TPanel). In addition,
component writers can use or publish this event for any descendant of TControl.
Controls that have contents that can change in size have an AutoSize property that
causes the control to adjust its size to its font or contained objects.
Using forms
When you create a form from the IDE, Delphi automatically creates the form in
memory by including code in the main entry point of your application function.
Usually, this is the desired behavior and you don’t have to do anything to change it.
That is, the main window persists through the duration of your program, so you
would likely not change the default behavior when creating the form for your main
window.
However, you may not want all your application’s forms in memory for the duration
of the program execution. That is, if you do not want all your application’s dialogs in
memory at once, you can create the dialogs dynamically when you want them to
appear.
Forms can be modal or modeless. Modal forms are forms with which the user must
interact before switching to another form (for example, a dialog box requiring user
input). Modeless forms are windows that are displayed until they are either obscured
by another window or until they are closed or minimized by the user.
private
public
constructor CreateWithButton(whichButton: Integer; Owner: TComponent);
end;
Here’s the manually coded constructor that passes the additional argument,
whichButton. This constructor uses the whichButton parameter to set the Caption
property of a Label control on the form.
constructor CreateWithButton(whichButton: Integer; Owner: TComponent);
begin
inherited Create(Owner);
case whichButton of
1: ResultsLabel.Caption := 'You picked the first button.';
2: ResultsLabel.Caption := 'You picked the second button.';
3: ResultsLabel.Caption := 'You picked the third button.';
end;
end;
When creating an instance of a form with multiple constructors, you can select the
constructor that best suits your purpose. For example, the following OnClick handler
for a button on a form calls creates an instance of TResultsForm that uses the extra
parameter:
procedure TMainForm.SecondButtonClick(Sender: TObject);
var
rf: TResultsForm;
begin
rf := TResultsForm.CreateWithButton(2, self);
rf.ShowModal;
rf.Free;
end;
CurrentColor each time a user selects a new color. The class declaration for the form is
as follows:
TColorForm = class(TForm)
ColorListBox:TListBox;
procedure ColorListBoxClick(Sender: TObject);
private
FColor:String;
public
property CurColor:String read FColor write FColor;
end;
The OnClick event handler for the listbox, ColorListBoxClick, sets the value of the
CurrentColor property each time a new item in the listbox is selected. The event
handler gets the string from the listbox containing the color name and assigns it to
CurrentColor. The CurrentColor property uses the setter function, SetColor, to store the
actual value for the property in the private data member FColor:
procedure TColorForm.ColorListBoxClick(Sender: TObject);
var
Index: Integer;
begin
Index := ColorListBox.ItemIndex;
if Index >= 0 then
CurrentColor := ColorListBox.Items[Index]
else
CurrentColor := '';
end;
Now suppose that another form within the application, called ResultsForm, needs to
find out which color is currently selected on ColorForm whenever a button (called
UpdateButton) on ResultsForm is clicked. The OnClick event handler for UpdateButton
might look like this:
procedure TResultForm.UpdateButtonClick(Sender: TObject);
var
MainColor: String;
begin
if Assigned(ColorForm) then
begin
MainColor := ColorForm.CurrentColor;
{do something with the string MainColor}
end;
end;
The event handler first verifies that ColorForm exists using the Assigned function. It
then gets the value of ColorForm’s CurrentColor property.
Alternatively, if ColorForm had a public function named GetColor, another form could
get the current color without using the CurrentColor property (for example, MainColor
:= ColorForm.GetColor;). In fact, there’s nothing to prevent another form from getting
the ColorForm’s currently selected color by checking the listbox selection directly:
with ColorForm.ColorListBox do
MainColor := Items[ItemIndex];
In the application, the user selects a color from the listbox and presses SelectButton to
save the choice and close the form. The OnClick event handler for SelectButton might
look like this:
procedure TColorForm.SelectButtonClick(Sender: TObject);
begin
with ColorListBox do
if ItemIndex >= 0 then
String(FColor^) := ColorListBox.Items[ItemIndex];
end;
Close;
end;
Notice that the event handler stores the selected color name in the string referenced
by the pointer that was passed to the constructor.
To use ColorForm effectively, the calling form must pass the constructor a pointer to
an existing string. For example, assume ColorForm was instantiated by a form called
ResultsForm in response to a button called UpdateButton on ResultsForm being clicked.
The event handler would look as follows:
procedure TResultsForm.UpdateButtonClick(Sender: TObject);
var
MainColor: String;
begin
GetColor(Addr(MainColor));
if MainColor <> '' then
{do something with the MainColor string}
else
{do something else because no color was picked}
end;
5 In the Palette page edit box, specify the Component palette page where you want
the template to reside. If you specify a page that does not exist, a new page is
created when you save the template.
6 Next to Palette Icon, select a bitmap to represent the template on the palette. The
default proposal will be the bitmap used by the component type of the first
component selected in step 2. To browse for other bitmaps, click Change. The
bitmap you choose must be no larger than 24 pixels by 24 pixels.
7 Click OK.
To remove templates from the Component palette, choose Component|Configure
Palette.
Creating frames
To create an empty frame, choose File|New|Frame, or choose File|New|Other and
double-click Frame. You can then drop components (including other frames) onto
your new frame.
It is usually best—though not necessary—to save frames as part of a project. If you
want to create a project that contains only frames and no forms, choose File|New|
Application, close the new form and unit without saving them, then choose File|
New|Frame and save the project.
Note When you save frames, avoid using the default names Unit1, Project1, and so forth,
since these are likely to cause conflicts when you try to use the frames later.
At design time, you can display any frame included in the current project by
choosing View|Forms and selecting a frame. As with forms and data modules, you
can toggle between the Form Designer and the frame’s form file by right-clicking and
choosing View as Form or View as Text.
If, on the other hand, you put your database components into a frame, later changes
would need to be made in only one place; changes to an original frame automatically
propagate to its embedded descendants when your projects are recompiled. At the
same time, you are free to modify any embedded frame without affecting the original
frame or other embedded descendants of it. The only limitation on modifying
embedded frames is that you cannot add components to them.
Figure 9.1 A frame with data-aware controls and a data source component
In addition to simplifying maintenance, frames can help you to use resources more
efficiently. For example, to use a bitmap or other graphic in an application, you might
load the graphic into the Picture property of a TImage control. If, however, you use
the same graphic repeatedly in one application, each Image object you place on a
form will result in another copy of the graphic being added to the form’s resource
file. (This is true even if you set TImage