Многодокументальный интерфейс (MDI) - это стандарт интерфейса для приложений Windows, которые позволяют пользователю одновременно работать с несколькими открытыми документами. Документ, в этом смысле, это обычно связанная с файлом задача, например, редактирование текстового файла или работа с файлом электронной таблицы. В приложениях MDI пользователь может, например, иметь несколько открытых файлов в одном приложении. Возможно, что вы уже использовали приложения MDI: Microsoft Exel, администратор программ Windows, администратор файлов Windows. Стандарт MDI является также частью спецификации общего доступа пользователя (CUA) фирмы IBM. ObjectWindows предусматривает объекты, позволяющие легко писать приложения MDI.
Имеются определенные компоненты, которые присутствуют в
каждом приложении MDI. Чаще всего основное окно вызывает окно с
рамкой. В области клиента окна-рамки есть невидимое окно - окно
клиента MDI - которое содержит дочернее окно, вызывающее дочерние
окна MDI. Это очень важно, т.к. обработка дочерних окон MDI
происходит скрытно от пользователя.
    Строка меню окна-рамки содержит меню, управляющее дочерними
окнами MDI. Меню дочернего окна содержит такие элементы как Tile
(Вывод без перекрытия), Cascade (Вывод с перекрытием), Arrange
(Упорядочить) и Close All (Закрыть все). Имя каждого открытого
окна MDI автоматически добавляется к концу этого меню с выбором
текущего окна.
    Каждое дочернее окно MDI имеет некоторые характеристики
перекрывающего окна. Его можно максимизировать до полного размера
окна клиента MDI или минимизировать в пиктограмму, которая
помещается к нижней границе окна-рамки. Дочернее окно MDI никогда не
выходит за границы его окна-рамки (обрамляющего окна). Дочернее
окно MDI не может иметь меню, поэтому все его функции реализуются
меню окна-рамки. Заголовок каждого дочернего окна MDI часто
представляет собой имя открытого файла, связанного с этим окном,
хотя его поведение заранее неизвестно и определяется программой.
Можно рассматривать приложение MDI как мини-сеанс Windows, когда
несколько приложений представлены окнами или пиктограммами.
    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 в ObjectWindows представляет собой
относительно простую задачу:
    Окно MDI обрабатывает для вас все специфические функции, а
ваши функции, специфические для приложения, могут перейти в
дочерние окна.
    Окно-рамка MDI всегда является основным окном приложения,
поэтому оно конструируется в методе InitMainWindow его объекта
приложения. Однако, существует два аспекта рамки MDI, которые
отличают его от других основных окон:
    * Рамка MDI всегда является основным окном, поэтому оно
никогда не имеет порождающего окна. Таким образом,
TMDIWindow.Init нет необходимости воспринимать в качестве
параметра указатель порождающего окна.
    * Окно-рамка MDI всегда должно иметь меню, так что вторым
параметром Init является описатель меню. Для основных
окон, отличных от MDI и производных от TWindows, вы
определяете Init для установки Attr.Menu в допустимый
описатель меню. TMDIWindow.Init устанавливает для вас AttrMenu.
    Типичный метод InitMainWindow для приложения MDI может
выглядеть следующим образом:
    Если предположить, что TMyFrame - это потомок TMDIWindow,
при этом будет создаваться окно-рамка MDI с заголовком "Заголовок
рамки" и строкой меню, заданной ресурсом "MenuName".
    Меню окна-рамки должно включать в себя меню дочернего окна в
стиле MDI. Открытие дочернего окна MDI добавляет его заголовок к
меню дочернего окна, а закрытие дочернего окна удаляет его из
списка. Это позволяет пользователю активизировать любое дочернее
окно, даже если оно не является видимым.
    Окно-рамка должно знать, каким элементом меню верхнего
уровня является меню его дочернего окна. Объект TMDIWindow хранит
целое значение позиции в поле объекта ChildMenuPos. TMDIWindow.Init
первоначально устанавливает ChildMenuPos в ноль, указывая
крайний левый элемент меню верхнего уровня. Однако, для установки
позиции ChildMenuPos вы можете переопределить Init для своего
производного от TMDIWindow типа:
    TMDIWindow.Init также вызывает InitClientWindow для
конструирования объекта TMDIClient, который будет служит его окном
клиента MDI. TMDIWindow.SetupWindow создает окно клиента MDI.
    TMDIWindow определяет автоматический метод реакции
CreateChild, который вызывается при выборе из меню варианта,
результатом которого будет команда с идентификатором Create_Child.
Обычно этот вариант меню называется New или Create. Как это
определено в TMDIWindow, CreateChild конструирует и создает дочернее
окно MDI типа TWindow вызовом TMDIWindow.InitChild. Для задания
корректного типа дочернего окна (производного от TWindow),
переопределим InitChild для вашего типа окна-рамки MDI:
    Может потребоваться, чтобы ваша окно-рамка воспроизводило
только одно дочернее окно MDI при своем первом появлении. Для
этого первого дочернего окна вы можете явно задать его размер. В
отличие от других дочерних окон, дочерние окна MDI должны быть
сконструированы и созданы в методе SetupWindow окна-рамки MDI, а
не в Init. Вы также должны явно создать экранный элемент
дочернего окна с помощью вызова MakeWindow:
    В некоторых приложениях вам может потребоваться создать
дочернее окно MDI в ответ на более чем один выбор в меню. Например,
пункты меню New и Open в редакторе файла могут приводить к
возникновению нового дочернего окна с заголовком в виде имени файла.
В этом случае определите для построения дочернего окна методы
автоматической реакции. ObjectWindows определяет команды
cm_MDIFileOpen и cm_MDIFileNew, что облегчает дифференциацию от
стандартных cm_FileOpen и cm_FileNew.
    Тип окна MDI в ObjectWindows содержит методы манипулирования
дочерними окнами MDI приложения MDI. Хотя большая часть скрытой
работы делается в TMDIClient, доступ к данным и функциям
происходит через метод TMDIWindow.
    TMDIWindow определяет методы реакции на сообщения Windows,
которые автоматически реагируют на выбор команды стандартного
меню MDI: Title, Cascade, Arrange Icon и Close All. Эти методы
ожидают основанных на командах сообщений с заранее определенными
константами идентификаторов меню. Обязательно используйте эти
идентификаторы при построении ресурса меню дочернего окна:
    Методы реакции TMDIWindows, подобные CMTileChildren,
вызывают другие методы TMDIWindows, такие как CMChildren. Эти методы
вызывают методы TMDIClient с тем же именем, например,
TMDIClient^.TileChildren. Для переопределения такого
автоматического поведения нужно переопределить TMDIWindow.TileChildren или
другой метод TMDIWindow. Для дочерних окон MDI не подходит
реагирование на основанные на командах сообщения, генерируемые меню
дочернего окна.
    Пользователь приложения MDI может свободно активизировать
любое открытое или минимизировать дочернее окно MDI. Однако, вам
может потребоваться предпринять некоторые действия, когда
пользователь дезактивирует одно дочернее окно активизацией другого.
Например, меню окна-рамки может отражать текущее состояние
активного дочернего окна, выделяя его цветом. Каждый раз, когда
дочернее окно становится активным или неактивным, оно получает
сообщение Windows wm_MDIActivate. Определив метод реакции на это с
общение для дочернего окна, вы можете отслеживать, какое дочернее
окно активно и соответственно реагировать.
Что такое приложение MDI?
Рис. 14.1 Компоненты приложения MDI.Меню дочернего окна
Дочерние окна MDI
Окна MDI в ObjectWindows
Построение приложения MDI
Построение рамки MDI
procedure TMDIApplication.InitMainWindow;
begin
MainWindow := New(PMyFrame, Init('Заголовок рамки',
LoadMenu(HInstance, 'MenuName'));
Создание меню дочерних окон
constructor TMyMDIWindow.Init(ATitle: PChar; AMenu: HMenu);
begin
inherited Init(ATitle, AMenu);
ChildMenuPos := 1;
end;
Создание дочерних окон MDI
function MyMDIWindow.InitChild: PWindowsObject;
begin
InitChild:=New(PMyChild, Init(@Self,
'Новое дочернее окно'));
end;
Автоматические дочерние окна
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
Действие Константа ID меню Метод TMDIWindow Tile cm_TileChildren CM_TileChildren Cascade cm_CascadeChildren CM_CascadeChildren Arrange Icons cm_ArrangeChildIcons CM_ArrangeChildIcons Close All cm_CloseChildren CM_CloseChildren Настройка активизации дочернего окна