0

我在 C++Builder 6 中创建了一个程序,现在我遇到了问题。

我有 6 个文件:Unit1.cpp, Unit1.h, Unit2.cpp, Unit2.h, Unit3.cpp, Unit3.h.

Unit1.cpp是主要形式的文件。

问题:我想在函数void __fastcall TForm3::Button1Click(TObject *Sender)aTStringGrid中创建,它将在Unit1.cppand中可见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与按下按钮的次数一样多的 s (具有唯一名称)?(现在我必须声明TStringGridUnit1.h

4

1 回答 1

0

首先,请注意您的代码正在创建多个TStringGrids. 它只是在表单的同一位置创建具有相同尺寸的所有它们,因此您只能看到顶部的那个。

--

您希望能够做的事情 ( Form1->dynamically_created_TStringGrid) 是不可能的,但是您可以使用几种方法来获得类似的行为。

std::vector 方法

单元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);
}

单元1.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的 on 时,Form1您会调用GetStringGridByName并传入TStringGrid您想要操作的名称。std::map即使作为public成员,您也可以使用 a 实现非常相似的东西。

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(); 
}

单元1.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如果您“忘记”您给它们的唯一名称,它也没有提供任何简单、可靠的方法来获取 s ,而sstd::vector允许您通过索引访问它们,或者如果您提供一个迭代器,则通过迭代器访问它们。有GetChildren,但使用起来看起来不是很直观。

--

起初我以为每次调用都会发生内存泄漏TForm1::MyFunction,但如果我正确理解了 Builder 6 文档,情况并非如此:

TComponent 类还引入了在整个 VCL 和 CLX 中传播的所有权概念。两个属性支持所有权:所有者和组件。每个组件都有一个 Owner 属性,该属性引用另一个组件作为其所有者。一个组件可能拥有其他组件。在这种情况下,所有拥有的组件都在组件的 Array 属性中引用。

组件的构造函数采用单个参数,用于指定新组件的所有者。如果传入的所有者存在,则将新组件添加到所有者的组件列表中。除了使用组件列表来引用自有组件之外,此属性还提供了自有组件的自动销毁。只要组件有一个所有者,它就会在所有者被销毁时被销毁。例如,由于 TForm 是 TComponent 的后代,因此表单拥有的所有组件都将被销毁,并且在表单被销毁时释放它们的内存。这假设表单上的所有组件在调用它们的析构函数时都会正确地清理自己。

[.pdf 第 53 页]

因此,即使您new每次将 ed 对象传递给该函数时都将其分配给 Grid1,但这些对象仍归该函数所有,并且在被破坏Form2时将被清除。Form2

综上所述,您应该知道,如果您坚持在 OP 中发布的实现,您将无法操作除最后一个之外的任何字符串网格,除非您从Form2->Array.

于 2014-12-15T18:27:03.517 回答