0

I am new to Delphi.

I would like to make an application in which will create a number of Buttons. Declaring an array of Tbuttons and create the buttons 1 by 1 is not very satisfying, because it is confusing and takes a lot of time. Using the Command For is also unsatisfying, because i won't be able to change some of button's properties, if needed, for example their position.

So i decided to declare a procedure in TForm1 Class, which creates the buttons based on what properties I send to the procedure. But for some reason it is not working (There aren't any syntax Errors):

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)                       //Declaring the procedure
  procedure CreateButton(Button: TButton; L: Integer; T: Integer); 
  procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  B1, B2: TForm1;         //Declaring controls
implementation

{$R *.dfm}

procedure TForm1.CreateButton(Button: TButton; L: Integer; T: Integer);
begin
  Button:= TButton.Create(Self);
  Button.Parent:= Self;
  Button.Width:= 100; Button.Height:= 50;
  Button.Left:= L; Button.Top:= T;
end;


procedure TForm1.FormCreate(Sender: TObject);
Var
  Button1, Button2: TButton;
begin
  B1.CreateButton(Button1, 100, 50);           //Sending properties
  B2.CreateButton(Button2, 200, 40);           //Sending properties
end;

end.
  • what do you mean by "not working"??? when ? which what errors? no one her can jump into your head and look with your eyes. Please read http://www.catb.org/~esr/faqs/smart-questions.html – Arioch 'The Jul 13 '13 at 21:17
  • 1
    You have two Button.Height in CreateButton... Change the second one to Button.Top := T; – Bill Jul 13 '13 at 21:17
  • I am sry, i mean that the Buttons 1,2 are not created – Nikolaidis Dimitris Jul 13 '13 at 21:23
  • How do you determine they are not created rather than created in wrong place or with wrong owner or created invisible ? Being a programmer you should be very sharp and certain with claims and facts. Otherwise your programs would do anything but the thing their users asked for. There are miles and miles between "i cannot see the buttons on screen" and "the buttons were not created" – Arioch 'The Jul 13 '13 at 21:27
  • Do you see anywhere in the code (Button.hide)? No, So their visible automatically becames TRUE, so they are not invisible. Also, i send the buttons in specific coordinates. Button1.top = 100, Button1.Left = 50 and Button2.top = 200, Button2.Left = 40 Even if the paremeters don't pass in "CreateButton" The Buttons will automatically be created in (Top, Left = 0, which they don't) – Nikolaidis Dimitris Jul 13 '13 at 21:50
  • And so ? does the line `TButton.Create` get executed or not ? Does it - or not ? If it does - then the buttons are created! and all you can say is "i cannot see the buttons i supposed to create". You did not yet presented any facts, that the buttons were NOT CREATED, rather then created on invisible forms B1 and B2 or something even more weird. – Arioch 'The Jul 13 '13 at 21:53
  • Are B1 and B2 forms even created before you try to create buttong on them ? I bet they are not. B1 would try to create a button on B2 and B2 would try to create a button on B1, so no matter in which sequence you create B1 and B2, one of those would definitely try to create a button on a not-yet-created form. – Arioch 'The Jul 13 '13 at 22:01
  • Button:= TButton.Create(Self); B1: Button:= Button1 Button.Parent:= Self; B2: Button:= Button2 You are absolutely right, It's propably because the line is not executed, but what i am asking is why it doesn't? – Nikolaidis Dimitris Jul 13 '13 at 22:06
  • 1) read my answer - you made a lot of conceptual errors, that i pointed at and fixed one by one. 2) how do you know if that line was executed or not ? hint: you can use debugger and put a breakpoint on it. Or you can add some simple logging commands before and after that line. Those are basic debugging techniques. http://docwiki.embarcadero.com/RADStudio/XE4/en/Overview_of_Debugging – Arioch 'The Jul 13 '13 at 22:12
  • Button = nil, which means the values of "Button1" and "Button2" are not sent, however the values of Top and Left are sent. So this means that i cannot send the value of button1 and button2 right? – Nikolaidis Dimitris Jul 13 '13 at 22:20
  • 1) use @ + name when communicating here, like in Twitter. Otherwise no one would be alerted that you wrote something. You're topic starter, you would be notified that something changed in your question. But i would not. 2) you can - but you should mark your parameter as `OUT` - the thing i put as the very 1st line in my answer and you discarded without even glancing the link i given you. Please, read some novice tutorials on pascal and Delphi, really do! http://pastebin.ca/2427231 – Arioch 'The Jul 14 '13 at 10:19
  • http://pastebin.ca/2427238 – Arioch 'The Jul 14 '13 at 10:42

1 Answers1

0

AS: during the communication with topic starters answer grown too. The total outcome is like http://pastebin.ca/2426760

 procedure TForm1.CreateButton(VAR Button: TButton; CONST L: Integer; CONST T: Integer);

That is of basics of Pascal language how to pass parameters to procedures/functions.

http://docwiki.embarcadero.com/RADStudio/XE4/en/Parameters_(Delphi)

Actually, I don't think there is any problem with the parameters
Button = nil, which means the values of "Button1" and "Button2" are not sent, however

http://pastebin.ca/2427238


Kudoes to Bill for spotting this. Using separate properties to position your controls is both inefficient and prone to copy-paste errors.

Using the 2nd link:

procedure TForm1.CreateButton(out Button: TButton; const L: Integer; const T: Integer);
begin
  Button:= TButton.Create(Self);
  Button.Parent:= Self;
  Button.SetBounds( L, T, 100, 50); 
end;

Actually what do you do with pointers to newly created buttons ? In your code you just loose them!

procedure TForm1.FormCreate(Sender: TObject);
Var
  Button1, Button2: TButton;
begin
...
end;

In this your code those pointers would be just lost! If you do need those values - pass them outside of the procedure. If you do not - do not ask for them - http://en.wikipedia.org/wiki/YAGNI http://en.wikipedia.org/wiki/KISS_principle

Procedure TForm1.CreateButton(const L, T: Integer);
begin
  With TButton.Create(Self) do begin
       Parent := Self;
       SetBounds( L, T, 100, 50); 
       Caption := 'Caption at ' + IntToStr(T);
       Name := 'Name at ' + IntToStr(L);
  End; 
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  B1.CreateButton( 100, 50);           //Sending properties
  B2.CreateButton( 200, 40);           //Sending properties
end;

Now to those B1, B2...

You claim that you want 2 buttons on the form, but you code shows you try to make THREE FORMS and one button on the 2nd form and one button on the 3rd form. So what do you really want ??? And do you check that B1 and B2 forms were created befoe tryign to add buttons to them ?

Perhaps you really wanted

procedure TForm1.FormCreate(Sender: TObject);
begin
  SELF.CreateButton( 100, 50);           //Sending properties
  SELF.CreateButton( 200, 40);           //Sending properties
end;

Then to go with DRY principle and to keep all the variables in one place.

http://docwiki.embarcadero.com/Libraries/XE2/en/System.Types.TPoint

Procedure TForm1.CreateButtons(const a: array of TPoint);
Var p: TPoint;
Begin
    for p in a do
        CreateButton( p.x, p.y );
End;

type TPointDynArray = array of TPoint;

procedure TForm1.FormCreate(Sender: TObject);
begin
   CreateButtons( TPointDynArray.Create(
       Point( 100,50 ), Point(200, 40) ) );
end;

Kudos to Delphi array initialization

Later you can always add more coordinates to an array and keep it consistent. Well, to bring down this to Delphi 7 abilities that would - somewhat redundantly - be coded like

const BtnCnt = 2;
      BtnLocations : array [1..BtnCnt] of TSize = (
         ( cx: 100, cy: 50 ), ( cx: 200, cy: 40 ) 
      );

Procedure TForm1.CreateButtons(const a: array of TSize);
Var i: integer;
Begin
    for i := Low(a) to High(a) do
        with a[i] do
             CreateButton( cx, cy );
End;

procedure TForm1.FormCreate(Sender: TObject);
begin
   CreateButtons( BtnLocations );
end;

But while Delphi 5 and Dephi 7 were great releases, they are very outdated. I definitely suggest you either upgradeing to Delphi XE or more recent, or side-stepping to CodeTyphon


TForm1 = class(TForm)                       //Declaring the procedure
    procedure CreateButton(Button: TButton; L: Integer; T: Integer); 

Declaring that one-purpose procedure in PUBLISHED section of the form class is also not a very good style. You'd better declare them in PRIVATE section. Adhering to "least visibility" would help you to make interdependencies controllable. Otherwise in a year your program would become a spaghetti mess, where you just cannot change anything without ruining everything else. I am workign on a project with 10+ years of history now and i see the consequences of "everything is public" very clear. It is a great pain!

Community
  • 1
  • 1
Arioch 'The
  • 15,799
  • 35
  • 62
  • Actually, I don't think there is any problem with the parameters. – Nikolaidis Dimitris Jul 13 '13 at 21:31
  • @NikolaidisDimitris then what is Your intention to declare 1st parameter to `CreateButton` ? What value does `Button` parameter transfers from `FormCreate` to `CreateButton` and how the latter does use it ? – Arioch 'The Jul 13 '13 at 21:35
  • B1 and B2 are 2 buttons. OnFormCreate procedure sends parameteres of those 2 buttons. B1 Button's Name = Button1, left = 100, top = 50. So the variables "Button, L, T" of CreateButton take the values: Button:= Button, T:= 50 = Button.Top; L:= 100 = Button.Left – Nikolaidis Dimitris Jul 13 '13 at 22:02
  • `var B1, B2: TForm1; ` - B1 and B2 are FORMS. Buttons do have type `TButton`, not `TForm`. And those buttons do not have neither names nor captions (you know the difference, don't you?) because after compilation there is no more "Button1" or "B2" but only nameless memory addresses. If you need those buttons to have names or captions -you should make string expression and assign those properties. – Arioch 'The Jul 13 '13 at 22:04
  • There above is fixed code for `CreateButton`, `CreateButtons` and `FormCreate` - try it and try to understand the differences. – Arioch 'The Jul 13 '13 at 22:09
  • I don't need those buttons to have neither names nor captions, it is not necessery. I just need them to be created. neither B1 nor B2 are forms. TFORM1 is a class. A Class which includes The CreateButton Procedure. – Nikolaidis Dimitris Jul 13 '13 at 22:12
  • TFORM1 is a class of forms, not buttons. B1 and B2 belongs to TFORM1 - `var B1, B2: TForm1;` - thus they belong to forms just liek any other variable of TFORM1 does. You code shows `var Form1, B1, B2: TForm1;` - they are of THE SAME type, they aree either all forms or all buttons. IF you say B1 is a button - then you say that both Form1 and TForm1 belong to buttons as well. That cannot be. – Arioch 'The Jul 13 '13 at 22:18