Функция инициализации приложения CWinApp::InitInstance 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Функция инициализации приложения CWinApp::InitInstance



Один из интересных аспектов приложения документ/вид – способ создания объектов окна-рамки, документа и вида. В функции InitInstance, сгенерированной с помощью AppWizard, содержится примерно следующее:

CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CMyDoc), RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CMyView) ); AddDocTemplate(pDocTemplate); ... CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if (!ProcessShellCommand(cmdInfo)) return FALSE; m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow();

Следующие операторы:

CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CMyDoc), RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CMyView) );

создают SDI-шаблон документа как объект MFC-класса CSingleDocTemplate. Шаблон документа (document template) – это очень важная компонента SDI-приложения документ/вид. С его помощью сопоставляются классы документа, окна-рамки и вида. В шаблоне документа также хранится идентификатор ресурса (по умолчанию IDR_MAINFRAME), по которому каркас приложения загружает меню, таблицу ускоряющих клавиш и другие ресурсы. Макрос RUNTIME_CLASS, которому в качестве параметра передается имя класса, возвращает указатель на объект CRuntimeClass. Он обеспечивает динамическое создание объектов класса каркасом приложения. После создания шаблона документа он добавляется в список шаблонов, хранящийся в объекте-приложении:

AddDocTemplate(pDocTemplate);

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

Операторы:

CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo);

вызывают CWinApp::ParseCommandLine для инициализации объекта CCommandLineInfo значениями, переданными через командную строку операционной системы (иногда так передается имя открываемого файла с документом). Далее выполняется "обработка" командной строки:

if (!ProcessShellCommand(cmdInfo)) return FALSE;

В частности, ProcessShellCommand вызывает CWinApp::OnFileNew для запуска приложения с пустым новым документом, если в командной строке не было указано имени файла. Если же имя было указано, то вызывается CWinApp::OpenDocumentFile для загрузки документа из файла. Именно на этой стадии выполнения программы каркас приложения создает объект-документ, окно-рамку и окно-вид на основе информации из шаблона документа. ProcessShellCommand возвращает TRUE в случае успешной инициализации или FALSE в случае ошибки. После успешной инициализации окно-рамка (и его дочернее окно-вид) выводятся на экран:

m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow();

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

 

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

В приложении документ/вид данные хранятся в объекте-документе. Это объект класса, унаследованного от CDocument (создается AppWizard 'ом). Термин "документ" несколько неоднозначен, т.к. сразу вызывает аналогию с документами текстовых редакторов или электронных таблиц. В действительности "документ" в архитектуре документ/вид – это просто некоторая структура данных, которая может описывать что-либо, например, колоду карт в карточной игре или имена и пароли пользователей в сетевой программе. Документ – это абстрактное представление данных программы, которое должно быть четко отделено от визуального представления. Обычно у объекта-документа есть открытые функции-члены, с помощью которых другие объекты, в первую очередь, окна-виды, могут обращаться к данным документа. Вся обработка данных выполняется только объектом-документом.

Данные документа часто хранятся в виде переменных-членов подкласса CDocument. Можно сделать их открытыми, но, в целях лучшей защищенности, переменные-члены лучше описать защищенными и завести для доступа к данным специальные функции-члены. Например, в текстовом редакторе объект-документ может хранить символы в виде объекта CByteArray и предоставлять доступ к ним с помощью функций-членов AddChar и RemoveChar. Для обслуживания объекта-вида могут потребоваться и более специализированные функции-члены, например, AddLine и DeleteLine.

 

3.1 Операции CDocument

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

Таблица 9.1. Основные операции класса CDocument

Функция-член Описание
GetFirstViewPosition Возвращает значение типа POSITION, которое можно передавать функции GetNextView для перебора всех окон-видов, связанных с данным документом.
GetNextView Возвращает указатель на CView – на следующее окно-вид в списке видов, связанных с данным документом.
GetPathName Возвращает имя файла документа (включая путь), например, "C:\Documents\Personal\MyFile.doc". Если у документа нет имени, возвращает пустую строку.
GetTitle Возвращает заголовок документа, например, "MyFile" (или пустую строку, если документу не было присвоено имени).
IsModified Возвращает флаг модификации документа – ненулевое значение, если в документе есть данные, несохраненные в файле.
SetModifiedFlagS Устанавливает или сбрасывает флаг модификации документа.
UpdateAllViews Обновляет все виды, связанные с данным документом (у каждого окна-вида вызывается функция OnUpdate)

Среди функций табл. 9.1 чаще всего используются SetModifiedFlag и UpdateAllViews. Функцию SetModifiedFlag надо вызывать при каждом изменении данных документа. Она устанавливает флаг, по значению которого MFC при закрытии документа выдает пользователю запрос на сохранение данных. UpdateAllViews вызывает перерисовку всех окон-видов (в MDI-приложениях их может быть несколько), связанных с этим документом. Функция UpdateAllViews вызывает у каждого вида функцию OnUpdate, которая по умолчанию объявляет окно-вид недействительным, а это приводит к его перерисовке.

 

Виртуальные функции CDocument

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

Таблица 9.2. Часто используемые виртуальные функции CDocument

Функция-член Описание
OnNewDocument Вызывается изнутри каркаса при создании нового документа. Перегружается для выполнения специфической инициализации, необходимой при создании каждого нового документа.
OnOpenDocument Вызывается каркасом при загрузке документа из файла.
DeleteContents Вызывается каркасом для удаления содержимого документа. Перегружается для освобождения памяти и других ресурсов, выделенных объекту-документу.
Serialize Вызывается каркасом для записи/чтения данных документа из файла. Перегружается почти всегда, чтобы документы можно было хранить в файлах.

В SDI-приложении MFC создает объект-документ только один раз – при запуске приложения. При открытии/закрытии файлов этот объект используется повторно. Поэтому заведены две виртуальные функции – OnNewDocument и OnOpenDocument. MFC вызывает OnNewDocument при создании нового документа (например, при выборе команды меню ФайлÞСоздать). Функцию OnOpenDocument MFC вызывает при загрузке документа с диска (при выборе команды ФайлÞОткрыть). В SDI-приложении вы можете выполнить однократную инициализацию документа в конструкторе класса, а также выполнять специфическую инициализацию в перегруженных функциях OnNewDocument и/или OnOpenDocument.

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

BOOL CMyDoc::OnNewDocument () { if (!CDocument::OnNewDocument()) return FALSE; // Некоторые действия по инициализации данных документа return TRUE; }   BOOL CMyDoc::OnOpenDocument(LPCTSTR lpszPathName) { if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE; // Некоторые действия по инициализации данных документа return TRUE; }

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

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

Для непосредственного выполнения операций чтения/записи документа на диск, каркас вызывает функцию документа Serialize. Serialize должна быть реализована так, чтобы помещать данные документа в файловый поток или считывать их оттуда. Каркас приложения делает все остальное, в т.ч. открывает файл для чтения или записи и создает объект класса CArchive, представляющий файловый поток. Например, Serialize в подклассе CDocument обычно выглядит так:

void CMyDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // Запись данных документа в поток ar } else { // Чтение данных документа из потока ar } }

В местах комментариев вы должны расположить операторы для чтения или записи данных документа в поток. Допустим, что в некотором объекте-документе хранятся две строки (объекты класса CString) с именами m_strName и m_strPhone. Тогда функция Serialize может быть написана примерно так:

void CMyDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // Запись в файловый поток ar << m_strName << m_strPhone; } else { // Чтение из файлового потока ar >> m_strName >> m_strPhone; } }

Если данные вашего документа состоят из переменных основных типов и сериализуемых (для которых у CArchive перегружены операторы ввода/вывода) классов, например, CString, то написать функцию Serialize особенно просто – достаточно применить к каждой переменной оператор << и >>. Для сохранения структур и других несериализуемых типов данных можно пользоваться функциями CArchive::Read и CArchive::Write. В классе CArchive есть функции ReadString и WriteString для сериализации строк произвольной структуры (например, с сохранением пробелов). Если возможностей CArchive для сохранения документа недостаточно, можно вызывать функцию CArchive::GetFile и получить указатель на объект CFile, посредством которого можно напрямую обращаться к файлу, с которым связан поток CArchive.

У CDocument есть и реже используемые виртуальные функции, например, OnCloseDocument (вызывается при закрытии документа) и OnSaveDocument (вызывается при сохранении документа).

 

Класс-вид

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

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

C объектом-документом может быть связано любое количество объектов-видов, но каждый вид принадлежит единственному документу. Каркас приложения хранит указатель на объект-документ в переменной-члене m_pDocument у каждого объекта-вида. Для доступа к этому указателю у объекта-вида есть функция-член GetDocument. Объект-документ может перебрать все связанные с ним виды, просматривая список функциями GetFirstViewPosition и GetNextView, а вид может получить указатель на свой документ простым вызовом GetDocument.

 

4.1 Виртуальные функции CView

Как и у класса CDocument, у класса CView есть несколько виртуальных функций для настройки поведения конкретного объекта-вида (табл. 9.3). Самой важной функцией является OnDraw, которая вызывается объектом-видом при получении сообщения WM_PAINT. В приложениях, не поддерживающих архитектуру документ/вид, сообщения WM_PAINT обрабатываются в обработчиках OnPaint и рисование выполняется посредством объектов CPaintDC. В приложениях документ/вид сообщение WM_PAINT обрабатывается каркасом приложения. В этом обработчике создается объект CPaintDC и вызывается виртуальная функция объекта-вида OnDraw. Например, для вывода в центре окна-вида строки, хранящейся в объекте-документе, функция OnDraw может быть реализована так:

void CMyView::OnDraw(CDC* pDC) { CMyDoc* pDoc = GetDocument(); CString string = pDoc->GetString(); CRect rect; GetClientRect(&rect); pDC->DrawText(string, rect, DT_SINGLELINE ¦ DT_CENTER ¦ DT_VCENTER); }

Обратите внимание, что OnDraw использует контекст устройства, переданный в функцию в качестве параметра, а не создает собственный контекст.

Таблица 9.3. Важнейшие виртуальные функции CView

Функция-член Описание
OnDraw Вызывается для рисования данных документа внутри окна-вида.
OnInitialUpdate Вызывается при присоединении окна-вида к объекту-документу. Перегружается для инициализации вида при загрузке документа из файла или при создании нового документа.
OnUpdate Вызывается при любом изменении данных документа, когда необходимо перерисовать окно-вид. Перегружается для реализации "интеллектуального" обновления окна-вида, когда перерисовывается не все окно, а только некоторая часть, связанная с измененными данными.

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

Две других часто перегружаемых виртуальных функции CView –OnInitialUpdate и OnUpdate. Вид, как и документ, в SDI-приложении создается только один раз и затем многократно используется. В SDI-приложениях OnInitialUpdate вызывается каждый раз, когда документ создается или открывается с диска. По умолчанию OnInitialUpdate вызывает OnUpdate, а OnUpdate по умолчанию объявляет все окно-вид недействительным для его перерисовки. В OnInitialUpdate удобно поместить инициализацию переменных-членов окна-вида, а также другие операции инициализации, необходимые при заведении нового документа. Например, в подклассах CScrollView в OnInitialUpdate обычно вызывается функция-член SetScrollSizes для задания границ полос прокрутки. В OnInitialUpdate надо вызывать функцию-член базового класса, иначе окно-вид не будет перерисовано.

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

В MDI-приложениях видов документа может быть несколько, и один из них является активным, а остальные – неактивными. Фокус ввода принадлежит активному виду. Для отслеживания, когда вид становится активным или неактивным, в нем можно перегрузить функцию CView::OnActivateView. Окно-рамка может получить указатель на активный вид или сделать какой-либо вид активным функциями CFrameWnd::GetActiveView и CFrameWnd::SetActiveView.

 

5. Класс "окно-рамка"

До сих пор было рассмотрено назначение трех объектов: приложение, документ и вид. Осталось рассмотреть еще один объект – окно-рамку, которое определяет рабочую область приложения на экране и служит контейнером для вида. В SDI-приложении есть только одно окно-рамка подкласса CFrameWnd, которое служит главным окном приложения и содержит внутри себя окно-вид. В MDI-приложениях есть окна-рамки двух типов – CMDIFrameWnd для главного окна и CMDIChildWnd для окон-видов.

Окна-рамки очень важны для приложений документ/вид. Это не просто главное окно приложения, а объект, который реализует значительную часть функциональности приложения документ/вид. Например, в классе CFrameWnd есть обработчики OnClose и OnQueryEndSession, которые дают пользователю возможность записать несохраненный документ перед завершением приложения или перед закрытием Windows. В CFrameWnd реализовано автоматическое изменение окна-вида при изменении размеров окна-рамки с учетом панелей инструментов, строки состояния и других компонент пользовательского интерфейса. В нем есть также функции-члены для работы с панелями инструментов, строкой состояния, для получения активного документа и видов и др.

Для лучшего понимания роли класса CFrameWnd можно сравнить его с общим классом окна CWnd. Класс CWnd – это оболочка на языке Си++ для работы с окном Windows. CFrameWnd унаследован от CWnd и в нем добавлено много новых средств, выполняющих типичные действия в приложениях документ/вид.

 



Поделиться:


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

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.141.198.146 (2.209 с.)