在运行时创建TCombobox的更快捷方式

时间:2016-06-27 03:14:26

标签: c++ c++builder vcl c++builder-xe2 tcombobox

我想在运行时使用大量具有相同列表的组合框填充表单。它们也获得相同的事件处理程序,该处理程序根据Sender对象的名称执行操作。然而,这需要相当长的时间,我猜测我做错了什么。

我正在使用XE2 Rad Studio C ++ Builder和VCL GUI。

编辑:这些框包含不同类型的内容,并分布在表单中的几个tabPages中。但是,有必要一目了然地在至少80个中显示它所选择的内容。用TLabel替换它们并在点击TLabel选择不同的元素时创建一个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;
    }
}

我的机器上的一次迭代似乎需要大约20ms(使用std::clock进行测试),这使得这部分长约10秒。指针在表单的破坏中被删除。我只是将他们的声明放在这里进行简化。

有没有更好的方法来创建多个组合框?也许克隆它们?

1 个答案:

答案 0 :(得分:3)

认真需要重新设计您的用户界面。在一个屏幕上使用具有相同值列表的512个TComboBox控件没有逻辑意义,并且浪费时间和资源。有更好的方法可以在屏幕上显示512个字符串,例如报告模式中的TListViewTListBox(两者都支持虚拟模式,因此它们可以共享公共数据而不会浪费内存)。或者使用TValueListEditorTStringGridesPickList内嵌编辑器。或者,如果您真的喜欢冒险,可以从头开始编写自定义控件,这样您就可以使用1个有效控件而不是512个独立控件。任何东西都优于512 TComboBox个控件。

话虽如此,TComboBox不支持虚拟模式,例如TListBoxTListView,但您仍可以进行一些优化以加快TComboBox TStringList 1}} es es little:

  1. 不要制作相同TComboBox::Items内容的512份副本。您添加到TComboBox的任何内容都存储在TStringList的内存中。您应该努力重用单个TComboBox::Style并让所有内容根据需要委托给它。在这种情况下,您可以将csOwnerDrawFixed属性设置为TComboBox::OnDrawItem,并使用TStringList事件按需绘制TComboBox字符串。您仍然需要为每个TComboBox添加字符串,但它们至少可以是空字符串。

  2. 子类CreateParams()覆盖其虚拟CBS_HASSTRINGS方法并删除TComboBox窗口样式,然后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... } 实际上不需要存储空字符串它的记忆。

  3. 尝试这样的事情:

    dump