Шаг 45.
Библиотека OWL.
Обзор многодокументного интерфейса

    На этом шаге мы рассмотрим создание MDI-приложения.

    Многодокументный интерфейс в Windows предлагает программистам мощное средство управления объектами, особенно окнами документов, которое улучшает приложения. MDI-приложения не только создают своего рода минирабочую область, в которой пользователь может располагать связанные окна и пиктограммы, но и обеспечивает программиста множеством легко реализуемых функций, которые автоматически управляют этими окнами. MDI-приложения требуют несколько больших усилий при программировании, но их преимущества намного перевешивают любые дополнительные усилия.

    В Windows имеется много MDI-приложений. Что же характеризует такое приложение? Вот список наиболее важных характеристик.


Рис.1. Окно MDI-приложения

    Рисунок 1 показывает основные элементы MDI-приложения. Единственный невидимый элемент на рисунке - это окно-клиент. Окно-клиент представляет собой окно, которое обычно охватывает всю рабочую область окна обрамления. Окно-клиент является дочерним по отношению к окну обрамления, а дочерние окна MDI - это дочерние окна для окна-клиента. Управляющие элементы окна-клиента, в основном, и выполняют работу MDI-приложения. Вы можете рассматривать его как невидимый контейнер, содержащий множество элементов, включая дочерние окна, линейки прокрутки, пиктограммы, т.е. все, что должно совместно работать в MDI-приложении.

    Вы можете управлять окном-клиентом различными способами, как и любым другим окном. Например, можно изменить размеры окна-клиента, чтобы оно не занимало больше всю рабочую область окна обрамления. Учтите, что для дочерних окон MDI родительским окном является окно-клиент, а не окно обрамления, и они не могут быть передвинуты за пределы окна обрамления. При уменьшении размера окна обрамления вы ограничиваете область, в которой может функционировать дочернее окно. Фактически, именно эта характеристика взаимоотношений окна-клиента и дочернего окна делает объекты TControlBar, TMessageBar и TStatusBar из OWL видимыми. Уменьшая размер окна-клиента, OWL может вместить эти специальные окна в окно обрамления.

    Следующий пример демонстрирует работу MDI-приложения.

#include <owl\applicat.h>
#include <owl\mdi.h>
#include <owl\mdichild.h>
#include <stdio.h>
#include "pr45_1.rc"

//Класс приложения.
class TApp: public TApplication
{
  public:
	 TApp():TApplication(){}
	 void InitMainWindow();
};

//Класс окна-клиента.
class TMDIClientTWndw : public TMDIClient
{
  public:
	  TMDIClientTWndw();
  protected:
          int childNum;
          TMDIChild *InitChild();  
};

//TMDIClientTWndw::TMDIClientTWndw()
// Это конструктор окна-клиента.
TMDIClientTWndw::TMDIClientTWndw() : TMDIClient()
{
  childNum = 1;  
}

//TMDIClientTWndw::InitChild()
// Эта функция, переопределяющая функцию класса
// TMDIClient, конструирует дочернее окно MDI, родительским 
// окном которого является окно-клиент.
TMDIChild *TMDIClientTWndw::InitChild()
{
  char s[20];
  sprintf (s, "Дочернее окно #%d", childNum);
  ++childNum;
  return new TMDIChild(*this, s);
}

void TApp::InitMainWindow()
{
  // Создать окно-клиент.
  TMDIClient *clientTWndw = new TMDIClientTWndw;
  // Сконструировать главное окно.
  TMDIFrame *wndw= new TMDIFrame("MDI-приложение",MENU_1,*clientTWndw);
  // Установить значение указателя MainWindow приложения.
  SetMainWindow(wndw);
}

int OwlMain(int,char *[])
{
  return TApp().Run();
}

    Файл ресурсов:

#ifndef WORKSHOP_INVOKED
#include "windows.h"
#endif

#include <owl\mdi.rh>
#include <owl\window.rh>

#define MENU_1   100

#ifdef RC_INVOKED

MENU_1 MENU
{
  POPUP "&File"
  {
	  MENUITEM "E&xit",    CM_EXIT
  }
  POPUP "&Window"
  {
	  MENUITEM "C&reate",         CM_CREATECHILD
	  MENUITEM "&Cascade",        CM_CASCADECHILDREN
	  MENUITEM "&Title",          CM_TILECHILDREN
	  MENUITEM "Arrange &Icons",  CM_ARRANGEICONS
	  MENUITEM "C&lose All",      CM_CLOSECHILDREN
  }
}

#endif
Текст этого приложения можно взять здесь.

    После запуска этой программы вы увидите окно, подобное приведенному на рисунке 1. Оконное меню File содержит только команду Exit, а меню Window - команды Create, Cascade, Tile, Arrange Icons и Close All, которые вы, вероятно, ожидали увидеть в меню Windows приложения MDI.

    Выберите команду Create для создания нового дочернего окна MDI. После того, как вы создали несколько дочерних окон, вы можете использовать команды Cascade и Tile для размещения их соответствующим образом в окне-клиенте. Уменьшите окна до пиктограмм, расположите пиктограммы вокруг окна-клиента, а затем используйте команду Arrange Icons, чтобы выстроить пиктограммы в линию в нижней части окна-клиента. Наконец, выберите команду Close All для одновременного закрыия всех дочерних окон (вы можете использовать системное меню любого окна для закрытия только одного этого окна).

    Рассмотрим работу этой программы.

    Посмотрите сначала на функцию InitMainWindow():

void TApp::InitMainWindow()
{
  // Создать окно-клиент.
  TMDIClient *clientTWndw = new TMDIClientTWndw;
  // Сконструировать главное окно.
  TMDIFrame *wndw= new TMDIFrame("MDI-приложение",MENU_1,*clientTWndw);
  // Установить значение указателя MainWindow приложения.
  SetMainWindow(wndw);
}

    InitMainWindow() сначала конструирует окно-клиент приложения. Каждое МDI-прилоэвение OWL должно иметь окно-клиент, производное от класса TMDIClient. Это означает, что вы должны включить заголовочный файл MDICHILD.H, так же, как и MDI.H, в свою программу. Эта программа имеет собственный класс окна-клиента, который, конечно, является производным от класса TMDIClient OWL. TMDIClient, в свою очередь, является производным от TWindow и обеспечивает функции отклика на сообщения для MDI-команд в меню Window, в число которых входят CmCreateChild(), CmCreateChildren(), CmCascadeChildren() и CmTileChildren(). TMDIClient содержит также переключатели доступности команд для меню Window, поэтому вам не нужно беспокоиться насчет активизации и запрещения команд в меню Window. Наконец, функции GetActiveMDIChild() и InitChild() класса TMDIClient позволяют получить указатель на активное дочернее окно и создать пользовательские дочерние MDI-окна.

    После завершения конструирования окна-клиента программа конструирует главное окно приложения, которое должно быть объектом класса TMDIFrame (или класса, производного от TMDIFrame). Конструктор TMDIFrame имеет в качестве параметров строку заголовка, идентификатор ресурсов меню и ссылку на окно-клиент. Класс TMDIFrame происходит из TFrameWindow и обрабатывает такие задачи, как поиск и сохранение расположения меню Window пограммы. Кроме того, этот класс определяет функцию-член GetClienTWindow(), которая возвращает указатель на окно-клиент окна обрамления, и функцию SetMenu(), которую вы можете вызвать для корректировки положения меню Window после установки новой строки меню.

    Программа создает не просто окно-клиент, а, скорее, собственную версию с именем TMDIClientTWndw, происходящую из TMDIClient:

class TMDIClientTWndw : public TMDIClient
{
  public:
	  TMDIClientTWndw();
  protected:
          int childNum;
          TMDIChild *InitChild();  
};

    Этот класс имеет защищенный член-данное childNum, который содержит количество дочерних окон. Это значение используется затем в заголовке каждого дочернего окна для отличия одного дочернего окна от другого. Программа инициализирует childNum значением, равным 1, в конструкторе класса. Класс TMDIClientTWndw переопределяет функцию InitChild() из TMDIClient, чтобы создать необходимый приложению тип дочернего окна. Когда пользователь выбирает команду Create из меню Window, OWL вызывает InitChild(), чтобы создать дочернее окно:

 TMDIChild *TMDIClientTWndw::InitChild()
{
  char s[20];
  sprintf (s, "Дочернее окно #%d", childNum);
  ++childNum;
  return new TMDIChild(*this, s);
}

    Функция сначала создает строку заголовка дочернего окна. Затем она увеличивает счетчик количества дочерних окон childNum и возвращает указатель на новое окно TMDIChild. Все дочерние окна в MDI-приложениях должны быть объектами класса TMDIChild (или класса, производного от этого класса). Сам класс TMDIChild происходит из TFrameWindow. Его конструктор получает в качестве параметра ссылку на окно-клиент и строку заголовка нового дочернего окна.

    Однако существует одна хитрость для того, чтобы обеспечить выполнение такого большого объема работы OWL. Вы должны быть уверены, что идентификаторы пункта вашего меню являются значениями, определенными OWL для меню Window. Заголовочный файл ресурса MDI.RH, находящийся вместе с другими Borland файлами include, определяет ряд констант, которые вы можете использовать для этой цели. Эти константы CM_CASCADECHILDREN (24361), CM_TILECHILDREN (24362), CM_TILECHILDRENHORIZ (24363), CM_ARRANGEICONS (24364), CM_CLOSECHILDREN (24365) и CM_CREATECHILD (24366). Окно-клиент OWL уже имеет функции ответа на сообщения, которые соответствуют тем же функциям идентификаторов пункта меню.

    Далее вы увидите, как наполнить эту "скорлупу" - MDI-оболочку - и получить полнофункциональный текстовый редактор.

    На следующем шаге мы рассмотрим создание MDI-редактора.




Предыдущий шаг Содержание Следующий шаг