17.3. РОДИТЕЛЬСКИЕ И ДОЧЕРНИЕ КОМПОНЕНТЫ

Класс TControl со своими наследниками образуют всю палитру видимых компонентов Delphi. Терминологически они называются элементами управления, так как на их основе прежде всего реализуются управляющие элементы Windows - кнопки, переключатели, списки и т. п. В тексте книги я часто буду употреблять слова компонент и элемент как синонимы.

Как уже отмечалось, некоторые из наследников TControl обладают дескрипторами окон и способны получать и обрабатывать Wwdows-сообщения, другие окон не имеют, но обязательно включаются в состав оконных компонентов, которые управляют ими, согласуясь с требованиями (сообщениями) Windows. Оконные элементы управления обладают специальной оконной функцией, в которую Windows посылает управляющие сообщения (например, извещения о манипуляции пользователя с мышью или о нажатии клавиш клавиатуры). В терминологии Windows такие элементы называются родительскими, а связанные с ними неоконные элементы - дочерними. Замечу, что оконный компонент может выступать как родительский не только по отношению к неоконным компонентам, но и к оконным. В этом случае он просто транслирует управляющие сообщения Windows в оконные функции дочерних компонентов. Обязательным требованием Windows является визуальная синхронизация дочерних элементов: они не могут выходить из границ своего родителя и появляются и исчезают вместе с ним. Иными словами, родитель с дочерними элементами рассматривается Windows как единое целое.

Класс TControl определяет свойство parent, которое содержит ссылку на родительский компонент:

property Parent: TWinControl;

Это свойство не следует путать с собственником owner: owner создал компонент (не обязательно - видимый), a parent управляет видимым компонентом. поскольку конструктор TComponent. Create не изменяет свойства parent (в родительском классе TComponent такого свойства нет), при создании видимых компонентов на этапе прогона программы это свойство необходимо изменять программно. Например, Следующий обработчик События OnCreate формы Form1 вставит надпись дочерний элемент в левый верхний угол формы:

procedure TFormI.FormCreate(Sender: TObject);

var

IbLabel: TLabel;

begin

IbLabel := TLabel.Create(Self);

IbLabel.Parent := Self;

IbLabel.Caption := 'Дочерний элемент';

end;

Если убрать оператор

IbLabel.Parent := Self;

метка никогда не узнает о том, что пришла пора прорисовать себя на экране, и ее текст не будет виден. Наоборот, изменение свойства parent подключает метку к списку дочерних элементов формы, и оконная функция формы обратится к нужному методу метки, чтобы заставить ее появиться на экране в момент появления самой формы. (Замечу, что приведенный выше пример является образчиком того, как не надо программировать: локальная переменная IbLabel будет уничтожена после выхода из процедуры FormCreate, содержащийся в ней указатель будет безвозвратно потерян для программы, и она никогда не сможет освободить связанные с меткой ресурсы памяти[ На самом деле ресурсы будут автоматически освобождены при завершении работы программы. ]. Правильнее было бы расположить переменную IbLabel вне процедуры, например, в секции public класса TForm1, чтобы в обработчике события OnDestroy формы выполнить вызов деструктора метки.)

Помимо свойства components каждый оконный компонент получает от своего родителя TWinControl свойство property Controls[Index: Integer]: TControl; содержащее список дочерних элементов.

Свойство

property ControlCount: Integer;

возвращает количество дочерних элементов (длину массива controls). Работать со списком controls можно с помощью следующих методов:

function ContainsControl( Control: TControl): Boolean; | Возвращает True, если компонент Control является дочерним элементом
function ControlAtPos(constPos: TPoint; AllowDisabled: Boolean): TControl; | Возвращает ссылку на компонент, которому принадлежит точка с координатами Роз. Если AllowDisabied=True, поиск ведется также среди запрещенных для выбора компонентов
function FindNextControl ( Curcontrol: TWinControl; GoForward, CheckTabStop, CheckParent: Boolean): TWinControl; | Ищет новый элемент в списке Controls. Cur-control определяет начальную позицию поиска; GoForward=True, если поиск идет от начальной позиции к концу списка; CheckTab Stop=True, если поиск идет только среди компонентов со свойством TabStop=True; если checkParent=True, поиск идет только среди оконных элементов
procedure GetTabOrderListfList: TList) ; | Создает список List всех дочерних компонентов в порядке их выбора клавишей Tab
procedure InsertCon- trol(AControl: TControl); | Вставляет новый дочерний элемент в список Controls. Программа не должна обращаться непосредственно к этому методу: для вставки дочернего элемента следует установить нужное значение свойства Parent во вставляемом компоненте
procedure NotifyControls(Msg: Word) ; | Посылает сообщение Msg во все дочерние оконные компоненты
procedure PaintControls(DC: HDC; First: TControl); | Перерисовывает все дочерние компоненты начиная с компонента First. Каждый дочерний компонент получает дескриптор графического устройства DC, с помощью которого он сможет прорисовать себя
procedure Realign; | Перерисовывает все компоненты со свойством Align не равным noAlign. Вызывается после изменения размеров родительского компонента.
procedure Repaint; | Перерисовывает родительский компонент и все его дочерние компоненты
procedure ScaleControls(M, D:Integer) ; | Перерисовывает все дочерние элементы с раз мерами, измененными в M./D раз по сравнению с предыдущими размерами
procedure SelectFirst; | Выбирает первый в порядке обхода клавишей Tab дочерний компонент
procedure SelectNext(CurControl: TWinControl; GoForward, CheckTabStop: Boolean) ; | Выбирает очередной в порядке обхода клавишей Tab дочерний компонент. CurControl определяет начальную точку поиска; GoForward= True, если поиск идет к концу списка; CheckTabStop=True, если выбираются только компоненты со свойством TabStop=True
procedure SetChildOrder(Child:TComponent; Order: Integers- | Устанавливает новый порядок выбора клавишей Tab компонента Child
procedure ShowControl(AControl:TControl); | Показывает дочерний компонент Acontrol

В некоторых случаях бывает необходимо послать сообщение в собственную оконную функцию, чтобы заставить компонент выполнить действия, не предусмотренные набором его свойств и методов. Для посылки сообщения служит метод

function Perform(Msg, WParam: Word; LParam: Longint): Longint;

Параметры обращения к методу соответствуют параметрам вызова оконной функции: Msg - код сообщения; WParam, LParam - уточняющие параметры.