marco
cantu

Mastering Delphi 5 Corrections

This is a list of corrections related with the first printing of the book. In following printings most of them have been fixed. The way to verify which printing you have is to look into the copyright page, the one with fine prints.


Chapter 2

Page 66: first paragraph, second to last word, "data" should actually be "date": long date format.

Chapter 3

Page 102: 5th line after listing, TButtonCount should actually be TCountButton.

Page 109: Single line listing at middle page, should be:

ListBox1.Items.Assign (Memo1.Lines);

Page 112: Last line before final listing should be: "...the following DivideTwicePlusOne function:"

Page 117: Just before listing the word "form" is missing from the sentece, "...I've added to the main form a copy of the ApplicationEvents component, ..."

Page 136: Listing, second part, add a missing part of declaration:

function TAthlete.Run: string;

Chapter 4

Page 177: The Contain example updates the ListDemo example but fails to use the best code when extracting items from the list. In fact, the line:

Listbox1.Items.Add ((TObject(ListDate [I]) as TDate).Text);

can be cahnged into the following code (simpler and more readable, but also more robust):

Listbox1.Items.Add ((ListDate [I] as TDate).Text);

Update: Container Classes

Shortly after the book went to press, Borland/Inprise made some last-minute changes in the code of the Container classes (described in Chapter 4, pp.176-179), which prevent the code of the Contain and DateList examples excerpted in the book from compiling. The source code for these programs included in the download file contains the correct version. The changes affect the listings at pages 178 and 179.

The first change relates to the fact that the Stack and Queue containers have no way to access specific values within the internal list each one maintains. This is actually how they are intended to operate, but makes it quite difficult to know what is inside one of these containers. You basically have to extract and reinsert each element to see what's available, as in the following updated code from the Contain program.

For a Stack object, I've created a second structure and moved all the items back and forth between the two. Of course, this would be a very inefficient technique if the stack held a large number of values:

procedure TForm1.btnListStackClick(
  Sender: TObject);
var
  Stack2: TStack;
begin
  Stack2 := TStack.Create;
  ListBox1.Clear;
  // removing the list items
  while Stack.Count > 0 do
  begin
    ListBox1.Items.Add (IntToStr (
      Integer (Stack.Peek)));
    Stack2.Push (Stack.Pop);
  end;
  // restoring the list items
  while Stack2.Count > 0 do
    Stack.Push (Stack2.Pop);

  ShowMessage ('Removed: ' + IntToStr (
    Integer (Stack.Pop)));
end;

The code for the Queue object is simpler, as you can use the queue as a circular buffer and immediately insert the items you've just removed:

procedure TForm1.btnQueueClick(Sender: TObject);
var
  I: Integer;
begin
  ListBox1.Clear;
  for I := 0 to Queue.Count - 1 do 
  begin
    ListBox1.Items.Add (IntToStr (
      Integer (Queue.Peek)));
    Queue.Push (Queue.Pop);
  end;
  ShowMessage ('Removed: ' + IntToStr (
    Integer (Queue.Pop)));
end;

The second change affects the DateList example. The names of some of the methods of the TObjectList class have changed, so that the inherited class appearing at page 179 won't compile. Again, the download source code is already correct. Here is the updated listing:

type

// inheritance based
TDateListI = class (TObjectList)
protected
  procedure SetObject (
    Index: Integer; Item: TDate); 
  function GetObject (Index: Integer): TDate; 
public
  function Add (Obj: TDate): Integer; 
  procedure Insert (Index: Integer; Obj: TDate);  
  property Objects [Index: Integer]: TDate 
    read GetObject write SetObject; default; 
end;

// wrapper based 
TDateListW = class(TObject)
private
  FList: TObjectList;
  function GetObject (Index: Integer): TDate;   
  procedure SetObject (
    Index: Integer; Obj: TDate); 
  function GetCount: Integer;
public
  constructor Create;
  destructor Destroy; override;
  function Add (Obj: TDate): Integer; 
  function Remove (Obj: TDate): Integer; 
  function IndexOf (Obj: TDate): Integer;
  property Count: Integer 
    read GetCount;
  property Objects [Index: Integer]: TDate 
    read GetObject write SetObject; default; 
end;

Chapter 5

Page 191:Line 4, "You make this choice by specifying the value of the MultiSelect property"

Page 192: in the first listing, the procedure ComboBox1KeyPress should have the code "with ComboBox1 do" instead of "with ComboBox3 do".

Page 209: in the second last listing, there is an incorrect parameter: var Msg: TMessage should have been var Msg: TWMSysCommand as correctly indicated in the following listing (the last two lines of the page).

Page 221: Last sentence: "Before doing this, however, we have to fill the background of the menu items (the rectangular area passed as a parameter) with the standard color for the menu (clMenu) or the selected menu items (clHighlight)"

Page 222: Final line in note, "To accommodate the increasing number of states in the Windows 2000 user interface style, Delphi 5 includes a new OnAdvancedDrawItem event for menus"

Page 235: Second listing: there are two duplicated lines at the end:

TargetNode.Expand (False);
TreeView1.Selected := TargetNode;
TargetNode.Expand (False);
TreeView1.Selected := TargetNode;

Which should simply be there once:

TargetNode.Expand (False);
TreeView1.Selected := TargetNode;


Chapter 6

Page 253: Line 5 after note: "I've written a single method, connected with the four commands"

Page 267: First line of Tip, "The program always updates the text of the ActiveLabel above the second list box" -> remove the word "second" as there is only one list box.

Page 269: First line after first listing: "With this code, the second list box always lists all of the forms in the application." - same problem, remove "second".

Page 273: 2nd line after Note, " To type in the caption of the form, the program simply adds the character to the current Caption, as you can see in Figure 6.10"

Page 279: 2nd last line of text: "The final call, Invalidate, …" - there is no final s


Chapter 7

Page 287: First line: "The tbsDropDown style indicates a drop-down button, a sort of combo box"

Page 310: third line after first listing: "This number is automatically copied into the Range field of the HorzScrollBar property of the form".

Page 314: The code of the HdrSlip example has a few problems (wrong header dragging and confused refresh) mainly caused by the alignment of the last listbox to alClient. Set this to alLeft (as suggested in the text of the book) to improve the program by far, although the last listbox might temporarily leave some of the client area of the form visible (the code in the OnResize event handler fixes the problem).

MenuBar: The book mentions (I think it is this chapter) a menubar component available from Borland. You can find it among Delphi 4 downloads in the Delphi Download page.


Chapter 8

Page 333: last sentence before heading: "Another alternative is to use MDI forms, covered in later in this chapter." - was "in the next chapter," a wrong reference.


Chapter 9

Page 388: Last line: "File > Uses Form" should actually be "File > Use Unit"

Page 416: First line: "At the end of the ActionTotalExecute method" - was SpeedButtonTotalClick method. Page 419: NonAware example: The example in the download files doens't work as is. In fact, it uses actions to implement the navigational buttons, but actions in Delphi 5 connect autoamtically to a datasource depending on the visible data-aware controls. Having no data-aware controls, they don't work in the example. The real solution would be to fix the dataset actions, but the simplest one is to add a data-aware control to the form (for example a DbEdit) and make it zero size and disable its TabStop (to make it non-visible and non-reacheable, while still leaving it active).

Page 422: First line of text: "An alternative approach for testing the value of a field is to handle the BeforePost of the data set" - remove On. On the second last line of text, "To accomplish this, you can handle the AfterInsert event of a data set" - remove "On" again.

Page 433: First line: "When the user double-clicks on the second list box in the main form" - remove "second" as there is only one listbox. Page 435: TGridForm.SpeedButton1Click method. In the printed code the statement FieldsForm.FieldsList.Clear is repeated twice, at the beginning and at the end of the code. It is required only at the beginning. In the sample source code, however, it is at the end, which produces an error in case the user selects the button after pressing the "Fields" button in the main form.

Page 439: Last line: OtherSlide should actually be OtherSlice


Chapter 10

Page 451: Just before second listing: "using the BeforeInsert event" no "On"

Page 457: First line: "The only other code for the two child forms is the closing code, which destroys the form, setting the Action parameter of the OnClose event handler to caFree." - not "nil"

Page 490: First word: Client/Server should be Enterprise


Chapter 11

Page 504: 2nd. Paragraph: Client/Server should be Enterprise

Page 507: After title "database component": "In local applications, programmers usually refer to the database by indicating the alias of the file path in the DatabaseName property of the Table and Query components."

Page 532: Final lines of text: "which receives a date in input and computes the highest salary among the employees hired on that date"


Chapter 12

Page 572: In the listing (right after the line with a wrong indentation) "Name" should be replaced by "FieldName":

  with BdeTable.Fields [I] do
    AdoTable.FieldByName(FieldName).Value := Value;


Chapter 15

Page 705: After the figure, the text says: "Pressing this button, you simply get the value of the number following 100. To see why I added this method to the example, you need to press the button a second time, after the message showing the result."

The text should have been, instead: "To see why I added this method to the example, you need to press the button of the message box showing the result."

Page 709: First sentence: "Once we have the IShellLink interface, we can call some of its methods, such as SetPath and SetWorkingDirectory:"

Page 712: Middle of listing: "Table1.Activate" should rather be: "Table1.Open" as it is in the listing.

new FilesToDo Example: There are problems with the registration code under Windows 2000. The program opened the registry starting with a default root key, while setting a root key appears to be safer. Also on the NT family, the class id should be added as a string value under the key, not as part of the key itself. This code makes the program work under Windows 2000 (and NT) but might not be compatible with 98/ME (I haven't checked). So you should either use this code or keep the original depending on your OS. [Thanks to Robert Meek for sending me this vversion of the code].

procedure TKeepItMenuFactory.UpdateRegistry(Register: Boolean);
var
  Reg: TRegistry;
begin
  inherited UpdateRegistry (Register);

  Reg := TRegistry.Create;
  Reg.RootKey := HKEY_CLASSES_ROOT;
  try
    // register or remove the menu handler
    if Register then
    begin
      if Reg.OpenKey('\*\ShellEx\ContextMenuHandlers\ToDo', 
	      True) = True then
        Reg.WriteString('', GUIDToString(Class_ToDoMenuMenu));
    end
    else
    begin
      if Reg.OpenKey('\*\ShellEx\ContextMenuHandlers\ToDo', 
	      False) = True then
        Reg.DeleteKey ('\*\ShellEx\ContextMenuHandlers\ToDo');
    end;
  finally
    Reg.CloseKey;
    Reg.Free;
  end;
end;


Chapter 16

Page 743: Second paragraph, "The IFontDisp interface..."

Page 761: 3rd line, "with the effect you can see in Figure 16.14:" - it is 15.14


Chapter 18

Page 836: Extra Hint. The Assert procedure can receive a second optional parameter indicating the message to be displayed when the condition expressed in the first parameter fails:

procedure Assert (expr: Boolean [; const msg: string]);


Chapter 19

Page 872: The code of the btnBrowseClick method at the end of the page works under Win98 but not under Win2000. It can be fixed by declaring a second string variable, setting its length, and assigning it to pszDisplayName:

var
  strdn: string;
begin
  SetLength (strdn, 200);
  ...
  bi.pszDisplayName := PChar (strdn);
  ... 


Chapter 20

Source code: The book refers to an HTML file with links to the various scripts. This is now available: download it and save it to the Part5/20 directory of the book source code.

BrokIsa example: In the project source code, a key line is missing: the creation of the web module. The main block should look like:

begin
  Application.Initialize;
  Application.CreateForm(TWebModule1, WebModule1);
  Application.Run;
end.

Page 943: The listing of the MailGen example contains an error. The test

if Memo1.Lines.Count > 1

should actually be

if Memo1.Lines.Count > 0

as in case there is a single line of text in the memo, the program won't add it to the message body.