C ++ Builder — Динамический StringGrid C ++ Builder

Я создал программу на 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, но только один. Как мне создать как можно больше TStringGrids (с уникальными именами), сколько раз нажата кнопка? (Теперь я должен объявить TStringGrid в Unit1.h).

0

Решение

Во-первых, обратите внимание, что ваш код является создание нескольких TStringGrids. Он просто создает их с одинаковыми размерами в одном и том же месте формы, поэтому вы видите только один сверху.

Что ты хочешь уметь делать (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 метод, но у меня нет никаких доказательств. Он также не предлагает простой и надежный способ добраться до StringGrids если вы «забудете» уникальные имена, которые вы им дали, в то время как std::vector позволяет получить к ним доступ по индексу или через итератор, если вы сделаете его доступным. Есть GetChildren, но это не выглядит очень интуитивно понятным в использовании.

Сначала я думал, что вы будете получать утечку памяти каждый раз, когда вы звоните TForm1::MyFunction, но если я понимаю Документация Builder 6 правильно, Это не относится к делу:

Класс TComponent также вводит понятие собственности, которое
распространяется по всему VCL и CLX. Поддержка двух свойств
Право собственности: Владелец и Компоненты. Каждый компонент имеет свойство Owner
который ссылается на другой компонент в качестве его владельца. Компонент может владеть
другие компоненты. В этом случае все принадлежащие компоненты упоминаются в
свойство Array компонента.

Конструктор компонента принимает один параметр, который используется для
укажите владельца нового компонента. Если переданный владелец существует,
новый компонент добавлен в список компонентов владельца. Помимо
используя список компонентов для ссылки на собственные компоненты, это свойство
также предусматривает автоматическое уничтожение принадлежащих компонентов. Как
Пока у компонента есть владелец, он будет уничтожен, когда
владелец уничтожен. Например, поскольку TForm является потомком
TComponent, все компоненты, принадлежащие форме, уничтожаются и их
память освобождается, когда форма уничтожена. Это предполагает, что все
компоненты в форме очищаются должным образом, когда их
деструкторы называются.

[.pdf стр. 53]

Так что, даже если вы назначаете newКогда объект ed передается в Grid1, каждый раз, когда вы передаете его этой функции, эти объекты все еще принадлежат Form2 и будет очищен, когда Form2 разрушен.

Все это говорит о том, что вы должны знать, что, если вы будете придерживаться реализации, которую вы разместили в OP, вы не сможете манипулировать ни одной из ваших строковых сеток, кроме последней, если вы не получите к ним доступ из Form2->Array,

0

Другие решения


По вопросам рекламы [email protected]