Я создал программу на 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
s (с уникальными именами), сколько раз нажата кнопка? (Теперь я должен объявить TStringGrid
в Unit1.h
).
Во-первых, обратите внимание, что ваш код является создание нескольких TStringGrid
s. Он просто создает их с одинаковыми размерами в одном и том же месте формы, поэтому вы видите только один сверху.
—
Что ты хочешь уметь делать (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.
Мой кишечник говорит, что он медленнее и менее безопасен, чем std::vector
метод, но у меня нет никаких доказательств. Он также не предлагает простой и надежный способ добраться до StringGrid
s если вы «забудете» уникальные имена, которые вы им дали, в то время как std::vector
позволяет получить к ним доступ по индексу или через итератор, если вы сделаете его доступным. Есть GetChildren
, но это не выглядит очень интуитивно понятным в использовании.
—
Сначала я думал, что вы будете получать утечку памяти каждый раз, когда вы звоните TForm1::MyFunction
, но если я понимаю Документация Builder 6 правильно, Это не относится к делу:
Класс TComponent также вводит понятие собственности, которое
распространяется по всему VCL и CLX. Поддержка двух свойств
Право собственности: Владелец и Компоненты. Каждый компонент имеет свойство Owner
который ссылается на другой компонент в качестве его владельца. Компонент может владеть
другие компоненты. В этом случае все принадлежащие компоненты упоминаются в
свойство Array компонента.Конструктор компонента принимает один параметр, который используется для
[.pdf стр. 53]
укажите владельца нового компонента. Если переданный владелец существует,
новый компонент добавлен в список компонентов владельца. Помимо
используя список компонентов для ссылки на собственные компоненты, это свойство
также предусматривает автоматическое уничтожение принадлежащих компонентов. Как
Пока у компонента есть владелец, он будет уничтожен, когда
владелец уничтожен. Например, поскольку TForm является потомком
TComponent, все компоненты, принадлежащие форме, уничтожаются и их
память освобождается, когда форма уничтожена. Это предполагает, что все
компоненты в форме очищаются должным образом, когда их
деструкторы называются.
Так что, даже если вы назначаете new
Когда объект ed передается в Grid1, каждый раз, когда вы передаете его этой функции, эти объекты все еще принадлежат Form2
и будет очищен, когда Form2
разрушен.
Все это говорит о том, что вы должны знать, что, если вы будете придерживаться реализации, которую вы разместили в OP, вы не сможете манипулировать ни одной из ваших строковых сеток, кроме последней, если вы не получите к ним доступ из Form2->Array
,