Опубликован: 10.03.2009 | Уровень: специалист | Доступ: платный
Лекция 2:

Библиотека классов MFC

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

Microsoft Foundation Classes (MFC). Иерархия классов

Примеры программ для лекции.

MFC – это библиотека классов, написанных на языке C++. MFC является оболочкой для Win32 API и содержит многоуровневую иерархию классов. Не все функции Win32 API включены в MFC. С другой стороны, эта библиотека классов охватывает большую часть функциональных возможностей Windows, и предоставляет разработчику ряд дополнительных механизмов для проектирования и создания программных продуктов.

На вершине иерархии MFC находится единственный базовый класс – CObject. Все остальные классы библиотеки MFC можно условно разбить на две группы: производные и не производные от него. Чаще всего, создание нового MFC-приложения поручается мастеру MFC Application Wizard. Мастер генерирует основной скелет приложения, который впоследствии заполняется нужным кодом, давая готовое приложение.

Основные классы MFC

Некоторые классы MFC порождаются непосредственно от CObject. Наиболее широко используемыми среди них являются CCmdTarget, CFile, CDC, CGDIObject и CMenu. Класс CCmdTarget предназначен для обработки сообщений. Класс CFile предназначен для работы с файлами. Класс CDC обеспечивает поддержку контекстов устройств. В этот класс включены практически все функции графики GDI. CGDIObject является базовым классом для различных GDI-объектов, таких как перья, кисти, шрифты и другие. Класс СMenu предназначен для работы меню.

Класс CCmdTarget

От класса CCmdTarget порождается очень важный класс CWnd. Он является базовым для создания всех типов окон, включая масштабируемые ("обычные") и диалоговые, а также различные элементы управления. Наиболее широко используемым производным классом является CFrameWnd. В большинстве программ главное окно создается с помощью именно этого класса. От класса CCmdTarget, через класс CWinThread, порождается единственный из наиболее важных классов, обращение к которому в MFC-программах происходит напрямую, это класс CWinApp. Это один из фундаментальных классов, поскольку предназначен для создания самого приложения. В каждой программе имеется один и только один объект этого класса. Как только он будет создан, приложение начнет выполняться.

Класс CWinApp

Класс CWinApp является базовым классом, на основе которого образуют обязательный объект – приложение Windows. Основными задачами объекта этого класса являются инициализация и создание главного окна, а затем опрос системных сообщений. Иерархия класса CWinApp: CObject -> CCmdTarget -> CWinThread -> CWinApp

Класс CWnd

Класс CFrameWnd ("окна-рамки") и производные от него классы определяют окна-рамки на мониторе. Элементы управления, создаваемые при проектировании интерфейса пользователя, принадлежат семейству классов элементов управления. Появляющиеся в процессе работы приложения диалоговые окна – это объекты классов, производных от CDialog. Классы CView, CFrameWnd, CDialog и все классы элементов управления наследуют свойства и поведение своего базового класса CWnd ("окно"), определяющего, по существу, Windows-окно. Этот класс, в свою очередь, является наследником базового класса CObject ("объект"). Как правило, структура приложения определяется архитектурой Document-View (документ-вид). Это означает, что приложение состоит из одного или нескольких документов – объектов, классы которых являются производными от класса CDocument (класс "документ"). С каждым из документов связаны один или несколько видов – объектов классов, производных от CView (класс "вид" ), и определяющих методы обработки объектов класса документа.

Соглашение об именах MFC

В качестве префикса, обозначающего имя класса, библиотека MFC использует заглавную букву "C" (от слова "class"), за которой идет имя, характеризующее назначение класса. Например:

  • CWinApp – класс, определяющий приложение;
  • CWnd – базовый класс для всех оконных объектов;
  • CDialog – класс диалога.

При определении имен функций-членов классов используется три варианта:

  1. Имя объединяет глагол и существительное – DrawText (нарисовать текст).
  2. Имя состоит только из существительного – DialogBox (блок диалога).
  3. Для функций, предназначенных для преобразования одного типа в другой, используются такие имена, как XtoY (из X в Y).

Для членов классов библиотеки MFC используется следующий способ назначения имен: обязательный префикс m_ (от class member – член класса), за которым идет префикс, характеризующий тип данных, и завершается все заданием содержательного имени переменной. Например, m_pMainWnd – указатель на класс главного окна. Для переменных, которые не являются членами класса, m_ не ставится.

Включаемые файлы

AFXWIN.H – содержит описание основных классов библиотеки и сводит воедино все включаемые файлы, необходимые для работы MFC.

AFX.H – содержит описания классов общего назначения, макросы, базовые типы данных MFC.

AFXRES.H – подключает стандартные идентификаторы ресурсов.

Обработка сообщений в MFC

Операционная система Windows взаимодействует с приложением, посылая ему сообщения. Таким образом, обработка сообщений является ядром всех приложений. В традиционных приложениях Windows (написанных с использованием только API), каждое сообщение передается в качестве аргументов оконной функции. В оконной функции, с помощью оператора switch, определяется тип сообщения, извлекается информация и производятся нужные действия. Используя библиотеку MFC, все это можно сделать проще.

Карта сообщений

Для создания стандартного окна в приложении должен наследоваться класс от CFrameWnd. Он содержит конструктор и макрос DECLARE_MESSAGE_MAP(). Макрос декларирует карту сообщений, которая определяет, какая член-функция класса должна вызываться в ответ на сообщение Windows. Этот макрос применяется для любого окна, в котором обрабатываются сообщения. Он должен быть последним в декларировании класса, использующего карту сообщений. В конце программы помещается реализация карты сообщений:

BEGIN_MESSAGE_MAP(CMainWnd /*класс окна*/, CFrameWnd /*класс-предок*/) END_MESSAGE_MAP()

Первый макрос всегда имеет два параметра, первый – класс окна, второй – класс, от которого порожден класс окна. В данном примере карта сообщений пустая, то есть все сообщения обрабатывает MFC.

В библиотеке MFC все возможные сообщения разделены на три основные категории:

  1. сообщения Windows;
  2. извещения элементов управления;
  3. командные сообщения (команды).

В первую категорию входят сообщения, имена которых начинаются с префикса WM_, за исключением WM_COMMAND. Во вторую категорию входят извещения (notification messages) от элементов управления и дочерних окон, направляемых родительским окнам. Третья категория охватывает все сообщения WM_COMMAND, называемых командами (командными сообщениями), от объектов интерфейса пользователя, который включает меню, кнопки панелей инструментов и акселераторы.

В MFC включен набор предопределенных функций – обработчиков сообщений, которые можно использовать в программе. Если программа содержит такую функцию, то она будет вызываться в ответ на поступившее, связанное с ней, сообщение. При наличии дополнительной информации в сообщении, она передается в качестве аргументов функции. Для организации обработки сообщений нужно выполнить следующие действия:

  • Включить в карту сообщений программы команду соответствующего сообщения.
  • Включить прототип функции-обработчика в описание класса, ответственного за обработку данного сообщения.
  • Включить в программу реализацию функции-обработчика.

Включение макрокоманд в карту сообщений

Чтобы программа могла ответить на сообщение, в карту сообщений должна быть включена соответствующая макрокоманда. Названия макрокоманд соответствуют именам стандартных сообщений Windows, но дополнительно имеют префикс ON_ и заканчиваются парой круглых скобок. Из этого правила есть исключение: сообщению WM_COMMAND соответствует макрокоманда ON_COMMAND(...). Причина в том, что это сообщение обрабатывается особым образом. Чтобы включить макрокоманду в очередь сообщений, необходимо поместить ее между командами BEGIN_MESSAGE_MAP(…) и END_MESSAGE_MAP(). Например, если необходимо обработать в программе сообщение WM_CHAR, то очередь должна выглядеть так:

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)
ON_WM_CHAR()
END_MESSAGE_MAP()

В очереди может находиться более одной макрокоманды. Сообщение WM_CHAR генерируется при нажатии алфавитно-цифровой клавиши на клавиатуре.

Включение обработчиков сообщений в описание класса Каждое сообщение, явно обрабатываемое в программе, должно быть связано с одним из обработчиков.

Обработчик – это член-функция класса, вызываемая приложением в ответ на сообщение, связанное с ней с помощью карты сообщений.

Прототипы для обработчиков всех сообщений заранее заданы в MFC. Например, объявим класс с обработчиком сообщения WM_PAINT. Это сообщение посылается окну, когда оно должно перерисовать свою клиентскую область.

Пример:

Class CMainWnd: public CFrameWnd 
{
public:
  CMainWnd();
  afx_msg void OnPaint();
  DECLARE_MESSAGE_MAP()
}

Спецификатор afx_msg означает объявление обработчика сообщения. На данный момент он не используется и представляет собой пустой макрос. Но в будущем возможны расширения. Поэтому использование спецификатора нужно считать обязательным. Для каждого обработчика должна быть описана его реализация. В ней могут производиться самые разные действия, которые требуются по логике работы программы.

Сообщение WM_PAINT

Операционная система Windows устроена таким образом, что за обновление содержимого окна отвечает программа. Например, если часть окна была перекрыта другим окном, а затем вновь открыта, или минимизированное окно было восстановлено, то окну посылается сообщение WM_PAINT. В ответ на него окно должно обновить свою клиентскую область. Прототип обработчика WM_PAINT следующий:

afx_msg void OnPaint();

Макрокоманда называется ON_WM_PAINT().

Для примера создадим обработчик, который выводит строку "Использование OnPaint()" в клиентскую область по координатам x = 25, y = 25:

afx_msg void CMainWnd::OnPaint()
{
  CPaintDC paintDC(this);
  paintDC.TextOut(25, 25, CString("Использование OnPaint()"));
}

В обработчике WM_PAINT нужно всегда пользоваться классом CPaintDC, который представляет собой класс клиентской области, но предназначенный для использования именно с этим сообщением. Это обусловлено архитектурой самой Windows. Функция TextOut(…) предназначена для вывода текста в контекст устройства (в данном случае – в окно). При ее использовании, по умолчанию первые два параметра определяют координаты верхнего левого угла текстовой строки. По умолчанию координаты представляют собой реальные пиксели, ось x направлена слева направо, ось y – сверху вниз. Эта функция перегруженная, наиболее удобный для нас вариант – когда третий параметр имеет тип CString. Этот класс входит в MFC и является очень удобной заменой для строк, завершаемых нулем. Большинство реальных окон (за исключением диалогов) должны обрабатывать сообщение WM_PAINT. Более того, если Вы хотите написать корректную программу, то весь вывод в окно должен осуществляться только в обработчике WM_PAINT. В случае получения контекста из обработчика WM_PAINT с помощью класса CPaintDC, Windows гарантирует наличие свободного контекста.

Жанат Агайдаров
Жанат Агайдаров
Казахстан
Сергей Пузырев
Сергей Пузырев
Украина