AppWizard и архитектура Document-View
О принципах устройства приложения рассказывалось выше. Теперь рассмотрим, как оно создается с помощью Visual C++. Сначала разберем одно важное понятие - проект. До сих пор приложение рассматривалось, только как совокупность объектов базовых и производных классов. Но для обеспечения работы приложения требуется нечто большее - наряду с описанием классов необходимо описание ресурсов, связанных с приложением, нужна справочная система и т.п. Термин "проект" как раз и используется, когда имеется в виду такой более общий взгляд на приложение.
В среде Visual C++ можно строить различные типы проектов:
и обычных консольных приложений,
и приложений под Windows с использованием API,
и статических и динамических библиотек и т. п.
Рассмотрим только создание проектов типа MFC AppWizard. Фирма Microsoft разработала специальный инструментарий, облегчающий и ускоряющий создание проектов в среде Visual C++.
Прежде всего, нужно отметить, что создание проекта - это не только творчество, но и большой объем технической работы, требующей внимания и аккуратности. Все Windows-приложения имеют достаточно общую структуру, и, следовательно, можно построить некоторые шаблонные заготовки, подходящие для того или иного типа проектов. Построению таких заготовок способствует то, что приложения, создаваемые на основе MFC, строятся из элементов фиксированных классов. Логическим развитием этой идеи было введение специальных классов и специальной архитектуры построения приложения, которая подходила бы широкому классу приложений. О такой архитектуре уже упоминалось, когда речь шла о библиотеке MFC, - это архитектура Document-View. Она является основной, но не единственной при построении проектов в среде Visual C++. Суть ее в том, что работу многих приложений можно рассматривать как обработку документов. При этом можно отделить сам документ, отвечающий за представление и хранение данных, от образа этого документа, видимого на экране и допускающего взаимодействие с пользователем, который просматривает и (или) редактирует документ. В соответствии с этой архитектурой библиотека MFC содержит два семейства классов, производных от базовых классов CDocument и CView.
В результате появилась двухэтапная технология создания проектов. Вначале создается некая заготовка проекта с общими свойствами, подходящими для многих проектов этого типа. На втором этапе производится уже настройка, учитывающая специфику задачи. Для каждого этапа фирма Microsoft разработала свое инструментальное средство.
Начальная заготовка - остов приложения - создается в диалоге с пользователем инструментальным средством AppWizard. В процессе диалога пользователь определяет тип и характеристики проекта, который он хочет построить. Определив, какие классы из MFC необходимы для этого проекта, AppWizard строит остовы всех нужных производных классов. Построенный AppWizard остов приложения содержит все необходимые файлы для создания стартового приложения, которое является законченным приложением и обладает разумными функциональными свойствами, общими для целого класса приложений. Естественно, никаких специфических для данного приложения свойств остов не содержит. Они появятся на следующем этапе, когда программист начнет работать с остовом, создавая из заготовки свое собственное приложение. Тем не менее стартовое приложение можно транслировать и запускать на исполнение.
Термин остов (приложения, класса, функции) применяется для заготовок, создаваемых инструментальными средствами AppWizard и ClassWizard.
ClassWizard
Созданный AppWizard остов приложения составлен так, что в дальнейшей работе с проектом можно использовать другое инструментальное средство - ClassWizard (мастер классов), предназначенное для создания остовов новых производных классов. Еще одно основное назначение ClassWizard в том, что он создает остовы для переопределяемых методов. Он позволяет показать все сообщения, приходящие классу, и создать остов обработчика любого из этих сообщений. Это только две основные функции ClassWizard. Он не всесилен, но его возможности довольно велики.
Первые MFC-приложения
Первое приложение, создаваемое с использованием библиотеки классов MFC, достаточно простое. Оно отображает на экране маленькую диалоговую панель, содержащую строку текста.
В этом приложении используется единственный класс, наследованный от базового класса CWinApp.
Простое приложение
Самые простые приложения с использованием библиотеки классов MFC можно создавать без применения автоматизированных средств разработки приложений MFC AppWizard. Приведем исходный текст приложения first:
Файл first.cpp
// Включаемый файл для MFC
#include <afxwin.h>
// Класс CFirstApp - главный класс приложения.
// Наследуется от базового класса CWinApp.
class CFirstApp:public CWinApp
{
public:
// Переопределение метода InitInstance,
// предназначенного для инициализациии приложения.
virtual BOOL InitInstance();
};
// Создание объекта приложения класса CFirstApp.
CFirstApp theApp;
// Метод InitInstance
// Переопределение виртуального метода InitInstance класса CWinApp.
// Он вызывается каждый раз при запуске приложения.
BOOL CFirstApp::InitInstance()
{
AfxMessageBox("First MFC-application");
return FALSE;
}
В этом приложении определен только один класс - CFirstApp, наследованный от базового класса CWinApp. В класс CFirstApp входит метод InitInstance. Кроме того, определена одна глобальная переменная - theApp.
Для использования в приложении классов или функций библиотеки MFC необходимо включить эту библиотеку в проект приложения. Программные коды библиотеки классов MFC могут использоваться приложением двумя разными способами. Код библиотеки MFC либо непосредственно записывается в выполняемый файл приложения, либо вызывается по мере необходимости из отдельной dll-библиотеки.
Использование для приложения DLL-библиотеки немного ускоряет процесс построения проекта и позволяет создавать выполняемые файлы значительно меньшего размера. Однако сам по себе такой выполняемый файл работать не будет. Для него необходима dll-библиотека. Поэтому, если приложение будет устанавливаться и на других компьютерах, его надо распространять вместе с dll-библиотекой.
Если для создания нового приложения используется MFC AppWizard, библиотека MFC подключается автоматически. Программисту не нужно вручную вносить изменения в проектный файл в этом случае.
Рассмотрим, как работает приложение first на уровне исходного текста. Сначала в текст приложения включается файл afxwin.h. В этом файле определены классы, методы, константы и другие структуры для библиотеки классов MFC. Кроме того, включаемый файл afxwin автоматически подключает другой файл - windows.h, необходимый для вызовов функций стандартного программного интерфейса Windows.
Сравним исходный текст приложения first с аналогичным приложением, созданным без использования библиотеки классов MFC. В этом приложении присутствует главная функция приложения WinMain, которая вызывается, когда пользователь или операционная система запускает приложение:
#include <windows.h>
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
// Отображение диалоговой панели.
MessageBox(NULL,"First MFC-application","Message",MB_OK);
// Завершение работы приложения
return 0;
}
Если посмотреть на текст программы first, то там нет хорошо знакомой функции WinMain. Не видно также переменных, представляющих параметры этой функции.
В приложениях, основанных на классах MFC, функция WinMain скрыта от программиста в определении класса CWinApp. В каждом приложении определяется главный класс приложения, наследуемый от базового класса CWinApp. Приложение должно иметь только один объект главного класса приложения, наследованного от класса CWinApp.
Класс CWinApp выполняет все действия, которые обычно выполняет функция WinMain, - инициализирует приложение, обрабатывает сообщения и завершает приложение. Для этого класс CWinApp включает виртуальные методы InitApplication, InitInstance, Run и ExitInstance.
Чтобы выполнить инициализацию приложения, функция WinMain вызывает методы InitApplication и InitInstance для объекта главного класса приложения. Метод InitApplication выполняет инициализацию на уровне приложения. Программист может переопределить этот метод в своем приложении. Метод InitInstance выполняет инициализацию каждой копии приложения. Обычно этот метод создает главное окно приложения. Программист должен обязательно переопределить этот метод в своем приложении. Остальные методы, например Run, можно не переопределять.
Затем функция WinMain начинает обрабатывать цикл сообщений. Для этого вызывается метод Run. Можно переопределить этот метод, чтобы реализовать собственный цикл обработки сообщений.
Когда приложение заканчивает работу и цикл обработки сообщений завершается, вызывается метод ExitInstance. Программист может переопределить этот метод, чтобы выполнить какие-либо действия перед завершением приложения.
В случае приложения first главный класс приложения, который называется CFirstApp, определяется следующим образом:
class CFirstApp:public CWinApp
{
public:
virtual BOOL InitInstance();
};
Этот класс наследуется от базового класса CWinApp. При этом базовый класс указан как public. Это означает, что в программе доступны все элементы базового класса CWinApp, объявленные как public. Можно вызывать методы класса CWinApp для объектов класса CFirstApp и обращаться к элементам данных класса CWinApp.
В объявлении класса CFirstApp объявлен виртуальный метод InitInstance. Этот метод переопределяется в приложении. Изначально метод InitInstance определен в классе CWinApp. Он отвечает за инициализацию приложения. Он вызывается каждый раз, когда пользователь запускает приложение. Если пользователь запустит приложение несколько раз, то метод InitInstance будет вызываться каждый раз.
Метод InitInstance обязательно должен быть переопределен в главном классе приложения. Остальные виртуальные методы можно оставить без изменения.
Сразу после объявления главного класса приложения создается объект theApp этого класса:
CFirstApp theApp;
Объект главного класса приложения должен быть определен как глобальный. В этом случае он будет создан сразу при запуске приложения и сможет управлять всей работой приложения. После создания глобального объекта вызывается функция WinMain, определенная в классе CWinApp. Она выполняет свои обычные функции - регистрирует классы окон, создает окно и т.д.
Нельзя создавать два или более объекта класса, наследованного от базового класса CWinApp. Каждое приложение должно иметь один и только один объект главного класса приложения.
Метод InitInstance главного класса приложения CFirstApp служит для инициализации. Он вызывается автоматически всякий раз, когда запускается очередная копия приложения. В приложении first метод InitInstance используется для вывода на экран диалоговой панели при помощи функции AfxMessageBox:
BOOL CFirstApp::InitInstance()
{
AfxMessageBox("First MFC-application");
return FALSE;
}
Функция AfxMessageBox определена в библиотеке классов MFC. Вместо функции AfxMessageBox можно воспользоваться функцией MessageBox программного интерфейса Windows.
Когда из приложения, созданного с использованием классов MFC, вызываются функции программного интерфейса API Windows, часто надо указывать перед именем функции символы ::. Например, вызов функции MessageBox может выглядеть следующим образом:
::MessageBox(NULL,"First MFC-application","Message",MB_OK);
В конце метода InitInstance вызывается оператор return и возвращается значение FALSE. Приложение сразу же завершается. Если метод InitInsatnce вернет значение TRUE, приложение продолжит свою работу и приступит к обработке очереди сообщений.