0

Specific question

How to create an array of buttons on Borland C++ Builder and work with it?

I'm using Borland C++ Builder 6 and Borland Developer Studio 2006 (Turbo C++ 2006).

Purpose

To work with a lot of buttons on a form just using a for loop with an index, for example, changing their caption, size and position.

I know if I have a button called Button1 and inside a click event of this button if I create another button (through TButton *Button2 = new TButton(Form1)), I can assign Button1 to Button2 (Button2 = Button1) and them I can simply modify caption of Button1 with Button2->Caption. So I would like to extend it assigning pointers of real components to elements of an array to them work with all of them with a for loop.

Well, if someone found an way to add all buttons as an array on a form, it's better :)

Tries

Following tests were made putting respective code on TForm1::Button1Click(), an event of a button on a form:

  • Test 1

    • Description: Creating an array directly
    • Code:

      TButton Buttons[3];
      
    • Result: Compile error:

      > [C++ Error] Unit1.cpp(23): E2248 Cannot find default constructor
      > to initialize array element of type 'TButton'
      
    • Comments:
      • I tested some variants of this test (e.g. TButton Buttons = new TButton[3], working with calloc function and others), but all of them points to the issue that TButton does not have a constructor without arguments, i.e., TButton(), but only TButton (TComponent *AOwner), TButton(void *ParentWindow) and TButton(const TButton &);
      • Any way to use operator new with arguments for TButton constructor prototypes, for an array?
  • Test 2

    • Description: Creating a vector
    • Code: Also add #include "vector.h" on unit header...

      vector<TButton> Buttons;
      Buttons[0].Caption="it is ok";
      Buttons[1].Caption="mayday, mayday";
      
    • Result: Debugger exception on 3rd line:

      > Project Project1.exe raised exception class EAccessViolation
      > with message 'Acceess violation at address 401075B9 in module
      > 'vcl60.bpl'. Read of address 00000254'. Proccess stopped. Use
      > Step or Run to continue.
      
    • Comments:
      • Yeah, I expected that it would be raised, but I put it here to someone say how to allocate memory for more elements on that vector after created, since vector<TButton> Buttons(3); does not work for the same reason test1 failed :(

General question

How to do it for any visual component?

kokbira
  • 608
  • 1
  • 10
  • 25

3 Answers3

3

All of your attempts failed for the same reason - you are trying to create an array/vector of actual TButton object instances instead of an array/vector of pointers to TButton instances.

To create a fixed-length array of button pointers:

TButton* Buttons[3];
...
Buttons[0] = Button1;
Buttons[1] = Button2;
Buttons[2] = Button3;
...
for(index = 0; index < 3; ++index)
{
    TButton *Btn = Buttons[index];
    // use Btn as needed...
}

To create a dynamic-length array of button pointers:

TButton** Buttons;
...
Buttons = new TButton*[3];
Buttons[0] = Button1;
Buttons[1] = Button2;
Buttons[2] = Button3;
...
for(index = 0; index < 3; ++index)
{
    TButton *Btn = Buttons[index];
    // use Btn as needed...
}
...
delete[] Buttons;

To create a vector of button pointers:

std::vector<TButton*> Buttons;
...
Buttons.push_back(Button1);
Buttons.push_back(Button2);
Buttons.push_back(Button3);
...
for(index = 0; index < 3; ++index)
{
    TButton *Btn = Buttons[index];
    // use Btn as needed...
}
/*
Or:
for(std::vector<TButton*>::iterator iter = Buttons.begin(); iter != Buttons.end(); ++iter)
{
    TButton *Btn = *iter;
    // use Btn as needed...
}
*/
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

All this is very nice and correctly true. But I mean the user’s question was some other intention. If for all the buttons we get each of them index does no special benefit - this is only a true method: the aim is to control all components with a click (button, panels, shapes and so on…) and don’t write for each index a new code, That why I changed a few program’s code:

void __fastcall TForm1::Button1Click(TObject *Sender)

{

typedef TPanel* TPanels;

TPanels Panels[3] = {Panel1, Panel2, Panel3};

int count;

for(count=0;count<3;count++)

Panels[count]->Left=random(100);

}  

As one can see instead of index here is count. Certainly don’t forget insert randomize() to TForm1

Failed Scientist
  • 1,977
  • 3
  • 29
  • 48
Alex
  • 11
  • 1
0

Miraculous Typedef + Pseudo Array = Solution

  • Miraculous Typedef:

    • After hours searching a way, I saw a typedef on that Stack Overflow and Google search journey and thought why not to:

      typedef TButton* TButtons;
      
    • Well, it changes all the things, because I could perform:

      TButtons Buttons[3];
      
  • Pseudo Array:

    • The issue remained on how to allocate memory for data stored on that Buttons[3] array, but with knowledge of 2nd paragraph of Purpose section of my question, I thought: forget new data, data is there, point to there (so I call that to build a pseudo array, because I create only an array of pointers to existing data):

      TButtons Buttons[3] = {Button1, Button2, Button3};
      
    • Where Button1, Button2 and Button3 were already created when I put them on the form normally (through my mouse).

Working example

  1. Create a new vcl/forms application project;
  2. Put 3 buttons as those on the left on figure bellow (Button1, Button2, Button3) to demonstrate that solution, and 1 great button (Button4) also as figure bellow to do the actions; the figure bellow point 2
  3. Insert following code on click event of the fourth button, the great one (Button4);

    typedef TButton* TButtons;
    TButtons Buttons[3] = {Button1, Button2, Button3};
    int index;
    
    for(index=0;index<3;index++)
    {
            Buttons[index]->Caption=(AnsiString)"teste "+index+" - "+(1+random(100));
            Buttons[index]->Left=25+4*random(100);
            Buttons[index]->Top=25+4*random(100);
    }
    
  4. Perform a "shazam!" run and play with that... like a game project
kokbira
  • 608
  • 1
  • 10
  • 25
  • 1
    You don't need the `TButtons` typedef, whose name is misleading anyway since you are creating an array of individual button pointers, not an array of button lists: `TButton* Buttons[3];`. As for the `vector` AV, that is because you did not put anything in the `vector` before accessing its elements. You have to `push_back()` the pointers into the `vector` before you can then use the `[]` operator to access them. – Remy Lebeau Sep 07 '12 at 23:43
  • @RemyLebeau, I thought I tried `TButton* Buttons[3];` before, but I saw that I didn't... So assign addresses to that array elements complete it and brings a clear solution. Thanks again :) – kokbira Sep 10 '12 at 12:19
  • Hey, @RemyLebeau, answer my question with your clean quite obvious :) solution and then I assign you the correct answer (to you earn some SO points). – kokbira Sep 10 '12 at 12:28
  • About your suggestion to use `push_back()`, I tried too, but the same error message about `TButton` may be created with `new` operator appeared... I had no success to create new entities, only to use addresses from existing ones... I think if I create a new class based on TButton with a constructor without arguments would solve that, but I haven't tried it yet... – kokbira Sep 10 '12 at 12:33
  • 1
    There is no need to create a new class. Simply pass `NULL` to the existing `TButton` constructor if you do not want the new button object to have an Owner assigned (an Owner will free the new object for you when the Owner itself is freed). – Remy Lebeau Sep 10 '12 at 20:33