Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Microsoft Visual C++ и MFC

© Александр Фролов, Григорий Фролов
Том 24, М.: Диалог-МИФИ, 1993.

[Назад] [Содеожание] [Дальше]

Приложение Single

В этом разделе мы рассмотрим однооконное приложение, созданное с использованием средств MFC AppWizard и расскажем, как его можно совершенствовать.

Создайте новое приложение с однооконным интерфейсом и назовите его Single. При определении свойств приложения оставьте все предложения по умолчанию. Наше приложение не будет поддерживать ни технологию OLE, ни базу данных, ни сетевые технологии. За счет этого оно будет меньше размером, что позволит лучше понять структуру приложений MFC. Процедура создания приложений с использованием MFC AppWizard описана в разделе “Приложение с оконным интерфейсом” и сейчас мы на ней останавливаться не будем.

В состав проекта Single входят следующие основные файлы:

Имя файла

Описание

Single.h

В этом файле перечислены другие включаемые файлы и описан главный класс приложения CSingleApp

Single.cpp

Основной файл приложения. В нем определены методы основного класса приложения CSingleApp.

MainFrm.h,

Содержит описание класса frame, который называется CMainFrame. Класс CMainFrame наследуется от базового класса CFrameWnd определенного в библиотеке классов MFC

MainFrm.cpp

Файл содержит определения методов класса CMainFrame

SingleDoc.h

Содержит описание класса документов приложения - CSingleDoc

SingleDoc.cpp

Включает определение методов класса CSingleDoc

SingleView.h

Содержит описание класса окна просмотра приложения - CSingleView

SingleView.cpp

Включает определение методов класса CSingleView

Single.rc

Файл ресурсов. В этом файле описаны все ресурсы приложения. Сами ресурсы могут быть записаны в каталоге RES, расположенном в главном каталоге проекта

Resource.h

Файл содержит определения идентификаторов ресурсов приложения, например, идентификаторы строк меню

res\Single.ico

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

res\Single.rc2

В этом файле определены ресурсы, которые нельзя редактировать с помощью редактора ресурсов среды Visual C++

res\Toolbar.bmp

Файл содержит изображение кнопок панели управления toolbar

StdAfx.h, StdAfx.cpp

Использование этих файлов позволяет ускорить процесс повторного построения проекта. Более подробное описание файлов представлено ниже

Single.clw

Файл содержит информацию, необходимую для правильной работы ClassWizard

ReadMe.txt

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

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

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

Рис. 5.10. Приложение Single

Ресурсы приложения

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

Шаблон меню

Большой интерес для нас представляет ресурс, описывающий меню приложения. В ресурсах приложения определен только один шаблон меню, имеющий идентификатор IDR_MAINFRAME.

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


//////////////////////////////////////////////////////////////
// Меню
IDR_MAINFRAME MENU PRELOAD DISCARDABLE 
BEGIN
	POPUP "&File"
	BEGIN
		MENUITEM "&New\tCtrl+N",    	ID_FILE_NEW
		MENUITEM "&Open...\tCtrl+O",	ID_FILE_OPEN
		MENUITEM "&Save\tCtrl+S",	ID_FILE_SAVE
		MENUITEM "Save &As...",  	ID_FILE_SAVE_AS
		MENUITEM SEPARATOR
		MENUITEM "&Print...\tCtrl+P",ID_FILE_PRINT
		MENUITEM "Print Pre&view",	ID_FILE_PRINT_PREVIEW
		MENUITEM "P&rint Setup...",	ID_FILE_PRINT_SETUP
		MENUITEM SEPARATOR
		MENUITEM "Recent File",   	ID_FILE_MRU_FILE1,GRAYED
		MENUITEM SEPARATOR
		MENUITEM "E&xit",        	ID_APP_EXIT
	END
	POPUP "&Edit"
	BEGIN
		MENUITEM "&Undo\tCtrl+Z",	ID_EDIT_UNDO
		MENUITEM SEPARATOR
		MENUITEM "Cu&t\tCtrl+X",	ID_EDIT_CUT
		MENUITEM "&Copy\tCtrl+C",	ID_EDIT_COPY
		MENUITEM "&Paste\tCtrl+V",	ID_EDIT_PASTE
	END
	POPUP "&View"
	BEGIN
		MENUITEM "&Toolbar",     	ID_VIEW_TOOLBAR
		MENUITEM "&Status Bar",  	ID_VIEW_STATUS_BAR
	END
	POPUP "&Help"
	BEGIN
		MENUITEM "&About Single...",	ID_APP_ABOUT
	END
END

Большая часть строк меню IDR_MAINFRAME имеет стандартные идентификаторы, описанные в библиотеке MFC. Некоторые из команд, соответствующих этим идентификаторам полностью обрабатываются MFC. Список стандартных команд с их описанием представлен в разделе “Стандартные команды”.

Панель управления toolbar

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


//////////////////////////////////////////////////////////////
// Панель управления Toolbar
IDR_MAINFRAME TOOLBAR DISCARDABLE  16, 15
BEGIN
	BUTTON		ID_FILE_NEW
	BUTTON		ID_FILE_OPEN
	BUTTON		ID_FILE_SAVE
	SEPARATOR
	BUTTON		ID_EDIT_CUT
	BUTTON		ID_EDIT_COPY
	BUTTON		ID_EDIT_PASTE
	SEPARATOR
	BUTTON		ID_FILE_PRINT
	BUTTON		ID_APP_ABOUT
END

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

Образ кнопок панели управления расположен в файле Toolbar.bmp, записанном в подкаталоге res каталога проекта.


//////////////////////////////////////////////////////////////
// Изображение Bitmap, определяющее кнопки приложения
IDR_MAINFRAME   BITMAP   MOVEABLE PURE   "res\\Toolbar.bmp"

Пиктограмма

В файле ресурсов приложения Single определены две пиктограммы IDR_SINGLETYPE и IDR_MAINFRAME. Каждая из этих пиктограмм содержит по два изображения различного размера 32х32 и 16х16 пикселов.


//////////////////////////////////////////////////////////////
// Пиктограммы
IDR_MAINFRAME	    ICON	DISCARDABLE	"res\\Single.ico"
IDR_SINGLETYPE   ICON	DISCARDABLE	"res\\SingleDoc.ico"

Пиктограмма IDR_MAINFRAME представляет минимизированное приложение (рис. 5.11). Эта же пиктограмма отображается в левом верхнем углу главного окна приложения.

Рис. 5.11. Пиктограмма IDR_MAINFRAME

Точно такая же пиктограмма используется всеми приложениями, построенными на основе MFC AppWizard, вне зависимости от типа их интерфейса с пользователем.

Пиктограмма IDR_SINGLETYPE может быть использована для представления документа, с которым работает приложение (рис. 5.12). Приложение с однооконным интерфейсом практически не использует эту пиктограмму.

Рис. 5.12. Пиктограмма IDR_SINGLETYPE

Таблица текстовых строк

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

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


//////////////////////////////////////////////////////////////
// Таблица текстовых строк
STRINGTABLE PRELOAD DISCARDABLE 
BEGIN
	IDR_MAINFRAME "Single\n\nSingle\n\n\nSingle.Document\n
					    Single Document"
END

Строка описания типа документа (IDR_MAINFRAME) состоит из семи фрагментов, разделенных символами перевода строки \n. Эти фрагменты строки отвечают за различные характеристики документа.

Формирование этой строки выполняется MFC AppWizard на основании информации, которую вы указали на страница Document Template Strings диалоговой панели Advanced Options (рис. 5.6).

Фрагмент

Поле панели Advanced Options

Описание

Первый

Main frame caption

Заголовок главного окна приложения. Используется для приложений с однооконным интерфейсом

Второй

Doc type name

(только для приложений с многооконным интерфейсом)

для приложений с однооконным интерфейсом этот фрагмент изначально пуст

Имя файла, присваиваемое новому документу по умолчанию. Если этот фрагмент отсутствует, используется имя Untitled

Третий

File new name (OLE short name)

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

Четвертый

Filter name

Название фильтра для имен файлов документов данного типа. Это название отображается в стандартных диалоговых панелях Open и Save As, в списке типов документов

Пятый

File extension

Расширение файлов документов данного типа, используемое по умолчанию

Шестой

File type ID

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

Седьмой

File type name (OLE long name).

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

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

Второй блок таблицы текстовых строк содержит две строки с идентификаторами AFX_IDS_APP_TITLE и AFX_IDS_IDLEMESSAGE. Строка, имеющая идентификатор AFX_IDS_IDLEMESSAGE, отображается в панели состояния, когда приложение находится в состоянии ожидания.

Когда пользователь создает объект главного класса приложения, он может указать имя приложения. Если это имя не указано, как в нашем приложении, тогда в качестве имени приложения используется строка, имеющая идентификатор AFX_IDS_APP_TITLE.


STRINGTABLE PRELOAD DISCARDABLE 
BEGIN
	AFX_IDS_APP_TITLE		"Single&qupt;
	AFX_IDS_IDLEMESSAGE	"Ready"
END

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


STRINGTABLE DISCARDABLE 
BEGIN
	ID_INDICATOR_EXT	"EXT"
	ID_INDICATOR_CAPS	"CAP"
	ID_INDICATOR_NUM	"NUM"
	ID_INDICATOR_SCRL	"SCRL"
	ID_INDICATOR_OVR	"OVR"
	ID_INDICATOR_REC	"REC"
END

И наконец, последний, самый большой блок текстовых строк содержит краткие описания каждой строки меню приложения. Идентификаторы этих строк соответствуют идентификаторам строк меню, которые они описывают.

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


STRINGTABLE DISCARDABLE 
BEGIN
	ID_FILE_NEW			"Create a new document\nNew"
	ID_FILE_OPEN			"Open an existing document\nOpen"
	ID_FILE_CLOSE	"Close the active document\nClose"
	ID_FILE_SAVE			"Save the active document\nSave"
	ID_FILE_SAVE_AS	"Save the active document with a new 
							name\nSave As"
	ID_FILE_PAGE_SETUP	"Change the printing options\nPage Setup"
	ID_FILE_PRINT_SETUP	"Change the printer and printing 
							options\nPrint Setup"
	ID_FILE_PRINT	"Print the active document\nPrint"
	ID_FILE_PRINT_PREVIEW "Display full pages\nPrint Preview"
	ID_APP_ABOUT	"	Display program information, version 
							number and copyright\nAbout"
	ID_APP_EXIT			"Quit the application; prompts to save 
							documents\nExit"
	ID_FILE_MRU_FILE1	"Open this document"
	ID_FILE_MRU_FILE2	"Open this document"
	ID_FILE_MRU_FILE3	"Open this document"
	ID_FILE_MRU_FILE4	"Open this document"
	ID_FILE_MRU_FILE5	"Open this document"
	ID_FILE_MRU_FILE6	"Open this document"
	ID_FILE_MRU_FILE7	"Open this document"
	ID_FILE_MRU_FILE8	"Open this document"
	ID_FILE_MRU_FILE9	"Open this document"
	ID_FILE_MRU_FILE10	"Open this document"
	ID_FILE_MRU_FILE11	"Open this document"
	ID_FILE_MRU_FILE12	"Open this document"
	ID_FILE_MRU_FILE13	"Open this document"
	ID_FILE_MRU_FILE14	"Open this document"
	ID_FILE_MRU_FILE15	"Open this document"
	ID_FILE_MRU_FILE16	"Open this document"
	ID_NEXT_PANE 	"Switch to the next window pane\nNext Pane"
	ID_PREV_PANE 	"Switch back to the previous window 
							pane\nPrevious Pane"
	ID_WINDOW_SPLIT	"Split the active window into panes\nSplit"
	ID_EDIT_CLEAR	"Erase the selection\nErase"
	ID_EDIT_CLEAR_ALL	"Erase everything\nErase All"
	ID_EDIT_COPY			"Copy the selection and put it on the 
							Clipboard\nCopy"
	ID_EDIT_CUT			"Cut the selection and put it on the 
							Clipboard\nCut"
	ID_EDIT_FIND			"Find the specified text\nFind"
	ID_EDIT_PASTE	"Insert Clipboard contents\nPaste"
	ID_EDIT_REPEAT	"Repeat the last action\nRepeat"
	ID_EDIT_REPLACE	"Replace specific text with different 
							text\nReplace"
	ID_EDIT_SELECT_ALL	"Select the entire document\nSelect All"
	ID_EDIT_UNDO			"Undo the last action\nUndo"
	ID_EDIT_REDO			"Redo the previously undone action\nRedo"
	ID_VIEW_TOOLBAR	"Show or hide the toolbar\nToggle ToolBar"
	ID_VIEW_STATUS_BAR	"Show or hide the status bar\nToggle 
							StatusBar"
END

Диалоговая панель

В ресурсах приложения определена только одна диалоговая панель с идентификатором IDD_ABOUTBOX. Она содержит краткую информацию о приложении и отображается на экране, когда пользователь выбирает из меню Help строку About Single.


//////////////////////////////////////////////////////////////
// Диалоговая панель
IDD_ABOUTBOX DIALOG DISCARDABLE  0, 0, 217, 55
CAPTION "About Single"
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
FONT 8, "MS Sans Serif"
BEGIN
	ICON		IDR_MAINFRAME,IDC_STATIC,11,17,20,20
	LTEXT		"Single Version 1.0",IDC_STATIC,40,10,119,8,
				SS_NOPREFIX
	LTEXT		"Copyright \251 1996",IDC_STATIC,40,25,119,8
	DEFPUSHBUTTON	"OK",IDOK,178,7,32,14,WS_GROUP
END

Таблица акселераторов

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


//////////////////////////////////////////////////////////////
// Таблица акселераторов
IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE
BEGIN
	"N",			ID_FILE_NEW,		VIRTKEY,CONTROL
	"O",			ID_FILE_OPEN,		VIRTKEY,CONTROL
	"S",			ID_FILE_SAVE,		VIRTKEY,CONTROL
	"P",			ID_FILE_PRINT,	VIRTKEY,CONTROL
	"Z",			ID_EDIT_UNDO,		VIRTKEY,CONTROL
	"X",			ID_EDIT_CUT,		VIRTKEY,CONTROL
	"C",			ID_EDIT_COPY,		VIRTKEY,CONTROL
	"V",			ID_EDIT_PASTE,	VIRTKEY,CONTROL
	VK_BACK,		ID_EDIT_UNDO,		VIRTKEY,ALT
	VK_DELETE,	ID_EDIT_CUT,		VIRTKEY,SHIFT
	VK_INSERT,	ID_EDIT_COPY,		VIRTKEY,CONTROL
	VK_INSERT,	ID_EDIT_PASTE,	VIRTKEY,SHIFT
	VK_F6,		ID_NEXT_PANE,		VIRTKEY 
	VK_F6,			ID_PREV_PANE,		VIRTKEY,SHIFT
END

Версия

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

Приложения, как правило, имеют только один ресурс, содержащий данные о версии, и который имеет имя VS_VERSION_INFO XE "VS_VERSION_INFO" . Приложение может получить данные из ресурса, описывающего версию приложения. Для этого можно воспользоваться функциями GetFileVersionInfo и VerQueryValue.

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

Общие замечания о ресурсах приложения

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

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

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

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

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

Базовый класс

Описание

CSingleApp

CWinApp XE "CWinApp"

Главный класс приложения

CMainFrame

CFrameWnd

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

CSingleDoc

CDocument XE "CDocument"

Класс документа приложения

CSingleView

CView XE "CView"

Класс окна просмотра документа

Кроме основных классов, создается также класс CAboutDlg, наследованный от базового класса CDialog, который отвечает за диалоговую панель About. Если во время определения характеристик приложения вы включите возможность работы с базами данных или использование технологии OLE, общий список классов приложения может стать шире.

Класс CSingleApp

Главный класс приложения CSingleApp наследуется от базового класса CWinApp. Вы можете просмотреть определение класса, если выполните двойной щелчок левой клавишей мыши по его названию в окне Project Workspace. Откроется окно редактора и в него загрузится файл Single.h. Курсор будет автоматически установлен на описание класса CSingleApp.


//////////////////////////////////////////////////////////////
// Класс CSingleApp:
class CSingleApp : public CWinApp
{
public:
	CSingleApp();

// Overrides
	//{{AFX_VIRTUAL(CSingleApp)
public:
	virtual BOOL InitInstance();
	//}}AFX_VIRTUAL

// Implementation
	//{{AFX_MSG(CSingleApp)
	afx_msg void OnAppAbout();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};
Таблица сообщений класса CSingleApp

Обратите внимание, что в последней строке определения класса CSingleApp расположена макрокоманда DECLARE_MESSAGE_MAP XE "DECLARE_MESSAGE_MAP" . Загадочная макрокоманда DECLARE_MESSAGE_MAP определена в файле afxwin.h следующим образом:


#define DECLARE_MESSAGE_MAP() \
private: \
	static const AFX_MSGMAP_ENTRY _messageEntries[]; \
protected: \
	static AFX_DATA const AFX_MSGMAP messageMap; \
	virtual const AFX_MSGMAP* GetMessageMap() const; \

Таким образом, DECLARE_MESSAGE_MAP не является расширением языка Си++, а просто добавляет к вашему классу несколько новых элементов.

Так как в классе CSingleApp расположена макрокоманда DECLARE_MESSAGE_MAP, то он может обрабатывать сообщения и имеет таблицу сообщений. Таблица сообщений класса CSingleApp расположена в файле реализации Single.cpp.


//////////////////////////////////////////////////////////////
// Таблица сообщений класса CSingleApp
BEGIN_MESSAGE_MAP(CSingleApp, CWinApp)
	//{{AFX_MSG_MAP(CSingleApp)
	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
	//}}AFX_MSG_MAP
	// Стандартные команды для работы с документами
	ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
	ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
	// Стандартная команда выбора принтера
	ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()

Кроме команды для обработки командного сообщения ID_APP_ABOUT, расположенного в блоке AFX_MSG_MAP, таблица сообщений содержит еще три макрокоманды, предназначенные для обработки командных сообщений с идентификаторами ID_FILE_NEW XE "ID_FILE_NEW" , ID_FILE_OPEN XE "ID_FILE_OPEN" , ID_FILE_PRINT_SETUP XE "ID_FILE_PRINT_SETUP" .

Командные сообщения ID_FILE_NEW, ID_FILE_OPEN, ID_FILE_PRINT_SETUP поступают, когда пользователь выбирает из меню приложения строки с соответствующими идентификаторами. Для обработки этих командных сообщений вызываются методы класса CWinApp.

Главный объект приложения

В приложении создается всего один объект класса CSingleApp. Этот объект определяется как статический, поэтому его конструктор получает управление сразу после запуска приложения.

CSingleApp theApp;
Конструктор класса CSingleApp

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


//////////////////////////////////////////////////////////////
// Конструктор класса CSingleApp 
CSingleApp::CSingleApp()
{
	// TODO: Здесь вы можете разместить свой код
}
Метод InitInstance

Метод InitInstance является виртуальным методом класса CWinApp. Когда вы наследуете главный класс приложения от базового класса CWinApp, этот метод необходимо переопределить.

MFC AppWizard переопределяет метод InitInstance автоматически для приложений с любым пользовательским интерфейсом. Однако реализация этого метода может различаться. Сравните переопределенный метод InitInstance для приложений с главной диалоговой панелью (приложение Dialog) и оконным интерфейсом (приложение Single).


//////////////////////////////////////////////////////////////
// Метод CSingleApp 
BOOL CSingleApp::InitInstance()
{
#ifdef _AFXDLL
	Enable3dControls();
#else
	Enable3dControlsStatic();
#endif

	// Загружаем файл конфигурации
	LoadStdProfileSettings(); 

	// Создаем шаблон документа
	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CSingleDoc),
		RUNTIME_CLASS(CMainFrame), 
		RUNTIME_CLASS(CSingleView));

	// Регистрируем шаблон документа
	AddDocTemplate(pDocTemplate);

	// Выполняем стандартную обработку командной строки
	// приложения
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);

	// Обрабатываем командную строку приложения
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	return TRUE;
}

После вызова метода Enable3dControls, описанного ранее, вызывается метод LoadStdProfileSettings. Этот метод загружает файл конфигурации приложения, имеющий расширение INI. В INI-файле записаны имена нескольких файлов, с которыми работало приложение. Эти имена файлов будут добавлены как отдельные строки в меню File приложения. Кроме того, в INI-файле может храниться и другая информация.

Метод LoadStdProfileSettings определен в классе CWinApp XE "CWinApp" следующим образом:


void LoadStdProfileSettings(UINT nMaxMRU = _AFX_MRU_COUNT); 

Необязательный параметр nMaxMRU определяет, сколько имен файлов документов будет запоминаться. Если указать в качестве параметра nMaxMRU нулевое значение, список файлов запоминаться не будет. По умолчанию параметру nMaxMRU присваивается значение _AFX_MRU_COUNT. Константа _AFX_MRU_COUNT XE "_AFX_MRU_COUNT" определена в файле afxwin.h.


#define _AFX_MRU_COUNT   4

Напомним вам, что количество запоминаемых имен файлов можно указать в диалоговой панели MFC AppWizard - Step 4 of 6 (рис. 5.3), во время разработки приложения средствами MFC AppWizard.

Затем начинается создание шаблона документов. Сначала создается указатель pDocTemplate на соответствующий класс. Для однооконных приложений это класс CSingleDocTemplate, а для многооконных - CMultiDocTemplate. Создается новый объект класса и в переменную pDocTemplate записывается указатель на него. Для создания шаблона документа используется оператор new.

Конструктору класса CSingleDocTemplate передаются четыре параметра.


CSingleDocTemplate(UINT nIDResource, 
						     CRuntimeClass* pDocClass, 
						     CRuntimeClass* pFrameClass, 
						     CRuntimeClass* pViewClass );

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

Остальные три параметра pDocClass, pFrameClass, pViewClass содержат указатели на объекты класса CRuntimeClass, полученные с помощью макрокоманд RUNTIME_CLASS XE "RUNTIME_CLASS" из классов документа CSingleDoc XE "CSingleDoc" , окна CMainFrame XE "CMainFrame" и окна просмотра CSingleView XE "CSingleView" . Таким образом, шаблон документа объединяет всю информацию, относящуюся к данному типу документов.

Созданный шаблон документов XE "шаблон документов" заносится в список шаблонов с которыми работает приложение. Для этого указатель на созданный шаблон документа передается методу AddDocTemplate из класса WinApp. Указатель на шаблон документов передается через параметр pTemplate.

void AddDocTemplate(CDocTemplate* pTemplate);

Указатель pTemplate указывает на объекты класса CDocTemplate. Однако мы передаем через него указатели на объекты класса CSingleDocTemplate. Это допустимо, так как класс CDocTemplate является базовым классом для CSingleDocTemplate.

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

После создания шаблона документа, обрабатывается командная строка приложения. Для этого создается объект cmdInfo класса CCommandLineInfo.

Объект cmdInfo передается методу ParseCommandLine, определенному в классе CWinApp. Он заполняет объект cmdInfo, данными, взятыми из командной строки приложения. Подготовленный объект cmdInfo передается методу ProcessShellCommand класса CWinApp для обработки.

Если обработка завершилась успешно, метод ProcessShellCommand возвращает ненулевое значение. Если при обработке командной строки приложения возникли ошибки, метод ProcessShellCommand возвращает нуль.

После успешной инициализации приложения и обработки командной строки метод InitInstance возвращает значение TRUE. Начинается обработка цикла сообщений.

Кроме конструктора и метода InitInstance в главном классе приложения CSingleApp определен метод OnAppAbout. Он расположен в блоке AFX_MSG. Поэтому для работы с этим методом вы можете использовать ClassWizard.

Метод OnAppAbout

Метод OnAppAbout вызывается для обработки командного сообщения ID_APP_ABOUT. Это сообщение поступает в очередь приложения, когда пользователь выбирает из меню Help строку About. Он создает объект класса CAboutDlg, представляющий модальную диалоговую панель и отображает ее на экране.


// Метод OnAppAbout
void CSingleApp::OnAppAbout()
{
	CAboutDlg aboutDlg;
	aboutDlg.DoModal();
}

Описание класса CAboutDlg, а также определение его методов содержится в файле Single.cpp. Класс CAboutDlg приложения Single полностью соответствует классу CAboutDlg приложения Dialog, описанного в предыдущей главе. Мы не будем повторять описание класса CAboutDlg, вы можете самостоятельно найти его в листинге 4.4.

Класс CSingleDoc

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

Класс CSingleDoc, несколько сложнее главного класса приложения, рассмотренного выше.


class CSingleDoc : public CDocument
{
protected: 
	CSingleDoc();
	DECLARE_DYNCREATE(CSingleDoc)

// Attributes
public:

// Operations
public:

// Overrides
	//{{AFX_VIRTUAL(CSingleDoc)
public:
	virtual BOOL OnNewDocument();
	virtual void Serialize(CArchive& ar);
	//}}AFX_VIRTUAL

// Implementation
public:
	virtual ~CSingleDoc();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Методы, предназначенные для обработки сообщений
protected:
	//{{AFX_MSG(CSingleDoc)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

Просмотрите исходные тексты приложения. Вы не обнаружите кода, который бы явно создавал объекты этого класса. Объект класса CSingleDoc создается динамически шаблоном документа, во время работы приложения. Шаблон документа также динамически создает еще два объекта - класса окна и класса окна просмотра.

Для того чтобы объекты любого класса, наследованного от базового класса CObject, в том числе и CSingleDoc XE "CSingleDoc" , можно было создавать динамически, необходимо выполнить следующее:

·         в описании класса надо поместить макрокоманду DECLARE_DYNCREATE XE "DECLARE_DYNCREATE" . В качестве параметра этой макрокоманды необходимо указать имя данного класса;

·         определить конструктор класса, который не имеет параметров;

·         разместить макрокоманду IMPLEMENT_DYNCREATE XE "IMPLEMENT_DYNCREATE" в файле реализации. Макрокоманда IMPLEMENT_DYNCREATE имеет два параметра. В первом указывается имя класса, а во втором имя его базового класса

MFC AppWizard автоматически выполняет все эти требования для класса документа приложения CSingleDoc, класса окна приложения CMainFrame и класса окна просмотра CSingleView.

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

Макрокоманда IMPLEMENT_DYNCREATE XE "IMPLEMENT_DYNCREATE" размещается в файле реализации класса. Для класса CSingleDoc этот файл называется SingleDoc.cpp. Обычно MFC AppWizard размещает макрокоманду IMPLEMENT_DYNCREATE непосредственно перед таблицей сообщений класса (если конечно данные класс обрабатывает сообщения).


// Макрокоманда необходима для динамического создания объектов 
// CSingleDoc
IMPLEMENT_DYNCREATE(CSingleDoc, CDocument)

// Таблица сообщений класса CSingleDoc
BEGIN_MESSAGE_MAP(CSingleDoc, CDocument)
	//{{AFX_MSG_MAP(CSingleDoc)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

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

Конструктор и деструктор класса CSingleDoc

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


// Конструктор класса CSingleDoc
CSingleDoc::CSingleDoc()
{
	// TODO:
}

Вместе с конструктором класса CSingleDoc, создается деструктор ~CSingleDoc. Деструктор не содержит кода и представляет собой такую же заготовку как и конструктор.


// Деструктор класса CSingleDoc
CSingleDoc::~CSingleDoc()
{
}
Методы OnNewDocument и Serialize

В классе CSingleDoc переопределены два виртуальных метода OnNewDocument и Serialize. Виртуальный метод OnNewDocument определен в классе CDocument XE "CDocument" , от которого непосредственно наследуется класс CSingleDoc. А вот виртуальный метод Serialize определен в классе CObject. Цепочка наследования классов в этом случае длиннее:

CSingleDoc <- CDocument <- CCmdTarget <- CObject 

Метод OnNewDocument вызывается, когда надо создать новый документ для приложения. Если вы переопределяете метод OnNewDocument (в данном случае за вас это делает MFC AppWizard), то сначала необходимо вызвать метод OnNewDocument базового класса, и только затем можно выполнять инициализацию документа. Более подробно об использовании метода OnNewDocument мы расскажем в следующих главах, когда к шаблону прложения, созданному MFC AppWizard, мы будем добавлять собственный код.


BOOL CSingleDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	// TODO: здесь можно выполнить инициализацию 
	// документа

	return TRUE;
}

Если создание нового документа прошло успешно, метод OnNewDocument должен вернуть значение TRUE, а в противном случае FALSE. Когда вызывается метод OnNewDocument базового класса CDocument, следует выполнять проверку возвращаемого им значения. Если CDocument::OnNewDocument вернет FALSE, значит создание документа на уровне класса CDocument не прошло и следует прекратить дальнейшие действия.

Большой интерес представляет метод Serialize. Он вызывается в тех случаях, когда надо загрузить документ из файла на диске или наоборот, записать его в файл. Метод Serialize вызывается, когда пользователь выбирает из меню File строки Open или Save.


//////////////////////////////////////////////////////////////
// Сохранение и восстановление документа 
void CSingleDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: здесь выполняется запись документа в файл
	}
	else
	{
		// TODO: здесь выполняется чтение документа из файла
	}
}

В качестве параметра ar методу Serialize передается объект класса CArchive, связанный с файлом в который надо записать или из которого надо прочитать документ.

Метод Serialize вызывается и для загрузки и для сохранения документа. Чтобы узнать, что надо делать с документом, используется метод IsStoring класса CArchive. Если он возвращает ненулевое значение, значит вы должны сохранить состояние документа в файле. В противном случае вы должны считать документ из файла. Боле подробно использование метода Serialize для сохранения и восстановления документов, описано в разделе “Запись и восстановление объектов” главы “Некоторые классы MFC”.

Методы AssertValid и Dump

Класс CSingleDoc содержит переопределения еще двух виртуальных методов - AssertValid и Dump, входящих в базовый класс CObject. Описание методов AssertValid и Dump вы можете найти в разделе “Класс CObject - основной класс MFC” главы “Некоторые классы MFC”.

Обратите внимание, что описание этих методов и их определение расположено в блоке #ifdef _DEBUG XE "_DEBUG" . Поэтому эти методы используются только для отладочной версии приложения. Когда выполняется окончательное построение приложения, эти методы не переопределяются.


//////////////////////////////////////////////////////////////
// Диагностические методы класса CSingleDoc 
#ifdef _DEBUG
void CSingleDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CSingleDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

Класс CSingleView

Следующий класс, который мы рассмотрим, является классом окна просмотра документа CSingleView. Этот класс наследуется от базового класса CView библиотеки MFC. Определения класса CSingleView вы можете найти в файле SingleView.h.

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

Для этого определяется конструктор класса, не имеющий параметров, в определении класса указывается макрокоманда DECLARE_DYNCREATE, а в файле реализации макрокоманда IMPLEMENT_DYNCREATE.


class CSingleView : public CView
{
protected:
	CSingleView();
	DECLARE_DYNCREATE(CSingleView)

// Attributes
public:
	CSingleDoc* GetDocument();

// Operations
public:

// Overrides
	//{{AFX_VIRTUAL(CSingleView)
public:
	virtual void OnDraw(CDC* pDC);
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
	//}}AFX_VIRTUAL

// Implementation
public:
	virtual ~CSingleView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Методы, предназначенные для обработки сообщений
protected:
	//{{AFX_MSG(CSingleView)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

Секция Overrides в описании класса CSingleView содержит описания переопределяемых виртуальных методов базового класса CView. Два метода описаны в ней как public - OnDraw и PreCreateWindow и три как protected - OnPreparePrinting, OnBeginPrinting, OnEndPrinting. Поэтому методы OnDraw и PreCreateWindow можно вызывать и из других классов приложения, а методы OnPreparePrinting, OnBeginPrinting, OnEndPrinting только из класса CSingleView.

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

Таблица сообщений класса CSingleView располагается в файле SingleView.cpp. Непосредственно перед ней находится макрокоманда IMPLEMENT_DYNCREATE.


// Объекты класса CSingleView могут создаваться динамически
IMPLEMENT_DYNCREATE(CSingleView, CView)

// Таблица сообщений класса CSingleView
BEGIN_MESSAGE_MAP(CSingleView, CView)
	//{{AFX_MSG_MAP(CSingleView)
	//}}AFX_MSG_MAP
	// Стандартные команды предназначенные для печати документа
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
Конструктор и деструктор класса CSingleView

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


// Конструктор класса CSingleView 
CSingleView::CSingleView()
{
	// TODO:
}

Вместе с конструктором класса CSingleView, MFC AppWizard определяет деструктор ~ CSingleView. Сразу после создания проекта деструктор не выполняет никаких действий. В дальнейшем вы можете использовать его совместно с конструктором CSingleView.


// Деструктор класса CSingleView 
CSingleView::~CSingleView()
{
}
Метод GetDocument

В секции атрибутов класса CSingleView после комментария Attributes объявлен метод GetDocument. Этот метод возвращает указатель на документ, связанный с данным окном просмотра. Если окно просмотра не связано ни с каким документом, метод возвращает значение NULL.

Интересно, что метод GetDocument имеет две реализации. Одна используется для отладочной версии приложения, а другая для окончательной.

Окончательная версия GetDocument определена непосредственно после самого класса окна просмотра CSingleView как встраиваемый (inline) метод. Когда вы используете страницу ClassView окна Project Workspace, чтобы просмотреть определение метода GetDocument, вы увидите именно этот код.


// Окончательная версия приложения
#ifndef _DEBUG	
inline CSingleDoc* CSingleView::GetDocument()
	{ return (CSingleDoc*)m_pDocument; }
#endif

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


// Отладочная версия приложения
#ifdef _DEBUG		
CSingleDoc* CSingleView::GetDocument()
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSingleDoc)));
	return (CSingleDoc*)m_pDocument;
}
#endif //_DEBUG

Макрокоманда RUNTIME_CLASS возвращает указатель на структуру CRuntimeClass, содержащую информацию о классе CSingleDoc. Метод IsKindOf, определенный в классе CObject, проверяет, принадлежит ли объект, на который указывает m_pDocument, к классу CSingleDoc или классу наследованному от CSingleDoc. Если в приложении есть ошибка и m_pDocument не указывает на документ приложения, макрокоманда ASSERT отображает соответствующее сообщение и прерывает работу приложения.

Метод PreCreateWindow

Виртуальный метод PreCreateWindow определен в классе CWnd. Он вызывается непосредственно перед созданием окна, связанного с объектом класса. В качестве параметра cs этому методу передается структура CREATESTRUCT, определяющая характеристики создаваемого окна. Приложение может изменить данные, записанные в этой структуре, чтобы повлиять на внешний вид создаваемого окна.

Классы, наследованные от CWnd, в том числе CView и CFrameWnd, переопределяют этот метод, изменяя структуру cs. В следующей таблице описано назначение полей структуры CREATESTRUCT.

Поле структуры CREATESTRUCT

Описание

lpCreateParams

Указатель на данные, используемые при создании окна

hInstance

Идентификатор приложения

hMenu

Идентификатор меню

hwndParent

Идентификатор родительского окна. Содержит NULL, если окно не имеет родительского окна

cy

Высота окна

cx

Ширина окна

y

Определяет y-координату верхнего левого угла окна. Для дочерних окон координаты задаются относительно родительского окна. Для родительского окна координаты указываются в экранной системе координат

x

Определяет x-координату верхнего левого угла окна. Координаты задаются также как и для поля y

style

Стиль класса

lpszName

Указатель на строку, закрытую двоичным нулем, в которой находится имя окна

lpszClass

Имя класса окна (смотри том 11 из серии “Библиотека системного программиста”)

dwExStyle

Дополнительные стили окна

MFC AppWizard переопределяет для вас метод PreCreateWindow, но не вносит в структуру cs никаких изменений и вызывает метод PreCreateWindow базового класса CView.


BOOL CSingleView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Здесь вы можете внести изменения в структуру cs

	// Вызов метода PreCreateWindow базового класса CView
	return CView::PreCreateWindow(cs);
}
Метод OnDraw

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

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

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

BOOL IsPrinting() const;

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

MFC AppWizard переопределяет для вас метод OnDraw класса CView следующим образом:


void CSingleView::OnDraw(CDC* pDC)
{
	CSingleDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	// TODO: Здесь вы можете расположить код, для отображения 
	// данных в контексте устройства pDC
}

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

Методы OnPreparePrinting, OnBeginPrinting и OnEndPrinting

Виртуальные методы OnPreparePrinting, OnBeginPrinting и OnEndPrinting, определенные в классе CView, вызываются, если пользователь желает распечатать документ, отображенный в данном окне просмотра.

Метод

Назначение

OnPreparePrinting

Вызывается перед печатью документа

OnBeginPrinting

Используется, для получения шрифтов и других ресурсов GDI

OnEndPrinting

Используется для освобождения ресурсов, полученных методом OnBeginPrinting

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


//////////////////////////////////////////////////////////////
// Методы используемые для печати документов
BOOL CSingleView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// Выполняется обработка по умолчанию
	return DoPreparePrinting(pInfo);
}

void CSingleView::OnBeginPrinting(CDC* /*pDC*/, 
	CPrintInfo* /*pInfo*/)
{
	// TODO: здесь можно выполнить дополнительную инициализацию 
	// перед печатью документа
}

void CSingleView::OnEndPrinting(CDC* /*pDC*/, 
	CPrintInfo* /*pInfo*/)
{
	// TODO: здесь можно выполнить действия после печати
	// документа
}
Методы AssertValid и Dump

Во время отладки приложения в состав класса CSingleView включаются переопределения виртуальных методов AssertValid и Dump. Эти методы определены в базовом классе CObject и используются при отладке приложения. Когда выполняется окончательное построение приложения, эти методы не переопределяются.


//////////////////////////////////////////////////////////////
// Диагностические методы класса CSingleView 
#ifdef _DEBUG
void CSingleView::AssertValid() const
{
	CView::AssertValid();
}

void CSingleView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
#endif //_DEBUG

Класс CMainFrame

Класс CMainFrame XE "CMainFrame" представляет главное окно нашего приложения. Внутри этого окна отображаются окно просмотра документа, а также панели управления и состояния. Определение класса CMainFrame расположено в файле MainFrm.h.

Класс CMainFrame наследуется от базового класса CFrameWnd, определенного в библиотеке MFC. Как правило у программиста не возникает необходимости как-либо дорабатывать класс главного окна приложения, созданный MFC AppWizard.


class CMainFrame : public CFrameWnd
{
protected: 
	CMainFrame();
	DECLARE_DYNCREATE(CMainFrame)

// Attributes
public:

// Operations
public:

// Overrides
	//{{AFX_VIRTUAL(CMainFrame)
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
	//}}AFX_VIRTUAL

// Implementation
public:
	virtual ~CMainFrame();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:  
	// Панель управления и панель состояния
	CStatusBar  m_wndStatusBar;
	CToolBar    m_wndToolBar;

// Методы, предназначенные для обработки сообщений
protected:
	//{{AFX_MSG(CMainFrame)
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

Шаблон документов приложения создает объекты класса CMainFrame динамически. Для этого в определении класса указана макрокоманда DECLARE_DYNCREATE, объявлен конструктор, не имеющий параметров, а в файле реализации добавлена макрокоманда IMPLEMENT_DYNCREATE.


// Объекты класса CMainFrame могут создаваться динамически
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
Таблица сообщений класса CMainFrame

Класс CMainFrame может получать и обрабатывать сообщения, поэтому в определении класса указана макрокоманда DECLARE_MESSAGE_MAP, а в файле реализации класса MainFrm.cpp, расположена таблица сообщений.


// Таблица сообщений класса CMainFrame
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	//{{AFX_MSG_MAP(CMainFrame)
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

Изначально в таблице сообщений расположена единственная макрокоманда ON_WM_CREATE. Эта макрокоманда устанавливает для обработки сообщения WM_CREATE метод OnCreate. Как вы знаете, сообщение WM_CREATE передается функции окна сразу после его создания, но до того, как окно появится на экране.

Конструктор и деструктор класса CMainFrame

MFC AppWizard определяет для вас конструктор и деструктор класса CMainFrame. Вы можете расположить в конструкторе и деструкторе CMainFrame код для инициализации объектов класса.


// Конструктор класса CMainFrame
CMainFrame::CMainFrame()
{
	// TODO: 
}

// Деструктор класса CMainFrame
CMainFrame::~CMainFrame()
{
}
Метод OnCreate

Метод OnCreate определен в классе CWnd следующим образом.

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

Параметр lpCreateStruct содержит указатель на объект CREATESTRUCT, содержащий характеристики создаваемого окна. Эта структура уже была нами описана ранее.

При нормальной работе OnCreate должен вернуть значение 0, чтобы продолжить создание окна. Если OnCreate возвращает –1, окно будет удалено (уничтожено).

MFC AppWizard переопределяет метод OnCreate в классе CMainFrame. Поэтому для обработки сообщения WM_CREATE будет вызван именно переопределенный метод OnCreate класса CMainFrame.


int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	// Вызываем метод OnCreate базового класса 
	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	// Создаем панель управления toolbar
	if (!m_wndToolBar.Create(this) ||
		!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
	{
		// Ошибка при создании панели управления toolbar
		TRACE0("Failed to create toolbar\n");
		return -1;      
	}

	// Создаем панель состояния status bar
	if (!m_wndStatusBar.Create(this) ||
		!m_wndStatusBar.SetIndicators(indicators,
		  sizeof(indicators)/sizeof(UINT)))
	{
		// Ошибка при создании панели состояния status bar
		TRACE0("Failed to create status bar\n");
		return -1; 
	}

	// TODO: вы можете изменить характеристики панели 
	// управления, убрав некоторые флаги CBRS_
	m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
		CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

	// TODO: вы можете запретить перемещение панели управления, 
	// если удалите следующие три строки программы
	m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
	EnableDocking(CBRS_ALIGN_ANY);
	DockControlBar(&m_wndToolBar);

	return 0;
}

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

Метод OnCreate базового класса CFrameWnd выполняет обработку сообщения WM_CREATE XE "WM_CREATE" по умолчанию и возвращает нулевое значение если обработка прошла без ошибок.

В случае возникновения ошибок при обработке сообщения в базовом классе возвращается -1. Метод CMainFrame::OnCreate при этом также прерывает дальнейшую обработку и возвращает -1, вызывая удаление окна.

Панель управления и панель состояния

Наиболее интересная задача, которую выполняет метод OnCreate, заключается в отображении панелей управления и состояния. Для панели управления и панели состояния в библиотеке классов MFC предусмотрены два класса CStatusBar XE "CStatusBar" и CToolBar XE "CToolBar" .

Классы CStatusBar и CToolBar имеют длинную цепочку наследования.


CStatusBar <- | <- CControlBar <- CWnd <- CCmdTarget <- CObject
CToolBar <- |

Полное описание этих классов заняло бы слишком много места, поэтому мы ограничимся рассказом о самых главных методах, необходимых для работы с панелями управления и состояния.

Панель управления

Класс CToolBar XE "CToolBar" представляет панель управления XE "панель управления" toolbar. Обычно панель управления содержит несколько кнопок и разделителей между ними. Для панели управления определен специальный ресурс типа Toolbar.

Чтобы создать панель управления toolbar, следует выполнить следующие действия.

·         Создать ресурс, описывающий панель toolbar

·         Создать объект класса CToolBar. Он будет представлять панель управления

·         Вызвать метод Create класса CToolBar, чтобы создать панель и связать ее с объектом представляющим панель управления

·         Вызвать метод LoadToolBar класса CToolBar. Он загрузит ресурс диалоговой панели и завершит построение панели управления

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

Объект m_wndToolBar класса CToolBar для управления этой панелью определяется в классе CMainFrame. Этот объект объявлен как protected, поэтому обращаться к нему можно только из класса главного окна приложения CMainFrame.


protected:
	CToolBar m_wndToolBar;

Создание самой панели управления и отображение ее на экране выполняется во время обработки метода OnCreate класса CMainFrame. При этом методы Create и LoadToolBar вызываются в одной строке.


if (!m_wndToolBar.Create(this) ||
	!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
	// Ошибка при создании панели управления toolbar
	TRACE0("Failed to create toolbar\n");
	return -1; 
}

В качестве родительского окна панели управления методу Create указано ключевое слово this. Таким образом, родительским окном является главное окно приложения, представленное объектом класса CMainFrame.

После создания панели управления сразу вызывается метод LoadToolBar, загружающий ресурс панели управления IDR_MAINFRAME. Если хотя бы один метод - Create или LoadToolBar, завершится с ошибкой, метод OnCreate класса CMainFrame возвращает -1.

Панель состояния

Для управления панелью состояния используется класс CStatusBar. Чтобы создать для окна панель состояния следует выполнить следующие действия.

·         Создать объект класса CStatusBar XE "CStatusBar" . Он будет представлять панель состояния и управлять ей

·         Вызвать метод Create класса CStatusBar, чтобы создать панель и связать ее с объектом представляющим панель состояния

·         Вызвать метод SetIndicators класса CStatusBar, чтобы связать каждый индикатор панели состояния с идентификатором текстовой строки

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

Объект m_wndStatusBar класса CStatusBar определяется как элемент класса CMainFrame. Это вполне естественно, так как панель состояния принадлежит именно окну класса CMainFrame.


protected:
	CStatusBar  m_wndStatusBar;

Создание панели состояния и отображение ее на экране выполняется во время обработки метода OnCreate класса CMainFrame сразу после создания панели управления.

Методы Create и SetIndicators, создающие панель, вызываются в одной строке.


// Создаем панель status bar
if (!m_wndStatusBar.Create(this) ||
	!m_wndStatusBar.SetIndicators(indicators,
		sizeof(indicators)/sizeof(UINT)))
{
	// Ошибка при создании панели состояния status bar
	TRACE0("Failed to create status bar\n");
	return -1; 
}

В качестве родительского окна панели состояния методу Create указано ключевое слово this. Таким образом, родительским окном панели состояния, также как и панели управления, является главное окно приложения, представленное объектом класса CMainFrame.

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

В нашем приложении массив indicators, описывающий панель состояния, определен в файле MainFrm.cpp непосредственно после таблицы сообщений.


static UINT indicators[] =
{
	ID_SEPARATOR,
	ID_INDICATOR_CAPS,
	ID_INDICATOR_NUM,
	ID_INDICATOR_SCRL,
};

Сразу после создания панели состояния вызывается метод SetIndicators. В первом параметре ему передается массив indicators, а во втором - количество элементов в этом массиве.

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

После создания панели управления toolbar метод SetBarStyle класса CControlBar устанавливает различные стили этой панели. Стили определяются одной или несколькими константами CBRS_.

Константа

Описание

CBRS_ALIGN_TOP

Панель управления может закрепляться в верхней части окна

CBRS_ALIGN_BOTTOM

Панель управления может закрепляться в нижней части окна

CBRS_ALIGN_LEFT

Панель управления может закрепляться на левой стороне окна

CBRS_ALIGN_RIGHT

Панель управления может закрепляться на правой стороне окна

CBRS_ALIGN_ANY

Панель управления может закрепляться с любой стороны окна

CBRS_FLOAT_MULTI

Несколько панелей управления могут объединяться вместе в одном мини-окне

CBRS_TOOLTIPS

Когда пользователь устанавливает курсор на органы управления панели toolbar, их названия отображаются в маленькой прямоугольной рамке tool tips. Более подробно о tool tips вы можете прочитать в томе 22 серии “Библиотека системного программиста”

CBRS_FLYBY

Текст в панели состояния изменяется, одновременно с отображением tool tips. В противном случае текст в панели состояния меняется только когда пользователь нажмет кнопку в панели управления

CBRS_SIZE_DYNAMIC

Когда панель управления отображается в окне, пользователь может изменять ее размеры. При этом органы управления панели будут отображаться в нескольких строках. Этот стиль доступен только для Visual C++ версии 4.0 и выше

По умолчанию MFC AppWizard устанавливает для панели управления стили CBRS_TOOLTIPS, CBRS_FLYBY, CBRS_SIZE_DYNAMIC. Вы можете изменить их по своему усмотрению.


m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
	CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

Чтобы панель управления могла отображаться в собственном маленьком окне, не прикрепленном ни к одной стороне родительского окна, два раза вызываются метод EnableDocking - для панели управления и для главного окна приложения. Затем вызывается метод DockControlBar для главного окна приложения.


m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
Метод PreCreateWindow

MFC AppWizard переопределяет для класса CMainFrame виртуальный метод PreCreateWindow, но не вносит в структуру cs никаких изменений и вызывает метод PreCreateWindow базового класса CFrameWnd.


BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Здесь вы можете внести изменения в структуру cs

	return CFrameWnd::PreCreateWindow(cs);
}
Методы AssertValid и Dump

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

Когда отладочный режим отключен, символ _DEBUG не определен и поэтому методы AssertValid и Dump класса CObject не переопределяются.


//////////////////////////////////////////////////////////////
// Диагностические методы класса CMainFrame 
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
	CFrameWnd::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
	CFrameWnd::Dump(dc);
}
#endif //_DEBUG

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

[Назад] [Содеожание] [Дальше]