ООП. Лабораторная работа 10. Многодокументные (MDI) приложения. MDI приложения позволяют в рамках окна главной формы (MDI frame window) работать с неограниченным количеством дочерних окон, содержащих документы различного типа (пример - Word, Excel). Шаг 1. Создайте новый проект (File/New Application). Дайте форме имя FrameForm (свойство Name) и измените ее заголовок на MDI Application. Установив свойство FormStyle на значение fsMDIForm сделайте форму обрамляющей формой многодокументного приложения. Шаг 2. С помощью команды меню File/New Form добавьте к проекту дочернюю форму. Дайте ей имя ChildForm и установите ее заголовок MDI Child. Установив свойство FormStyle на значение fsMDIChild сделайте форму дочерней (подчиненной) формой многодокументного приложения. Сохраните проект и его формы (File/Save All). Проекту дайте имя MDIAppl.dpr, модулю обрамляющей формы - MDIFrame.pas, а модулю дочерней -MDIChild.pas. Шаг 3. По умолчанию, попытка закрытия дочернего окна приводит к его сворачиванию. Для реализации полного закрытия дочернего окна в событии OnClose замените значение параметра Action, управляющего порядком закрытия окон, с caMinimize (свернуть окно) на caFree (закрыть окно): procedure TMDIChild.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; Шаг 4. Для организации обращения между обрамляющей и дочерними формами обеспечим взаимную видимость их модулей. Для этого из обрамляющей формы FrameForm командой File/Use Unit подключите модуль MDIChild.pas, а из дочерней ChildForm - модуль обрамляющей формы MDIFrame.PAS. Если обрамляющая и дочерняя имеют собственные меню, то при открытии дочерней формы набор ее меню добавляются к набору меню обрамляющей формы. Порядок образования объединенного меню определяется свойством GroupIndex (групповой номер) компонента TMenuItem: объединенные меню располагаются в порядке возрастания значений свойства GroupIndex; меню дочерней формы заменяют меню главной формы с тем-же значением GroupIndex; группы меню с одинаковым GroupIndex добавляются или заменяются целиком. Шаг 5. Установите на обрамляющей форме компонент MainMenu и двойным щелчком вызовите у него окно Дизайнера Меню. Создайте два меню: File, состоящее из пунктов New, Open, пустой (-), Exit и меню Window, состоящее из пунктов Tile и Cascade. Шаг 6. На дочерней форме также установите компонент MainMenu. В окне Дизайнера Меню с помощью команды Insert From Template... всплывающего меню (щелчок правой кнопки мыши) вставьте из шаблона расширенный вариант меню File и меню Edit. Шаг 7. Для организации правильного объединения меню форм установите следующие значения их свойств GroupIndex. В форме FrameForm File1.GroupIndex = 0 Window1.GroupIndex = 6. В форме ChildForm File1.GroupIndex = 0 Edit1.GroupIndex = 1. Шаг 8. Запустите приложение. Дочерняя форма открылась автоматически. Внимательно изучите содержимое набора меню. Определите, меню какой формы представлены и объясните, почему так получилось. Закройте дочернее окно и также изучите набор меню. Шаг 9. Откажитесь от автоматического и выберите “ручной” способ открытия дочерней формы. Для этого в окне настройки параметров проекта (меню Project/Options) на странице Forms переведите пункт ChildForm из списка Auto-Create Forms в список Available Forms: Для манипулирования дочерними формами во время работы приложения доступны следующие свойства обрамляющей формы: Свойство Тип Описание MDIChildren [i :Integer] TForm Массив дочерних форм в порядке их создания. MDIChildCount Integer Количество открытых дочерних форм. ActiveMDIChild TForm Активная дочерняя форма. Шаг 10. Опишите процедуру открытия новой дочерней формы, вызываемую выбором команды File/New меню обрамляющей формы (обработчик события OnClick пункта New в форме FrameForm: procedure TFrameForm.New1Click(Sender: TObject); begin with TChildForm.Create(Self) do Caption := Caption + ' ' + IntToStr(Self.MDIChildCount); end; Здесь первой строкой вызывается метод создания дочерней формы типа TChildForm; в скобках указано имя владельца этой дочерней формы - Self (сама, т.е. обрамляющая форма). Во второй строке к заголовку дочерней формы добавляется ее номер - количество открытых дочерних форм. Шаг 11. Т.к. после открытия дочерней формы ее меню File заменит соответствующее меню обрамляющей формы, то определим реакцию на выбор пункта меню File/New для дочерних форм: procedure TChildForm.New1Click(Sender: TObject); begin FrameForm.New1.Click; end; Шаг 12. В обрамляющей форме в обработчиках выбора пунктов Tile и Cascade меню Window запишите по одной строке Tile; и Cascade; соответственно. Эти методы изменяют расположение дочерних окон. Шаг 13. Для того, чтобы в меню Window был представлен список имен открытых дочерних окон установите имя объекта, отвечающего за этот пункт (Window1) в качестве значения свойства WindowMenu обрамляющего окна. Шаг 14. Для примера работы с отдельными дочерними окнами определим реакцию на выбор пункта меню File/Close для дочерних форм: procedure TChildForm.Close1Click(Sender: TObject); begin with FrameForm do if ActiveMDIChild <> nil then ActiveMDIChild.Close; end; Здесь необходимость первой строки вызвана тем, что ссылка на активную дочернюю форму ActiveMDIChild является свойством обрамляющей формы. Шаг 15. Готовый шаблон MDI-приложения можно просто загрузить из Хранилища Объектов (File/New/Project). Опробуйте данный способ. Изучите обработчики пунктов меню Window. Задание. Разместите на дочернем окне редактор Memo и дополните созданное MDIприложение следующими пунктами меню: FrameForm - Window/Set Red Color – окрашивает фон редактора Memo текущего окно в красный цвет. FrameForm - Window/Minimize all – сворачивает все подчиненные окна (если сразу не получится, посмотрите, как это сделано в шаблоне MDI - приложения). FrameForm - Window/Restore all – восстанавливает свернутые подчиненные окна. FrameForm - Window/Close all – закрывает все подчиненные окна. FrameForm - Window/Table – открывает параллельное окно с информационной таблицей (TStringGrid). В таблице должны быть представлены номер, заголовок, размеры и состояние (свернутое, распахнутое, нормальное) всех подчиненных окон приложения. Любое изменение в массиве подчиненных окон должно одновременно отображаться в таблице (если открыто данное окно).