Приложение с однооконным интерфейсом, созданное средствами 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\nSingle 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"
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. Приложение может получить данные из ресурса, описывающего версию приложения. Для этого можно воспользоваться функциями GetFileVersionInfo и VerQueryValue.
Сейчас мы не станем подробно останавливаться на этом ресурсе. Большинство приложений не нуждается в определении данного ресурса, тем более на начальном этапе разработки. Поэтому мы продолжим изучения исходного текста самого приложения.
Общие замечания о ресурсах приложения
Внимательно изучив различные ресурсы приложения Single вы должны заметить, что четыре типа ресурсов имеют элементы с одинаковым идентификатором. Существует меню, строковый ресурс, таблица акселераторов и пиктограмма, которые имеют один и тот же идентификатор IDR_MAINFRAME.
Мы не станем полностью приводить исходные тексты приложения Single. Вы можете получить их самостоятельно, повторив описанную нами процедуру создания однооконного приложения. Исходные тексты приложения Single с комментариями на русском языке вы также можете приобрести на дискете, продаваемой с книгой. Вместо этого мы опишем отдельные классы определенные в приложении и их связь друг с другом.
MFC AppWizard создает для приложения Single, обладающего однооконным интерфейсом, 4 основных класса. Эти классы представляют основу любого однооконного приложения, созданного MFC AppWizard.
Класс приложения |
Базовый класс |
Описание |
CSingleApp |
CWinApp |
Главный класс приложения |
CMainFrame |
CFrameWnd |
Класс главного окна приложения |
CSingleDoc |
CDocument |
Класс документа приложения |
CSingleView |
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. Загадочная макрокоманда 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, ID_FILE_OPEN, 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 следующим образом:
void LoadStdProfileSettings(UINT nMaxMRU = _AFX_MRU_COUNT);
Необязательный параметр nMaxMRU определяет, сколько имен файлов документов будет запоминаться. Если указать в качестве параметра nMaxMRU нулевое значение, список файлов запоминаться не будет. По умолчанию параметру nMaxMRU присваивается значение _AFX_MRU_COUNT. Константа _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 из классов документа CSingleDoc , окна CMainFrame и окна просмотра CSingleView . Таким образом, шаблон документа объединяет всю информацию, относящуюся к данному типу документов.
Созданный шаблон документов заносится в список шаблонов с которыми работает приложение. Для этого указатель на созданный шаблон документа передается методу 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, можно было создавать динамически, необходимо выполнить следующее:
• в описании класса надо поместить макрокоманду DECLARE_DYNCREATE. В качестве параметра этой макрокоманды необходимо указать имя данного класса;
• определить конструктор класса, который не имеет параметров;
• разместить макрокоманду IMPLEMENT_DYNCREATE в файле реализации. Макрокоманда IMPLEMENT_DYNCREATE имеет два параметра. В первом указывается имя класса, а во втором имя его базового класса
MFC AppWizard автоматически выполняет все эти требования для класса документа приложения CSingleDoc, класса окна приложения CMainFrame и класса окна просмотра CSingleView.
Таблица сообщений класса CSingleDoc
Макрокоманда 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, от которого непосредственно наследуется класс 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 . Поэтому эти методы используются только для отладочной версии приложения. Когда выполняется окончательное построение приложения, эти методы не переопределяются.
//////////////////////////////////////////////////////////////
// Диагностические методы класса 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 представляет главное окно нашего приложения. Внутри этого окна отображаются окно просмотра документа, а также панели управления и состояния. Определение класса 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 , а затем создает и отображает внутри главного окна панель управления toolbar и панель состояния status bar.
Метод OnCreate базового класса CFrameWnd выполняет обработку сообщения WM_CREATE по умолчанию и возвращает нулевое значение если обработка прошла без ошибок.
В случае возникновения ошибок при обработке сообщения в базовом классе возвращается –1. Метод CMainFrame::OnCreate при этом также прерывает дальнейшую обработку и возвращает –1, вызывая удаление окна.
Панель управления и панель состояния
Наиболее интересная задача, которую выполняет метод OnCreate, заключается в отображении панелей управления и состояния. Для панели управления и панели состояния в библиотеке классов MFC предусмотрены два класса CStatusBar и CToolBar.
Классы CStatusBar и CToolBar имеют длинную цепочку наследования.
CStatusBar←|←CControlBar←CWnd←CmdTarget←CObject
CToolBar ←|
Полное описание этих классов заняло бы слишком много места, поэтому мы ограничимся рассказом о самых главных методах, необходимых для работы с панелями управления и состояния.
Панель управления
Класс CToolBar представляет панель управления 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 . Он будет представлять панель состояния и управлять ей
• Вызвать метод 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. В следующей главе мы расскажем как вы можете доработать полученное приложение, чтобы создать простейший графический редактор, с возможностью записи подготовленных в нем документов в файл.