Глава 14. Объекты MDI
Многодокументальный интерфейс (MDI) - это стандарт интерфей-
са для приложений Windows, которые позволяют пользователю однов-
ременно работать с несколькими открытыми документами. Документ, в
этом смысле, это обычно связанная с файлом задача, например, ре-
дактирование текстового файла или работа с файлом электронной
таблицы. В приложениях MDI пользователь может, например, иметь
несколько открытых файлов в одном приложении. Возможно, что вы
уже использовали приложения MDI: Microsoft Excel, администратор
программ Windows, администратор файлов Windows. Стандарт MDI яв-
ляется также частью спецификации общего доступа пользователя
(CUA) фирмы IBM.
ObjectWindows предусматривает объекты, позволяющие легко пи-
сать приложения MDI.
Что такое приложение MDI?
-----------------------------------------------------------------
Имеются определенные компоненты, которые присутствуют в каж-
дом приложении MDI. Чаще всего основное окно вызывает окно с рам-
кой. В области клиента окна-рамки есть невидимое окно - окно кли-
ента MDI - которое содержит дочернее окно, вызывающее дочерние
окна MDI. Это очень важно, т.к. обработка дочерних окон MDI про-
исходит скрытно от пользователя.
+-----------------------------------------------------------+-+-+
|#=#XXXXXXXXXXXXXXXXXXXXMDI ConformistXXXXXXXXXXXXXXXXXXXXXX|^|v|
+-----------------------------------------------------------+-+-|
| MDI Children |
+---------------------------------------------------------------|
|+---------------------------------------------------+ |
||##################Child #1#########################| |
|+---------------------------------------------------| |
|| +--+---------------------------------------------------+ |
|| | X|####################Child #2#######################| |
|| +--+---------------------------------------------------| |
|| | +--+-----------------------------------------------+-+-+|
|| | | X|#=#XXXXXXXXXXXXXXXXChild #3XXXXXXXXXXXXXXXXXXXX|^|v||
|+----| +--+-----------------------------------------------+-+-||
| | | +---+ ^ ||
| | | | X | CanClose блоки минимизации и ---+ ||
| +----| +---+ максимизации ||
| | ^ ||
| +-----------------------------+---------------------+|
| дочернее окно MDI -+ |
| +---+ |
| | <+--- пиктограмма |
| +---+ |
| Child #4 ^ |
+----------------------------+----------------------------------+
| ^
окно клиента MDI -+ |
окно-рамка MDI -+
Рис. 14.1 Компоненты приложения MDI.
Меню дочернего окна
-----------------------------------------------------------------
Строка меню окна-рамки содержит меню, управляющее дочерними
окнами MDI. Меню дочернего окна содержит такие элементы как Tile
(Вывод без перекрытия), Cascade (Вывод с перекрытием), Arrange
(Упорядочить) и Close All (Закрыть все). Имя каждого открытого
окна MDI автоматически добавляется к концу этого меню с выбором
текущего окна.
Дочерние окна MDI
-----------------------------------------------------------------
Каждое дочернее окно MDI имеет некоторые характеристики пе-
рекрывающего окна. Его можно максимизировать до полного размера
окна клиента MDI или минимизировать в пиктограмму, которая поме-
щается к нижней границе окна-рамки. Дочернее окно MDI никогда не
выходит за границы его окна-рамки (обрамляющего окна). Дочернее
окно MDI не может иметь меню, поэтому все его функции реализуются
меню окна-рамки. Заголовок каждого дочернего окна MDI часто
представляет собой имя открытого файла, связанного с этим окном,
хотя его поведение заранее неизвестно и определяется программой.
Можно рассматривать приложение MDI как мини-сеанс Windows, когда
несколько приложений представлены окнами или пиктограммами.
Окна MDI в ObjectWindows
-----------------------------------------------------------------
ObjectWindows определяет типы для представления рамок MDI и
клиентов MDI. Это соответственно TMDIWindow и TMDIClient.
TMDIWindow является производным от TWindow, но TMDIClient на са-
мом деле представляет собой управляющий элемент и является произ-
водным от TControl. В приложении MDI ObjectWindows, окно-рамки
владеет своим окном клиента MDI и хранит его в поле ClientWnd.
Окно-рамка также содержит каждое из дочерних окон MDI в связанном
списке ChildList. Дочерние окна MDI являются экземплярами типа
объекта, производного от написанного вами TWindow.
Методы TMDIWindow занимаются в основном конструированием и
управлением дочерними окнами MDI, окном клиента MDI и обработкой
выбора в меню. Главная работа TMDIClient происходит скрытно от
пользователя и состоит в управлении дочерними окнами MDI. При
разработке приложений MDI вы в общем случае будете создавать но-
вые производные типы для своих рамок и дочерних окон соответс-
твенно от TMDIWindow и TWindow.
Построение приложения MDI
-----------------------------------------------------------------
Построение приложения MDI в ObjectWindows представляет собой
относительно простую задачу:
* Построение основного окна MDI.
* Установка меню дочернего окна.
* Предоставление основному окну возможности создания дочер-
них MDI.
Окно MDI обрабатывает для вас все специфические функции, а
ваши функции, специфические для приложения, могут перейти в до-
черние окна.
Построение рамки MDI
-----------------------------------------------------------------
Окно-рамка MDI всегда является основным окном приложения,
поэтому оно конструируется в методе InitMainWindow его объекта
приложения. Однако, существует два аспекта рамки MDI, которые от-
личают его от других основных окон:
* Рамка MDI всегда является основным окном, поэтому оно ни-
когда не имеет порождающего окна. Таким образом,
TMDIWindow.Init нет необходимости воспринимать в качестве
параметра указатель порождающего окна.
* Окно-рамка MDI всегда должно иметь меню, так что вторым
параметром Init является описатель меню. Для основных
окон, отличных от MDI и производных от TWindows, вы опре-
деляете Init для установки Attr.Menu в допустимый описа-
тель меню. TMDIWindow.Init устанавливает для вас AttrMenu.
Типичный метод InitMainWindow для приложения MDI может выг-
лядеть следующим образом:
procedure TMDIApplication.InitMainWindow;
begin
MainWindow := New(PMyFrame, Init('Заголовок рамки',
LoadMenu(HInstance, 'MenuName'));
Если предположить, что TMyFrame - это потомок TMDIWindow,
при этом будет создаваться окно-рамка MDI с заголовком "Заголовок
рамки" и строкой меню, заданной ресурсом "MenuName".
Создание меню дочерних окон
-----------------------------------------------------------------
Меню окна-рамки должно включать в себя меню дочернего окна в
стиле MDI. Открытие дочернего окна MDI добавляет его заголовок к
меню дочернего окна, а закрытие дочернего окна удаляет его из
списка. Это позволяет пользователю активизировать любое дочернее
окно, даже если оно не является видимым.
Окно-рамка должно знать, каким элементом меню верхнего уров-
ня является меню его дочернего окна. Объект TMDIWindow хранит це-
лое значение позиции в поле объекта ChildMenuPos. TMDIWindow.Init
первоначально устанавливает ChildMenuPos в ноль, указывая край-
ний левый элемент меню верхнего уровня. Однако, для установки по-
зиции ChildMenuPos вы можете переопределить Init для своего про-
изводного от TMDIWindow типа:
constructor TMyMDIWindow.Init(ATitle: PChar; AMenu: HMenu);
begin
inherited Init(ATitle, AMenu);
ChildMenuPos := 1;
end;
TMDIWindow.Init также вызывает InitClientWindow для констру-
ирования объекта TMDIClient, который будет служит его окном кли-
ента MDI. TMDIWindow.SetupWindow создает окно клиента MDI.
Создание дочерних окон MDI
-----------------------------------------------------------------
TMDIWindow определяет автоматический метод реакции
CreateChild, который вызывается при выборе из меню варианта, ре-
зультатом которого будет команда с идентификатором Create_Child.
Обычно этот вариант меню называется New или Create. Как это опре-
делено в TMDIWindow, CreateChild конструирует и создает дочернее
окно MDI типа TWindow вызовом TMDIWindow.InitChild. Для задания
корректного типа дочернего окна (производного от TWindow), пере-
определим InitChild для вашего типа окна-рамки MDI:
function MyMDIWindow.InitChild: PWindowsObject;
begin
InitChild:=New(PMyChild, Init(@Self,
'Новое дочернее окно'));
end;
Автоматические дочерние окна
-----------------------------------------------------------------
Может потребоваться, чтобы ваша окно-рамка воспроизводило
только одно дочернее окно MDI при своем первом появлении. Для
этого первого дочернего окна вы можете явно задать его размер. В
отличие от других дочерних окон, дочерние окна MDI должны быть
сконструированы и созданы в методе SetupWindow окна-рамки MDI, а
не в Init. Вы также должны явно создать экранный элемент дочерне-
го окна с помощью вызова MakeWindow:
procedure MyMDIWindow.SetupWindow;
var
ARect: TRect;
NewChild: PMyChild;
begin
TMDIWindow.SetupWindow;
NewChild:=PMyChild(InitChild);
GetClientRect(HWindow, ARect);
with NewChild^.Attr, ARect do
begin
W:=(right*4) div 5;
H:=(bottom*3) div 5;
Title:='Child #1';
end;
Application^.MakeWindow(NewChild);
end;
В некоторых приложениях вам может потребоваться создать до-
чернее окно MDI в ответ на более чем один выбор в меню. Например,
пункты меню New и Open в редакторе файла могут приводить к воз-
никновению нового дочернего окна с заголовком в виде имени файла.
В этом случае определите для построения дочернего окна методы ав-
томатической реакции. ObjectWindows определяет команды
cm_MDIFileOpen и cm_MDIFileNew, что облегчает дифференциацию от
стандартных cm_FileOpen и cm_FileNew.
Управление дочерним окном MDI
-----------------------------------------------------------------
Тип окна MDI в ObjectWindows содержит методы манипулирования
дочерними окнами MDI приложения MDI. Хотя большая часть скрытой
работы делается в TMDIClient, доступ к данным и функциям происхо-
дит через метод TMDIWindow.
TMDIWindow определяет методы реакции на сообщения Windows,
которые автоматически реагируют на выбор команды стандартного ме-
ню MDI: Title, Cascade, Arrange Icon и Close All. Эти методы ожи-
дают основанных на командах сообщений с заранее определенными
константами идентификаторов меню. Обязательно используйте эти
идентификаторы при построении ресурса меню дочернего окна:
Стандартные методы, команды и действия MDI Таблица 14.1
+----------------+------------------------+---------------------+
| Действие | Константа ID меню | Метод TMDIWindow |
+----------------+------------------------+---------------------|
| Tile | cm_TileChildren | CM_TileChildren |
| Cascade | cm_CascadeChildren | CM_CascadeChildren |
| Arrange Icons| cm_ArrangeChildIcons | CM_ArrangeChildIcons|
| Close All | cm_CloseChildren | CM_CloseChildren |
+----------------+------------------------+---------------------+
Методы реакции TMDIWindows, подобные CMTileChildren, вызыва-
ют другие методы TMDIWindows, такие как CMChildren. Эти методы
вызывают методы TMDIClient с тем же именем, например,
TMDIClient^.TileChildren. Для переопределения такого автоматичес-
кого поведения нужно переопределить TMDIWindow.TileChildren или
другой метод TMDIWindow. Для дочерних окон MDI не подходит реаги-
рование на основанные на командах сообщения, генерируемые меню
дочернего окна.
Настройка активизации дочернего окна
-----------------------------------------------------------------
Пользователь приложения MDI может свободно активизировать
любое открытое или минимизировать дочернее окно MDI. Однако, вам
может потребоваться предпринять некоторые действия, когда пользо-
ватель дезактивирует одно дочернее окно активизацией другого.
Например, меню окна-рамки может отражать текущее состояние актив-
ного дочернего окна, выделяя его цветом. Каждый раз, когда дочер-
нее окно становится активным или неактивным, оно получает сообще-
ние Windows wm_MDIActivate. Определив метод реакции на это с об-
щение для дочернего окна, вы можете отслеживать, какое дочернее
окно активно и соответственно реагировать.
Обработка сообщений в приложении MDI
-----------------------------------------------------------------
Как и для обычных порождающих и дочерних окон, основанные на
командах и дочерних идентификаторах сообщения Windows сначала
поступают в дочерние окна для их восприятия и обработки. Затем
сообщения поступают в порождающее окно. Однако, в случае приложе-
ния MDI сообщения поступают к текущему дочернему окну MDI, затем
к окну клиента MDI, и, наконец, к окну-рамке MDI (которое являет-
ся порождающим окном для всех дочерних окон MDI). Следовательно,
меню окна-рамки можно использовать для управления работой в теку-
щем активном дочернем окне MDI. Затем шанс отреагировать получают
окно клиента и окно-рамка.
Пример приложения MDI
-----------------------------------------------------------------
Программа MDITest создает приложение MDI, показанное на
Рис. 14.1. Полный текст файла MDITEST.PAS содержится на ваших
дистрибутивных дискетах.
Назад | Содержание | Вперед