0

C++Builder 6 でプログラムを作成しましたが、現在問題が発生しています。

、、、、、、の6 つUnit1.cppのファイルUnit1.hがあります。Unit2.cppUnit2.hUnit3.cppUnit3.h

Unit1.cppメインフォーム用のファイルです。

問題:と で表示される関数void __fastcall TForm3::Button1Click(TObject *Sender)aを作成したいと思います。次のクリックは、新しい名前で新規作成する必要があります (以前のもの)TStringGridUnit1.cppUnit2.cppTStringGrid

私は自分の問題を解決しようとしましたが、いくつかのコードを書きましたが、それでは十分ではありません。
私は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が作成されますが、1 つだけです。TStringGridボタンが押された回数と同じ数の (一意の名前を持つ)を作成するにはどうすればよいですか? (今、私はで宣言TStringGridしなければなりませんUnit1.h)。

4

1 に答える 1

0

まず、コードが複数の を作成していることに注意してくださいTStringGrid。フォームの同じ場所に同じ寸法でそれらをすべて作成しているだけなので、一番上にあるものだけが表示されます。

--

あなたができるようにしたいこと ( Form1->dynamically_created_TStringGrid) は不可能ですが、同様の動作を得るために利用できる方法がいくつかあります。

std::vector メソッド

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呼び出して渡します。メンバーとしても、a で非常によく似たものを実装することもできます。GetStringGridByNameTStringGridstd::mappublic

FindChildControl メソッド

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、それを a に保存する代わりに使用しstd::vector.ますstd::vectorStringGridまた、指定した一意の名前を「忘れた」場合に sに到達するための簡単で信頼できる方法も提供しませんが、std::vectorではインデックスによって、またはイテレータを使用可能にした場合はイテレータを介してそれらにアクセスできます。はありますがGetChildren、直感的に使用できるようには見えません。

--

最初は、 を呼び出すたびにメモリ リークが発生すると思っていましたが、 Builder 6 のドキュメントを正しくTForm1::MyFunction理解していれば、そうではありません。

TComponent クラスは、VCL および CLX 全体に伝播される所有権の概念も導入します。Owner と Components の 2 つのプロパティが所有権をサポートします。すべてのコンポーネントには、所有者として別のコンポーネントを参照する Owner プロパティがあります。コンポーネントは、他のコンポーネントを所有する場合があります。この場合、所有されているすべてのコンポーネントは、コンポーネントの Array プロパティで参照されます。

コンポーネントのコンストラクターは、新しいコンポーネントの所有者を指定するために使用される単一のパラメーターを取ります。渡された所有者が存在する場合、新しいコンポーネントが所有者の Components リストに追加されます。Components リストを使用して所有されているコンポーネントを参照する以外に、このプロパティは、所有されているコンポーネントの自動破棄も提供します。コンポーネントに所有者がいる限り、所有者が破棄されるとコンポーネントも破棄されます。たとえば、TForm は TComponent の子孫であるため、フォームが所有するすべてのコンポーネントは破棄され、フォームが破棄されるとメモリが解放されます。これは、フォーム上のすべてのコンポーネントが、デストラクタが呼び出されたときに適切にクリーンアップされることを前提としています。

[.pdf ページ 53]

newそのため、 ed オブジェクトをその関数に渡すたびに Grid1 に割り当てていても、それらのオブジェクトはまだ所有されており、破棄Form2されたときにクリーンアップされます。Form2

とは言っても、OP に投稿した実装に固執する場合は、最後のものを除いて文字列グリッドを操作できないことに注意してくださいForm2->Array

于 2014-12-15T18:27:03.517 に答える