-2

実行時に同一のリストを持つ多数のコンボボックスをフォームに入力したいと考えています。Senderまた、オブジェクトの名前に応じて動作する同じイベント ハンドラーも取得します。ただし、これにはかなり時間がかかり、何か間違ったことをしていると推測していました。

XE2 Rad Studio C++ Builder と VCL GUI を使用しています。

編集:これらのボックスにはさまざまな種類のコンテンツが含まれており、フォーム内のいくつかのタブページに分散されています。ただし、選択したものを一目で少なくとも 80 個表示する必要があります。TLabel をクリックして別の要素を選択するときに、それらを TLabels に置き換えて TCombobox を作成する方がよいでしょうか?

コードは次のようになります。

void __fastcall TForm::TForm(){
    int i=0;
    TStringList* targetlist = new TStringList();
    targetlist->Add("Normal");
    targetlist->Add("Inverted");
    Vcl::Stdctrls::TComboBox **com = new Vcl::Stdctrls::TComboBox[512];
    for(i=0;i<512;++i){
        com[i]=new Vcl::Stdctrls::TComboBox(this);
        com[i]->Parent=this;
        com[i]->Name.printf(L"Combo_%d", i);
        com[i]->SetBounds(10, 198 + 20 * i, 130, 200);
        com[i]->Items = targetlist;
        com[i]->ItemIndex = 0;
        com[i]->Style = csDropDownList;
        com[i]->OnChange = MyComboTriggerChange;
    }
}

私のマシンでは、1回の反復に約20ミリ秒かかるようです( でテスト済みstd::clock)。これにより、この部分は約10秒長くなります。ポインターは、フォームの破棄時に削除されます。簡単にするために、ここに宣言を入れただけです。

複数のコンボボックスを作成するより良い方法はありますか? 多分それらをクローンしますか?

4

1 に答える 1

3

UI を真剣に再設計する必要があります1 つの画面で512TComboBoxのコントロールを同じ値のリストとともに使用することは、論理的に意味がなく、時間とリソースの無駄です。512 文字列を画面に表示するにはTListView、レポート モードやTListBox(どちらも仮想モードをサポートしているため、メモリを浪費することなく共通のデータを共有できます) など、より良い方法があります。または、インライン エディタでTValueListEditorまたはを使用します。または、本当に冒険好きなら、ゼロからカスタム コントロールを作成して、512 個の個別のコントロールではなく 1 つの効率的なコントロールを使用するようにします。512コントロールよりも優れています。TStringGridesPickListTComboBox

そうは言っても、やdoTComboBoxのような仮想モードはサポートしていませんが、 es を少し高速化するために行うことができる最適化がいくつかあります。TListBoxTListViewTComboBox

  1. TStringList同じコンテンツの 512 のコピーを作成しないでください。に追加するものはすべて、のメモリTComboBox::Items内に保存されます。TComboBoxシングルを再利用TStringListし、必要に応じてすべてを委任するように努める必要があります。この場合、TComboBox::Styleプロパティを に設定しcsOwnerDrawFixed、イベントを使用して文字列をオンデマンドでTComboBox::OnDrawItem描画できます。TStringListそれぞれに文字列を追加する必要がありますTComboBoxが、少なくとも空の文字列にすることができます。

  2. サブクラスTComboBoxを作成して仮想メソッドをオーバーライドし、ウィンドウ スタイルをCreateParams()削除すると、実際にはメモリに空の文字列を格納する必要がなくなります。CBS_HASSTRINGSTComboBox

次のようなことを試してください:

class TMyComboBox : public Vcl::Stdctrls::TComboBox
{
    typedef Vcl::Stdctrls::TComboBox inherited;

private:
    TStrings *fSharedItems;

    void __fastcall SetSharedItems(TStrings *Values)
    {
        if (fSharedItems != Values)
        {
            fSharedItems = Values;

            Items->BeginUpdate();
            try
            {
                Items->Clear();
                if (fSharedItems)
                {
                    for (int i = 0; i < fSharedItems->Count; ++i)
                        Items->Add(L"");
                }
            }
            __finally
            {
                Items->EndUpdate();
            }
        }
    }

protected:
    virtual void __fastcall CreateParams(TCreateParams &Params)
    {
        inherited::CreateParams(Params);
        Params.Style &= ~CBS_HASSTRINGS;
    }

    virtual __fastcall DrawItem(int Index, TRect Rect, TOwnerDrawState State)
    {
        // draw the items however you want...

        if (fSharedItems)
            Canvas->TextRect(Rect.Left, Rect.Top, fSharedItems->Strings[Index]);
    }

public:
    __fastcall TMyComboBox(TComponent *Owner)
        : Vcl::Stdctrls::TComboBox(Owner)
    {
        Style = csOwnerDrawFixed;
    }

    __property TStrings* SharedItems = {read=fSharedItems, write=SetSharedItems};
};

class TMyForm : public TForm
{
    ...
private:
    TStringList* targetlist;
    TMyComboBox **com;
    void __fastcall MyComboTriggerChange(TObject *Sender);
    ...
public:
    __fastcall TMyForm(TComponent *Owner);
    __fastcall ~TMyForm();
    ...
};

__fastcall TMyForm::TMyForm(TComponent *Owner)
    : TForm(Owner)
{
    targetlist = new TStringList;
    targetlist->Add("Normal");
    targetlist->Add("Inverted");

    com = new TMyComboBox*[512];
    for(int i=0;i<512;++i)
    {
        com[i] = new TMyComboBox(this);
        com[i]->Parent = this;
        com[i]->Name = String().sprintf(L"Combo_%d", i);
        com[i]->SetBounds(10, 198 + 20 * i, 130, 200);
        com[i]->SharedItems = targetlist;
        com[i]->ItemIndex = 0;
        com[i]->OnChange = &MyComboTriggerChange;
    }
}

__fastcall TMyForm::~TMyForm()
{
    delete targetlist;
    delete[] com;
}

void __fastcall TMyForm::MyComboTriggerChange(TObject *Sender)
{
    TMyComboBox *cb = static_cast<TMyComboBox*>(Sender);
    // use targetlist->Strings[cb->ItemIndex] as needed...
}
于 2016-06-27T19:32:33.780 に答える