пятница, 17 апреля 2009 г.

Ускоряем добавление элементов в ComboBox или ListBox

Это перевод Speeding up adding items to a combobox or listbox. Автор: Реймонд Чен.

Просто небольшой совет: если вы собираетесь добавить много элементов в ListBox или ComboBox, то есть несколько небольших трюков, которые вы можете сделать для существенного ускорения этой операции (заметьте: улучшения будут работать, если вы хотите добавить действительно МНОГО элементов. Конечно же, юзабилити ListBox-а с сотней элементов может быть низка, но я предполагаю, что у вас на это есть действительно хорошая причина).

Во-первых, вы можете отключить перерисовку, пока вы добавляете элементы (вообще-то, это работает для любых элементов управления):
  SetWindowRedraw(Handle, FALSE);
try
... добавляем элементы ...
finally
SetWindowRedraw(Handle, True);
InvalidateRect(Handle, nil, True);
end;
Это подавит обновление контрола при каждом добавлении нового элемента (*). Но есть и ещё кое-что, что можно сделать:

  SendMessage(hwndCombo, CB_INITSTORAGE, cItems, cbStrings);
// для ListBox используйте LB_INITSTORAGE
... добавляем элементы ...
cItems - это число элементов, которые вы собираетесь добавить, а cbStrings это суммарное кол-во памяти (в байтах), необходимое для хранения всех строк, что вы хотите вставить.

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

Некоторые люди рекомендуют использовать LockWindowUpdate, но это неверно. LockWindowUpdate отключает перерисовку в окне, которое вы ей указываете, но она не предназначена для подавления мигания в процессе обновления контролов.

Очевидное ограничение LockWindowUpdate: только одно окно может быть заблокировано в каждый момент времени. Так что, если два окна попытаются одновременно использовать трюк с LockWindowUpdate, то получится это только у одного из них. Это не слишком-то надёжно, не так ли?

LockWindowUpdate была спроектирована, чтобы помогать при перерисовке во время операций drag/drop. Если вы рисуете курсор для операции drag/drop, вы не хотите, чтобы окно под курсором начало рисоваться (и портить ваш прекрасный курсор). Поэтому вы блокируете перерисовку окна, пока вы рисуете курсор и разблокируете его, когда курсор покидает окно.

Вот почему может быть только одно заблокированное окно: в каждый момент времени может быть только одна drag/drop операция, потому что у нас есть только одна мышь.

Примечания переводчика:
(*) В Delphi, если вы используете VCL, то эта функциональность уже заключена в базовые классы. Делается это так:
  ListBox.Items.BeginUpdate;
try
... добавляем элементы ...
finally
ListBox.Items.EndUpdate;
end;

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.