我在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"
和按钮点击功能是:
void __fastcall TForm3::Button1Click(TObject *Sender)
{
Form1->MyFunction(Form1->Grid); //Grid was declarated previous in Unit1.h
}
现在,当我使用此方法时,我动态创建TStringGrid
,但只有一个。如何按下按钮的次数创建尽可能多的TStringGrid
(具有唯一名称)? (现在我必须在TStringGrid
)中声明Unit1.h
。
答案 0 :(得分:0)
首先,请注意您的代码 正在创建多个TStringGrid
。它只是在窗体上的相同位置创建所有相同尺寸的所有内容,因此您只能在顶部看到它。
-
您希望能够做什么(Form1->dynamically_created_TStringGrid
)是不可能的,但有几种方法可以让您获得类似的行为。
<强> 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
}
使用此方法,您可以调用AddStringGrid()
并存储返回值。然后,当您想要操纵TStringGrid
上的给定Form1
时,您会调用GetStringGridByName
并传入您想要操作的TStringGrid
的名称。您还可以使用std::map
实现非常类似的内容,即使是public
成员。
<强> 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
}
此版本基本上使用Parent -> Children
关系来查找动态创建的TStringGrid
,而不是将其存储在std::vector.
我的直觉中表示它比{{1}更慢且更不安全方法,但我没有任何证据。如果你忘记&#34;它也没有提供任何简单,可靠的方式来获得std::vector
s。您给它们的唯一名称,而StringGrid
允许您通过索引访问它们,或者通过迭代器(如果您可以使用它)。有std::vector
,但使用起来看起来不太直观。
-
起初我以为每次拨打GetChildren
时都会收到内存泄漏,但如果我理解Builder 6 documentation correctly,情况并非如此:
TComponent类还引入了所有权的概念 在整个VCL和CLX中传播。两个属性支持 所有权:所有者和组件。每个组件都有一个Owner属性 引用另一个组件作为其所有者。组件可能拥有 其他组件。在这种情况下,引用所有拥有的组件 组件的Array属性。
组件的构造函数采用一个用于的参数 指定新组件的所有者。如果传入的所有者存在,则 新组件将添加到所有者的组件列表中。除了 使用“组件”列表引用自有组件,此属性 还提供自动销毁自有组件。如 只要该组件具有所有者,它就会被销毁 老板被摧毁了。例如,因为TForm是其后代 TComponent,表单拥有的所有组件都被销毁了 表单被销毁时释放的内存。这假定所有的 表单上的组件在他们的时候正确地清理它们 析构函数被称为。
[.pdf page 53]
因此,即使每次将TForm1::MyFunction
ed对象传递给Grid1时都要为其分配new
ed对象,这些对象仍由Form2
拥有,并在{{1}时清除被破坏了。
所有这一切,你应该知道,如果你坚持你在OP中发布的实现,你将无法操纵任何字符串网格,除了最后一个,除非你访问它们来自Form2
。