First, note that your code is creating multiple TStringGrid
s. It is just creating them all with the same dimensions in the same place on the form, so you only see the one on top.
--
What you want to be able to do (Form1->dynamically_created_TStringGrid
) is not possible, but there are a couple of methods available to you to get similar behavior.
The std::vector method
Unit1.h
#ifndef Unit1H
#define Unit1H
#include <vector>
//your other includes here
class PACKAGE Form1 : public TForm
{
__published: //IDE-managed Components
//your components here
private:
/.../
std::vector<TStringGrid *> SGridVec;
public:
/.../
AnsiString AddStringGrid();
TStringGrid * GetStringGridByName(const AnsiString &Name);
TStringGrid * GetStringGridByIndex(const unsigned int Index);
}
Unit1.cpp
AnsiString TForm1::AddStringGrid()
{
SGridVec.push_back(new TStringGrid(Form2)); //Form2 is owner and handles memory management
if (SGridVec.back())
{
SGridVec.back()->Parent = Form2;
SGridVec.back()->Name = "some uniquely generated name";
return SGridVec.back()->Name;
}
return ""; //add was unsuccessful
}
TStringGrid * TForm1::GetStringGridByName(const AnsiString &Name)
{
for(std::vector<TStringGrid *>::iterator sgItr = SGridVec.begin();
sgItr != SGridVec.end();
++sgItr)
{
if (*sgItr && (*sgItr)->Name == Name)
{
return *sgItr;
}
}
return NULL; //StringGrid with Name was not found
}
TStringGrid * TForm1::GetStringGridByIndex(const unsigned int Index)
{
if (Index < SGridVec.size() && SGridVec.at(Index) != NULL)
return SGridVec.at(Index);
return NULL; //StringGrid at Index was not found
}
Using this method you could call AddStringGrid()
and store the return value. Then when you wanted to manipulate a given TStringGrid
on Form1
you would call GetStringGridByName
and pass in the name of the TStringGrid
you want to manipulate. You could also implement something very similar with a std::map
, even as a public
member.
The FindChildControl method
Unit1.h
#ifndef Unit1H
#define Unit1H
#include <map>
//your other includes here
class PACKAGE Form1 : public TForm
{
__published: //IDE-managed Components
//your components here
public:
/.../
AnsiString AddStringGrid();
}
Unit1.cpp
AnsiString TForm1::AddStringGrid()
{
TStringGrid *temp_ptr = new TStringGrid(Form2); //Form2 is owner and handles memory management
if (temp_ptr)
{
temp_ptr->Parent = Form2;
temp_ptr->Name = "some uniquely generated name";
return temp_ptr->Name;
}
return ""; //add was unsuccessful
}
void SomeClass::SomeFunctionThatUsesForm2sTStrinGrids(/.../)
{
/.../ //some code
TStrinGrid *temp_ptr = static_cast<TStringGrid *>(Form2->FindChildControl("name of control"));
if (temp_ptr)
{
//do stuff to the string grid
}
/.../ //some other code
}
This version basically uses the Parent -> Children
relationship to find the dynamically created TStringGrid
instead of storing it in a std::vector.
My gut says that it is slower and less safe than the std::vector
method, but I don't have any proof. It also doesn't offer any simple, reliable way to get at the StringGrid
s if you "forget" the unique names you gave them, while the std::vector
lets you access them by index, or via an iterator if you make one available. There is GetChildren
, but it does not look very intuitive to use.
--
At first I thought you would get a memory leak every time you call TForm1::MyFunction
, but if I'm understanding the Builder 6 documentation correctly, that is not the case:
The TComponent class also introduces the concept of ownership that is
propagated throughout the VCL and CLX. Two properties support
ownership: Owner and Components. Every component has an Owner property
that references another component as its owner. A component may own
other components. In this case, all owned components are referenced in
the component’s Array property.
A component's constructor takes a single parameter that is used to
specify the new component's owner. If the passed-in owner exists, the
new component is added to the owner's Components list. Aside from
using the Components list to reference owned components, this property
also provides for the automatic destruction of owned components. As
long as the component has an owner, it will be destroyed when the
owner is destroyed. For example, since TForm is a descendant of
TComponent, all components owned by the form are destroyed and their
memory freed when the form is destroyed. This assumes that all of the
components on the form clean themselves up properly when their
destructors are called.
[.pdf page 53]
So even though you are assigning a new
ed object to Grid1 every time you pass it in to that function, those objects are still owned by Form2
and will be cleaned up when Form2
is destructed.
All that said, you should be aware that, if you stick with the implementation you have posted in the OP, you won't be able to manipulate any of your string grids except for the last one unless you access them from Form2->Array
.