Основы mfc


Содержание

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

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

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

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

Класс 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 , то очередь должна выглядеть так:

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

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

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

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

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

Сообщение WM_PAINT

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

afx_msg void OnPaint();

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

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

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

Создание проектов MFC

Создание проектов MFC

После того как были рассмотрены основные вопросы объектно-ориентированного программирования в eVC, можно перейти к обсуждению создания проектов на основе MFC (Microsoft Foundation Classes).

MFC создавались как стройная иерархия классов, позволяющая в полной мере использовать такое преимущество объектно-ориентированного программирования, как повторное использование кода, инкапсулированного в объекты. Проанализировав основные паттерны программирования в Windows, программисты Microsoft выделили наиболее часто используемые объекты, модели поведения приложений и шаблоны кода, на основе которых они создали свою объектную иерархию. Эта иерархия дала возможность разработчикам сосредоточить свое внимание на реализации логики работы приложения, а не деталей его функционирования. С другой стороны, MFC производит стандартизацию основных операций и стиля программирования. Когда разработчик программирует в MFC, он получает в свое распоряжение большое количество шаблонов и мастеров, но взамен вынужден ограничить свою свободу дополнительными правилами, такими, например, как отказ от множественного наследования внутри иерархии классов MFC.

Структура MFC образует дополнительный программный слой между приложением и Windows API. Конечно, MFC не заставляет разработчика выбирать между использованием WinAPI и MFC, просто для большинства стандартных случаев ему предлагается более логичный и менее трудоемкий путь.

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

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

Диаграмму, в которой отображены все классы MFC, можно увидеть на сайте Microsoft по адресу http://msdn.microsoft.conn/library/default.asp7urN/library/en-us/vcnnfc98/htnnl/mfcHierarchyChart.asp. Также можно просто открыть сайт msdn.microsoft.com, перейти в раздел Library, набрать в строке поиска MFC, в результатах поиска выбрать тему Microsoft Foundation Class Library и на тематической странице выбрать ссылку Hierarchy chart.

Это действительно впечатляющее зрелище. В классы MFC «завернут» практически весь Windows API. Подавляющее число классов MFC являются наследниками класса CObject, хотя в правой части таблицы можно увидеть отдельный набор классов, не подпадающих под это общее правило.

Надо отметить, что далеко не все классы, отображенные на этой диаграмме входят в состав MFC для Windows CE. В разделе справки Microsoft Foundation Class Library for Windows CE.NET ? Guide to MFC for Windows CE.NET ? Unsupported MFC Classes указаны классы, которые отсутствуют в мобильной версии Windows. Для многих из этих классов в Windows CE определен собственный аналог, а некоторые просто отсутствуют. Раздел справки Differences from Desktop MFC дает полное описание замен и исключений, которые сделаны в мобильной версии MFC.

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

Класс CObject является базовым классом для большинства классов MFC. Когда разработчик создает в приложении MFC свои собственные классы, он должен наследовать их от CObject.

В классе CObject заложено несколько базовых свойств, которые поддерживаются всеми классами MFC. Они перечислены в следующем списке.

? Сериализация – одна из мощнейших возможностей MFC. Любой объект может сохранить себя в архиве, а затем восстановиться из него. Для устройств с весьма ограниченным объемом рабочей памяти это жизненно важное свойство. Кроме того, в качестве объектов могут выступать и объекты документов, что помогает сохранять в нужные моменты информацию в архив. Сериализация реализуется в CObject методами IsSerializableO и SerializeO.

? Run-time class information – получение информации о классе, из которого создан объект во время выполнения. Эта возможность реализована при помощи функций GetRuntimeClassO и IsKindOfO. Она создает преимущества в преобразовании типов и полиморфном применении объектов.

? Object diagnostic output – позволяет в любой момент вызвать для объекта метод DumpO, который выведет в отдельный объект значения указанных полей. Эта возможность может очень пригодиться во время отладки. Метод DumpO для каждого создаваемого объекта должен программировать разработчик. Также диагностика состояния объекта реализуется методом AssertValidO.

? Классы CObList и СОЬАггау, предназначенные для работы с типом CObject, позволяют создавать коллекции и массивы объектов, формат которых совместим с другими классами коллекций или массивами.

Поскольку этими свойствами обладает класс, стоящий на вершине иерархии классов MFC, то все остальные классы также наделены этими свойствами.

Для создания простейшего MFC-приложения нужен только этот класс, поскольку объект этого класса и есть само приложение. Класс CWi пАрр отвечает за создание, инициализацию и запуск объекта приложения. Функция InitlnstanceO создает основное окно приложения и должна быть переписана, если разработчик создает приложение MFC вручную. Отметим, что руководство программиста eVC не рекомендует «ручной» режим создания приложений и классов, настоятельно советуя использовать встроенные средства.

Этот класс отвечает за то, как будет отображаться информация на экране. Именно поэтому необходимо переопределить в классе CView метод OnDrawO.

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

? Класс CCtrlView обеспечивает поддержку архитектуры documentview за счет дочерних классов CEditView, CListView и CTreeView.

? Класс CEditView обеспечивает представление документа в виде простого многострочного текстового редактора. Этот класс может использоваться в роли компонента Memo.

? Класс CListView отвечает за представление информации в виде списка.

? Класс CTreeView отображает информацию в виде дерева.

? Класс CFormView создает диалоговое окно, которое может содержать другие элементы управления.

? Класс CScrollView – это класс CView с поддержкой полос прокрутки.

В этом объекте хранится абстрактное представление данных. Сам объект типа CDocument никогда не появляется перед пользователем. Пользователь взаимодействует с объектом документа через ассоциированный с ним объект CView. Базовые возможности объекта CDocument перечислены в следующем списке.

? Сохранение и загрузка документа.

? Хранение списка объектов CView, ассоциированных с документом.

? Хранение названия и пути документа.

? Поддержка флага модификации, показывающего, сохранены ли внесенные в документ изменения.

Ассоциированный с документом объект CView формирует изображение документа в окне и позволяет обрабатывать действия пользователя. С одним документом могут быть связаны несколько объектов CView для разного способа отображения документа.

Этот класс позволяет реализовать окно приложения. Достаточно обширный список его возможностей приведен ниже.

? Обработка приходящих сообщений и передача их подчиненным компонентам.

? Контроль поведения, размещения и отображения подчиненных компонентов.

? Поддержка справочного контекста и горячих клавиш.

? Поддержка операций drag-and-drop.

? Стандартные операции рабочего окна приложения.

Этот класс должен так связать между собой объекты типа CFrameWnd, CView и CDocument, чтобы в результате получить именно то, что пользователь обычно называет документом. Результатом работы класса CDocTemplate будет текстовый файл, электронная таблица или графическое изображение, открытые в окне с соответствующими пунктами меню и инструментами.

Национальная библиотека им. Н. Э. Баумана
Bauman National Library

Персональные инструменты

Microsoft Foundation > Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 22:55, 21 марта 2020.

Microsoft Foundation Classes
Разработчики: Microsoft
Выпущена: 1992 ; 27 years ago ( 1992 )
Предыдущий выпуск: 14.10.25008.0 / 7 March 2020 года ; 2 years ago ( 2020-03-07 )
Написана на: С++
Операционная система: Microsoft Windows
Лицензия: Proprietary
Веб-сайт msdn .microsoft .com /en-us /library /d06h2x6e .aspx

Microsoft Foundation Classes (сокр. MFC) – библиотека для языка С++, содержащая набор классов для разработки графических интерфейсов для ОС семейства Microsoft Windows.

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

Содержание

История

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

  • MFC должна служить объектно-ориентированным интерфейсом для доступа к API операционных систем семейства Windows с помощью повторно используемых компонент-классов;
  • Издержки по времени вычислений и по объему запрашиваемой памяти при использовании MFC должны быть минимальны.

Первая версия MFC 1.0 была выпущена в 1992 году и была совмещена с релизом Microsoft C/C++ 7.0. В дальнейшем новые версии MFC были связаны с выходившими версиями Visual C++. К числу примечательных версий MFC следует отнести MFC 7.0, которая вышла вместе с Visual C++ .NET 2002 и в которой было впервые реализовано взаимодействие с платформой .NET. На данный момент последней является версия MFC 14.0.24210.0, вышедшая в июне 2020 года, совместная с Visual C++ 2015 Up. 3.

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

Начиная с версии MFC 11.0 поддерживаемся создание интерфейсов Office, аналогичных тем, что используются в пакете Microsoft Office.

В апреле 2008 года Microsoft выпустила, после многолетнего бездействия, значительное обновление к MFC под названием MFC Feature Pack. Это обновление предлагалось к установке как дополнение к Visual Studio 2008. В основе своей это были добавочные классы MFC, права на которые были приобретены у российской фирмы BCGSoft [Источник 1] .

Архитектура приложений

Создание приложения с использованием преимуществ MFC подразумевает следование определенной последовательности операций с размещением и обработкой данных приложения. Структура MFC содержит два ориентированных на приложение компонента: документ (document) и представление (view). Документ – имя, присвоенное набору данных приложения, с которыми взаимодействует пользователь. В общем массиве данных документ рассматривается как единое целое, основанный не только на текстовой природе: это могут быть данные игры, геометрической модели, иных коллекций данных, т.е. это абстрактное представление данных программы в памяти компьютера. Документ в программе определяется как объект класса документа, а сам класс документа наследуется от класса библиотеки MFC по имени CDocument. При создании приложения возможно использовать несколько типов документов.

Используя платформу MFC, пользователь имеет выбор: работать с несколькими документами одновременно или только с одним. Однодокументарный интерфейс сокр. SDI (Single Document Interface) поддерживается библиотекой для программ, которым нужно открывать по одному документу за раз. Программы, использующие в своей работе несколько документов одновременно, сокращенно называются MDI (Multiple Document Interface). Значительным преимуществом работы MDI является возможность организовать одновременную обработку документов разного типа, каждый из которых отображается в собственном визуальном окне.

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

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

Отметим, что приложения MFC можно писать и без использования архитектуры «документ/представление», но доступ к большинству возможностей библиотеки будет ограничен, т.к. работа приложения возможно только при поддержке указанной основы. Подобное условие со стороны разработчиков можно рассмотреть как ограничение, но в действительности, большинство программ, обрабатывающих документы какого-либо типа, могут быть преобразованы в указанную архитектуру.

Стандартные классы

На сегодняшний день MFC содержит около 200 классов, представляющих практически все необходимое для написания Windows-приложений: от окон до элементов управления ActiveX. Каждый класс имеет свое целевое назначение: одни классы используются непосредственно, другие (базовые) в целях создания производных классов. Классы дифференцированы по сложности: например, класс CPoint предназначен для хранения двумерных координат точки, а класс CWnd инкапсулирует функциональность окна Windows. Выделим четыре базовых класса, которые появляются почти в каждом Windows-приложении на основе MFC:

  • Класс приложения CMyAPp;
  • Класс обрамляющего окна CMyWnd;
  • Класс представления CMyView, которые определяет, как должны отображаться данные, содержащиеся в CMyDoc, созданное объектом CMyWnd;
  • Класс документа CMyDoc, которые определяет содержащий данные документ.

На рисунке 1 изображена схема структуры наследования библиотечных классов MFC (большинство классов унаследованы от класса CObject). Именно этот класс обеспечивает для своих подклассов такие возможности, как запись и чтение данных объекта на диск, средства динамического получения информации о классе (Run-time class information, RTCI), диагностическая поддержка.

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

Библиотека MFC предоставляет программисту «каркас» приложения, это т.н. заготовка, содержащая определенный набор классов и функций для выполнения типичных операций приложения Windows, например, по созданию главного окна, работе с меню и т.д. Используя для написания приложения платформу MFC, пользователь может перегружать виртуальные функции классов «каркаса», добавляя новые классы. Центральное место в «каркасе» приложения MFC занимает класс СWinApp, в котором содержатся общие аспекты работы приложения, например, главный цикл обработки сообщений.

Создание приложений

При разработки программ на базе MFC используются четыре основных инструмента:

  • Мастер создания приложений (Application Wizard) для создания базового кода программы;
  • Контекстное меню в Class View (Представление классов) для добавления новых классов и ресурсов к проекту;
  • Контекстное меню класса используется в Class View для расширения и настройки существующих классов программы;
  • Редактор ресурсов применяется для модификации меню и панели инструментов.

В MFC доступно несколько редакторов ресурсов, каждый из которых применяется в определенной ситуации (зависит от вида редактируемого ресурса)

Win32 против MFC — Часть I — Основы приложения MFC

Written on 10 Октября 2013 .

ОГЛАВЛЕНИЕ

Основы приложения MFC

Приложение MFC инкапсулирует большую часть Win32 API, упрощая жизнь каждого программиста. Есть много книг и статей о точке входа приложения MFC. Все они в той или иной степени заявляют, что точкой входа приложения MFC является функция InitInstance программы.
Это порождает новый вопрос: «Где находится функция WinMain, если функция InitInstance является точкой входа?»

Чтобы выяснить, что происходит внутри, создайте программу-пример, чтобы изучить и просмотреть детали, скрытые от программиста MFC. Для создания программы-примера запустите MSVC++ 6.0. В меню «Файл» выберите пункт «Новый». Выбрав вкладку «Проект», выделите Мастер приложений MFC (.exe) и в поле редактирования имени проекта введите «sdisample» и нажмите кнопку Ok. Выберите «Отдельный документ» и нажмите кнопку «Завершить». Нажмите Ok, чтобы позволить мастеру создать каркас приложения.

На первый взгляд выяснится, что приложение содержит следующие классы:
• CAboutDlg
• CMainFrame
• CSdiSampleApp
• CSdiSampleDoc
• CSdiSampleView

Один из этих классов по имени CSdiSampleApp унаследован от класса CWinApp:

Вышеуказанный класс имеет функцию-член по имени InitInstance, называемую точкой входа приложения. Встает вопрос, почему эта функция называется точкой входа приложения MFC? Ответ на данный вопрос лежит за архитектурой MFC. Глупо, да?

Было сказано, что каждая программа Windows содержит две функции: WinMain и wndProc. То же самое относится к приложениям MFC. Они тоже имеют функцию WinMain и wndProc.

Запустите программу путем нажатия кнопки F10. Вы вскоре выясните, что выполнение программы останавливается на следующей функции:

Посмотрите внимательно! Функция имеет знакомые параметры, такие же, как у функции WinMain. Но что за мерзость объявлена перед WINAPI? extern «C» сообщает компилятору, как компилировать эту функцию, и WINAPI определено следующим образом:

А что насчет _tWinMain? Она объявлена следующим образом:

Оказались снова в том же самом месте! Здесь рассмотренная ранее функция WinMain:

а здесь функция, сгенерированная MFC:

Сравнение этих двух функций показывает, что они одинаковые. Ловко, да? Теперь тщательней рассмотрим функцию _tWinMain и ее реализацию:

Как видно, она вызывает и возвращает функцию AfxWinMain, функцию WinMain каркаса приложения! Но какой она является и как реализована? Ниже приведена важная часть функции AfxWinMain:

Сначала AfxWinMain вызывает AfxWinInit, функцию, вызывающую MFCO42D.DLL (если программа выполняется в отладочной версии), а также инициализирующую переменные-члены надлежащим именем файла выполнения, файла справки и файла .ini. (Правда, AfxWinMain делает немного больше, но это опущено, потому что MFC тут не переделывается).

Затем AfxWinMain вызывает функцию InitApplication, которую можно легко переопределить в классе CSdiSampleApp с помощью мастера класса. Эта функция используется для выполнения однократной инициализации приложения, и через несколько строк она вызывает функцию InitInstance, названную точкой входа приложения MFC. Затем функция AfxWinMain вызывает функцию «Выполнить»! Эта функция вызывает надлежащую функцию CWinApp::Run(), которая в свою очередь вызывает функцию CWinThread::Run().
В этом методе представлен цикл обработки сообщений, реализованный следующим образом:

Как видно, эта функция содержит цикл, и этот цикл прервется, если и только если будет получено сообщение WM_QUIT, и, следовательно, обладает функциональностью вышеназванного цикла обработки сообщений:

Однако между двумя этими циклами есть ряд отличий. Первое и самое важное заключается в том, что CWinThread::Run() вызывает функцию-член OnIdle приложения, когда программе нечего обрабатывать. Во-вторых, он вызывает метод ExitInstance после получения сообщения WM_QUIT и перед выходом из программы. Итак, программист MFC может сделать все, что нужно путем переопределения метода ExitInstance, следя, чтобы этот код вызывался всегда, когда программа собирается завершиться.

PumpMessage, с другой стороны, инкапсулирует API TranslateMessage и DispatchMessage внутри. Теперь имеется цикл обработки сообщений для приложения MFC. Однако еще ничего не было сказано о wndProc приложения MFC. Эта функция является достоинством MFC и будет рассмотрена во второй части данной статьи.

2. Введение в MFC

На сегодня существует более десятка версий библиотеки MFC. Практически каждая новая версия среды Microsoft Visual C++ (MSVC) поставляется с обновленной версией библиотеки MFC, в которой исправлены обнаруженные ошибки и добавлены новые классы.

Все версии библиотеки MFC можно разделить на две группы. К первой относятся 16-разрядные версии MFC, предназначенные для операционных систем Windows 3.1 и 3.11. Вторая группа включает версии MFC, предназначенные для 32-разрядных операционных систем Windows NT и Windows 95. В следующей таблице перечислены все основные версии Microsoft Visual C++ и соответствующие им версии MFC.

Среда разработки Версия MFC Разрядность
Microsoft C/C++ версии 7.0 1.0 16
MSVC 1.0 2.0 16
MSVC 1.1 2.1 32
MSVC 1.5 2.5 16
MSVC 2.0 2.51 16
MSVC 2.1 2.52 16
MSVC 2.2 2.52b 16
MSVC 4.0 2.5c 16
MSVC 2.0 3.0 32
MSVC 2.1 3.1 32
MSVC 2.2 3.2 32
MSVC 4.0 4.0 32
MSVC 4.1 4.1 32

Вы легко можете определить версию библиотеки MFC, установленной на вашем компьютере. Для этого достаточно просмотреть включаемый файл afxver_.h, расположенный в каталоге include библиотеки MFC. В одной из первых строк этого файла определена константа _MFC_VER, содержащая версию MFC:

// Microsoft Foundation Classes версии 4.00

Мы будем рассматривать библиотеку MFC версий 3.0, 4.0 и 4.1, однако приведенная информация верна и для других версий MFC. В тех случаях, когда эти версии имеют существенные отличия мы будем на это специально указывать.

Классы библиотеки MFC

Библиотека классов MFC содержит большое количество разнообразных классов. Так MFC версии 4.0 включает немного меньше 200 классов. Каждый класс, как правило, содержит от нескольких единиц до нескольких десятков различных методов и элементов данных. Конечно это значительно усложняет освоение программирования с помощью MFC. Но не стоит расстраиваться и опускать руки. Вам вовсе не обязательно знать как устроены все 200 классов. Большинство приложений можно построить на основе нескольких основных классов. Более того, самое простое приложение, которое мы предложим вашему вниманию, будет использовать только один класс из библиотеки MFC.

Мы не станем приводить здесь всю иерархию классов MFC. Вы можете изучить ее, воспользовавшись документацией или справочной системой среды Visual C++. Чтобы просмотреть иерархию классов в справочной системе Visual C++, выберите из окна Project Workspace страницу InfoView, откройте описание MFC 4.0, а затем из раздела Class Library Reference выберите статью Hierarcy Chart (рис. 2.1).

Рис. 2.1. Просмотр иерархии классов MFC

Сейчас мы кратко рассмотрим назначение основных классов библиотеки MFC и их связь друг с другом.

Самый базовый класс MFC (класс CObject)

Подавляющее большинство классов библиотеки MFC наследовано от базового класса CObject, лежащего в основе всей иерархии классов этой библиотеки. Методы и элементы данных класса CObject представляют наиболее общие свойства наследованных из него классов MFC.

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

Для объектов классов, наследованных от базового класса CObject уже во время работы приложения можно получить разнообразную информацию о классе объекта.

Ряд методов класса CObject предназначен для получения дампа объектов класса во время отладки приложения. Эта особенность класса может ускорить процесс поиска ошибок в приложении.

Основа структуры приложения (класс CCmdTarget)

Непосредственно от класса CObject наследуются ряд классов, которые сами являются базовыми для остальных классов MFC. В первую очередь это класс CCmdTarget, представляющий основу структуры любого приложения. Основной особенностью класса CCmdTarget и классов, наследованных от него является то, что объекты этих классов могут получать от операционной системы сообщения и обрабатывать их.

Структура классов, связанных с классом CCmdTarget представлена на рисунке 2.2.

Рис. 2.2. Класс CCmdTarget

Подзадачи приложения (классы CWinThread и CWinApp)

От класса CCmdTarget наследуется класс CWinThread, представляющий подзадачи приложения. Простые приложения, которые мы будем рассматривать в первой книге, посвященной MFC, имеют только одну подзадачу. Эта подзадача, называемая главной, представляется классом CWinApp, наследованным от класса CWinThread.

Документ приложения (класс CDocument)

Большинство приложений работают с данными или документами, хранимыми на диске в отдельных файлах. Класс CDocument, наследованный от базового класса CCmdTarget, служит для представления документов приложения.

Шаблон документов (классы CDocTemplate, CSingleDocTemplate и CMultiDocTemplate)

Еще один важный класс, наследуемый от CCmdTarget, называется CDocTemplate. От этого класса наследуются два класса CSingleDocTemplate и CMultiDocTemplate. Все эти классы предназначены для синхронизации и управления основными объектами представляющими приложение – окнами, документами и используемыми ими ресурсами.

Окна (класс CWnd)

Практически все приложения имеют пользовательский интерфейс, построенный на основе окон. Это может быть диалоговая панель, одно окно или несколько окон, связанных вместе. Основные свойства окон представлены классом CWnd , наследованным от класса CCmdTarget.

Вы очень редко будете создавать объекты класса CWnd. Класс CWnd сам является базовым классом для большого количества классов, представляющих разнообразные окна. На рисунке 2.3 представлена только небольшая часть дерева наследования класса CWnd.

Рис. 2.3. Класс CWnd

Перечислим классы, наследованные от базового класса CWnd.

• Обрамляющие окна (класс CFrameWnd)

Класс CFrameWnd представляет окна, выступающие в роли обрамляющих окон (frame window), в том числе главные окна приложения. От этого класса также наследуются классы CMDIChildWnd и CMDIFrameWnd, используемые для отображения окон многооконного интерфейса MDI. Класс CMDIFrameWnd представляет главное окно приложения MDI, а класс CMDIChildWnd – его дочерние окна MDI. Класс CMiniFrameWnd применяется для отображения окон уменьшенного размера. Такие окна обычно используются для отображения в них панели управления.

• Окна органов управления

В предыдущих томах серии “Библиотека системного программиста” мы рассказывали о том, что существует ряд органов управления, встроенных в операционную систему. К ним относятся кнопки, полосы прокрутки, редакторы текста, переключатели и т. д.

Для работы с этими органами управления в библиотеке MFC предусмотрены специальные классы, наследованные непосредственно от класса CWnd.

Класс Орган управления
CAnimateCtrl Используется для отображения видеоинформации
CBitmapButton Кнопка с рисунком
CButton Кнопка
CComboBox Список с окном редактирования
CEdit Поле редактирования
CHeaderCtrl Заголовок для таблицы
CHotKeyCtrl Предназначен для ввода комбинации клавиш акселераторов
CListBox Список
CListCrtl Может использоваться для отображения списка пиктограмм
CProgressCtrl Линейный индикатор
CPropertySheet Блокнот. Может состоять из нескольких страниц
CRichEditCtrl Окно редактирования, в котором можно редактировать форматированный текст
CScrollBar Полоса просмотра
CSliderCtrl Движок
CSpinButtonCtrl Обычно используется для увеличения или уменьшения значения какого-нибудь параметра
CStatic Статический орган управления
CTabCtrl Набор “закладок”
CToolBarCtrl Панель управления
CToolTipCtrl Маленькое окно содержащее строку текста
CTreeCtrl Орган управления, который позволяет просматривать иерархические структуры данных

• Управляющие панели (классы CControlBar, CStatusBar, CDialogBar)

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

Так, класс CStatusBar предназначен для создания панели управления. Эта панель обычно содержит ряд кнопок, дублирующих действие меню приложения.

Класс CStatusBar управляет панелью состояния. Панель состояния отображается в виде полосы в нижней части экрана. В ней приложение может отображать всевозможную информацию, например краткую подсказку о выбранной строке меню.

Большие возможности представляет управляющая панель, созданная на основе класса CDialogBar. Такая панель использует обычный шаблон диалоговой панели, который вы можете разработать в редакторе ресурсов Visual C++.

• Блокнот (класс CPropertySheet)

Класс CPropertySheet представляет блокнот – диалоговую панель, содержащую несколько страниц. Отдельные страницы такого блокнота управляются объектами другого класса – CPropertyPage. Класс CPropertyPage наследуется от базового класс CDialog, который мы рассмотрим ниже.

• Окна просмотра (класс CView и классы наследованные от него)

Большой интерес представляет класс CView и классы, наследуемые от него (рис. 2.4). Эти классы представляют окно просмотра документов приложения. Именно окно просмотра используется для вывода на экран документа, с которым работает приложения. Через это окно пользователь может изменять документ.

Разрабатывая приложение, вы будете наследовать собственные классы просмотра документов либо от базового класса CView, либо от одного из нескольких порожденных классов, определенных в библиотеке MFC.

Классы, наследованные от CCtrlView, используют для отображения документа готовые органы управления. Например, класс CEditView использует орган управления edit (редактор). Более подробно эти классы будут описаны позже, когда мы будем рассказывать о средствах автоматизированного программирования MFC AppWizard и ClassWizard.

Класс CScrollView представляет окно просмотра, которое имеет полосы свертки. В классе определены специальные методы, управляющие полосами просмотра


Класс CFormView позволяет создать окно просмотра документа, основанное на диалоговой панели. От этого класса наследуются еще два класса CRecordView и CDaoRecordView. Эти классы используются для просмотра записей баз данных.

Рис. 2.4. Класс CView

• Диалоговые панели (класс CDialog и классы наследованные от него)

Кроме перечисленных классов от базового класса CWnd наследуются классы, управляющие диалоговыми панелями. Если вы желаете создать диалоговую панель, вы можете наследовать класс от CDialog (рис. 2.5).

Вместе с диалоговыми панелями обычно используется класс CDataExchange. Класс CDataExchange обеспечивает работу процедур обмена данными DDX (Dialog Data Exchange) и проверки данных DDV (Dialog Data Validation) используемых для диалоговых панелей. В отличие от класса CDialog, класс CDataExchange не наследуется от какого-либо другого класса.

Когда вы создаете блокнот, состоящий из нескольких страниц, то каждая такая страница является объектом класса, наследованного от CPropertyPage.

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

Чтобы создать стандартный диалог, вы можете просто определить объект соответствующего класса. Дальнейшее управление такой панелью осуществляется методами класса.

Рис. 2.5. Класс CDialog

Исключения (класс CException)

Для реализации механизма исключений в MFC определен специальный класс CException, наследованный от базового класса CObject. Все исключения, определенные в MFC, наследуются от этого класса. Вот список классов, наследованных от CException и их краткое описание. Более полное описание классов, связанных с исключениями, вы можете найти в разделе “Исключения – класс CException” главы “Вспомогательные классы MFC”.

Класс Описание
CArchiveException Исключение, вызванное ошибкой при использовании объекта класса CArchive. Класс CArchive применяется для сохранения и загрузки документа из файла на диске
CDaoException Ошибка при работе с базами данных (при использовании классов DAO)
CDBException Ошибка при работе с базами данных (при использовании ODBC)
CFileException Ошибка, связанная с файловой системой
CMemoryException Недостаточно оперативной памяти
CNotSupportedException Попытка выполнить неопределенную операцию
COleDispatchException, COleException Ошибка OLE
CResourceException Не найден ресурс
CUserException Ошибка приложения, вызванная действиями пользователя
Илон Маск рекомендует:  aside в HTML

Массивы, списки и словари

В состав MFC включен целый набор классов, предназначенных для хранения информации в массивах, списках и словарях. Все эти классы наследованы от базового класса CObject.

Не смотря на то, что в языке Си определено понятие массива, классы MFC обеспечивают вам более широкие возможности. Вы, например, можете динамически изменять размер массива, определенного с помощью соответствующего класса.

Для представления массивов предназначены следующие классы.

Класс Массив содержит
CByteArray Байты
CDWordArray Двойные слова
CObArray Указателей на объекты класса CObject
CPtrArray Указателей типа void
CStringArray Объекты класса CString
CUIntArray Элементы класса unsigned integer или UINT
CWordArray Слова

Фактически все перечисленные в таблице классы различаются только типом элементов массива. Поэтому вместо использования этих классов гораздо проще воспользоваться шаблоном CArray. Используя шаблон CArray, вы можете определять массивы из элементов любых типов и классов. Шаблон CArray наследует свойства класса CObject.

Для построения массивов вы можете также воспользоваться шаблоном CTypedPtrArray. Этот шаблон не наследуется от базового класса CObject, поэтому использовать методы класса CObject для него нельзя.

Для решения многих задач используются такие структуры хранения данных, как списки. MFC включает ряд классов, наследованных от базового класса CObject, которые предоставляют программисту готовое средство для создания собственных списков. В этих классах определены все методы необходимые при работе со списками – добавление нового элемента, вставка нового элемента, определение следующего или предыдущего элемента в списке, удаление элемента и т. д.

Класс Список содержит элементы
CObList Указатели на объекты класса CObject
CPtrList Указатели типа void
CStringList Объекты класса CString

Перечисленные в таблице классы позволяют построить списки из элементов любых типов и объектов любых классов. Однако удобнее пользоваться шаблоном CList, также наследованным от базового класса CObject. Для построения списков вы можете также использовать шаблон CTypedPtrList. Этот шаблон не наследуется от базового класса CObject.

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

Класс Ключевое поле Поле, связанное с ключевым
CMapPtrToPtr Указатель типа void Указатель типа void
CMapPtrToWord Указатель типа void Слово
CMapStringToOb Объекты класса CString Указатели на объекты класса CObject
CMapStringToPtr Объекты класса CString Указатель типа void
CMapStringToString Объекты класса CString Объекты класса CString
CMapWordToOb Слово Указатели на объекты класса CObject
CMapWordToPtr Слово Указатель типа void

Вы можете создавать словари, имеющие поля любых типов и классов, если воспользуетесь шаблоном CMap. Шаблон CMap наследуется от базового класса CObject. Для построения словарей можно также использовать шаблон CTypedPtrMap. Шаблон CTypedPtrMap не наследуется от базового класса CObject.

Файловая система (класс CFile)

Библиотека MFC включает класс для работы с файловой системой компьютера. Он называется CFile и также наследуется от базового класса CObject. Непосредственно от класса CFile наследуются еще несколько классов – CMemFile, CStdioFile, CSocketFile.

При работе с файловой системой вам может потребоваться получить различную информацию о некотором файле – например, дату создания, размер и т. д. Для хранения этих данных предназначен специальный класс CFileStatus. Класс CFileStatus один из немногих классов, которые не наследуются от базового класса CObject.

Контекст отображения (класс CDC)

Для отображения информации в окне или на любом другом устройстве приложение должно получить так называемый контекст отображения. Основные свойства контекста отображения определены в классе CDC. От него наследуется четыре различных класса, представляющие контекст отображения различных устройств (рис. 2.6).

Рис. 2.6. Класс CDC

В следующей таблице приведено краткое описание классов, наследованных от CDC.

Класс Описание
CClientDC Контекст отображения, связанный с внутренней областью окна (client area). Для получения контекста конструктор класса вызывает функцию программного интерфейса GetDC, а деструктор – функцию ReleaseDC
CMetaFileDC Класс предназначен для работы с метафайлами
CPaintDC Конструктор класса CPaintDC для получения контекста отображения вызывает метод CWnd::BeginPaint, деструктор метод CWnd::EndPaint. Объекты данного класса могут использовать только при обработке сообщения WM_PAINT. Это сообщение обычно обрабатывает метод OnPaint
CWindowDC Контекст отображения, связанный со всем окном. Для получения контекста конструктор класса вызывает функцию программного интерфейса GetWindowDC, а деструктор – функцию ReleaseDC

Объекты графического интерфейса (класс CGdiObject)

Для отображения информации используются различные объекты графического интерфейса – GDI объекты. Для каждого из этих объектов библиотека MFC содержит описывающий его класс, наследованный от базового класса CGdiObject (рис. 2.7).

Рис. 2.7. Класс CGdiObject

Класс Описание
CBitmap Растровое изображение bitmap
CBrush Кисть
CFont Шрифт
CPalette Палитра цветов
CPen Перо
CRgn Область внутри окна

Меню (класс CMenu)

Практически каждое приложение имеет собственное меню. Оно как правило отображается в верхней части главного окна приложения. Для управления меню в состав MFC включен специальный класс CMenu, наследованный непосредственно от базового класса CObject.

Для управления меню и панелями управления используется также класс CCmdUI. Этот класс не наследуется от базового класса CObject.

Объекты класса CCmdUI создаются, когда пользователь выбирает строку меню или нажимает кнопки панели управления. Методы класса CCmdUI позволяют управлять строками меню и кнопками панели управления. Так например, существует метод, который делает строку меню неактивной.

Базы данных (классы для работы с базами данных)

В MFC включены несколько классов, обеспечивающую поддержку приложений, работающих с базами данных. В первую очередь это классы ориентированные на работу с ODBC драйверами – CDatabase и CRecordSet. Поддерживаются также новые средства для работы с базами данных DAO (Data Access Object). Для этого предназначены классы CDaoDatabase, CDaoRecordSet, CDaoQueryDef, CDaoTableDef, CDaoWorkspace и CLongBinary.

Для работы с базами данных также предназначены классы CFieldExchange и CDaoFieldExchange. Это самостоятельные классы, они не наследуются от базового класса CObject.

Классы CFieldExchange и CDaoFieldExchange работают с процедурами обмена данными RFX (Record Field Exchange ) для классов управляющих базами данных.

Синхронизация задач приложения (класс CSyncObject)

Библиотека MFC позволяет создавать многозадачные приложения. Для синхронизации отдельных задач приложения предусмотрен ряд специальных классов. Все они наследуются от класса CSyncObject , представляющего собой абстрактный класс (рис. 2.8).

Рис. 2.8. Класс CSyncObject

В некоторых случаях требуется, чтобы участок программного кода мог выполняться только одной задачей. Такой участок называют критической секцией кода. Для создания и управления критическими секциями предназначены объекты класса CCriticalSection.

Объекты класса CEvent представляют событие. При помощи событий одна задача приложения может передать сообщение другой.

Объекты класса CMutex позволяют в данный момент времени представить ресурс в пользование только одной задачи. Остальным задачам доступ к ресурсу запрещается.

Объекты класса CSemaphore представляют собой семафоры. Семафоры позволяют ограничить количество задач, которые имеют доступ к какому-либо ресурсу.

Сокеты (классы CAsyncSocket и CSocket)

Для тех, кто занимается сетевыми коммуникациями, в состав библиотеки MFC включены классы CAsyncSocket и наследованный от него класс CSocket (рис. 2.9). В класс CAsyncSocket включен программный интерфейс Windows Socket.

Класс CSocket предоставляет программисту более высокий уровень для работы с сокетами. Это значительно облегчает задачу программирования сетевых приложений.

Программирование на уровне программного интерфейса Windows с использованием сокетов описано в двадцать третьем томе серии “Библиотека системного программиста”, который называется “Глобальные сети компьютеров”.

Рис. 2.9. Класс CAsyncSocket

Классы, не имеющие базового класса

Кроме классов, наследованных от базового класса CObject, библиотека MFC включает ряд самостоятельных классов. У них нет общего базового класса и они имеют различное назначение.

Несколько классов, которые не наследуются от базового класса CObject, мы уже описали. К ним относятся класс CCmdUI, CFileStatus, CDataExchange, CFieldExchange и CDaoFieldExchange.

Простые классы

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

Класс Описание
CPoint Объекты класса описывают точку
CRect Объекты класса описывают прямоугольник
CSize Объекты класса определяют размер прямоугольника
CString Объекты класса представляют собой текстовые строки переменной длинны
CTime Объекты класса служат для хранения даты и времени. Большое количество методов класса позволяют выполнять над объектами класса различные преобразования
CTimeSpan Объекты класса определяют период времени

Архивный класс (класс CArchive)

Класс CArchive используется для сохранения и восстановления состояния объектов в файлах на диске. Перед использованием объекта класса CArchive он должен быть привязан к файлу – объекту класса CFile.

Более подробно о процессе сохранения и восстановления объектов вы можете прочитать в разделе “Сохранение и восстановление объектов”. Пример использования класса CArchive для записи и восстановления документов в файлах представлен в разделе “Простейший графический редактор” главы “Однооконный интерфейс”.

Информация о классе объекта (структура CRuntimeClass)

Во многих случаях бывает необходимо уже во время работы приложения получить информацию о классе объекта и его базовом классе. Для этого любой класс, наследованный от базового класса CObject связан с структурой CRuntimeClass. Она позволяет определить имя класса объекта, размер объекта в байтах, указатель на конструктор класса, не имеющий аргументов и деструктор класса. Можно также узнать подобную информацию о базовом классе и некоторые дополнительные сведения.

Отладка приложения (классы CDumpContext, CMemoryState)

В отладочной версии приложения вы можете использовать класс CDumpContext. Он позволяет выдавать состояние различных объектов в текстовом виде.

Класс CMemoryState позволяет локализовать проблемы, связанные с динамическим выделением оперативной памяти. Такие проблемы обычно возникают, когда пользователь выделяет память, используя оператор new, а затем забывает ввернуть эту память операционной системе.

Печать документа (класс CPrintInfo)

Класс CPrintInfo предназначен для управления печатью документов на принтере. Когда пользователь отправляет документ на печать или выполняет предварительный просмотр документа перед печатью, создается объект класса CPrintInfo. Он содержит различную информацию о том, какие страницы документа печатается и т. д.

Кроме описанных нами классов библиотека MFC включает большое количество классов, предназначенных для организации технологии OLE. Из-за ограниченного объема книги мы не будем рассматривать приложения, поддерживающие OLE технологию.

Первое приложение MFC

Первое приложение MFHello, которое мы создадим с использованием библиотеки классов MFC будет очень простое. Единственное, что оно будет делать – это отображать на экране маленькую диалоговую панель, содержащую строку “Hello, MFC!”.

Исходный текст приложения, представленный в листинге 2.1, состоит всего из двенадцати строк, не считая строк комментариев. В нашем первом приложении мы использовали единственный класс библиотеки MFC, наследованный от базового класса CWinApp.

Чтобы создать новый проект, выберите из меню File строку New. На экране появится диалоговая панель New, содержащая одноименный список New и две кнопки. Выберите из списка New строку Project Workspace. Откроется диалоговая панель New project workspace (рис. 4.1 из главы “Приложение с главной диалоговой панелью”). В ней вы должны указать тип приложения, который будет разрабатываться, имя проекта и расположение каталога для записи в него файлов проекта.

Самые простые приложения с использованием библиотеки классов MFC мы будем создавать без использования автоматизированных средств разработки приложений MFC AppWizard. Поэтому в качестве типа приложения выберите из списка Type строку Application.

В поле Name введите имя нового проекта. Наш первый проект мы назвали именем MFHello. Расположение каталога для размещения файлов проекта отображается в поле Location. По умолчанию каталог проекта называется точно также как сам проект и будет размещен в каталоге Projects среды разработки Visual C++. Вы можете выбрать для проекта любой другой каталог, если нажмете на кнопку Browse.

Теперь нажмите кнопку Create. Будут созданы служебные файлы проекта. Они получат названия MFHello.mak, MFHello.ncb и MFHello.mdp. Файл MFHello.mdp является основным файлом проекта. В этих файлах определяется, какие исходные файлы содержит проект, указываются характеристики создаваемого приложения, конфигурация самой среды разработки Visual C++.

Окно Project Workspace

Microsoft Visual C++ версии 4.0 имеет удобные средства для просмотра исходных текстов файлов проекта, кодов классов приложения, ресурсов, а также для получения справочной информации.

Откройте окно Project Workspace. Обычно оно расположено в левой части экрана, но вы можете переместить его в другое место и даже закрыть. Если окно закрыто, откройте его. Для этого выберите из меню View строку Project Workspace. Окно Project Workspace состоит из нескольких страниц. Вы можете открыть их, нажимая на соответствующие закладки. Количество страниц зависит от того, установлена ли справочная система и открыт ли проект.

ClassView. Средство для просмотра и редактирования классов приложения

ResourceView. Позволяет просматривать и редактировать ресурсы приложения

FileView. Выполняет просмотр файлов приложения

InfoView. Справочная система Microsoft Visual C++. В нее включена информация о языке Си, Си++, библиотеки классов MFC, функций програмного интерфейса Windows

Откройте окно Project Workspace и выберите страницу FileView. Так как сначала в проекте нет ни одного файла, вы увидите пустую папку проекта. Теперь надо создать новый текстовый файл и набрать в нем исходный текст нашего первого приложения.

Чтобы создать новый файл, вы можете нажать кнопку New Source File( ) в стандартной панели управления или выбрать из меню File строку New, а затем из списка в открывшейся панели New выбрать строку Text File. Откроется новое окно текстового редактора. В нем надо набрать исходный текст приложения, представленного листингом 2.1. Сохраните набранный текст в файле под именем MFHello.cpp в каталоге проекта. Для этого выберите из меню File строку Save As.

Листинг 2.1. Файл MFHello.cpp

// Наследуем от базового класса CWinApp главный

class CMFHelloApp : public CWinApp <

// Мы будем переопределять метод InitInstance,

// предназначенный для инициализации приложения

// Создаем объект приложение класса CMFHelloApp

// Метод InitInstance класса CMFHelloApp

// Переопределяем виртуальный метод InitInstance

// класса CWinApp. Он вызывается каждый раз при запуске

Единственный файл с исходным текстом приложения создан и его надо включить в проект. Выберите из меню Insert строку Files into Project. На экране появится диалоговая панель Insert Files into Project. Выберите файл MFHello.cpp и нажмите кнопку Add. Диалоговая панель закроется. Просмотрите еще раз папку с файлами проекта. Теперь в ней расположен файл MFHello.cpp (рис. 2.10).

Рис. 2.10. Файлы проекта MFHello

Откройте страницу ClassView в окне Project Workspace. В ней отображаются все классы, определенные в приложении и все глобальные переменные. Для каждого класса приложения можно видеть входящие в него элементы (рис. 2.11).

На странице ClassView отображается древовидная структура классов вашего приложения. Когда вы в первый раз открываете ClassView, структура классов отображается в виде закрытой папки . Чтобы ее открыть, щелкните два раза левой кнопкой мыши по изображению папки или один раз по символу , расположенному левее папки. В открытой папке символом представлены классы приложения и еще одним символом папки глобальные объекты приложения. Папку с глобальными объектами можно открыть также как папку с классами. Вы можете открыть и сами классы. Так вы сможете просмотреть элементы класса – методы и данные. Методы обозначаются символом , а данные символом . Если методы или данные объявлены как protected, перед ними отображается символ , а если как private – символ .

В нашем проекте определен только один класс CMFHelloApp. В класс CMFHelloApp входит метод InitInstance. Кроме того, определена одна глобальная переменная MFHelloApp.

Рис. 2.11. Классы проекта MFHello

Если вы используете в приложении классы или функции библиотеки классов MFC, то проект надо настроить. Выберите из меню Build строку Settings или нажмите комбинацию клавиш . На экране появится диалоговая панель Project Settings. В этой панели расположены несколько страниц, позволяющих настроить различные характеристики проекта.

Откройте страницу General. Мы привели внешний вид этой страницы на рисунке 2.12. Обратите внимание на список Microsoft Foundation Classes. По умолчанию из этого списка выбрана строка No Using MFC. Она означает, что приложение не будет использовать библиотеку MFC. Так как в приложении MFHello и всех остальных приложениях, описанных в этой книге, задействованы классы MFC, выберите из списка Microsoft Foundation Classes строку Use MFC in a Shared Dll (mfc40(d).dll) или строку Use MFC in a Static Library.

Что же выбрать – Use MFC in a Shared Dll или Use MFC in a Static Library? Оказывается программные коды библиотеки классов MFC могут использоваться приложением двумя способами. Код библиотеки MFC либо непосредственно записывается в выполнимый файл приложения, либо вызывается по мере необходимости из отдельной dll-библиотеки.

Использование для приложения dll-библиотеки немного ускоряет процесс построения проекта и позволяет создавать выполнимые файлы значительно меньшего размера. Однако сам по себе такой выполнимый файл работать не будет. Для него необходима dll-библиотека. Поэтому если приложение устанавливается и на других компьютерах, его надо распространять вместе с dll-библиотекой.

Для MFC версии 4.0 dll-библиотека хранится в файлах Mfc40d.dll и Mfc40.dll. В файле Mfc40d.dll находится отладочная версия MFC, а в файле Mfc40.dll отладочная информация отсутствует. В ходе установки Visual C++ эти dll-библиотеки записываются в системный каталог операционной системы.

Если вы забудете указать, что приложение использует MFC, то во время построения проекта на этапе установления связи (Linking…) будут обнаружены ошибки:

error LNK2001: unresolved external symbol __endthreadex

error LNK2001: unresolved external symbol __beginthreadex

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

Рис. 2.12. Диалоговая панель Project Settings

Если вы все сделали, постройте проект. Для этого вы можете выбрать из меню Build строку Build MFHello.exe – создать выполнимый файл MFHello.exe или строку Rebuild All – заново оттранслировать все исходные файлы проекта. Если в ходе построения выполнимого файла приложения нашего проекта возникли ошибки, исправьте их и заново оттранслируйте проект. После успешного построения проекта запустите полученное приложение, выбрав из меню Build строку Execute MFHello.exe.

На экране появится маленькая диалоговая панель (рис. 2.13). Название этой диалоговой панели соответствует названию выполнимого файла приложения MFHELLO. В диалоговой панели отображается текстовое сообщение “Hello, MFC!”, пиктограмма с восклицательным знаком внутри треугольника и кнопка OK. Как только вы нажмете кнопку OK, диалоговая панель закрывается и приложение завершит свою работу.

Рис. 2.13. Приложение MFHello

Посмотрим, как работает приложение MFHello на уровне исходного текста. Первая строка, не считая строки комментария, содержит директиву препроцессора #include, которая включает файл afxwin.h :

В этом файле определены классы, методы, константы и другие структуры для библиотеки классов MFC. Кроме того включаемый файл afxwin.h автоматически подключает другой включаемый файл windows.h уже известный вам по предыдущим томам серии библиотеки системного программиста. Поэтому даже если из приложения будут вызываться функции стандартного программного интерфейса Windows файл windows.h включать не надо.

В предыдущих томах серии “Библиотека системного программиста”, посвященных программированию в среде операционных систем Windows и Windows 95, мы рассказывали о функции WinMain , которая является главной функцией приложения. Эта функция вызывается, когда пользователь или операционная система запускает приложение. Все приложения, которые мы рассматривали до сих пор содержали функцию WinMain:

// Самое простое приложение Windows

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) <

// Отображаем на экране небольшую панель с сообщением

MessageBox(NULL,»Hello, world», «Text Message», MB_OK);

Взгляните на исходные тексты приложения. Вы нигде не обнаружите хорошо знакомой функции WinMain. Не видно также переменных, представляющих параметры этой функции.

Оказывается, в приложениях, основанных на классах MFC, функция WinMain скрыта от программиста в определении класса CWinApp. В каждом приложении определяется главный класс приложения, наследуемый от базового класса CWinApp. Обычно этот класс называют CProjectApp, где в качестве Project указывают имя проекта. Приложение должно иметь только один объект главного класса приложения, наследованного от класса CWinApp.

Класс CWinApp выполняет все действия, которые обычно выполняла функция WinMain – инициализирует приложение, обрабатывает сообщения и завершает приложение. Для этого класс CWinApp включает виртуальные методы InitApplication, InitInstance, Run и ExitInstance.

Чтобы выполнить инициализацию приложения, функция WinMain вызывает методы InitApplication и InitInstance для объекта главного класса приложения. Метод InitApplication выполняет инициализацию на уровне приложения. Вы можете переопределить этот метод в своем приложении. Метод InitInstance выполняет инициализацию каждой запущенной копии приложения. Обычно метод InitInstance создает главное окно приложения. Вы обязательно должны переопределить этот метод в своем приложении. Остальные методы, например Run, можно не переопределять.

Затем функция WinMain начинает обрабатывать цикл сообщений. Для этого вызывается метод Run. Вы можете переопределить этот метод, чтобы реализовать собственный цикл обработки сообщений.

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

В нашем случае главный класс приложения, который называется CMFHelloApp, определяется следующим образом:

// Наследуем от базового класса CWinApp главный

class CMFHelloApp : public CWinApp <

// Мы будем переопределять метод InitInstance,

// предназначенный для инициализации приложения

Мы наследуем класс CMFHelloApp от базового класса CWinApp. При этом базовый класс указан как public. Это означает, что в программе доступны все элементы базового класса CWinApp, объявленные как public. Мы можем вызывать методы класса CWinApp для объектов класса CMFHelloApp и обращаться к элементам данных класса CWinApp.

В определении класса CMFHelloApp мы объявляем виртуальный метод InitInstance. Он будет нами переопределен. Изначально метод InitInstance определен в классе CWinApp. Метод InitInstance отвечает за инициализацию приложения. Он вызывается каждый раз, когда пользователь запускает приложение. Если пользователь запустит приложение несколько раз, то метод InitInstance будет вызываться каждый раз.

Метод InitInstance обязательно должен быть переопределен в вашем главном классе приложения. Остальные виртуальные методы можно оставить без изменения.

Сразу после объявления главного класса приложения мы создаем объект этого класса – MFHelloApp. Вы должны определить объект главного класса приложения как глобальный. В этом случае он будет создан сразу при запуске приложения и сможет управлять всей работой приложения. После создания глобальных объектов вызывается функция WinMain, определенная в классе CWinApp. Она выполняет свои обычные функции – регистрирует классы окон, создает окно, и т. д.

Нельзя создавать два и более объектов класса, наследованного от базового класса CWinApp. Каждое приложение должно иметь один и только один объект главного класса приложения:

// Создаем объект приложение класса CMFHelloApp

Метод InitInstance главного класса приложения CMFHelloApp служит для инициализации. Он вызывается автоматически каждый раз, когда запускается очередная копия приложения. Мы используем метод InitInstance чтобы вывести на экран компьютера диалоговую панель с сообщением “Hello, MFC!”. Для этого вызываем функцию AfxMessageBox:

// Метод InitInstance класса CMFHelloApp

// Переопределяем виртуальный метод InitInstance

// класса CWinApp. Он вызывается каждый раз при запуске

Функция AfxMessageBox определена в библиотеке классов MFC. Вместо функции AfxMessageBox вы можете воспользоваться хорошо известной вам функцией MessageBox программного интерфейса Windows.

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

В конце метода InitInstance мы вызываем оператор return и возвращаем значение FALSE. Приложение сразу завершается. Если метод InitInstance вернет значение TRUE, приложение продолжит работу и приступит к обработке очереди сообщений. Более подробно о методе InitInstance и свойствах базового класса CWinApp вы узнаете позже, когда мы будем рассматривать средства автоматизированной разработки приложений.

Средства ClassView

Конечно, вы можете продолжать набирать исходные тексты приложения вручную непосредственно в текстовом редакторе. Но во многих случаях среда VIsual C++ может оказать вам значительную помощь. Одним из средств, способных оказать вам такую помощь уже сейчас, является ClassView.

Используя ClassView можно быстро добавлять к классам новые элементы, просматривать структуру наследования классов и выполнять другие полезные операции. После того как вы разберетесь с основными принципами построения приложений Windows с использованием классов MFC, мы продолжим изучение вспомогательных средств VIsual C++. В следующих главах книги мы рассмотрим средства автоматизированного проектирования приложений MFC AppWizard и средство для разработки классов ClassWizard.

А сейчас приступим к описанию возможностей ClassView. Выберите из списка ClassView название класса, который вы желаете просмотреть или изменить, и нажмите правую клавишу мыши. На экране появится временное меню, представленное на рисунке 2.14.

Рис. 2.14. Временное меню класса

Строки этого меню позволяют выполнять над классами все основные действия. Строка Go to Definition позволяет просмотреть в окне редактирования исходный текст класса. Вы можете редактировать класс непосредственно, но для добавления в класс новых методов и данных удобнее пользоваться строками Add Function и Add Variable.

Добавление к классу нового метода

Чтобы добавить в класс новый метод, выберите из временного меню строку Add Function. На экране появится диалоговая панель Add Member Function, представленная на рисунке 2.15.

Рис. 2.15. Диалоговая панель Add Member Function

В поле Function Type следует ввести тип значения, возвращаемого методом. Объявление метода запишите в поле Function Declaration. В этой же диалоговой панели можно определить область видимости метода. Для этого предназначен переключатель с зависимой фиксацией Access. Он может находиться в трех положениях: Public, Protected и Private. Переключатели Static и Virtual позволяют определить, что добавляемый метод должен быть объявлен, соответственно, как статический или виртуальный.

Когда все поля диалоговой панели заполнены, нажмите кнопку OK. В объявлении класса будет добавлен новый метод. Название метода также появится в списке элементов класса в окне ClassView.

Добавление к классу нового элемента данных

Процедура добавления в класс новых данных сходна с только что описанной процедурой добавления метода. Для этого выберите из меню строку Add Variable. На экране появится диалоговая панель Add Member Variable, представленная на рисунке 2.16.

Рис. 2.16. Диалоговая панель Add Member Variable

В поле Variable Type надо ввести тип данных, а в поле Variable Declaration – название соответствующей переменной. Область видимости переменной определяется переключателем Access.

С помощью ClassView можно просмотреть список названий файлов в которых используется данный класс. Для этого надо выбрать из временного меню строку References. На экране появится диалоговая панель Definitions and References.

Просмотр дерева наследования классов

ClassView предоставляет очень интересную и полезную возможность просмотра дерева наследования классов приложения. Для этого выберите название интересующего вас класса из списка классов и откройте временное меню, нажав правую кнопку мыши. Строки Derived Classes и Base Classes позволяют просмотреть последовательность классов, порожденных от данного класса или последовательность базовых классов.

На рисунке 2.17 мы воспользовались возможностями ClassView для изучения последовательности базовых классов для основного класса приложения MFHello.

Рис. 2.17. Порядок наследования, диалоговая панель Base Classes and Members

Диалоговая панель Base Classes and Members не имеет кнопок OK и Cancel. Она закрывается в том случае, если вы выберите из нее элемент класса или переключитесь на другое окно. Иногда удобно, чтобы диалоговая панель постоянно присутствовала на экране. Вы можете “прикрепить” ее к главному окну Microsoft Visual C++. Нажмите кнопку , она изменится на . Теперь в любой момент времени вы сможете открыть панель Base Classes and Members.

В левой части этой панели отображается список классов в порядке наследования. Базовые классы расположены ниже и правее наследуемых классов. Вы наглядно можете определить, что основным базовым классом для CMFHelloApp является класс CObject. Из этого класса наследуются классы CCmdTarget, CWinThread, CWinApp и только затем класс CMFHelloApp, определенный в приложении.

В правой части экрана отображаются элементы класса, выбранного из списка классов. Вы можете просмотреть не только элементы классов, определенных в приложении, но также и элементы классов из библиотеки MFC. Все элементы класса разделены на три группы в зависимости от их области видимости – Public, Protected и Private.

Панель Base Classes and Members позволяет легко перейти к редактированию любого элемента класса. Для этого выберите название этого элемента из списка и сделайте по нему двойной щелчок левой кнопкой мыши.

Чтобы вам было легче отличить методы от данных класса, перед методами располагается символ f, а перед данными d. Непосредственно перед именем метода или данных расположен символ, позволяющий отличить статические и виртуальные методы. Перед названиями статических методов расположен символ , а перед виртуальными – .

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

Тип метода Отображать
All Все методы
Virtual Виртуальные методы
Static Статические методы
Non–Static Все методы, кроме статических
Non–Virtual Все методы, кроме виртуальных
Non–Static Non-Virtual Все методы, кроме статических и виртуальных
None Не отображать методы класса

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

Тип элементов данных Отображать
All Все элементы данных
Static Статические элементы данных
Non–Static Все данные, кроме статических
None Не отображать элементы данных

В нижней правой части диалоговой панели Base Classes and Members отображаются названия файлов в которых определен (группа Definitions), и в которых используется (группа References) выбранный элемент. Двойной щелчок левой кнопкой мыши позволяет открыть в редакторе соответствующий файл. Курсор при этом сразу устанавливается в то место, где объявляется или используется выбранный элемент класса.

Редактирование методов класса

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

Рис. 2.18. Временное меню метода

Чтобы открыть в редакторе файл, в котором объявляется метод и перейти к его редактированию, выберите из временного меню метода строку Go to Definition. После того как вы добавите в класс новый метод, ClassWizard создаст шаблон метода. Строка Go to Declaration из временного меню метода позволяет изменить этот шаблон по вашему усмотрению.

Возможности ClassView можно использовать даже на этапе отладки приложения. Так, из временного меню метода можно установить точку прерывания непосредственно на начало метода. Для этого выберите из меню строку Set Breakpoint.

Редактирование элементов данных класса

Временное меню данных класса отличается от временного меню метода. Если выбрать из списка элементов класса данные и нажать правую кнопку мыши, на экране появится меню, представленное на рисунке 2.19.

Рис. 2.19. Временное меню метода

Приложение с единственным окном

Первое созданное нами приложение не имело главного окна. Для вывода сообщения на экран мы использовали функцию AfxMessageBox, которая очень похожа на функцию MessageBox программного интерфейса операционной системы Windows.

Следующее приложение, которое мы будем рассматривать, немного сложнее. При запуске оно будет отображать на экране компьютера обычное окно, имеющее заголовок, системное меню и кнопки управления.

Точно так же как в приложении MFHello, в нашем втором приложении мы будем использовать класс CWinApp в качестве главного класса приложения. Для управления окном приложения мы создадим еще один класс, наследуемый от базового класса CFrameWnd , входящего в библиотеку MFС.

Создайте новый проект, как мы рассказывали выше, и назовите его именем MFStart. В качестве типа приложения выберите из списка Type строку Application (рис. 4.1 из главы “Приложение с главной диалоговой панелью”). Автоматизированные средства разработки приложений MFC AppWizard мы рассмотрим позже.

Наберите в редакторе исходный текст приложения и сохраните его в файле MFStart.cpp (листинг 2.2). Наш пример без учета строк комментариев состоит всего из двадцати строк исходного текста, поэтому набор текста не займет у вас много времени. Включите набранный файл в проект.

Листинг 2.2. Файл MFStart.cpp

// Наследуем от базового класса CWinApp главный

class CMFStartApp : public CWinApp <

// Мы будем переопределять метод InitInstance,

// предназначенный для инициализации приложения

// Создаем объект приложение класса CMFStartApp

// Наследуем от базового класса CFrameWnd класс

// CMFStartWindow. Он будет представлять главное

class CMFStartWindow : public CFrameWnd <

// Объявляем конструктор класса CMFStartWindow


// Метод InitInstance класса CMFStartApp

// Переопределяем виртуальный метод InitInstance

// класса CWinApp. Он вызывается каждый раз при запуске

// Создаем объект класса CMFStartWindow

// Отображаем окно на экране. Параметр m_nCmdShow

// определяет режим в котором оно будет отображаться

// Конструктор класса CMFStartWindow

// Создаем окно приложения, соответствующее

// данному объекту класса CMFStartWindow

Просмотрите папку с файлами проекта. Теперь в ней расположен файл MFStart.cpp. Затем откройте страницу ClassView в окне Project Workspace (рис. 2.20). В ней отображаются два класса CMFStartApp и CMFStartWindow. В класс CMFStartApp входит метод InitInstance, а в класс CMFStartWindow конструктор CMFStartWindow. Кроме того, определена глобальная переменная MFStartApp.

Рис. 2.20. Классы проекта MFStart

Постройте проект и запустите полученное приложение, выбрав из меню Build строку Execute MFStart.exe. На экране появится главное окно приложения, представлене нами на рисунке 2.21. Оно имеет стандартный заголовок с надписью Hello MFC, системное меню и кнопки для изменения размера окна. Чтобы завершить приложение, вы можете выбрать строку Close из системного меню главного окна или нажать на кнопку .

Рис. 2.21. Приложение MFStart

Приложение MFStart очень простое. Оно состоит из одного главного окна и не содержит ни меню, ни каких либо других органов управления. Тем не менее, окно приложения MFStart обладает всеми возможностями окон Windows. Оно имеет заголовок, системное меню и кнопки управления. Вы можете изменить размер этого окна, увеличить его на весь экран и даже уменьшить до размера пиктограммы.

Так же как и у приложения MFHello, первая строка исходного текста приложения MFStart, не считая строки комментария, содержит директиву препроцессора #include, которая включает файл afxwin.h. Этот файл включается в исходные тексты всех приложений, использующих библиотеку классов MFC.

Затем мы определяем главный класс приложения, который наследуется от базового класса CWinApp . Главный класс приложения MFHello, который называется CMFStartApp, определяется следующим образом:

// Наследуем от базового класса CWinApp главный

class CMFStartApp : public CWinApp <

// Мы будем переопределять метод InitInstance,

// предназначенный для инициализации приложения

Как видите главный класс приложения MFStart определяется точно так же как у приложения MFHello. Класс CMFStartApp наследуется от базового класса CWinApp. При этом базовый класс указан как public. Мы можем вызывать методы класса CWinApp для объектов класса CMFStartApp и обращаться к элементам данных класса CWinApp. В определении класса CMFStartApp объявлен виртуальный метод InitInstance. Он будет переопределен нами несколько позже, после объявления класса окна приложения.

После объявления главного класса приложения мы создаем объект этого класса – MFStartApp:

// Создаем объект приложение класса CMFStartApp

Второй класс, определенный в нашем приложении, наследуется от базового класса CFrameWnd как public и будет представлять главное окно приложения. В классе главного окна мы определили только конструктор, который будет описан ниже:

// Наследуем от базового класса CFrameWnd класс

// CMFStartWindow. Он будет представлять главное

class CMFStartWindow : public CFrameWnd <

// Объявляем конструктор класса CMFStartWindow

Метод InitInstance главного класса приложения CMFStartApp служит для инициализации. Он вызывается автоматически каждый раз, когда запускается очередная копия приложения.

Мы используем метод InitInstance, чтобы отобразить на экране окно приложения. Для этого мы создаем объект класса CMFStartWindow и записываем указатель на этот объект в элемент данных m_pMainWnd класса CWinThread (класс CWinThread является базовым для класса CWinApp). Таким образом, объект приложения и объект окна приложения связываются вместе.

Для создания объекта класса CMFStartWindow мы используем оператор new. Он создает новый объект указанного класса, отводит память и возвращает указатель на него. При создании нового объекта оператором new для него автоматически вызывается конструктор, описанный ниже.

Окно появится на экране только после того, как будет вызван метод ShowWindow. В качестве параметра методу ShowWindow передается параметр m_nCmdShow. Переменная m_nCmdShow является элементом класса CWinApp. Его назначение соответствует параметру nCmdShow функции WinMain, то есть определяет, как должно отображаться главное окно приложения сразу после его запуска.

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

В конце метода InitInstance мы вызываем оператор return и возвращаем значение TRUE, означающее, что инициализация приложения завершилась успешно и можно приступать к обработке очереди сообщений.

Если метод InitInstance вернет значение FALSE, приложение немедленно завершится. Мы использовали эту возможность в приложении MFHello, описанном выше.

// Метод InitInstance класса CMFStartApp

// Переопределяем виртуальный метод InitInstance

// класса CWinApp. Он вызывается каждый раз при запуске

// Создаем объект класса CMFStartWindow

// Отображаем окно на экране. Параметр m_nCmdShow

// определяет режим в котором оно будет отображаться

Чтобы создать окно, мы создаем объект класса CMFStartWindow. Такой объект не является собственно окном, которое пользователь видит на экране компьютера, а представляет собой внутреннее представление окна. Для создания окна предназначается метод Create, определенный в классе CFrameWnd. Он создает окно и связывает его с объектом Си++, в нашем случае с объектом класса CMFStartWindow:

// Конструктор класса CMFStartWindow

// Создаем окно приложения, соответствующее

// данному объекту класса CMFStartWindow

Для упрощения мы поместили описание классов, определения их методов и определения глобальных переменных в одном файле. На практике описания различных классов размещают в отдельных включаемых файлах. А определения методов записывают в программные файлы, имеющие расширение cpp.

Например, мы могли бы поместить описание классов CMFStartApp и CMFStartWindow в файлы MFStartApp.h и MFStartWindow.h. Метод InitInstance класса CMFStartApp и определение глобальной переменной MFStartApp можно поместить в файл MFStartApp.cpp, а определение конструктора класса CMFStartWindow – в файл MFStartWindow.cpp.

Так как в методе InitInstance класса CMFStartApp мы создаем новый объект класса CMFStartWindow, то мы должны включить в файл MFStartApp.cpp не только файл MFStartApp.h но еще и файл MFStartWindow.h. В проект MFStart мы должны записать оба программных файла MFStartApp.cpp и MFStartWindow.cpp. Листинги, представленные ниже содержат проект MFStart, разделенный на несколько файлов. Для того, чтобы сократить размер файлов, мы убрали из них комментарии.

Файл MFStartApp.h содержит описание главного класса приложения CMFStartApp. Этот файл представлен в листинге 2.3.

Листинг 2.3. Файл MFStartApp.h

class CMFStartApp : public CWinApp <

Виртуальный метод InitInstance переопределен нами в файле MFStartApp.cpp. В этом же файле создается объект класса CMFStartApp, представляющий само приложение. Файл MFStartApp.cpp показан в листинге 2.4.

Листинг 2.4. Файл MFStartApp.cpp

Класс окна приложения CMFStartWindow определяется в файле MFStartWindow.h, представленном листингом 2.5. Мы наследуем класс CMFStartWindow от базового класса CFrameWnd.

Листинг 2.5. Файл MFStartWindow.h

class CMFStartWindow : public CFrameWnd <

И наконец, последний файл MFStartWindow.cpp модифицированного проекта MFStart показан в листинге 2.6. В этом файле определяется конструктор класса CMFStartWindow.

Листинг 2.6. Файл MFStartWindow.cpp

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

Как вы знаете из предыдущих томов серии “Библиотека системного программиста”, работа приложений операционной системы Windows основана на обработке сообщений. Когда пользователь работает с устройствами ввода/вывода компьютера, например клавиатурой или мышью, драйверы этих устройств создают сообщения, описывающие его действия. Каждое нажатие на клавиши клавиатуры вызывает генерацию ряда сообщений, определяющих, какая клавиша нажата. Перемещение мыши вызывает сообщения, описывающие траекторию перемещения указателя мыши и т. д. Другие сообщения могут вырабатываться операционной системой или самими приложениями.

Илон Маск рекомендует:  Pos - Функция Delphi

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

Приложение в цикле, который называется циклом обработки сообщений, получает сообщения из очереди приложения и направляет их соответствующей функции окна, которая и выполняет обработку сообщения. Цикл обработки сообщений обычно состоял из оператора while в котором циклически вызывались функции GetMessage и DispatchMessage:

Для более сложных приложений цикл обработки сообщений содержал вызовы других функций, например TranslateMessage, TranslateAccelerator. Они обеспечивали предварительную обработку сообщений.

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

Функция обработки, сообщения опознает, какое именно сообщение поступило для обработки и выполняет соответствующие действия. Сообщения распознаются по его коду. Обычно функция окна содержит оператор switch, который служит для определения кода сообщений. Вот пример типичной функции окна:

long FAR PASCAL _export WndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam) <

return DefWindowProc(hwnd, message, wParam, lParam);

В сложных приложениях функция окна может обрабатывать большое количество разнообразных сообщений и оператор switch может стать очень длинным. Конечно, работать с блоком программного кода, который не помещается на одном экране, очень неудобно.

Чтобы “избавиться” от длинного оператора switch, применялись всевозможные ухищрения. Например, в приложении создавался массив, каждый элемент которого содержал код сообщения и указатель на функцию для его обработки. В функции окна помещался только небольшой программный код, который при получении сообщения просматривал массив, искал для него соответствующий элемент массива и вызывал определенную в нем функцию.

Если вы используете библиотеку классов MFC, то за обработку сообщений отвечают классы. Любой класс, наследованный от базового класса CCmdTarget, может обрабатывать сообщения. Чтобы класс смог обрабатывать сообщения, необходимо, чтобы он имел таблицу сообщений класса. В этой таблице для каждого сообщения указан метод класса, предназначенный для его обработки.

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

• сообщения от органов управления;

Оконные сообщения

Эта группа включает сообщения, предназначенные для обработкой функцией окна. Практически все сообщения, идентификаторы которых начинаются префиксом WM_, за исключением сообщения WM_COMMAND, относятся к этой группе.

Оконные сообщения предназначаются для обработки объектами, представляющими окна. Это могут быть практически любые объекты класса CWnd или классов, наследованных от него, например CFrameWnd, CMDIFrameWnd, CMDIChildWnd, CView, CDialog. Характерной чертой этих классов является то, что они включают идентификатор окна.

Большинство этих сообщений имеют параметры, детально характеризующие сообщение. Например сообщение WM_SIZE передается окну, когда пользователь меняет его размер и имеет параметры, определяющие новый размер окна.

Сообщения от органов управления

Эта группа включает в себя сообщения WM_COMMAND от дочерних окон (включая окна стандартных классов), передаваемые их родительскому окну. Сообщения от органов управления обрабатываются точно таким же образом, что и оконные сообщения.

Исключение составляет сообщение WM_COMMAND с кодом извещения BN_CLICKED. Это сообщение передается кнопкой, когда пользователь на нее нажимает. Обработка сообщений с кодом извещения BN_CLICKED от органов управления происходит аналогично обработке командных сообщений.

Командные сообщения

Сообщения WM_COMMAND от меню, кнопок панели управления и клавиш акселераторов. В отличие от оконных сообщений и сообщений от органов управления, командные сообщения могут быть обработаны более широким спектром объектов. Эти сообщения обрабатывают не только объекты, представляющие окна, но также объекты классов, представляющих приложение, документы и шаблон документов.

Характерной особенностью командных сообщений является идентификатор. Идентификатор командного сообщения определяет объект, который вырабатывает (посылает) данное сообщение.

В приложении MFMenu строка Beep меню Test имеет идентификатор ID_TEST_BEEP. Когда пользователь выберет данную строку, в очередь приложения поступит сообщение WM_COMMAND с идентификатором ID_TEST_BEEP или другими словами, командное сообщение ID_TEST_BEEP.

Таблица сообщений

В библиотеке классов MFC для обработки сообщений используется специальный механизм, который получил название Message Map – таблица сообщений .

Таблица сообщений состоит из набора специальных макрокоманд, ограниченных макрокомандами BEGIN_MESSAGE_MAP и END_MESSAGE_MAP. Между ними расположены макрокоманды, отвечающие за обработку отдельных сообщений.

Макрокоманда BEGIN_MESSAGE_MAP представляет собой заголовок таблицы сообщений. Она имеет два параметра. Первый параметр содержит имя класса таблицы сообщений. Второй параметр указывает его базовый класс.

Если в таблице сообщений класса отсутствует обработчик для сообщения, оно передается для обработки базовому классу, указанному вторым параметром макрокоманды BEGIN_MESSAGE_MAP. Если таблица сообщений базового класса также не содержит обработчик этого сообщения, оно передается следующему базовому классу и т. д.

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

• Стандартные сообщения Windows обрабатываются функцией “default window procedure”

• Командные сообщения передаются по цепочке следующему объекту, который может обработать командное сообщение. Более подробно мы расскажем об этой цепочке в главах “Однооконный интерфейс” и “Многооконный интерфейс”

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

Макрокоманда Устанавливает методы для обработки сообщений
ON_WM_ Стандартных сообщений операционной системы Windows
ON_REGISTERED_MESSAGE Зарегистрированные сообщения операционной системы Windows
ON_MESSAGE Сообщений, определенных пользователем
ON_COMMAND, ON_COMMAND_RANGE Командных сообщений
ON_UPDATE_COMMAND_UI, ON_UPDATE_COMMAND_UI_RANGE Сообщений, предназначенных для обновления пользовательского интерфейса
ON_ , ON_CONTROL_RANGE Сообщений от органов управления

Перечисленные в таблице макрокоманды имеют различное количество параметров в зависимости от типа обрабатываемых ими сообщений.

Обрабатывает стандартные сообщения операционной системы Windows. Вместо указывается имя сообщения без префикса WM_. Так, например для обработки сообщения WM_SIZE предназначена макрокоманда ON_WM_SIZE.

Для обработки сообщений, определенных в таблице сообщений макрокомандами ON_WM_ , вызываются одноименные методы. Имя метода обработчика соответствует названию сообщения, без учета префикса WM_.

В классе CWnd определены обработчики для стандартных сообщений. Эти обработчики будут использоваться по умолчанию. Вот некоторые из таких методов.

Сообщение Макрокоманда Метод обработчик
WM_CHAR ON_WM_CHAR() afx_msg void OnChar(UINT, UINT, UINT);
WM_CREATE ON_WM_CREATE() afx_msg int OnCreate(LPCREATESTRUCT);
WM_HSCROLL ON_WM_HSCROLL() afx_msg void OnHScroll(UINT, UINT, CWnd*);
WM_KEYDOWN ON_WM_KEYDOWN() afx_msg void OnKeyDown(UINT, UINT, UINT);
WM_KEYUP ON_WM_KEYUP() afx_msg void OnKeyUp(UINT, UINT, UINT);
WM_LBUTTONDOWN ON_WM_LBUTTONDOWN() afx_msg void OnLButtonDown(UINT, CPoint);
WM_LBUTTONUP ON_WM_LBUTTONUP() afx_msg void OnLButtonUp(UINT, CPoint);
WM_PAINT ON_WM_PAINT() afx_msg void OnPaint();
WM_SIZE ON_WM_SIZE() afx_msg void OnSize(UINT, int, int);
WM_TIMER ON_WM_TIMER() afx_msg void OnTimer(UINT);
WM_VSCROLL ON_WM_VSCROLL() afx_msg void OnVScroll(UINT, UINT, CWnd*);

Все методы-обработчики определены с ключевым словом afx_msg. Оно позволяет отличить эти методы от остальных методов класса. На этапе препроцессорной обработки ключевое слово afx_msg удаляется. Определение afx_msg вы можете найти в файле afxwin.h:

Макрокоманды ON_WM_ не имеют параметров. Однако методы, которые вызываются для обработки соответствующих сообщений, имеют параметры, количество и назначение которых зависит от обрабатываемого сообщения.

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

Макрокоманда ON_REGISTERED_MESSAGE обслуживает сообщения операционной системы Windows, зарегистрированные с помощью функции RegisterWindowMessage. Параметр nMessageVariable указывает идентификатор сообщения, для которого будет вызываться метод memberFxn.

Макрокоманда ON_MESSAGE обрабатывает сообщения, определенные пользователем. Идентификатор сообщения (его имя) указывается параметром message. Метод, который вызывается для обработки сообщения, указывается параметром memberFxn.

Макрокоманды ON_COMMAND предназначены для обработки командных сообщений. Командные сообщения поступают от меню, кнопок панели управления и клавиш акселераторов. Характерной особенностью командных сообщений является то, что с ними связан идентификатор сообщения.

Макрокоманда ON_COMMAND имеет два параметра. Первый параметр соответствует идентификатору командного сообщения, а второй имени метода, предназначенного для обработки этого сообщения. Таблица сообщений должна содержать не больше одной макрокоманды для командного сообщения.

В общем случае командные сообщения не имеют обработчиков, используемых по умолчанию. Существует только небольшая группа стандартных командных сообщений, имеющих методы обработчики, вызываемые по умолчанию. Эти сообщения соответствуют стандартным строкам меню приложения. Так, например, если вы (или MFC AppWizard) присвоите строке Open меню File идентификатор ID_FILE_OPEN, то для его обработки будет вызван метод OnFileOpen, определенный в классе CWinApp. Список стандартных командных сообщений и их описание представлены в главах “Однооконный интерфейс” и “Многооконный интерфейс”.

Принято, что методы обработчики командных сообщений (как и методы обработчики всех других сообщений) должны быть определены с ключевым словом afx_msg.

Макрокоманда ON_COMMAND ставит в соответствие одному командному сообщению один метод-обработчик. В некоторых случаях более удобно, когда один и тот же метод-обработчик применяется для обработки сразу нескольких командных сообщений с различными идентификаторами. Для этого предназначена макрокоманда ON_COMMAND_RANGE .

Она назначает один метод memberFxn для обработки ряда командных сообщений, идентификаторы которых лежат в интервале от id1 до id2.

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

Параметр id указывает идентификатор сообщения, а параметр memberFxn имя метода для его обработки.

Методы, предназначенные для обработки данного класса сообщений, должны быть определены с ключевым словом afx_msg и иметь один параметр – указатель на объект класса CCmdUI . Для удобства, имена методов, предназначенных для обновления пользовательского интерфейса, начинаются с OnUpdate:

afx_msg void OnUpdate (CCmdUI* pCmdUI);

В качестве параметра pCmdUI методу передается указатель на объект класса CCmdUI. В нем содержится информация о объекте пользовательского интерфейса, который надо обновить – строке меню или кнопке панели управления. Класс CCmdUI также включает методы, позволяющие изменить внешний вид представленного им объекта пользовательского интерфейса.

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

При этом посылается несколько сообщений, по одному для каждой строки меню. С помощью макрокоманд ON_UPDATE_COMMAND_UI можно определить методы-обработчики, ответственные за обновление внешнего вида каждой строки меню и соответствующей ей кнопке на панели управления. Эти методы могут изменять состояние строки меню – отображать ее серым цветом, запрещать ее выбор, отображать около нее символ v и т. д.

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

Дополнительную информацию об обновлении пользовательского интерфейса приложения вы можете получить в разделе “Однооконный интерфейс”.

Макрокоманда ON_UPDATE_COMMAND_UI_RANGE обеспечивает обработку сообщений, предназначенных для обновления пользовательского интерфейса, идентификаторы которых лежат в интервале от id1 до id2. Параметр memberFxn указывает метод используемый для обработки.

ON_UPDATE_COMMAND_UI_RANGE(id1, id2, memberFxn)

Макрокоманды ON_ предназначены для обработки сообщений от органов управления. Такие сообщения могут передаваться органами управления диалоговой панели. Сообщения от органов управления не имеют обработчиков, используемых по умолчанию. При необходимости вы должны определить их самостоятельно.

Все макрокоманды ON_ имеют два параметра. В первом параметре id указывается идентификатор органа управления. Сообщения от этого органа управления будут обрабатываться методом memberFxn.

Макрокоманда ON_CONTROL_RANGE обрабатывает сообщения, идентификаторы которых находятся в интервале от id1 до id2. Параметр wNotifyCode содержит код извещения. Метод-обработчик указывается параметром memberFxn.

ON_CONTROL_RANGE(wNotifyCode, id1, id2, memberFxn)

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

Однако ClassWizard не всесилен. Так он не позволяет определить один метод для обработки нескольких сообщений. Как вы уже знаете, для этих целей предназначены макрокоманды ON_COMMAND_RANGE и ON_CONTROL_RANGE. Если вы решите воспользоваться этими макрокомандами, вам придется редактировать таблицу сообщений непосредственно, без использования ClassWizard.

Более подробно об использовании ClassWizard для создания обработчиков сообщений вы можете прочитать в разделе “Средства ClassWizard” главы “Приложение с главной диалоговой панелью”. А сейчас мы рассмотрим механизм обработки сообщений, используемый MFC, на примере нескольких приложений.

Приложение MFMenu

Приложения, которые мы рассматривали до сих пор, фактически никак не могли взаимодействовать с пользователем. Они не имели ни меню, ни панели управления. И самое главное – они не содержали обработчиков сообщений.

Сейчас мы рассмотрим приложение MFMenu, которое имеет меню и содержит обработчики сообщений, передаваемых приложению, когда пользователь открывает меню и выбирает из него строки. Для создания приложения MFMenu мы также не станем пользоваться средствами автоматизированной разработки MFC AppWizard, и наберем текст приложения вручную. Этот позволит вам лучше разобраться с механизмом сообщений.

Создайте новый проект под названием MFMenu. В качестве типа приложения выберите из списка Type строку Application (рис. 4.1 из главы “Приложение с главной диалоговой панелью”). Наберите в редакторе исходный текст приложения и сохраните его в файле MFMenu.cpp (листинг 2.7). Чтобы быстрее набрать текст приложения, вы можете получить его, изменив исходный текст приложения MFStart. Затем включите этот файл в проект.

Листинг 2.7. Файл MFMenu.cpp

// Класс CMFMenuApp – главный класс приложения

class CMFMenuApp : public CWinApp <

// Мы будем переопределять метод InitInstance,

// предназначенный для инициализации приложения

// Создаем объект приложение класса CMFMenuApp

// Класс CMFMenuWindow – представляет главное окно

class CMFMenuWindow : public CFrameWnd <

// Объявляем конструктор класса CMFMenuWindow

// Объявляем методы для обработки команд меню

// Макрокоманда необходима, так как класс

// CMFMenuWindow обрабатывает сообщения

// Обрабатывает команду ID_TEST_BEEP

// Таблица сообщений класса CMFMenuWindow

// Метод InitInstance класса CMFMenuApp

// Создаем объект класса CMFMenuWindow

// Конструктор класса CMFMenuWindow

// Создаем окно приложения, соответствующее

// данному объекту класса CMFMenuWindow

Create(NULL, «Hello MFC», WS_OVERLAPPEDWINDOW, rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU));

Добавить в проект новый ресурс очень просто. Вы можете для этого воспользоваться кнопками панели управления Progect или установить указатель мыши на название типа ресурса и нажать правую кнопку мыши. На экране появится временное меню свойств данного ресурса.

Если у вас уже есть ресурсы, которые разработаны ранее и записаны в отдельных файлах на диске, вы можете подключить их к своему проекту. Для этого надо выбрать из временного меню свойств ресурса строку Import. На экране появится диалоговая панель Import Resource с приглашением ввести имя файла подключаемого вами ресурса. Новый ресурс проекта будет записан в подкаталог RES, расположенный в каталоге проекта.

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

Среда Visual C++ версии 4.0 не только позволяет просматривать и редактировать ресурсы приложения, она позволяет сразу после создания ресурса вызвать ClassWizard и подключить к ресурсу управляющий программный код. Пока мы не будем использовать ClassWizard, а код, управляющий ресурсами приложения, создадим вручную.

Создание меню для приложения MFMenu

Так как наше приложение будет содержать меню, мы приступим к созданию ресурсов приложения. Для этого создайте новый файл ресурсов. Выберите из меню File строку New, а затем из открывшейся диалоговой панели выберите строку Resource Script и нажмите кнопку OK.

Теперь надо создать меню. Выберите из меню Insert строку Resource. На экране появится диалоговая панель Insert Resource. Выберите из нее строку Menu и нажмите кнопку OK. Вы сможете в диалоговом режиме разработать меню. Чтобы быстрее перейти к редактированию меню, вы можете нажать кнопку New Menu ( ) из панели управления Project или просто нажать комбинацию кнопок .

Создайте меню, содержащее единственную строку Test, при выборе которой открывается меню, содержащее три строки – Beep и Exit. Внешний вид меню во время разработки представлен на рисунке 2.22.

Рис. 2.22. Разработка меню приложения

Когда вы создаете новое меню верхнего уровня или определяете строки, входящие в это меню, на экране появляется диалоговое окно Menu Item Properties (рис. 2.23). В нем полностью описывается выбранный элемент меню. В поле Caption задается название меню или строки меню. В названии вы можете вставить символ &. Он будет означать, что символ, следующий за ним, можно будет использовать для быстрого выбора данного элемента меню. Например, если перед названием строки меню Beep поставить символ &, то во время работы приложения символ B будет отображаться с подчеркиванием, и строку B eep можно будет выбрать, нажав комбинацию клавиш .

Рис. 2.23. Диалоговая панель Menu Item Properties

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

Редактор ресурсов сам предлагает вам название идентификатора, создавая его из названия главного меню и строки меню. Так например строке Beep меню Test по умолчанию будет присвоен идентификатор ID_TEST_BEEP.

В поле Prompt можно в нескольких словах описать данный пункт меню. Введенная вами строка будет записана в строковый ресурс. Ей будет присвоен тот же самый идентификатор, что и пункту меню. Приложение может использовать строку описания, чтобы предоставить пользователю краткую справку о меню.

Если вы разрабатываете приложение с помощью средств MFC AppWizard, то при выборе пользователем строк меню их описание будет появляться в панели состояния StatusBar. Что интересно, для этого вам не потребуется написать ни одной строки текста программы. Это будет сделано автоматически благодаря возможностям библиотеки классов MFC и MFC AppWizard.

Остальные переключатели диалоговой панели Menu Item Properties описаны в следующей таблице.

Переключатель Описание
Break Этот переключатель может принимать три различных значения – None, Column и Bar. Он позволяет задать структуру меню. По умолчанию выбрано значение None оно соответствует нормальному виду меню без деления на колонки. Если выбрать значение Column, тогда пункт меню будет размещен в новом столбце. Значение Bar соответствует Column, за исключением меню верхнего уровня. Если указать Bar для меню верхнего уровня, то новая колонка будет отделена от старой вертикальной линией
Checked Если установить переключатель, то строка меню будет выделена символом √. Потом, обращаясь к специальным методам, вы сможете удалять или отображать этот символ
Grayed Если включить переключатель Grayed, тогда пункт меню будет отображаться серым цветом и будет недоступен для выбора пользователем. Такая возможность удобна, если вам надо сделать недоступным какие-либо возможности приложения. Впоследствии приложение может сделать пункт меню доступным. Для этого надо вызвать соответствующий метод
Help Если установить переключатель Help, тогда для него будет установлено выравнивание по правому краю. Обычно этот переключатель устанавливают для меню верхнего уровня, которое управляет справочной системной приложения
Inactive Если включен переключатель Grayed, тогда переключатель недоступен. В противном случае вы можете установить переключатель Inactive. В этом случае пункт меню будет неактивен
Pop-up Вы можете создавать многоуровневые меню. Если вы включите переключатель Pop-up, то данный пункт меню будет являться меню верхнего уровня, которое можно открыть. По умолчанию, все пункты главного меню имеют установленный переключатель Pop-up. Так как меню верхнего уровня служит только для объединения других пунктов меню, то оно не имеет идентификатора
Separator Если переключатель установлен, тогда в меню вставляется разделитель. Для разделителя все остальные поля и переключатели диалоговой панели не используются

Сохраните файл ресурсов в файле с именем MFMenu.rc. Редактор ресурсов создает кроме самого файла ресурсов еще включаемый файл, в котором определяются константы, используемые в файле ресурсов. В нашем случае в нем определяются идентификаторы меню приложения. По умолчанию этот файл сохраняется под именем resource.h . Вы можете изменить его, выбрав из меню View строку Resource Includes. Для нашего приложения мы изменили имя включаемого файла для ресурсов на MFMenuRes.h. Содержимое этого файла представлено листингом 2.8.

Листинг 2.8. Файл MFMenuRes.h

// Включаемый файл, созданный Microsoft Developer Studio

Основы mfc

На этом шаге мы приведем фрагмент иерархии классов MFC .

Библиотека MFC реализована как набор классов C++ . Одним из основных способов повторного использования кода в C++ является механизм наследования . Он позволяет создать производный класс, обладающий всеми характеристиками родительского. Подобно другим библиотекам классов C++ , классы, входящие в MFC , организованы в виде наследственной иерархии. Она содержит огромное количество узкоспециальных классов, производных от нескольких базовых, обеспечивающих всех своих потомков общими функциями.

В качестве примера на рисунке 1 показана структура наследования класса CDialog , представляющего диалоговое окно Windows .

Рис.1. Структура наследования класса CDialog

На вершине иерархии MFC находится класс CObject . Он является базовым для большинства классов MFC , обеспечивая их основными функциями, к которым относится в том числе сериализация (сохранение и восстановление объектов в/из файла), информация о классе периода выполнения, поддержка диагностики и отладки (проверка достоверности и создание дампов), совместимость с классами наборов.

CCmdTarget — базовый класс для объектов, способных обрабатывать сообщения Windows .

Класс CWnd представляет окно. Тот факт, что класс CDialog является производным от CWnd , подтверждает, что диалог — это специальный тип окна.

Проиллюстрируем, как использовать справочную систему Visual C++ для просмотра иерархии классов MFC (MFC Hierarchy Chart) .

  • Просмотр MFC Hierarchy Chart.
    1. Запустите Visual C++ . В меню Help выберите пункт Index . Откроется библиотека MSDN , причем курсор будет помещен в поле Туре in the keyword to find ( Введите ключевое слово для поиска ).
    2. В этом поле наберите hierarchy chart .
    3. В появившемся списке дважды щелкните элемент hierarchy chart . В правой панели окна появится изображение иерархии классов MFC .
    4. Изучите иерархию классов MFC . Обратите внимание на то, что классы объединены в группы — их названия помечены полужирным начертанием. Посмотрите, какие классы унаследованы от классов CObject , CCmdTarget и CWnd .

Рис.2. Окно с иерархией классов

На следующем шаге мы приведем классификацию классов MFC .

Глава 1. Введение в Visual C++

В связи с тем, что сегодня уровень сложности программного обеспечения очень высок, разработка приложений Windows с использованием только какого-либо языка программирования (например, языка C) значительно затрудняется. Программист должен затратить массу времени на решение стандартных задач по созданию многооконного интерфейса. Реализация технологии связывания и встраивания объектов — OLE — потребует от программиста еще более сложной работы.

Чтобы облегчить работу программиста практически все современные компиляторы с языка C++ содержат специальные библиотеки классов. Такие библиотеки включают в себя практически весь программный интерфейс Windows и позволяют пользоваться при программировании средствами более высокого уровня, чем обычные вызовы функций. За счет этого значительно упрощается разработка приложений, имеющих сложный интерфейс пользователя, облегчается поддержка технологии OLE и взаимодействие с базами данных.

Современные интегрированные средства разработки приложений Windows позволяют автоматизировать процесс создания приложения. Для этого используются генераторы приложений. Программист отвечает на вопросы генератора приложений и определяет свойства приложения — поддерживает ли оно многооконный режим, технологию OLE, трехмерные органы управления, справочную систему. Генератор приложений, создаст приложение, отвечающее требованиям, и предоставит исходные тексты. Пользуясь им как шаблоном, программист сможет быстро разрабатывать свои приложения.

Подобные средства автоматизированного создания приложений включены в компилятор Microsoft Visual C++ и называются MFC AppWizard. Заполнив несколько диалоговых панелей, можно указать характеристики приложения и получить его тексты, снабженные обширными комментариями. MFC AppWizard позволяет создавать однооконные и многооконные приложения, а также приложения, не имеющие главного окна , -вместо него используется диалоговая панель. Можно также включить поддержку технологии OLE, баз данных, справочной системы.

Конечно, MFC AppWizard не всесилен. Прикладную часть приложения программисту придется разрабатывать самостоятельно. Исходный текст приложения, созданный MFC AppWizard, станет только основой, к которой нужно подключить остальное. Но работающий шаблон приложения — это уже половина всей работы. Исходные тексты приложений, автоматически полученных от MFC AppWizard, могут составлять сотни строк текста. Набор его вручную был бы очень утомителен.

Нужно отметить, что MFC AppWizard создает тексты приложений только с использованием библиотеки классов MFC (Microsoft Foundation Class library). Поэтому только изучив язык C++ и библиотеку MFC, можно пользоваться средствами автоматизированной разработки и создавать свои приложения в кратчайшие сроки.

Некоторые сведения о программировании Windows-приложений

MFC Ї это базовый набор (библиотека) классов, написанных на языке С++ и предназначенных для упрощения и ускорения процесса программирования под Windows. Перед изучением библиотеки MFC и ее использованием для создания Windows-приложений, следует вспомнить, как работает сама Windows и каковы принципы взаимодействия программ с ней, какова структура типичной Windows-программы.

Программная среда Windows

Рассмотрим наиболее важные моменты работы Windows и принципы взаимодействия программ с ней.

Интерфейс вызовов функций в Windows

Благодаря данному интерфейсу доступ к системным ресурсам осуществляется через целый рад системных функций. Совокупность таких функций называется прикладным программным интерфейсом, или API (Application Programming Interfase). Для взаимодействия с Windows приложение запрашивает функции API, с помощью которых реализуются все необходимые системные действия, такие как выделение памяти, вывод на экран, создание окон и т.п.

Библиотека MFC инкапсулирует многие функции API. Хотя программам и разрешено обращаться к ним напрямую, все же чаще это будет выполняться через соответствующие функции-члены. Как правило, функции-члены либо аналогичны функциям API, либо непосредственно обращаются к нужной части интерфейса.

Библиотеки динамической загрузки (DLL)

Поскольку API состоит из большого числа функций, может сложиться впечатление, что при компиляции каждой программы, написанной для Windows, к ней подключается код довольно значительного объема. В действительности это не так. Функции API содержатся в библиотеках динамической загрузки (Dynamic Link Libraries, или DLL), которые загружаются в память только в тот момент, когда к ним происходит обращение, т.е. при выполнении программы. Рассмотрим, как осуществляется механизм динамической загрузки.

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

Win16 или Win32

В настоящее время широко распространены две версии API. Первая называется Win16 и представляет собой 16-разрядную версию, используемую в Windows 3.1. Вторая, 32-разрядная версия, называется Win32 и используется в Windows 95 и Windows NT. Win32 является надмножеством для Win16 (т.е. фактически включает в себя этот интерфейс), так как большинство функций имеет то же название и применяется аналогичным образом. Однако, будучи в принципе похожими, оба интерфейса все же отличаются друг от друга. Win32 поддерживает 32-разрядную линейную адресацию, тогда как Win16 работает только с 16-разрядной сегментированной моделью памяти. Это привело к тому, что некоторые функции были модифицированы таким образом, чтобы принимать 32-разрядные аргументы и возвращать 32-разрядные значения. Часть из них пришлось изменить с учетом 32-разрядной архитектуры. Была реализована поддержка потоковой многозадачности, новых элементов интерфейса и прочих нововведений Windows.

Так как Win32 поддерживает полностью 32-разрядную адресацию, то логично, что целые типы данных (intergers) также объявлены 32-разрядными. Это означает, что переменные типа int и unsignerd будут иметь длину 32 бита, а не 16, как в Windows 3.1. Если же необходимо использовать переменную или константу длиной 16 бит, они должны быть объявлены как short. (дальше будет показано, что для этих типов определены независимые typedef-имена.) Следовательно, при переносе программного кода из 16-разрядной среды необходимо убедиться в правильности использования целочисленных элементов, которые автоматически будут расширены до 32 битов, что целочисленных элементов, которые автоматически будут расширены до 32 битов, что может привести к появлению побочных эффектов.

Другим следствием 32-разрядной адресации является то, что указатели больше не нужно объявлять как near и far. Любой указатель может получить доступ к любому участку памяти. В Windows 95 и Windows NT константы near и far объявлены (с помощью директивы #define)пустыми.


Одним из подмножеств API является GDI (Graphics Device Interfase Ї интерфейс графического устройства). GDI Ї это та часть Windows, которая обеспечивает поддержку аппаратно-независимой графики. Благодаря функциям GDI Windows-приложение может выполняться на самых различных компьютерах.

Многозадачность в Windows

Как известно, все версии Windows поддерживают многозадачность. В Windows 3.1 имеется только один тип многозадачности Ї основанный на процессах. В более передовых системах, таких как Windows 95 и Windows NT, поддерживается два типа многозадачности: основанный на процессах и основанный на потоках. Давайте рассмотрим их чуть подробнее.

Процесс Ї это программа, которая выполняется. При многозадачности такого типа две или более программы могут выполняться параллельно. Конечно, они по очереди используют ресурсы центрального процессора и с технической точки зрения, выполняются неодновременно, но благодаря высокой скорости работы компьютера это практически незаметно.

Поток Ї это отдельная часть исполняемого кода. Название произошло от понятия «направление протекания процесса¬. В многозадачности данного типа отдельные потоки внутри одного процесса также могут выполняться одновременно. Все процессы имеют по крайней мере один поток, но в Windows 95 и Windows NT их может быть несколько.

Отсюда можно сделать вывод, что в Windows 95 и Windows NT допускается существование процессов, две или более частей которых выполняются одновременно. Оказывается, такое предположение верно. Следовательно, при работе в этих операционных системах возможно параллельное выполнение, как программ, так и отдельных частей самих программ. Это позволяет писать очень эффективные программы.

Есть и другое существенное различие между многозадачностями Windows 3.1 и Windows 95/NT. В Windows 3.1 используется неприоритетная многозадачность . Это означает, что процесс, выполняющийся в данный момент, получает доступ к ресурсам центрального процессора и удерживает их в течение необходимого ему времени. Таким образом, неправильно выполняющаяся программа может захватить все ресурсы процессора и не давать выполняться другим процессам. В отличие от этого в Windows 95 и Windows NT используется приоритетная многозадачность . В этом случае каждому активному потоку предоставляется определенный промежуток времени работы процессора. По истечению данного промежутка управление автоматически передается следующему потоку. Это не дает возможность программам полностью захватывать ресурсы процессора. Интуитивно должно быть понятно, что такой способ более предпочтителен.

Взаимодействие программ и Windows

Во многих операционных системах взаимодействие между системой и программой инициализирует программа. Например, в DOS программа запрашивает разрешение на ввод и вывод данных. Говоря другими словами, не- Windows-программы сами вызывают операционную систему. Обратного процесса не происходит. В Windows все совершенно наоборот: именно система вызывает программу. Это осуществляется следующим образом: программа ожидает получения сообщения от Windows. Когда это происходит, то выполняется некоторое действие. После его завершения программа ожидает следующего сообщения.

Windows может посылать программе сообщения множества различных типов. Например, каждый раз при щелчке мышью в окне активной программы посылается соответствующее сообщение. Другой тип сообщений посылается, когда необходимо обновить содержимое активного окна. Сообщения посылаются также при нажатии клавиши, если программа ожидает ввода с клавиатуры. Необходимо запомнить одно: по отношению к программе сообщения появляются случайным образом. Вот почему Windows-программы похожи на программы обработки прерываний: невозможно предсказать, какое сообщение появиться в следующий момент.

Основы программирования под Windows

Поскольку архитектура Windows-программ основана на принципе сообщений, все эти программы содержат некоторые общие компоненты. Обычно их приходится в явном виде включать в исходный код. Но, к счастью, при использовании библиотеки MFC это происходит автоматически; нет необходимости тратить время и усилия на их написание. Тем не менее, чтобы до конца разобраться, как работает Windows-программа, написанная с использованием MFC, и почему она работает именно так, необходимо в общих чертах понять назначение этих компонентов.

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

Все Windows-программы должны содержать специальную функцию, которая не используется в самой программе, но вызывается самой операционной системой. Эту функцию обычно называют функцией окна , или процедурой окна . Она вызывается Windows, когда системе необходимо передать сообщение в программу. Именно через нее осуществляется взаимодействие между программой и системой. Функция окна передает сообщение в своих аргументах. Согласно терминологии Windows, функции, вызываемые системой, называются функциями обратного вызова . Таким образом, функция окна является функцией обратного вызова.

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

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

Как объяснялось выше, Windows взаимодействует с программой, посылая ей сообщения. Все приложения Windows должны организовать так называемый цикл сообщений (обычно внутри функции WinMain()). В этом цикле каждое необработанное сообщение должно быть извлечено из очереди сообщений данного приложения и передано назад в Windows, которая затем вызывает функцию окна программы с данным сообщением в качестве аргумента. В традиционных Windows-программах необходимо самостоятельно создавать и активизировать такой цикл. При использовании MFC это также выполняется автоматически. Однако важно помнить, что цикл сообщений все же существует. Он является неотъемлемой частью любого приложения Windows.

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

Как будет показано дальше, каждое окно в Windows-приложении характеризуется определенными атрибутами, называемыми классом окна . (Здесь понятие «класс¬ не идентично используемому в С++. Оно, скорее, означает стиль или тип.) В традиционной программе класс окна должен быть определен и зарегистрирован прежде, чем будет создано окно. При регистрации необходимо сообщить Windows, какой вид должно иметь окно и какую функцию оно выполняет. В то же время регистрация класса окна еще не означает создание самого окна. Для этого требуется выполнить дополнительные действия. При использовании библиотеки MFC создавать собственный класс окна нет необходимости. Вместо этого можно работать с одним из заранее определенных классов, описанных в библиотеке. В этом еще одно ее преимущество.

Специфика программ для Windows

Структура Windows-программ отличается от структуры программ других типов. Это вызвано двумя обстоятельствами: во-первых, способом взаимодействия между программой и Windows, описанным выше; во-вторых, правилами, которым следует подчиняться для создания стандартного интерфейса Windows-приложения (т.е. чтобы сделать программу «похожей « на Windows-приложение).

Цель Windows Ї дать человеку, который хотя бы немного знаком с системой, возможность сесть за компьютер и запустить любое приложение без предварительной подготовки. Для этого Windows предоставляет дружественный интерфейс пользователя. Теоретически, если пользователь сумел запустить одно Windows-приложение, то он сумеет запустить и любое другое. Конечно, на практике придется немного потренироваться, чтобы научиться использовать большинство программ с максимальной эффективностью. Однако это связано исключительно с тем, что программа делает, а не с тем, как ею пользоваться. Ведь, фактически, значительная часть кода Windows-приложения предназначена именно для организации интерфейса с пользователем.

Хотя создание удобного интерфейса «под Windows¬ является основной задачей при написании любой Windows-программы, такой интерфейс не создается автоматически. То есть вполне можно написать программу, в которой элементы интерфейса используются неэффективно. Чтобы этого избежать, необходимо целенаправленно применять методику, описанную в данной книге. Только программы, написанные таким способом, будут выглядеть и работать действительно так, как надлежит Windows-программам.

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

Типы данных в Windows

В Windows-программах вообще (и в использующих библиотеку MFC в частности) не слишком широко применяются стандартные типы данных из С или С++, такие как int или char*. Вместо них используются типы данных, определенные в различных библиотечных (header) файлах. Наиболее часто используемыми типами являются HANDLE, HWND, BYTE, WORD, DWORD, UNIT, LONG, BOOL, LPSTR и LPCSTR. Тип HANDLE обозначает 32-разрядное целое, используемое в качестве дескриптора. Есть несколько похожих типов данных, но все они имеют ту же длину, что и HANDLE, и начинаются с литеры Н. Дескриптор Ї это просто число, определяющее некоторый ресурс. Например, тип HWND обозначает 32-разрядное целое Ї дескриптор окна. В программах, использующих библиотеку MFC, дескрипторы применяются не столь широко, как это имеет место в традиционных программах. Тип BYTE обозначает 8-разрядное беззнаковое символьное значение, тип WORD Ї 16-разрядное беззнаковое короткое целое, тип DWORD Ї беззнаковое длинное целое, тип UNIT — беззнаковое 32-разрядное целое. Тип LONG эквивалентен типу l o ng. Тип BOOL обозначает целое и используется, когда значение может быть либо истинным, либо ложным. Тип LPSTR определяет указатель на строку, а LPCSTR Ї константный (const) указатель на строку.

Преимущества использования MFC

Как уже упоминалось, MFC Ї это базовый набор (библиотека) классов, написанных на языке С++ и предназначенных для упрощения и ускорения процесса программирования для Windows. Библиотека содержит многоуровневую иерархию классов, насчитывающую около 200 членов. Они дают возможность создавать Windows-приложения на базе объектно-ориентированного подхода. С точки зрения программиста, MFC представляет собой каркас, на основе которого можно писать программы для Windows.

Библиотека MFC разрабатывалась для упрощения задач, стоящих перед программистом. Как известно, традиционный метод программирования под Windows требует написания достаточно длинных и сложных программ, имеющих ряд специфических особенностей. В частности, для создания только каркаса программы таким методом понадобится около 75 строк кода. По мере же увеличения сложности программы ее код может достигать поистине невероятных размеров. Однако та же самая программа, написанная с использованием MFC, будет примерно в три раза меньше, поскольку большинство частных деталей скрыто от программиста.

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

Еще одним существенным преимуществом MFC является упрощение взаимодействия с прикладным программным интерфейсом (API) Windows. Любое приложение взаимодействует с Windows через API, который содержит несколько сот функций. Внушительный размер API затрудняет попытки понять и изучить его целиком. Зачастую даже сложно проследить, как отдельные части API связанны друг с другом! Но поскольку библиотека MFC объединяет (путем инкапсуляции) функции API в логически организованное множество классов, интерфейсом становится значительно легче управлять.

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

Замечание . Небольшое число классов, определенных в библиотеке, не связанно непосредственно с программированием под Windows. Это, в частности, классы, предназначенные для создания строк, управления файлами и обработки особых ситуаций. Иногда называемые классами общего назначения , они могут использоваться как Windows-, так и не- Windows-приложениями.

Обзор среды Microsoft Developer Studio

Студия разработчика фирмы Microsoft (Microsoft Developer Studio) — это интегрированная среда для разработки, позволяющая функционировать различным средам разработки, одна из которых Visual C++, другая — Visual J++. В дальнейшем будет идти речь только о среде разработки Visual C++.

В студии разработчика можно строить обычные программы на C и С++, создавать статические и динамические библиотеки, но основным режимом работы является создание Windows-приложений с помощью инструмента MFC AppWizard (Application Wizard — мастер приложений) и библиотеки базовых классов MFC (Microsoft Foundation Class Library). Такие приложения называются MFC-приложениями. Главная особенность этих Windows-приложений состоит в том, что они работают как совокупность взаимодействующих объектов, классы которых определены библиотекой MFC.

Библиотека MFC

Главная часть библиотеки MFC состоит из классов, используемых для построения компонентов приложения. С каждым MFC-приложением связывается определяющий его на верхнем уровне объект theApp , принадлежащий классу, производному от CWinApp .

Как правило, структура приложения определяется архитектурой Document-View (документ-облик). Это означает, что приложение состоит из одного или нескольких документов — объектов, классы которых являются производными от класса CDocument (класс «документ»). С каждым из документов связаны один или несколько обликов — объектов классов, производных от CView (класс «облик «) и определяющих облик документа.

Класс CFrameWnd («окна-рамки») и производные от него определяют окна-рамки на дисплее. Элементы управления , создаваемые при проектировании интерфейса пользователя, принадлежат семейству классов элементов управления. Появляющиеся в процессе работы приложения диалоговые окна — это объекты классов, производных от CDialog .

Классы CView, CFrameWnd, CDialog и все классы элементов управления наследуют свойства и поведение своего базового класса CWnd («окно»), определяющего по существу Windows-окно. Этот класс в свою очередь является наследником базового ласса CObject («объект»).

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

Архитектура приложения

У всех Windows-приложений фиксированная структура, определяемая функцией WinMain. Структура приложения, построенного из объектов классов библиотеки MFC, является еще более определенной.

Приложение состоит из объекта theApp , функции WinMain , и некоторого количества других объектов. Сердцевина приложения — объект theApp — отвечает за создание всех остальных объектов и обработку очереди сообщений. Объект theApp является глобальным и создается еще до начала работы функции WinMain . Работа функции WinMain заключается в последовательном вызове двух методов объекта theApp : InitInstance и Run . В терминах сообщений можно сказать, WinMain посылает объекту theApp сообщение InitInstance, которое приводит в действие метод InitInstance .

Получив сообщение InitInstance, theApp создает внутренние объекты приложения . Процесс создания выглядит как последовательное порождение одних объектов другими. Набор объектов, порождаемых в начале этой цепочки, определен структурой MFC практически однозначно — это главная рамка, шаблон, документ, облик. Их роли в работе приложения будут обсуждаться позже.

Следующее сообщение, получаемое theApp, — Run — приводит в действие метод Run . Оно как бы говорит объекту: «Начинай работу, начинай процесс обработки сообщений из внешнего мира». Объект theApp циклически выбирает сообщения из очереди и инициирует обработку сообщений объектами приложения.

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

Когда пользователь выбирает команду меню окна главной рамки, то возникают командные сообщения . Они отправляются сначала объектом theApp объекту главная рамка, а затем обходят по специальному маршруту целый ряд объектов, среди которых первыми являются документ и облик, информируя их о пришедшей от пользователя команде.

При работе приложения возникают и обычные вызовы одними объектами методов других объектов. В объектно-ориентированной терминологии такие вызовы могут называться сообщениями . В Visual C++ некоторым методам приписан именно этот статус (например, методу OnDraw).

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

Каркас приложения

Наследование — одна из фундаментальных идей объектно-ориентированного программирования. Именно этот механизм наследования позволяет программисту дополнять и переопределять поведение базового класса, не вторгаясь в библиотеку MFC, которая остается неизменной. Все изменения делаются в собственном производном классе. Именно в этом и заключается работа программиста.

Объекты, их которых состоит приложение, являются объектами классов, производных от классов библиотеки MFC. Разработка приложения состоит в том, что программист берет из библиотеки MFC классы CWinApp, CFrameWnd, CDocument, CView и т.д. и строит производные классы. Приложение создается как совокупность объектов этих производных классов. Каждый объект несет в себе как наследуемые черты, определяемые базовыми классами, так и новые черты, добавленные программистом. Наследуемые черты определяют общую схему поведения, свойственную таким приложениям. Новые же черты позволяют реализовать специфические особенности поведения приложения, необходимые для решения стоящей перед ним задачи.

При определении производного класса программист может:

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

Приложение, построенное на основе библиотеки MFC, — «айсберг», большая часть которого невидима, но является основой всего приложения. Часть приложения, лежащую в библиотеке MFC, — framework — называется каркасом приложения . Рассмотрим работу приложения как процесс взаимодействия между каркасом и частью приложения, разработанной программистом. Совершенно естественно, что в методах, определенных программистом, могут встречаться вызовы методов базового класса, что вполне можно рассматривать как вызов функции из библиотеки. Важнее, однако, что и метод производного класса, определенный программистом, может быть вызван из метода родительского класса. Другими словами, каркас и производный класс в этом смысле равноправны — их методы могут вызывать друг друга. Такое равноправие достигается благодаря виртуальным методам и полиморфизму , имеющимся в арсенале объектно-ориентированного программирования.

Если метод базового класса объявлен виртуальным и разработчик переопределил его в производном классе, это значит, что при вызове данного метода в некоторой полиморфной функции базового класса в момент исполнения будет вызван метод производного класса и, следовательно, каркас вызывает метод, определенный программистом. Точнее говоря, обращение к этому методу должно производиться через ссылку на производный объект либо через объект, являющийся формальным параметром и получающий при вызове в качестве своего значения объект производного класса. Когда вызывается виртуальный метод М1, переопределенный разработчиком, то согласно терминологии Visual C++, каркас посылает сообщение М1 объекту производного класса, а метод М1 этого объекта обрабатывает это сообщение. Если сообщение М1 послано объекту производного класса, а обработчик этого сообщения не задан программистом, объект наследует метод М1 ближайшего родительского класса, в котором определен этот метод. Если же обработчик такого сообщения создан программистом, он автоматически отменяет действия, предусмотренные родительским классом в отсутствие этого обработчика.

Каркас приложений

С Visual C++ тесно связано еще одно понятие — каркас приложений , которое близко и созвучно понятию каркаса приложения, но в отличие от него относится не к одному конкретному приложению, а к библиотеке, с помощью которой строятся многие приложения. Каркас приложений — это библиотека классов, из которых программист берет не только набор классов, играющих роль дополнительных типов данных, но и классы, служащие строительными блоками приложения на самом верхнем уровне. С этой точки зрения, каркас приложения является частью каркаса приложений, относящейся к данному приложению. Примеры каркасов приложений — библиотеки классов MFC и OWL.

Проект приложения

О принципах устройства приложения рассказывалось выше. Теперь рассмотрим, как оно создается с помощью Visual C++. Сначала разберем одно важное понятие — проект . До сих пор приложение рассматривалось, как только как совокупность объектов базовых и производных классов. Но для обеспечения работы приложения требуется нечто большее — наряду с описанием классов необходимо описание ресурсов, связанных с приложением, нужна справочная система и т.п. Термин «проект» как раз и используется, когда имеется в виду такой более общий взгляд на приложение.

В среде Visual C++ можно строить различные типы проектов. Такие проекты после их создания можно компилировать и запускать на исполнение. Фирма Microsoft разработала специальный инструментарий, облегчающий и ускоряющий создание проектов в среде Visual C++. Например, мастер MFC AppWizard (exe) позволяет создать проект Windows-приложения которое имеет однодокументный, многодокументный или диалоговый интерфейс и использует библиотеку MFC.

Создаваемый остов приложения составлен так, что в дальнейшей работе с проектом можно использовать другое инструментальное средство — ClassWizard (мастер классов), предназначенное для создания остовов новых производных классов. Еще одно основное назначение ClassWizard в том, что он создает остовы для переопределяемых методов. Он позволяет показать все сообщения, приходящие классу, и создать остов обработчика любого из этих сообщений. Это только две основные функции ClassWizard. Он не всесилен, но его возможности довольно велики.

Использование средств разработки

В состав компилятора Microsoft Developer Studio встроены средства, позволяющие программисту облегчить разработку приложений. В первую очередь к ним относятся MFC AppWisard, ClassWizard и редактор ресурсов.

Благодаря MFC AppWizard среда разработчика позволяет быстро создавать шаблоны новых приложений. При этом программисту не приходится писать ни одной строчки кода. Достаточно ответить на ряд вопросов, касающихся того, какое приложение требуется создать, и исходные тексты шаблона приложения вместе с файлами ресурсов готовы. Эти тексты можно оттранслировать и получить готовый загрузочный модуль приложения.

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

Для создания ресурсов приложения предназначен редактор ресурсов. Он позволяет быстро создавать новые меню, диалоговые панели, добавлять кнопки к панели управления toolbar и т.д.

Средство ClassWizard позволяет подключить к созданным и отредактированным ресурсам управляющий ими код. Большую часть работы по описанию и определению функций, обрабатывающих сообщения от меню, органов управления диалоговых панелей и т.д., также берет на себя средство ClassWizard.

Типы мастеров проектов

В среде Visual C++ можно строить различные типы проектов. Такие проекты после их создания можно компилировать и запускать на исполнение. Фирма Microsoft разработала специальный инструментарий, облегчающий и ускоряющий создание проектов в среде Visual C++.

Рассмотрим некоторые типы проектов, которые можно создавать при помощи различных средств (мастеров проектов) Microsoft Visual C++:

MFC AppWizard (exe) Ї при помощи мастера приложений можно создать проект Windows-приложения которое имеет однодокументный, многодокументный или диалоговый интерфейс. Однодокументное приложеие может предоставлять пользователю в любой момент времени работать только с одним файлом. Многодокументное приложение, напротив, может одновременно представлять несколько документов, каждый в собственном окне. Пользовательский интерфейс диалогового приложения представляет собой единственное диалоговое окно.

MFC AppWizard (dll) Ї этот мастер приложений позволяет создать структуру DLL, основанную на MFC. При помощи него можно определить характеристики будующей DLL.

AppWizard ATL COM Ї это средство позволяет создать элемент управления ActiveX или сервер автоматизации, используя новую библиотеку шаблонов ActiveX (ActiveX Template Library — ATL). Опции этого мастера дают возможность выбрать активный сервер (DLL) или исполняемый внешний сервер (exe-файл).

Custom AppWizard Ї при помощи этого средства можно создать пользовательские мастера AppWizard. Пользовательский мастер может базироваться на стандартных мастерах для приложений MFC или DLL, а также на существующих проектах или содержать только определеямые разработчиком шаги.

DevStudio Add-in Wizard Ї мастер дополнений позволяет создавать дополнения к Visual Studio. Библиотека DLL расширений может поддерживать панели инструментов и реагировать на события Visual Studio.

MFC ActiveX ControlWizard — мастер элементов управления реализует процесс создания проекта, содержащего один или несколько элементов управления ActiveX, основанных на элементах управления MFC.

Win32 Application Ї этот мастер позволяет создать проект обычного Window-приложения. Проект создается незаполненным, файлы с исходным кодом в него следует добавлять вручную.

Win32 Console Application Ї мастер создания проекта консольного приложения. Консольная приложение Ї это программа, которая выполняется из командной cтроки окна DOS или Windows и не имеет графического интерфейса (окон). Проект консольного приложения создается пустым, предполагая добавление файлов исходного текста в него вручную.

Win32 Dynamic-Link Library Ї создание пустого проекта динамически подключаемой библиотеки. Установки компилятора и компоновщика будут настроены на создание DLL. Исходные файлы следует добавлять вручную.

Win32 Static Library Ї это средство создает пустой проект, предназначенный для генерации статической (объектной) библиотеки. Файлы с исходным кодом в него следует добавлять вручную.

Преимущества мастеров проектов

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

Например, все Windows-приложения имеют достаточно общую структуру, и, следовательно, можно построить некоторые шаблонные заготовки, подходящие для того или иного типа проектов. Построению таких заготовок способствует то, что приложения, создаваемые на основе MFC, строятся из элементов фиксированных классов. Логическим развитием этой идеи было введение специальных классов и специальной архитектуры построения приложения, которая подходила бы широкому классу приложений. О такой архитектуре уже упоминалось, когда речь шла о библиотеке MFC, — это архитектура Document-View. Она является основной, но не единственной при построении проектов в среде Visual C++.

Суть этой архитектуры в том, что работу многих приложений можно рассматривать как обработку документов. При этом можно отделить сам документ, отвечающий за представление и хранение данных, от образа этого документа, видимого на экране и допускающего взаимодействие с пользователем, который просматривает и (или) редактирует документ. В соответствии с этой архитектурой библиотека MFC содержит два семейства классов, производных от базовых классов CDocument и CView .

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

Начальная заготовка — остов приложения — создается в диалоге с пользователем инструментальным средством AppWizard. В процессе диалога пользователь определяет тип и характеристики проекта, который он хочет построить. Определив, какие классы из MFC необходимы для этого проекта, AppWizard строит остовы всех нужных производных классов. Построенный AppWizard остов приложения содержит все необходимые файлы для создания стартового приложения , которое является законченным приложением и обладает разумными функциональными свойствами, общими для целого класса приложений. Естественно, никаких специфических для данного приложения свойств остов не содержит. Они появятся на следующем этапе, когда программист начнет работать с остовом, создавая из заготовки свое собственное приложение. Тем не менее стартовое приложение можно транслировать и запускать на исполнение.

Термин остов (приложения, класса, функции) применяется для заготовок, создаваемых инструментальными средствами AppWizard и ClassWizard. Нужно подчеркнуть — остов приложения и каркас приложения — разные понятия.

Создаваемый остов приложения составлен так, что в дальнейшей работе с проектом можно использовать другое инструментальное средство — ClassWizard (мастер классов).

Обзор возможностей >

Средство ClassWizard предоставляет широкий спектр услуг. Он позволяет не только добавлять к существующему классу новые методы и данные.

Создание нового класса. При помощи ClassWizard можно добавить новый класс, созданный на основе базовых классов. В качестве базового класса можно использовать классы, наследованные от класса CCmdTarget или класса CRecordset . Для наследования классов от других базовых классов использовать средства ClassWizard нельзя. Такие классы надо создавать вручную, непосредственно в текстовом редакторе.

Объекты, порожденные от класса CCmdTarget , могут обрабатывать сообщения Windows и команды, поступающие от меню, кнопок, акселераторов. Класс CCmdTarget и другие наследованные от него классы имеют таблицу сообщений (Message Map) — набор макрокоманд, позволяющий сопоставить сообщения Windows и команды метода класса.

Полученная заготовка класса полностью работоспособна. Ее можно дополнить по своему усмотрению новыми методами и данными. Эту работу можно выполнить вручную, но гораздо лучше и проще воспользоваться услугами ClassWizard. За счет использования ClassWizard процедура создания собственного класса значительно ускоряется и уменьшается вероятность совершить ошибку во время объявления методов.

Включение в класс новых методов. Очень удобно использовать ClassWizard для включения в состав класса новых методов. Можно добавлять к классу методы, служащие для обработки сообщений Windows и команд от объектов, а также методы, переопределяющие виртуальные методы базовых классов.

ClassWizard не только позволяет добавить в класс новые методы, но и удалить их. ClassWizard самостоятельно удалит объявление метода из класса.

Включение в класс новых элементов данных. ClassWizard позволяет включать в класс не только новые методы, но и элементы данных, связанные с полями диалоговых панелей, форм просмотра и форм для просмотра записей баз данных и полей наборов записей. ClassWizard использует специальные процедуры, чтобы привязать созданные им элементы данных к класса к полям диалоговых панелей. Эти процедуры носят названия «обмен данными диалоговой панели» и «проверка данных диалоговой панели» (Dialog Data Exchange and Dialog Data Validation — DDX/DDV). Чтобы привязать поля из наборов записей к переменным, используется процедура обмена данными с полями записей (Record Field Exchange — RFX).

Процедуры DDX/DDV и RFX значительно упрощают программисту работу с диалоговыми панелями. Они позволяют связать поля диалоговых панелей и переменные. Когда пользователь редактирует поля диалоговых панелей, процедуры DDV проверяют введенные значения и блокируют ввод запрещенных значений. Затем процедуры DDX автоматически копируют содержимое полей диалоговых панелей в привязанные к ним элементы данных класса. И наоборот, когда приложение изменяет элементы данных класса, привязанные к полям диалоговой панели, процедуры DDX могут сразу отобразить новые значения полей на экране компьютера.

Имена, используемые в MFC

Библиотека MFC содержит большое количество классов, структур, констант и т.д. Для того, чтобы текст MFC-приложений был более легким для понимания, принято применять ряд соглашений для используемых имен и комментариев.

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

Чтобы отличить элементы данных, входящих в класс, от простых переменных, их имена принято начинать с префикса m_. Названия методов классов, как правило, специально не выделяются, но обычно их начинают с заглавной буквы.

Библиотека MFC включает в себя, помимо классов, набор служебных функций. Названия этих функций начинаются с символов Afx, например AfxGetApp . Символы AFX являются сокращением от словосочетания Application FrameworkX, означающих основу приложения, его внутреннее устройство.

Символы AFX встречаются не только в названии функций MFC. Многие константы, макрокоманды и другие символы начинаются с этих символов. В общем случае AFX является признаком, по которому можно определить принадлежность того или иного объекта (функция, переменная, ключевое слово или символ) к библиотеке MFC.

Когда приложение разрабатывается средствами MFC AppWizard и ClassWizard, они размещают в исходном тексте приложения комментарии следующего вида:

Такие комментарии образуют блок кода программы, который управляется только средствами MFC AppWizard и ClassWizard. Пользователь не должен вручную вносить изменения в этом блоке. Для этого необходимо употреблять средства ClassWizard.

В следующей таблице представлено краткое описание некоторых блоков //<

Описание

// <//>>AFX_DATA

Включает объявление элементов данных класса. Используется в описании классов диалоговых панелей.

// <//>>AFX_DATA_INIT

Включает инициализацию элементов данных класса. Используется в файле реализации классов диалоговых панелей.

// <//>>AFX_DATA_MAP

Включает макрокоманды DDX, предназначенные для связывания элементов данных класса и органов управления диалоговых панелей. Используется в файле реализации классов диалоговых панелей.

// <//>>AFX_MSG

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

// <//>>AFX_MSG_MAP

Включает макрокоманды таблицы сообщений класса. Используются совместно с AFX_MSG.

// <//>>AFX_VIRTUAL

Включает описание переопределенных виртуальных методов класса. Блок AFX_VIRTUAL используется при описании класса.

MFC AppWizard и ClassWizard помогают разрабатывать приложения. Они создают все классы и методы, необходимые для его работы. Программисту остается дописать к ним свой код. В тех местах, где можно вставить свой код, MFC AppWizard и ClassWizard, как правило помещают комментарии:

Основы работы с текстом в MFC. Функции вывода текста, установки цветов, режимов отображения, получение метрик

В Windows есть практически неограниченные возможности по управлению выводом текста. Некоторые из функций сейчас утратили свое былое значение (или то, что было задумано, оказалось почти невозможным реализовать), другие же очень широко используются.

Любой шрифт, с которым мы имеем дело в Windows, характеризуется несколькими параметрами. Гарнитура (typeface) — это совокупность нескольких начертаний шрифта, объединенных стилевыми и другими признаками. Пример гарнитур: Arial, Times New Roman, MS Sans Serif. Размер шрифта — это высота прямоугольника, в который помещаются все символы шрифта, выражается в специальных единицах — пунктах. Пункт равен 1/72 части дюйма. Эта единица пришла из полиграфии. Начертание — это специфические характеристики шрифта. В Windows доступны четыре начертания: нормальное (normal), курсивное (italic), жирное (bold) и жирное курсивное (bold italic). Кроме того, шрифты могут быть моноширинные (fixed pitch‘, пример — Courier New, и пропорциональные (variable pitch), пример — Times New Roman.

Сейчас в Windows в основном используются шрифты двух групп: растровые (примеры — MS Sans Serif, Fixedsys) и контурные TrueType (примеры — Arial, Courier New). Первые представляют собой жестко определенные битовые матрицы для каждого символа и предназначены для отображения не очень крупного текста на экране. Вторые представляют собой очень сложные объекты. В них заданы контуры символов, которые закрашиваются по определенным правилам. Каждый шрифт TrueType — это программа на специальном языке, которая выполняется интерпретатором под названием растеризатор. Программа шрифта полностью определяет способ расчета конкретных битовых матриц символов на основе контуров. При использовании символов маленького размера (высотой приблизительно до 30 точек) модель контуров становится некорректной и символы сильно искажаются. Для борьбы с этим в качественных шрифтах используется разметка (хинты). Разметка шрифта -чрезвычайно сложный и долгий процесс, поэтому на рынке встречается немного качественно размеченных шрифтов. Поэтому использовать TrueType шрифты для вывода текста на экран нежелательно, за исключением стандартных шрифтов Windows (Times New Roman, Arial и Courier New), которые очень качественно размечены.

Координаты при выводе текста

За вывод текста в окно в MFC отвечает функция CDC::TextOut(). Ей нужно указать координаты для вывода строки. Эти координаты являются логическими координатами, то есть они измеряются в логических единицах. Это относится и к другим функциям вывода информации в окно. В процессе отображения информации логические координаты преобразуются в пиксели. По умолчанию логическими координатами являются пиксели, что для нас очень удобно.

Задание цвета текста и фона

При выводе текста с помощью функции TextOutQ по умолчанию текст выводится черным цветом на текущем (обычно белом) фоне. Однако с помощью следующих функций эти параметры можно изменить:

virtual COLORREF CDC::SetTextColor(COLORREF Color); virtual COLORREF CDC::SetBkColor(COLORREF Color);

Функции возвращают значение предыдущего цвета. Тип COLORREF представляет собой 32-разрядное беззнаковое целое число — представление цвета в виде красной, зеленой и синей компонент, каждая размером в 8 бит. Для формирования этого значения существует макрос RGB().

Задание режима отображения фона

С помощью функции SetBkMode() можно задать режим отображения фона. Прототип функции такой: int CDC::SetBkMode(int Mode);

Функция определяет, что происходит с текущим цветом фона (а также некоторых других элементов) при отображении текста. Режим может принимать одно из двух значений: OPAQUE и TRANSPARENT. В первом случае при выводе текста будет выводится также и текущий фон. Во втором случае фон выводится не будет (он будет «прозрачным»). По умолчанию используется режим OPAQUE.

Получение метрик текста

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

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

BOOL CDC::GetTextMetrics(LPTEXTMETRICS TextAtttrib) const; Параметр является указателем на структуру TEXTMETRIC, в которую будут записаны установки текущего шрифта контекста устройства. Структура имеет достаточно много полей. Наиболее важные поля следующие:

LONG tmHeight Полная высота шрифта

LONG tmAscent Высота над базовой линией

LONG tmDescent Высота подстрочных элементов

LONG tmlntemalLeading Пустое пространство над символами

LONG tmExternalLeading Пустой интервал между строками

LONG tmMaxCharWidth Максимальная ширина символов

Для получения числа логических единиц по вертикали между строками нужно сложить значения tmHeight и tmExternalLeading. Это не то же самое, что и высота символов.

Предположим, что мы имеем готовый инициализированный экземпляр класса CFont, содержащий некоторый шрифт (как это сделать, мы рассмотрим чуть ниже). Для изменения шрифта в контексте устройства используется член-функция SelectObject(), которая в нашем случае принимает один параметр — указатель на объект шрифта. После выполнения этой функции текст будет выводится новым шрифтом. Хотя функция возвращает указатель на объект старого шрифта, сохранять его вовсе не обязательно.

Инициализация объекта шрифта: выбор шрифта

После того, как объект класса CFont создан, необходимо инициализировать его конкретным шрифтом из установленных в системе, с заданными параметрами. Это может быть как растровый, так и контурный шрифт. Наверное, Вы справедливо ожидаете наличия функции, которая позволяет задать только гарнитуру шрифта, начертание и размер, после чего шрифт будет проинициализирован. К сожалению, ни в MFC ни в Windows такой функции нет. Единственная функция, которая подходит для выполнения этой задачи, имеет такой прототип:

BOOL CFont: :CreateFont(int nHeight, int nWidth,

Функция крайне неудобна, и смысл многих ее параметров на сегодняшний день не актуален.

Функция была создана давно, и тогда казалась увлекательной идея подстановки и замены шрифтов, суть которой заключалась в следующем: программист задает такие параметры шрифта, какие он хочет иметь, a Windows сама на основе имеющихся в системе шрифтов произведет необходимые трансформации и синтезирует требуемый шрифт из имеющихся. Впоследствии оказалось, что эта технология не может быть удовлетворительно работоспособной (так как практически это сложная задача из области искусственного интеллекта). Также функция позволяет проводить трансформации шрифта — растягивать и сжимать его, выводить текст под углом. Сейчас это используется редко. Графические пакеты используют свои алгоритмы трансформаций, и часто используют шрифты PostScript. Суть же заключается в том, что качественно могут быть отображены только те шрифты и в тех начертаниях, которые присутствуют в системе, причем без трансформаций (то есть с использованием хинтов, которые отключаются при трансформациях). Для большинства современных программ требуется высокое качество отображения текста, поэтому никакие трансформации и подстановки неуместны. Практически, являются разумными лишь два варианта поведения: либо программа будет использовать точно тот шрифт, который запросила, в таком виде, в каком его создал разработчик, либо откажется работать при отсутствии шрифта.

Рассмотрим пример кода, который позволяет задать размер шрифта, начертание и гарнитуру, минимизировав возможные трансформации шрифта и синтеза при отсутствии заданного. Такие же параметры для функции CreateFontQ Вы можете использовать в своих программах.

Желательно также проверять наличие шрифта, если он не является стандартным. Вот код, который используется в примере программы (указатель на объект шрифта хранится в переменной mjpFoni):

void CMainFrame::SetClientFont(CString Typeface, // Гарнитура

int Size, // размер в пунктах

BOOL Bold, // Признак жирного начертания

BOOL Italic // Признак наклонного начертания

// Получим контекст окна

// Узнаем, сколько пикселей в одном логическом дюйме У

int pixelsPerlnch = winDC.GetDeviceCaps(LOGPIXELSY);

// Узнаем высоту в пикселях шрифта размером Size пунктов

int fontHeight = -MulDiv(Size, pixelsPerlnch, 72);

// Устанавливаем параметр жирности для функции CreateFont()

int Weight = FW_NORMAL;

// Удаляем предыдущий экземпляр шрифта — нельзя дважды инициализировать шрифт вызовом CreateFont().

mjpFont = new CFont;

// Создание шрифта. Большинство параметров не используются.

m_pFont->CreateFont(fontHeight, 0, 0, 0, Weight, Italic, О, О,

Лекция 4. Обзор библиотеки MFC

Назначение библиотеки MFC

Microsoft Foundation Classes (сокращенно MFC) – это библиотека классов на языке Си++, разработанная фирмой Microsoft в качестве объектно-ориентированной оболочки для Windows API. Существуют и другие библиотеки классов для Windows, но преимущество MFC в том, что она написана компанией-разработчиком ОС. MFC постоянно развивается, чтобы соответствовать возможностям новых версий Windows.

MFC содержит около 200 классов, представляющих практически все необходимое для написания Windows-приложений: от окон до элементов управления ActiveX. Одни классы можно использовать непосредственно, а другие – в качестве базовых для создания новых классов. Некоторые классы MFC очень просты, например, класс CPoint для хранения двумерных координат точки. Другие классы являются более сложными, например, класс CWnd инкапсулирует функциональность окна Windows. В приложении MFC напрямую вызывать функции Windows API приходится редко. Вместо этого программист создает объекты классов MFC и вызывает их функции-члены. В MFC определены сотни функций-членов, которые служат оболочкой функций API, и часто их имена совпадают с именами соответствующих функций API. Например, для изменения местоположения окна в API есть функция SetWindowPos. В MFC это действие выполняется с помощью функции-члена CWnd::SetWindowPos.

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

В каркасе приложения MFC есть понятия высокого уровня, которых нет в Windows API. Например, архитектура «документ/вид» является мощной инфраструктурой, надстроенной над API и позволяющей отделить данные программы от их графического представления. Эта архитектура отсутствует в API и полностью реализована в каркасе приложения с помощью классов MFC.

1.1 Преимущества использования Си++/MFC по сравнению с Си/Windows API

При разработке программ для Windows на языке Си с использованием функций API возникает ряд сложностей. Функций и сообщений Windows очень много, их тяжело запомнить. Оконные процедуры на Си принимают характерную и трудно читаемую форму в виде обширных операторов switch, часто вложенных друг в друга.

Объектно-ориентированное проектирование имеет ряд преимуществ по сравнению со структурным при разработке больших проектов: легче создавать повторно используемые компоненты, есть более гибкие средства скрытия данных и процедур.

Применительно к программированию для Windows можно сказать, что без готовой библиотеки классов ООП дает весьма незначительное уменьшение количества исходного текста, который должен написать программист. Основные преимущества ООП проявляются при использовании библиотеки классов – т.е. набора повторно используемых компонент. Эти компоненты облегчают решение типичных задач, например, для добавления в приложение MFC стыкуемой панели инструментов можно использовать класс CToolBar, которому надо только указать параметры кнопок панели. Использовать сложные технологии Windows, например, технологии ActiveX (в том числе COM и OLE) без готовых классов практически невозможно.

Еще одно преимущество, предоставляемое MFC, – это готовый каркас приложения. Он устроен таким образом, что объекты Windows (окна, диалоговые окна, элементы управления и др.) выглядят в программах как объекты классов Си++.

Основные задачи проектирования MFC

При проектировании MFC перед разработчиками Microsoft стояли две основных задачи:

1) MFC должна служить объектно-ориентированным интерфейсом для доступа к API операционных систем семейства Windows с помощью повторно используемых компонент – классов.

2) накладные расходы по времени вычислений и по объему памяти при использовании MFC должны быть минимальны.

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

Уменьшение накладных расходов на библиотеку MFC было достигнуто за счет решений, определяющих способ реализации классов MFC – о том, как именно объекты ОС будут оформлены в виде классов. Одно из этих решений – способ связи между объектами MFC и объектами Windows. В Windows информация о свойствах и текущем состоянии окна хранится в служебной памяти, принадлежащей ОС. Эта информация скрыта от приложений, которые работают с окнами исключительно посредством дескрипторов (переменных типа HWND). В MFC «оболочкой» окна является класс CWnd. Но в нем нет переменных-членов, дублирующих все свойства окна с заданным HWND. В классе CWnd хранится только дескриптор окна. Для этого заведена открытая переменная-член CWnd::m_hWnd типа HWND. Когда программист запрашивает у объекта CWnd какое-нибудь свойство окна (напр., заголовок), то этот объект вызывает соответствующую функцию API, а затем возвращает полученный результат.

Описанная схема применяется в MFC для реализации практически всех классов, служащих оболочками объектов Windows, т.е. внутри этих классов хранятся только дескрипторы объектов.

1.3 Архитектура «документ/вид»

В устройстве каркаса приложения MFC важнейшую роль играет архитектура «документ/вид». Это такой способ проектирования приложения, когда в нем отдельно создаются объекты-документы, ответственные за хранение данных приложения, и объекты-виды, ответственные за отображение этих данных различными способами. Базовыми классами для документов и видов в MFC служат классы CDocument и CView. Классы каркаса приложения CWinApp, CFrameWnd и др. работают совместно с CDocument и CView, чтобы обеспечить функционирование приложения в целом. Сейчас пока рано обсуждать детали архитектуры «документ/вид», но вы должны, как минимум, знать термин «документ/вид», часто упоминаемый при рассмотрении MFC.

Приложения MFC можно писать и без использования документов и видов (например, при изучении основ MFC). Но доступ к большинству возможностей каркаса возможен только при поддержке архитектурs «документ/вид». В действительности это не является жестким ограничением структуры приложения, и большинство программ, обрабатывающих документы какого-либо типа, могут быть преобразованы в эту архитектуру. Не следует думать (по аналогии с термином «документ»), что эта архитектура полезна только для написания текстовых редакторов и электронных таблиц. «Документ» – это абстрактное представление данных программы в памяти компьютера. Например, документ может быть просто массивом байт для хранения игрового поля компьютерной игры, или он действительно может быть электронной таблицей.

Какие именно преимущества получают в MFC приложения «документ/вид»? В частности, это значительное упрощение печати и предварительного просмотра, готовый механизм сохранения и чтения документов с диска, преобразование приложений в серверы документов ActiveX (приложения, документы которых можно открывать в Internet Explorer). Подробно архитектура документ/вид будет рассмотрена позже.

Иерархия классов MFC

Большинство классов MFC явно или неявно унаследованы от класса CObject. Класс CObject обеспечивает для своих подклассов три важных возможности:

· сериализация (запись или чтение данных объекта на диск);

· средства динамического получения информации о классе;

· диагностическая и отладочная поддержка.

Под термином «сериализация» подразумевается преобразование данных объекта в последовательную форму, пригодную для записи или чтения из файла. Используя CObject в качестве базового класса, легко создавать сериализуемые классы, объекты которых можно записывать и считывать с диска стандартными средствами MFC.

Динамическая информация о классе (Run-time class information, RTCI) позволяет получить во время выполнения программы название класса и некоторую другую информацию об объекте. Механизм RTCI реализован независимо от механизма динамической идентификации типа (RTTI), встроенного в Си++. Во многом эти средства похожи, но RTCI был разработан на несколько лет раньше.

Диагностические и отладочные возможности CObject позволяют проверять состояние объектов подклассов CObject на выполнение некоторых условий корректности и выдавать дампы состояния объектов в отладочное окно Visual C++.

CObject предоставляет подклассам еще ряд полезных возможностей. Например, для защиты от утечек памяти в отладочном режиме в классе перегружены операторы new и delete. Если вы динамически создали объект подкласса CObject, и забыли удалить его до завершения программы, то MFC выдаст в отладочное окно Visual C++ предупреждающее сообщение.

Последнее изменение этой страницы: 2020-08-01; Нарушение авторского права страницы

mfc Начало работы с mfc

замечания

Классы Microsoft Foundation или MFC — это библиотека, которая предоставляет объектно-ориентированную оболочку вокруг API Win32. Инкапсулируя «необработанный» API Win32 в C ++-классах, MFC значительно упрощает создание графических приложений и управление ресурсами.

MFC существует очень долгое время. Он был впервые представлен в 1992 году с версии 7 компилятора Microsoft C / C ++. В это время разработка C ++ только начала взлетать. Последующие версии Visual Studio поставляются со значительно улучшенными версиями MFC. Он по-прежнему включен в последнюю версию Visual Studio 2015. Но его устаревшие корни, к сожалению, довольно заметны. Поскольку большинство из них было разработано до стандартизации языка C ++, классы MFC не используют в полной мере современные возможности C ++, такие как шаблоны, предоставляют собственные пользовательские реализации других стандартных функций C ++, таких как RTTI, и используют множество нестандартных идиом , Эти факты делают почти невозможным компиляцию приложения MFC с любым компилятором, отличным от Microsoft. С другой стороны, MFC хорошо интегрирована в Visual Studio, что значительно облегчает процесс разработки.

Во время ранней разработки библиотека называлась расширением Application Framework (сокращенно AFX). Затем отдел маркетинга изменил свое имя на MFC, но было слишком поздно менять какой-либо код, поэтому большая часть кода по-прежнему ссылается на «Afx» вместо «Mfc». Заметным примером является стандартный предварительно скомпилированный заголовочный файл, который автоматически генерируется Visual Studio: он называется StdAfx.h .

7 апреля 2008 г. Microsoft выпустила обновление для классов MFC в качестве внеполосного обновления для Visual Studio 2008 и MFC 9. В обновлении реализованы новые конструкции пользовательского интерфейса, в том числе ленты (аналогичные лентам Microsoft Office 2007) и связанные с ним виджеты пользовательского интерфейса, полностью настраиваемые панели инструментов, стыковочные панели (например, Visual Studio 2005), которые могут свободно размещаться или состыковываться с любой стороны и вкладками документов. Новые функции предоставляются в новых классах, так что старые приложения продолжают работать. Это обновление основано на BCGSoft в BCGControlBar Library Professional Edition и было названо MFC Feature Pack .

Итак, теперь MFC состоит из двух библиотек с разными подходами:

  • Классический MFC (обертка для Win32 API).
  • MFC Feature Pack (смешанный набор из элементов управления Win32 API и новые элементы управления самонастраиванием, такие как лента).

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

  • Приложения для настольных компьютеров MFC (обзор)
  • Ссылка MFC (ссылка на API)
  • MFC Feature Pack (обзор)
  • Справочник по набору компонентов MFC (ссылка API Feature Pack)
  • Образцы пакета MFC Feature Pack

Основная программа MFC

Резюме:

IDD_DIALOG1 должен быть идентификатором диалогового окна, определенного в файле ресурсов проекта, созданном редактором ресурсов, например, встроенным в Visual Studio. (Файл ресурсов обычно имеет расширение .rc.) Чтобы настроить поведение диалогового окна, вы можете получить новый класс из CDialog.

Модальное диалоговое окно запускает собственный цикл сообщений. Вызов «dlg.DoModal ();» не возвращается, пока пользователь не закроет диалог.

Если бы мы вернули TRUE из InitInstance (), он запустил цикл сообщений приложения. Это используется, когда у вас более сложное приложение, не связанное с диалогом.

Илон Маск рекомендует:  Assigned - Функция Delphi
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL