Более быстрый способ создания TCombobox во время выполнения

Я хочу заполнить форму во время выполнения с помощью множества комбинированных списков с одинаковыми списками. Они также получают тот же обработчик событий, который действует в зависимости от Sender Наименование объектов. Тем не менее, это занимает довольно много времени, и я догадался, что я что-то не так делаю.

Я использую XE2 Rad Studio C ++ Builder и графический интерфейс VCL.

Редактировать: Эти поля содержат различные виды контента и распределены по нескольким вкладкам внутри формы. тем не менее, необходимо отобразить то, что он выбрал, по крайней мере, 80 из них с первого взгляда. Может быть, было бы лучше заменить их на TLabels и создать TCombobox при нажатии на TLabel, чтобы выбрать другой элемент?

Код выглядит примерно так:

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;
}
}

Одна итерация, кажется, занимает около 20 мс на моей машине (проверено с std::clock), что делает эту часть длиной ~ 10 с. Указатели удаляются при уничтожении формы. Я просто разместил их декларации здесь для упрощения.

Есть ли лучший способ создать несколько комбинированных списков? Может клонировать их?

-2

Решение

Вы шутки в сторону нужно перепроектировать свой интерфейс. Используя 512 TComboBox элементы управления на одном экране с одинаковым списком значений не имеют логического смысла и являются пустой тратой времени и ресурсов. Существуют лучшие способы отображения 512 строк на экране, такие как TListView в режиме отчета или TListBox (оба они поддерживают виртуальный режим, поэтому они могут обмениваться общими данными без потери памяти). Или используйте TValueListEditor или же TStringGrid с esPickList встроенный редактор. Или, если вы действительно любите приключения, напишите собственный элемент управления с нуля, чтобы вы использовали 1 эффективный элемент управления вместо 512 отдельных элементов управления. Все лучше, чем 512 TComboBox управления.

Что, как говорится, TComboBox не поддерживает виртуальный режим, как TListBox а также TListView сделать, но есть несколько оптимизаций, которые вы можете сделать, чтобы ускорить ваш TComboBoxЭто немного:

  1. не делайте 512 копий одного и того же TStringList содержание. Все, что вы добавляете в TComboBox::Items хранится внутри TComboBoxв памяти. Вы должны стремиться повторно использовать свой сингл TStringList и пусть все делегируют ему по мере необходимости. В этом случае вы можете установить TComboBox::Style собственность на csOwnerDrawFixed и использовать TComboBox::OnDrawItem событие, чтобы нарисовать TStringList Строки по запросу. Вам все еще нужно добавить строки к каждому TComboBox, но они могут быть пустыми строками, по крайней мере.

  2. подкласс TComboBox переопределить его виртуальный 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

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

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector