This seems to work well until I try to create the 11th button. Any suggestions?

procedure TForm1.FormClick(Sender: TObject);
var
  nb: TButton;
begin
  Inc(n);
  nb := TButton.Create(Self);
  nb.OnClick := ButtonClick;
  SetLength(ca, n);
  ca[n] := nb;
  ca[n].Left := 8;
  ca[n].Top := (((n - 1) * nb.Height) + 8);
  ca[n].ParentWindow := Form1.Handle;
end;

Oops! First day for the kids to go back to school, so a bit rushed. I should have included the following from the interface section of the form:

ca: array of TButton;
n: Integer;

Oh yes, I should have put that in as well. The resulting application exits without an error, but when run from te IDE the following exception occurrs:

Project Project1.exe has raised exception class EAccessViolation with message 'Access violation at addresss 00401cDF in module 'Project1.exe'. read of address 00000EB8'. Processed stopped. Use Step or Run to continue.

The help indicates the following:
Debugger exception notification dialog box
You have received the following message:
Project xxxx raised exception class yyyyy with message 'zzzzzz'.
Process stopped. Use Step or Run to continue.
This dialog box appears when a program you're debugging raises an exception, and you have set options that instruct the debugger to handle exceptions (see the Language Exceptions, OS Exceptions pages of the Tools|Debugger options dialog). Both language exceptions and operating system exceptions show this dialog. If the 'yyyyy' in the message is a class name, it indicates that the exception is a language exception. If the 'yyyyy' is a hexadecimal value, it means that the exception is an operating system exception.
If the location of the exception does not correspond to a source location, a checkbox labeled "View CPU' appears in the lower left corner of the dialog box.
After pressing OK on the dialog box, the IDE shows you the location where the exception occurred. If you checked the View CPU checkbox, the CPU view is displayed. If the location of the exception corresponds directly to a source location, that source location is shown (and the View CPU checkbox does not appear on the dialog box).
If the exception location does not correspond to source and you do not check the View CPU checkbox, the IDE traverses the call stack looking for a call in the stack that contains source and will show you the first call found that has source.
What should you do when you see this dialog?
In most cases, clicking OK and doing a Run|Run to continue will work just fine. In some cases, the state of the program will prevent you from running or continuing will not allow them to continue (you will repeatedly see the exception message). In this case, you will need to choose Run|Program Reset to end the current program run and release it from memory.

When I view the CPU history the highlighted line is:
00401CDF 3311 xor edx, [ecx]

Unfortunately I don't have a clue what that means. I have done some searching and the most common errors associated with this exception occurr by calling non-existant objects, indexing empty strings and so on, neither of which is the case here.

And there is absolutely no other code involved ? I can easily run this code in Delphy 5, 2007 and 2009 without issues.

Made a couple of changes - simplified it really - and the problem has been solved.

Inc(n);
  SetLength(ca, n);
  ca[n] := TButton.Create(nil);
  ca[n].OnClick := ButtonClick;;
  ca[n].Left := 8;
  ca[n].Top := (((n - 1) * ca[n].Height) + 8);
  ca[n].ParentWindow := Form1.Handle;

1. You can use the class object list TObjectList. Only need to take care of his creation and removal.

private
  btn: TObjectList;

procedure TForm1.FormClick(Sender: TObject);
begin
 with Btn.Items[Btn.Add(TButton.Create(Self)] do
 begin   
   OnClick := ButtonClick;;
   Left   := 8;
   Top    := (((Btn.Count - 1) * Height) + 8);
   Parent := Self; 
 end;
end;

2. Can be even easier. A parent already knows all her children.

procedure TForm1.FormClick(Sender: TObject);
begin
 with TButton.Create(Self) do
 begin   
   OnClick := ButtonClick;;
   Left   := 8;
   Top    := (((Self.ControlCount - 1) * Height) + 8);
   Parent := Self; 
 end;
end;

Access to any button can be so

procedure TForm1.FormClick(Sender: TObject);
var
  i: integer;
begin
 for i:=0 to Self.ControlCount-1 do
   if Self.Controls[i] is TButton then
     with Self.Controls[i] as TButton do
     begin   
       Caption := 'Hello world!';
     end;
end;

Edited 5 Years Ago by Wolfgan: n/a

This question has already been answered. Start a new discussion instead.