Глава 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  содержится  на  ваших
        дистрибутивных дискетах.
                              Назад | Содержание | Вперед