Глава 9. Интерфейсные объекты
Объекты, представляющие окна, диалоговые окна и управляющие
элементы, называются интерфейсным объектами. В данной главе об-
суждаются общие требования к интерфейсным объектам и их поведе-
ние, а также взаимодействие с реальными окнами, диалоговыми бло-
ками и выводимыми на экран управляющими элементами.
В этой главе поясняется также взаимосвязь между различными
интерфейсными объектами приложения, а также механизм передачи со-
общений Windows.
Примечание: Приводимый здесь материал относится к ок-
нам, диалоговым блокам и управляющим элементам.
Для чего нужны интерфейсные объекты?
-----------------------------------------------------------------
Для чего нужны интерфейсные объекты, если в Windows уже есть
окна, диалоговые блоки и управляющие элементы?
Одна из основных трудностей программирования в Windows - это
достаточно сложная работа с визуальными элементами. Иногда вам
нужно послать в окно сообщение, в другой раз - вызвать функцию
API Windows. Для разных типов элементов экрана соглашения будут
различными.
ObjectWindows уменьшает большую часть этих сложностей, пре-
доставляя объекты, инкапсулирующие элементы экрана и избавляющие
вас от необходимости иметь дело непосредственно с Windows. К тому
же они обеспечивают более удобный интерфейс.
Что делают интерфейсные объекты?
-----------------------------------------------------------------
Интерфейсные объекты предоставляют методы для создания, ини-
циализации, управления и уничтожения соответствующих элементов
экрана, и имеют содержащие данные поля, включая описатель интер-
фейсного элемента и его порождающего и дочернего окна. Методы
объекта берут на себя многие детали программирования в Windows.
Взаимосвязь объект/элемент во многом аналогична связи файла
DOS с переменной Паскаля. Имея файл, вы можете присвоить файловую
переменную, представляющую физическую структуру фактического фай-
ла на диске, а затем работать с этой файловой переменной. С по-
мощью ObjectWindows вы можете определить объект, представляющий
физическое окно, управляющий элемент или диалоговый блок, который
фактически обслуживается администратором окон Windows. Вы работа-
ете с объектом, а он берет на себя функции по обслуживанию эле-
мента экрана.
Общий интерфейсный объект
-----------------------------------------------------------------
Все интерфейсные объекты ObjectWindows наследуют из единс-
твенного абстрактного объектного типа TWindowsObject, который
определяет поведение, общее для окна, диалога и объектов управля-
ющих элементов, видоизменяемых и специализируемых в производных
объектных типах TDialog, TWindow и TControl.
В качестве общего предка всех интерфейсных объектов методы
TWindowsObject обеспечивают единообразный способ поддержки взаи-
мосвязи между объектами и элементами экрана (включая создание и
уничтожение объектов), обслуживают соотношения "родитель-потомок"
между интерфейсными объектами и регистрируют новый классы Windows
(см. Главу 10).
Новые типы, производные от TWindowsObject, определяются ред-
ко, но он служит основой объектно-ориентированной модели окон. Он
определяет большинство наследуемых объектами функциональных воз-
можностей, когда вы получаете из TWindow и TDialog новые типы.
Создание интерфейсных объектов
-----------------------------------------------------------------
Задание полного интерфейсного объекта с соответствующими ин-
терфейсными элементами требует двух шагов:
* Построения объекта.
* Создания элемента экрана.
Первым шагом является вызов конструктора Init, который стро-
ит интерфейсный объект и устанавливает его атрибуты, такие как
стиль и меню.
Второй шаг заключается в вызове метода создания окна объекта
приложения, MakeWindow, связывающего интерфейсный объект с новым
элементом экрана. Эта связь поддерживается полем HWindow экрана
(описателем окна).
Примечание: Об описателях окон рассказывается в Главе 7
"Иерархия ObjectWindows".
MakeWindow вызывает метод Create объекта, который всегда со-
общает Windows о необходимости создания элемента на экране.
Create создает также метод SetupWindow, который инициализирует
интерфейсный объект путем создания, например, дочерних окон.
Допустимость описателя окна
-----------------------------------------------------------------
Обычно в Windows вновь созданный интерфейсный элемент полу-
чает (от Windows) сообщение wm_Create, на которое требуется отве-
тить инициализацией. Интерфейсный объект ObjectWindows не будет
получать сообщений wm_Create, поэтому не забудьте определить для
инициализации метод SetupWindow.
Если инициализация интерфейсного объекта требует описателя
элемента экрана (например, для вызова функции API Windows), то
она не должна вызываться раньше SetupWindow. То есть, перед вызо-
вом SetupWindow поле HWindow интерфейсного объекта не является
допустимым и использоваться не должно. Если вы хотите вызывать
функцию API или нечто требующее описателя окна, не вызывайте их
в конструкторе Init. Поместите такие вызовы в метод SetupWindow.
|<----HWindow допустим--->|
| |
|<-------------------интерфейсный объект допустим---------->|
--+-----------------------------------------------------------+-->
^ ^ ^ ^ ^
| | | | |
Init вызывает | | | |
наследуемый Init | | | |
| | Done |
SetupWindow вызывает наследуемый |
SetupWindow | Done вызывает наследуемый
| метод Done
|
Наследуемый SetupWindow вызывает Create
Рис. 9.1 Когда окно имеет допустимый описатель.
Видимость на экране
-----------------------------------------------------------------
Создание интерфейсного объекта и соответствующего визуально-
го элемента не обязательно означает, что вы что-то видите на эк-
ране. Когда метод Create указывает Windows на создание элемента
экрана, Windows проверяет, включает ли стиль окна ws_Visible. Ес-
ли да, то интерфейсный элемент будет выводиться. В противном слу-
чае он будет скрытым.
ws_Visible и другие стили окна обычно устанавливаются или
сбрасываются конструктором Init в поле Attr.Style объекта.
В любой момент после создания элемента экрана вы можете вы-
вести или скрыть его, вызвав метод Show интерфейсного объекта.
Уничтожение интерфейсных объектов
-----------------------------------------------------------------
Как и в случае создания интерфейсный объектов, их уничтоже-
ние предполагает выполнение двух шагов:
* Уничтожение визуального интерфейсного элемента (Destroy).
* Уничтожение интерфейсного объекта (Dispose).
Уничтожением экранного элемента занимается метод Destroy ин-
терфейсного объекта, который делает следующее: он вызывает функ-
цию Windows DestroyWindow, чтобы избавиться от элемента экрана, и
устанавливает поле HWindow объекта в 0. Таким образом, проверив
указатель, вы можете сообщить, связан ли еще объект с элементом
экрана.
Уничтожить элемент экрана вы можете без уничтожения объекта
(если хотите создавать и выводить его снова).
Примечание: Уничтожение самого окна обычно не требует-
ся. Это делается автоматически при закрытии окна.
Когда пользователь закрывает на экране окно, ObjectWindows
обнаруживает, что данный элемент экрана уничтожен, устанавливает
поле HWindow соответствующего объекта в 0 и вызывает деструктор
объекта Done.
Связь порождающего и дочернего объектов
-----------------------------------------------------------------
В приложении Windows совместная работа элементов экрана
(окон, диалоговых блоков и управляющих элементов) обеспечивается
с помощью связей "родитель-потомок". Порождающие окна управляют
своими дочерними окнами, а Windows отслеживает эти связи.
ObjectWindows поддерживает параллельный набор связей между соот-
ветствующими интерфейсными объектами.
Дочернее окно - это элемент экрана (оно не обязано быть ок-
ном), который управляется другим элементом экрана. Например, бло-
ки списка обслуживаются окном или диалоговым блоком, в котором
они выводятся. Они выводятся на экран только при выводе их порож-
дающих окон. Диалоговые блоки, в свою очередь, являются дочерними
окнами, управляемыми порождающими их окнами.
Когда вы перемещаете или закрываете порождающее окно, дочер-
ние окна автоматически закрываются, и в некоторых случаях переме-
щаются в нем. Конечным предком всех дочерних интерфейсных элемен-
тов является основное окно, хотя вы можете иметь окна и диалоги
без порождающих окон.
Порождающими окнами могут быть только диалоговые блоки и ок-
на, но не порождающие элементы. Дочерним окном может быть любой
интерфейсный элемент.
Список дочерних окон
-----------------------------------------------------------------
Когда вы строите объект дочернего окна, то можете в качестве
параметра конструктора Init можете задать порождающее окно (при-
мер вы можете найти в Главе 10). Объект дочернего окна отслежива-
ет свое порождающее окно через указатель на его поле Parent. Он
отслеживает также объекты его дочерних окон, сохраненные в поле
ChildList. Дочернее окно, на которое в данный момент установлен
ChildList, является последним созданным дочерним окном.
Построение дочерних окон
-----------------------------------------------------------------
Как и в случае интерфейсных объектов, объекты дочерних окон
создаются в два этапа (построение объекта и создание элемента эк-
рана). Объекты порожденного окна следует строить с помощью конс-
труктора Init порождающего окна. Например, объект окна, наследую-
щий из TWindow и содержащий командную кнопку должен иметь пример-
но следующий вид:
constructor TMyWindow.Init(AParent: PWindowsObject;
ATitle: PChar);
begin
inherited Init(AParent, ATitle);
TheButton := New(PButton, Init(@Self, id_TheButton,
'Текст кнопки', 20, 10, 100, 25, True));
end;
Обратите внимание на использование указателя Self для связи
дочернего объекта (TheButton) с порождающим (экземпляром
TMyWindow). Конструктор интерфейсного объекта автоматически до-
бавляет к своему списку дочерних окон новые объекты.
Создание дочерних элементов экрана
-----------------------------------------------------------------
Когда построен список дочерних элементов интерфейсного объ-
екта, создание элементов экрана для дочерних окон выполняется ав-
томатически. Создание родительского окна (через вызов MakeWindow)
включает в себя вызов метода SetupWindow порождающего окна. Одним
из наследуемых действий SetupWindow является вызов для каждого из
окон в списке дочерних окон методов SetupWindow.
Примечание: Автоматическое создание можно запретить.
См. ниже раздел "Запрещение автоматического создания".
При создании нового производного объектного типа нужно пом-
нить об инициализации объекта в SetupWindow после вызова наследу-
емого метода SetupWindow, например:
procedure TMyCheckBox.SetupWindow;
begin
inherited SetupWindow; { сначала по умолчанию }
.
.
. { выполнить инициализацию объекта }
end;
Уничтожение дочерних окон
-----------------------------------------------------------------
Вызов деструктора порождающего окна приводит к вызову дест-
рукторов всех его дочерних окон, так что вашей программе не нужно
явно вызывать деструкторы дочернего окна. Это же справедливо для
метода CanClose, который возвращает True только после вызова
CanClose для всех его дочерних окон.
Запрещение автоматического создания
-----------------------------------------------------------------
Чтобы явно исключить дочернее окно из механизма автоматичес-
кого создания и вывода, вызовите после его создания метод
DisableAutoCreate. Чтобы явно добавить в механизм создания и вы-
вода дочернее окно (такое как диалоговый блок, который при нор-
мальном выводе будет исключен), вызовите после построения его ме-
тод EnableAutoCreate.
Итерация дочерних окон
-----------------------------------------------------------------
Иногда желательно написать методы, для реализации функции
выполняющие итерации по каждому дочернему окну данного окна. Нап-
ример, можно проверить в окне все кнопки с независимой фиксацией.
В этом случае используйте метод TWindowsObject.ForEach:
procedure TMyWindow.CheckAllBoxes;
procedure CheckTheBox(ABox: PWindowsObject); far;
begin
PCheckBox(ABox)^.Check;
end;
begin
ForEach(@CheckTheBox);
end;
Использование метода ForEach (и аналогичных методов
FirstThat и LastThat) похоже на применение методов с аналогичными
названиями в TCollection. Хотя ObjectWindows не использует наборы
для обслуживания дочерних окон, методы итерации работают анало-
гично.
Поиск определенного дочернего окна
-----------------------------------------------------------------
Иногда желательно иметь методы, выполняющие итерацию по
списку окон в поиске конкретного окна. Например, в окне с нес-
колькими кнопками вам может потребоваться найти первую установ-
ленную кнопку с независимой фиксацией. В этом случае метод
TWindowsObject.FirstThat можно записать так:
function TMyWindow.GetFirstChecked: PWindowsObject;
function IsThisOneChecked(ABox: PWindowsObject): Boolean;
far;
begin
IsThisOneChecked := (ABox^.GetCheck = bf_Checked);
end;
begin
GetFirstChecked := FirstThat(@IsThisOneChecked);
end;
Назад | Содержание | Вперед