Советы по Delphi

         

Tabbednotebook и куча ресурсов


Тема: Как избежать использования кучи ресурсов (Resource Heap) при работе с TabbedNotebook

Данный документ расскажет о том, как с помощью Object Pascal можно управлять числом активных handlesWindows (оконных дескрипторов), в особенности кучей ресурсов пользователя (User Resource heap), а также следить за этими показателями. О чем этот документ? Попробую коротко и доходчиво: Windows следит за каждым элементом, имеющим фокус, через его дескриптор (Handle). Исходя из этого, Windows не может одновременно поддерживать несколько оконных дескрипторов (4-байтных указателей), и в этом совете мы приведем простой пример кода, позволяющего "легко" загружать ресурсы и обходить эти ограничения, встающие перед разработчиками Delphi.

USER DLL в действительности является библиоткой, распределяющей и поддерживающей ресурсы для всех окон и связанных структур данных, включая элементы управления, имеющие фокус, и другие неупомянутые объекты, но вместе с тем необходимо помнить, что эта библиотека работает под Windows. С этим связаны ограничения при работе с ресурсами USER DLL, и эта та проблема, над которой мы будем работать в этом совете. Данный пример добавляет загрузку ресурса для каждого элемента управления, добавляемого на форму, здесь мы берем 4 байта из кучи USER в 64К *.

Почему мы уверены в том, что у нас это получится? Мы будем разрушать** дескрипторы окон, которые Windows, согласно своей архитектуре, должна помнить. Разрушая эти дескрипторы, мы, таким образом, избегаем освобождения пользовательских (USER) ресурсов, это означает, что нам не нужно будет снова создавать вышеуказанные объекты. Наоборот, текущая архитектура VCL обладает способностью следить за вышеуказанными объектами, которые, в действительности, являются указателями на структуру. Так, зная, что VCL поддерживает дескриптор и windows создаст новый дескриптор КАК ТРЕБУЕТСЯ, то вместо поддержания постоянно одного дескриптора (как это подразумевалось при создании архитектуры Windows), мы можем управлять пользовательскими (USER) ресурсами вручную, позволяя разработчику легко загружать их по мере необходимости.

Данный пример демонстрирует работу с дескрипторами пользовательских (USER) ресурсов компонента Delphi TTabbedNoteBook (в части освобождения дескрипторов страниц), Delphi DestroyHandle (процедура TWinControl для удаления пользовательских (USER) дескрипторов), и работу вызова Windows API LockWindowUpdate (блокировка нежелательной перерисовки).

Технология освобождения дескриптора страницы TTabbedNoteBook может работать и с любыми потомками TWinControl. TWinControl - класс предка, который умеет создавать и разрушать оконные дескрипторы; CreateHandle & DestroyHandle.

* 64К для Win3.1 & 64К только для 16-битной подсистемы Win95. Для получения дополнительной информации обратитесь в Microsoft или к MSDN.
** Как побочный эффект при разрушении вышеописанных дескрипторов, TTabbedNotebook, используемый в данном примере, гораздо быстрее выполняет перемещение страниц.

Демонстрационный код

Следующий код с приведенными обработчиками событий является "отрывком" из большого проекта с компонентами TTimer, TTabbedNotebook (с множеством страниц) и большим разнообразием визуальных элементов управления на каждой странице компонента. (Позже мы подчеркнем преимущества кода, приведенного ниже, перед его добавлением в ваш проект) Приведенный код должен располагаться соответственно в обработчиках событий OnTimer компонента TTimer и OnChange компонента TTabbedNotebook. Вот каким должен быть ваш новый код:

<Модуль с объявленными в нем TTabbedNotebook и TTimer>

   

...
Implementation

Type
TSurfaceWin = class(TWinControl);

procedure TForm1.Timer1Timer(Sender: TObject);
begin
{Данный код заменяет заголовок формы на системную информацию,
содержащую в процентах free SYSTEM, GDI, &USER для windows.} caption := 'SYSTEM: ' +
inttostr(getfreesystemresources(GFSR_SYSTEMRESOURCES)) + ' GDI: ' + inttostr(getfreesystemresources(GFSR_GDIRESOURCES)) + ' USER: ' + inttostr(getfreesystemresources(GFSR_USERRESOURCES)); end;

procedure TForm1.TabbedNotebook1Change(Sender: TObject; NewTab:
Integer;  var AllowChange: Boolean); begin
{LockWindowUpdate запрещает перерисовку данного окна}
LockWindowUpdate(handle);

{Причина использования TSurfaceWin в том, что вызов DestroyHandle в TWinControl объявлен как абстрактный, поэтому данный вызов возможен только его потомками, реализовавшими данную процедуру. Следующая строка читает индекс текущей страницы TabbedNotebook и разрушает ее дескриптор при перемещении на другую страницу. ПРИМЕЧАНИЕ: Даже если мы уничтожаем дескриптор, Windows помнит страничный объект и переназначает/создает новый при нажатии на другой закладке. }
TSurfaceWin(TabbedNotebook1.pages.objects[tabbedNotebook1.pageindex]).DestroyHandle;

{Выключаем блокировку формы, чтобы любой элемент управления мог перерисовывать себя}
LockWindowUpdate(0);
end;

[001069]



Содержание раздела