Урок №3 - Исследование    структуры приложения MFC   

     На этом уроке мы узнаем на что похоже типичное приложение MFC, как оно использует классы приложений, документов и шаблонов документов.

     Для этого мы построим приложение HW (Hello World).

     Создание проекта HW
     Выберите из меню File (Файл) команду New (Создать), затем в диалоговом окне New перейдите во вкладку Projects (Проекты) и выберите MFC AppWizard (EXE). Введите имя проекта (HW). Щелкните на кнопке ОК.
     HW должен быть проектом с однодокументным интерфейсом (SDI); установите эту опцию в диалоговом окне AppWizard. Большинство других установок по умолчанию следует принять, за исключением нескольких, доступных при щелчке на кнопке Advanced (Дополнительно) на четвертом шаге AppWizard. В этом дополнительном диалоговом окне введите HW в качестве расширения файла (File extension) и измените заголовок основного окна (Main frame caption) на "Hello, World!".
     После этих изменений можно позволить мастеру AppWizard создать этот проект.
     Исследование объекта-приложения
     Как видим, AppWizard создал для проекта HW 5 классов. Взгляните на класс CHWApp. Этот класс порожден от CWinApp и представляет само приложение. Класс CHWApp объявляется в HW.h. Этот файл можно открыть двойным щелчком на классе CHWApp во вкладке ClassView или на имени файла во вкладке FileView. В этом объявлении можно увидеть 3 функции-члена: конструктор, перекрытую виртуальную функцию InitInstance и CAppAbout.
     В HW.cpp объявляется глобальный объект типа CHWApp с именем theApp. Когда начнется выполнение, этот объект будет сконструирован (т.е., будет вызван его конструктор).
     Функции InitApplication и InitInstance соответствуют одноразовой инициализации определенного экземпляра. Эти функции вызываются перед входом в цикл сообщений. Взгляните на HW.cpp - файл реализации класса CHWApp (чтобы открыть этот файл из ClassView, необходимо развернуть класс CHWApp и дважды щелкнуть на одной из его функций).
     В структуре создана только перекрытая версия InitInstance, но не InitApplication. Поскольку приложения Win32 запускаются в отдельных адресных пространствах, инициализации приложения (в противоположность инициализациям экземпляра) применяются редко (так как они в любом случае влияют на текущий экземпляр).
     В InitInstance проводится несколько инициализаций. Эти шаги инициализации отражают варианты выбора при создании приложения с помощью мастера AppWizard. Например, выбрано трехмерное представление по умолчанию в приложении HW; соответственно, трехмерное представление включается в InitInstance.
     Возможно, самым важным инициализационным шагом является создание шаблона документа. Объект типа CSingleDocTemplate (так как выбрано приложение SDI) создается и добавляется к шаблонам документов приложения с помощью функции AddDocTemplate. Информация, которая хранится в шаблонах документов, используется при выборе пользователем команды New из меню File. Реализация этой команды по умолчанию находится в функции CWinApp::OnFileNew. Эта функция использует информацию шаблона для определения, какие объекты необходимо создать для представления нового документа и его просмотра.
     В файлах HW.h и HW.cpp мы встретились с макросами DECLARE_MESSAGE_MAP, BEGIN_MESSAGE_MAP и END_MESSAGE_MAP. Что представляют собой эти макросы и как они связываются с основным циклом сообщений приложения в функции Run объекта приложения?
     Функция Run отправляет сообщения их окнам назначения, как и любое приложение делает это в своем основном цикле. В действительности он вызывает для этой цели ту же функцию, ::DispatchMessage. Таким образом, первым получателем сообщения всегда является окно.
     Функция обработки сообщений в объекте, способном получать сообщения обычно передает или маршрутизирует сообщения в следующем порядке:      Например, командное сообщение, которое в конце концов обрабатывается классом документа приложения, может пройти путь через его окно-рамку и окно просмотра перед тем, как его действительно достигнет обработчик сообщения в классе документа.
     Итак, макрос DECLARE_MESSAGE_MAP объявляет массив входов таблицы сообщений частью объявления класса. Макросы BEGIN_MESSAGE_MAP и END_MESSAGE_MAP заключают между собой последовательность инициализаций этого массива, представляющие собой отдельные сообщения, на которые должен отвечать класс.
     Посмотрите на входы таблицы сообщений в HW.cpp. Эти входы по умолчанию связывают несколько стандартных команд из меню File с их реализацией по умолчанию, являющейся частью класса CWinApp. Макрос ON_COMMAND - один из нескольких, упрощающих создание входа таблицы сообщений. Обычно эти входы создаются мастером классов ClassWizard автоматически; однако иногда необходимо добавить их вручную (например, при обработке специальных сообщений приложения).
     Окна-рамки, документы и окна просмотра
     В простом Windows-приложении, отличном от MFC-приложения, обычно создается одно окно, и его клиентская область представляет вывод этого приложения. Приложения MFC, с другой стороны, используют по меньшей мере два окна: окно-рамку и окно просмотра.
     Окно-рамка управляет панелью инструментов, меню и другими компонентами пользовательского интерфейса приложения. Окно просмотра, в свою очередь, предназначено для представления данных документа-приложения.
     Объект-документ не является визуальным. Этот объект представляет данные приложения и обычно соответствует содержимому файла. Объект-документ тесно взаимодействует с окном просмотра для представления данных для пользователя.
     В следующих разделах рассмотрим объявление и реализацию этих трех классов.
     Класс окна-рамки
     Окно-рамка приложения поддерживается классом CMainFrame, который объявляется в MainFrm.h.
     Здесь есть конструктор, деструктор, перекрытые PreCreateWindow и OnCreate и несколько функций отладки. Однако обратите внимание на переменные-члены этого класса: m_wndStatusBar и m_wndToolBar. Они соответствуют единственной панели инструментов и строке состояния приложения.
     Реализация CMainFrame находится в файле MainFrm.cpp. Функция-член OnCreate, которая находится в этом файле, заслуживает более пристального рассмотрения. Именно в этой функции инициализируется панель инструментов и строка состояния.
     Класс документа
     Объявление класса документа в файле HWDoc.h предусматривает перекрытие двух функций: OnNewDocument и Serialize. Функция OnNewDocument вызывается при выборе пользователем команды File, New. Хотя в приложениях MDI OnNewDocument вызывается только при создании нового объекта документа, ситуация в программах SDI несколько отличается. В этом случае OnNewDocument вызывается для повторной инициализации единственного объекта-документа приложения, т.е. множество операций инициализации, которые обычно входят в конструктор, находятся в этом методе.
     Функция Serialize вызывается при чтении или сохранении документа. Эту функцию необходимо перекрыть и написать собственный программный код сохранения и чтения данных документа в новой версии.
     Функция Serialize вызывается явно из CDocument::OnOpenDocument. Использование DECLARE_SERIALIMPLEMENT_SERIAL ) необходимо только для классов, которые считывают данные из CArchive с помощью оператора >>
     Обе перекрытые функции CHWDoc реализованы в файле HWDoc.cpp. Их реализации по умолчанию не выполняют никаких действий; необходимо самостоятельно написать программный код для инициализации документа и для чтения и сохранения его данных.
     Класс окна просмотра
     Объявление класса окна просмотра по умолчанию в HWView.h включает несколько перекрытий функций. Самой значимой из них является OnDraw. Эта функция отвечает за представление и внешний вид данных документа, соответствующего этому классу окна просмотра.
     Обратите внимание на то, что этот класс, как и класс документа, объявляется с макросом DECLARE_DYNCREATE. Использование этого макроса необходимо, так как при создании нового документа окно просмотра создается динамически.
     Реализация класса окна просмотра в HWView.cpp содержит несколько сюрпризов. Реализацию перекрытых функций необходимо написать самостоятельно. Однако для получения работающего приложения необходимо отредактировать только функцию OnDraw. Для поддержки возможностей печати нет необходимости корректировать какие-либо связанные с печатью функции, хотя это можно сделать, если процесс печати покажется неудовлетворительным.
     Обратите внимание, что здесь содержится несколько входов таблицы сообщений, связанных с печатью. Они вызывают методы базового класса, которые реализуют печать и предварительный просмотр по умолчанию.
     Ресурсы структуры приложения
     Для завершения исследования структуры MFC-приложения необходимо рассмотреть тему ресурсов, сгенерированных мастером AppWizard. Для просмотра списка ресурсов, откройте проект во вкладке ResourseView и разверните единственный отображенный элемент.
     Небольшого объяснения требует ресурс акселератора; он содержит быстрые клавиши для многих стандартных функций меню. Сама строка меню определена в единственном ресурсе меню приложения.
     AppWizard создал один ресурс диалогового окна - диалоговое окно About (О программе). Это окно отображается при выборе пользователем команды About из меню Help.
     Две сгенерированные пиктограммы включают IDR_MAINFRAME - пиктограмму приложения и IDR_HWTYPE - пиктограмму, представляющую тип документа приложения.
     Таблица строк содержит множество строк. Многие из них соответствуют сообщениям структуры MFC; другие представляют сообщения строки состояния, всплывающие подсказки и некоторые текстовые элементы для этого приложения. Особый интерес представляет строковый ресурс IDR_MAINFRAME, называемый еще строкой шаблона документа. Эта строка содержит до 9 подстрок, разделенных символом новой строки (\n). Мастер AppWizard установил для нее следующее значение:
     Общий синтаксис этой строки такой:

<эаголовок_окна>\n<имя_документа>\n<новый_файл>
\n<фильтр>\n<расширеиие_фильтра>\n
<тип_в_реестре>\n<название_типа_в_реестре>

     <заголовок_окна> - Заголовок основного окна приложения.
     <имя_документа> - Исходное имя документа для окна документа (это имя с числом будет использовано для заголовка окна).
     <новый_файл> - Тип документа, отображаемый в диалоговом окне New для приложений, поддерживающих несколько типов.
     <фильтр> - фильтр, используемый в файловых диалоговых окнах
     <расширение_фильтра> - Расширение, используемое в файловых диалоговых окнах
     <тип_в_реестре> - Тип файла, регистрирующийся в системном реестре
     <название_типа_в_реестре> - Видимое название типа файла, регистрирующееся в системном реестре
     Файл ресурсов также содержит ресурс панели инструментов и ресурс информации о версии. Обратите внимание, как несколько ресурсов делят один и тот же идентификатор IDR_MAINFRAME. Такие общие идентификаторы используются, когда приложение вызывает конструктор CStringDocTempIate (или CMultipleDocTemplate). Он определяет меню, пиктограмму, таблицу акселераторов и строку шаблона документа, соответствующих определенному типу документа.
     Добавление программного кода к приложению
     Теперь, когда мы увидели основные элементы структуры MFC, пришло время посмотреть на то, как изменить эту структуру, добавив к ней собственный программный код. Попробуем выполнить одну простую задачу. В классе документа добавим текстовое поле и проинициализируем его из ресурса; в классе окна просмотра добавим программный код для отображения этой строки в центре окна просмотра приложения.

     Добавление ресурса строки
     Откройте рабочее пространство проекта с вкладкой ResourceView и таблицу строк. Добавьте имя строки IDS_HELLO и установите ее значение "Hello World!".

     Изменение класса документа
     Первым шагом в изменении приложения будет добавление переменной в класс документа.
     Для этого необходимо отредактировать файл HWDoc.h. В разделе атрибутов добавьте объявление для следующей переменной типа CString:

     //Атрибуты public:
     CString m_sStr;

     Переменная m_sStr должна быть где-то инициализирована. Ее также необходимо добавить в функцию Serialize для обеспечения возможности сохранять и считывать ее из файла. Эти изменения необходимо сделать в файле HWDoc.cpp.
     Для гарантии повторной инициализации этой строки при каждом выборе пользователем команды New из меню File, инициализируем ее в функции OnNewDocument. Ниже показана измененная функция OnNewDocument:

     BOOL CHWDoc::OnNewDocument() {
          if (!CDocument::OnNewDocument())
          return FALSE;
          // TODO: добавьте здесь программный код повторной
          инициализации
          // (документы SDI будут повторно использовать этот
          документ)
          m_sStr.LoadString(IDS_HELLO);
          return TRUE ;
     }


     Измененная функция serialize:

     void CHWDoc::Serialize(CArchive& ar) {
          if (ar.IsStoring()) {
          // TODO: здесь добавьте программный код для сохранения
          ar << m_sStr;
     }
     else {
          // ТООО: здесь добавьте программный код для чтения
          ar >> m sStr;
     }

     Осталось отобразить данную строку. Это будет реализовано в классе окна просмотра.
     Изменение класса окна просмотра
     Для отображения строки необходимо изменить функцию OnDraw класса окна просмотра. Поскольку мастер AppWizard предоставил пустую реализацию этой функции, уже не нужно изменять объявление класса; необходимо только добавить программный код к существующей структуре функции в HWView.cpp:

     void CYAHView::OnDraw(CDC* pDC) {
          CYAHDoc* pDoc = GetDocument();
          ASSERT_VALID (pDoc) ;
          // TODO: здесь добавьте программный код для рисования
          данных
          CRect rect;
          GetClientRect(&rect) ;
          pDC->DPtoLP(&rect) ;
          pDC->DrawText(pDoc->m_sStr, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE) ;
     }


     Теперь необходимо только перекомпилировать и запустить это приложение.

Содержание

Hosted by uCoz



Смотрите также:



Hosted by uCoz