1

I have a program in which I need to update a database table with information entered into edit boxes, with a button at the end to do the updating. However, the form is created at runtime and all the elements including the button are also created in the same way. I figured a way to allow the database arguments would be to define a procedure to update the database such as:

procedure UpdateDatabase(Field1,Field2,Field3:string);
begin
//update database here...
end;

Then assign the OnClick event of my button to this procedure with the parameters pre filled like:

Button1.OnClick := UpdateDatabase(Edit1.text,Edit2.Text,Edit3.Text);

However the types are incompatible as it requires a different data type. I also noticed that parameters can't usually be passed into a OnClick function. Is there actually a way of achieving what I have proposed?

This is my current create button code:

function buttonCreate(onClickEvent: TProcedure; 
  left: integer; top: integer; width: integer; height: integer; 
  anchors: TAnchors; caption: string; parent: TWinControl; form: TForm;): TButton;
var
  theButton: TButton;
begin
  theButton := TButton.Create(form);
  theButton.width := width;
  theButton.height := height;
  theButton.left := left;
  theButton.top := top;
  theButton.parent := parent;
  theButton.anchors := anchors;
  //theButton.OnClick := onClickEvent;
  theButton.Caption := caption;
  result := theButton;
end;

Any and all help appreciated!

5
  • Yes, your procedure needs to abide by the rules of the event type (Sender: TObject). Then, wrap your own procedure inside of that. Commented Feb 1, 2015 at 17:29
  • Can you give an example? Sorry, I'm a bit new to Delphi. Commented Feb 1, 2015 at 17:30
  • Are the Edit controls created before or after the button control? Commented Feb 1, 2015 at 20:37
  • @John Order of creation shouldn't matter, as long as there's a reference to the control at the time it's needed. You could create all the buttons before the edit controls and still make it work. But it highly depends on the design of the application, which we cannot see, so cannot be too sure. Commented Feb 2, 2015 at 5:03
  • Pascal does not contain a TButton or TForm, so the Pascal tag does not apply here. If your question is about the generic Pascal language, include that tag. If it's about the Delphi language (which is not Pascal, although it has it's origins in that language), use the Delphi tag and omit the Pascal tag. Commented Feb 14, 2015 at 0:31

2 Answers 2

6

Event handlers must be declared exactly how the event type is defined. An OnClick event is declared as a TNotifyEvent which takes parameters (Sender: TObject). You cannot break that rule.

In your case, you can wrap your own procedure inside of the event handler, like so...

procedure TForm1.Button1Click(Sender: TObject);
begin
  UpdateDatabase(Edit1.text,Edit2.Text,Edit3.Text);
end;

Note that TNotifyEvent is a procedure "of object", which means your event handler must be declared inside of an object. In your case, the event handler should be declared inside your form (not in a global location).

Sign up to request clarification or add additional context in comments.

6 Comments

But in this scenario Edit1.text and the like will be undefined, as those components are also being created at runtime. Is there any way to carry across the data?
No, that is not the case, as long as this event handler is declared inside of the same form. Now that I read over your code more thoroughly, it appears you are referencing a form variable (most likely global) which is not naturally the way to do it. All this should be self-contained inside the form, and you won't have to worry about that.
But the references to Edit1.Text are not valid identifiers as the component Edit1 has not been created when compiling?
I just realized what you mean by Edit1 is undefined - because you're dynamically creating all the controls in runtime. You'll somehow need to pass a pointer to these controls, but that's a matter of how you're designing your project and beyond my range of help. This answers your question about assigning an OnClick handler.
@JamesPaterson When you create Edit1 you'll need to store a reference to it somewhere and use that reference in your event handler. Or you could dynamically find the control via some property such as it's name, Tag property etc.
|
2

Have you thought about descending a control from TButton with the edit controls as field members?

Here's an example that hopefully you can glean some ideas from.

  TButtonHack = class(TButton)
    fEdit1,
    fEdit2,
    fEdit3: TEdit;
  procedure Click; override;
  public
  constructor Create(AOwner: TComponent; AParent: TWinControl; Edit1, Edit2, Edit3: TEdit); Reintroduce;
end;

Constructor TButtonHack.Create(AOwner: TComponent; AParent: TWinControl;  Edit1, Edit2, Edit3: TEdit);
begin
  inherited Create(AOwner);
  Parent := AParent;
  Left := 100;
  Top := 100;
  Width := 100;
  Height := 20;
  Caption := 'ButtonHack';
  fEdit1 := Edit1;
  fEdit2 := Edit2;
  fEdit3 := Edit3;
end;

procedure TButtonHack.Click;
begin
  Inherited Click;
  Showmessage(fEdit1.text+','+ fEdit2.text+','+fEdit3.text);
end;

To test, drop a button, and three TEdits on a form.

procedure TForm1.Button1Click(Sender: TObject);
var
  ButtonHack: TButtonHack;
begin
  ButtonHack := TButtonHack.Create(Form1, Form1, Edit1, Edit2, Edit3);
end;

Whether you create the edits ahead of time or from within the TButtonHack is up to you. I've simplified it as much as possible just as an example.

3 Comments

Inheritance would be a poor choice. As a rule you should avoid inheritance. You simply don't need it. You just need the OnClick handler to be able to see the edits. Certainly setting parent and position in constructor is a very bad smell. On a more mundane note, I think you don't fully understand what var means in that context.
I know that objects are passed by reference, used var as a means to state intention in this example. Edited and removed.
Objects are not "passed by reference". I know what you mean, but the terminology you use is imprecise. A variable of a type derived from TObject, is a reference. That's a fancy name for a pointer. When you pass a reference, e.g. Sender: TObject you are passing a reference by value. That is you pass the value of the pointer that holds the address of the object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.