我在C++Builder 6中创建了一个程序,现在我遇到了一个问题。
我有6个文件:Unit1.cpp,Unit1.h,Unit2.cpp,Unit2.h,Unit3.cpp,Unit3.h。
Unit1.cpp是主窗体的文件。
问题:我想在函数void __fastcall TForm3::Button1Click(TObject *Sender)中创建一个TStringGrid,它将在Unit1.cpp和Unit2.cpp中可见。下一次单击应创建具有新名称的新TStringGrid (以前的存在)
我试图解决我的问题,我写了一些代码,但这对我来说是不够的。
在Unit1.h中,我添加了:
void __fastcall MyFunction(TStringGrid *Grid1); 在Unit1.cpp中,我添加了:
void __fastcall TForm1::MyFunction(TStringGrid *Grid1)
{
Grid1 = new TStringGrid(Form2);
Grid1->Parent = Form2;
}在Unit3.cpp中,我添加了:
#include "Unit1.h"Button click函数是:
void __fastcall TForm3::Button1Click(TObject *Sender)
{
Form1->MyFunction(Form1->Grid); //Grid was declarated previous in Unit1.h
}现在,当我使用这个方法时,我动态地创建了一个TStringGrid,但只有一个。如何创建与按下按钮次数一样多的TStringGrid(具有唯一名称)?(现在我必须在TStringGrid中声明Unit1.h)。
发布于 2014-12-15 18:27:03
首先,请注意,您的代码正在创建多个TStringGrid,它只是在窗体上相同的位置上创建具有相同维度的所有它们,所以您只看到顶部的一个。
--
您想要做的事情(Form1->dynamically_created_TStringGrid)是不可能的,但是有几种方法可以用于获得类似的行为。
std::向量法
单位1.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
}使用此方法,您可以调用AddStringGrid()并存储返回值。然后,当您想在Form1上操作给定的Form1时,您将调用GetStringGridByName并传入您想要操作的TStringGrid的名称。您还可以在std::map中实现一些非常类似的东西,甚至作为public成员。
FindChildControl方法
单位1.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
}这个版本基本上使用Parent -> Children关系来查找动态创建的TStringGrid,而不是存储在std::vector.中--我的直觉说,它比std::vector方法更慢、更不安全,但我没有任何证据。如果您“忘记”给StringGrid的唯一名称,那么它也没有提供任何简单、可靠的方法来获取它们,而std::vector允许您通过索引访问它们,或者如果您可以使用迭代器,则可以访问它们。有GetChildren,但使用起来不太直观。
--
起初,我以为每次调用TForm1::MyFunction时都会发现内存泄漏,但如果我理解正确的构建器6文档,情况就不是这样:
TComponent类还引入了在VCL和CLX中传播的所有权概念。有两个属性支持所有权:所有者和组件。每个组件都有一个所有者属性,该属性将另一个组件引用为其所有者。组件可以拥有其他组件。在这种情况下,所有拥有的组件都在组件的Array属性中引用。 组件的构造函数接受一个参数,用于指定新组件的所有者。如果传入所有者存在,则将新组件添加到所有者的组件列表中。除了使用“组件”列表引用拥有的组件外,该属性还提供了自动销毁所属组件的功能。只要组件有所有者,它就会在所有者被销毁时被销毁。例如,由于TForm是TComponent的后代,表单拥有的所有组件都会被销毁,并且在销毁表单时释放它们的内存。这假定表单上的所有组件在调用其析构函数时都会正确地清理它们自己。 .pdf第53页
因此,即使每次将newed对象传递给该函数时,都会将它分配给Grid1,但这些对象仍然属于Form2,在Form2被销毁时将被清除。
尽管如此,您应该知道,如果您坚持在OP中发布的实现,那么您将无法操作任何字符串网格,除非您从Form2->Array访问它们。
https://stackoverflow.com/questions/27489169
复制相似问题