Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
3 семестр, WinAPI, MFC.pdf
Скачиваний:
393
Добавлен:
15.06.2014
Размер:
6 Мб
Скачать
☆

Рис. 32. Несколько документов двух типов, используемых одним приложением

Таким образом, если внимательно посмотреть на перечисленные функции и члены класса CWinApp, при работе в рамках архитектуры "документ/представление", роль объекта-приложения заключается в создании, хранении и организации доступа к списку доступных для использования шаблонов документов. Фактически его роль сводится лишь к передаче управления "диспетчеру документов", представленному классом CDocManager, который, собственно, и выполняет всю необходимую для этого работу. Схематично процесс создания шаблона документа изображен на рис. 34.

Роль фреймов в архитектуре "документ/представление"

Фрейм документа, который мы будем здесь рассматривать, имеет две основные составляющие — собственно фрейм и его содержимое, представляющее на экране данные документа. Эти два компонента представлены и управляются различными группами классов библиотеки MFC: классы фреймов (CFrameWndw. CMDIChildWnd) и классы представлений (CView, CScrollView и другие). Процесс создания главного и дочерних фреймов подробно обсуждался в первом томе (см. главы 11, 12) и нет смысла повторяться. Вместо этого рассмотрим несколько фрагментов кода из приложения NoteDraw:

// описание класса (файл Childfrm.h) class CNoteFrame : public CMDIChildWnd {

I/ Для возможности динамического создания объекта // класса CNoteFrame вызывается макрос DECLARE_DYNCREATE(CNoteFrame)

protected:

CNoteFrame();

//реализация класса (файл Childfrm.cpp)

//Для возможности динамического создания объекта // класса CNoteFrame

вызывается макрос IMPLEMENT DYNCREATE(CNoteFrame, CMDIChildWnd)

Интерес здесь представляют два макроса, подробно описанные в главе 8 первого тома - DECLARE_DYNCREATE и IMPLEMENT_DYNCREATE -и защищенный (protected) конструктор по умолчанию. Дело в том, что все вышеперечисленные составляющие архитектуры "документ/представление (документ, фрейм и представление) создаются шаблоном документов динамически, во время выполнения программы. Кроме того, эти макросы охватывают также все возможности двух других групп макросов —

DECLARE_DYNAMIC, IMPLEMENT^ DYNAMIC, DECLARE_SERIAL и IMPLEMENT_ SERIAL, что гарантирует также поддержку получения информации времени выполнения и сериализации. Забыв включить эти макросы соответственно в объявление и реализацию некоторого класса, вы тем самым исключаете для него возможность корректной работы механизмов RUNTIME_CLASS и сериализации.

Рассмотрим функции класса CFrameWnd, которые связаны с архитектурой "документ/представление".

void BOOL CFrameWnd::OnCreateClient(

LPCREATESTRUCT Ipcs, CCreateContext *pContext) -

вызывается только библиотекой классов MFC из обработчика OnCreate и не должнавызыватьсянепосредственно. В качестве параметров в функцию передаются: Ipcs — указатель на структуру CREATESTRUCT и pContext— указатель на структуру CCreateContext:

struct CCreateContext{

CRuntimeClass* m_pNewViewdass; CDocument* m_pCurrentDoc;

CDocTemplate* m_pNewDocTemplate;

CView* m_pLastView;

CFrameWnd* m_pCurrentFrame;

CCreateContext ();

Структура CCreateContext создается шаблоном документа (при создании документа и ассоциированных с ним компонентов). Перечислим поля этой структуры (все поля могут содержать NULL):

m_pNewViewClass

указатель на структуру CRuntimeClass вновь создаваемого

представления

 

m_pCurrentDoc

указатель на уже существующий документ, с которым ассо-

циируетсяновоепредставление

m_pNewDocTemplate указатель на шаблон документа, с которым ассоциирован

создаваемыйфрейм

 

m_pLastView

указатель на начальное представление, к которому добав-

ляется создаваемое, например, при работе с разделенным окном или при создании дополнительного представления документа

m_pCurrentFrame указатель на текущий фрейм, к которому добавляется создаваемый, например, при создании дополнительного фрейма документа

Библиотекой MFC эта структура используется в следующих функциях: CWnd::Create, CFrame Wnd::Create View, CFrame Wnd:: Load Frame, CFrameWnd:;OnCreateClient, CFrameWndr.Create, CSplitterWndr.Create и CSplitterWnd::Create View.

virtual void CFrameWnd::ActivateFrame(int nCmdShow = -1) —

активизирует фрейм, т. е. делает его видимым и доступным для пользователя. Параметр nCmdShow принимает такие же значения, как и посылаемые в функцию CWnd::ShowWindow. По умолчанию функция делает фрейм видимым и переводит его на самый верх Z-порядка, и при необходимости то же самое выполняет для главного окна приложения. При переопределении, после проведения необходимых действий, например, разворачивания дочернего окна, необходимо вызвать соответствующую функцию базового класса с явным указанием параметра nCmdShow, как, например, сделано в приложении NoteDraw.

void CNoteFrame::ActivateFrame(int nCmdShow)

{

// Разворачиваем фрейм документа

CMDIChildWnd::ActivateFrame(SW MAXIMIZE);

void CFrameWnd::lnitialUpdateFrame( CDocument *pDoc,

BOOL bMakeVisible) -

вызывается после создания нового фрейма и инициирует вызов обработчика OnlnitialUpdate для всех своих представлений. При этом активизируется представление, у которого идентификатор дочернего окна установлен в AFX_IDW_PANE_FIRST. Если значение параметра bMakeVisible равно TRUE, то фрейм делается видимым; в противном случае — нет. Параметр pDoc определяетдокумент, ассоциированныйсданнымфреймом.

virtual CFrameWnd* CFrameWnd::GetActiveFrame() -

возвращает указатель на активное дочернее окно MDI-приложения. При работе с SDI-приложениями функция возвращает указатель на текущий объект — this.

void CFrameWnd::SetActiveView( CView *pViewNew, BOOL bNotify = TRUE) -

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

// Установить фокус на область (1, 0) SetActiveView((CView*)m_spltWnd.GetPane(1, 0) )

;

Параметр bNotify определяет, будет ли само представление извещено об активизации. Если его значение равно TRUE, то для активизируемого представления вызывается функция OnActivateView.

CView* CFrameWnd::GetActiveView() -

возвращаетуказательнаобъекттекущегоактивногопредставления. Еслитакого нет, то возвращается NULL.

CWnd* CFrameWnd::CreateView(

CCreateContext *pContext,

UINT nID = AFX_IDW_PANE_FIRST) -

создает представление внутри фрейма, которое не является производным от CView, и возвращает указатель на него. После выполнения функции необходимо самостоятельно установить активность и видимость вновь созданного представления. Параметр pContext определяет тип представления и документа, а пЮ — идентификатор представления.

virtual CDocument* CFrameWnd::GetActiveDocument() —

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

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

BOOL CNoteFrame::OnCreateClient(LPCREATESTRUCT Ipcs,

CCreateContext* pContext)

//создаем разделенное окно Windows // с двумя строками и одним столбцом

if(!m_spltWnd.CreateStatic(this, 2, 1))

//создаем представление в первой строке (горизонтальная область) if(!m_spltWnd.CreateView(0, 0, pContext->m_pNewViewClass, CSize(lpcs->cx, lpcs->cy*2/3), pContext))

Характер рассмотренных функций достаточно наглядно показывает роль фрейма в архитектуре "документ/представление". Прежде всего, фрейм хранит путь к текущему активному представлению. В случае, когда он содержит более одного представления, например, при работе с разделенным окном, то в качестве активного принимается самое последнее используемое представление.1 Последняя из описанных выше функций показывает, что фрейм имеет также доступ к документу, ассоциированному с текущим активным представлением. Кроме того, фрейм занимается координацией взаимодействия между различными представлениями, ассоциированными с определенным документом, направляя им команды и получая от них извещения. Маршруты, по которым осуществляется обмен сообщениями, подробно описаны нами в главе 10. И последнее. Мы уже говорили, что с каждым документом ассоциируются определенные ресурсы меню и акселераторов. Так вот, задачу разделения этих ресурсов среди документов, созданных на основе одного шаблона, и замены ресурсов при активизации документа другого типа также с успехом решают главный фрейм и фрейм документа.

В заключение коротко перечислим те шаги, которые необходимо проделать для организации работы в рамках архитектуры "документ/представление":

О создать объект-приложение;

Q создать объекты-документы (см. главу 27);

Q создать необходимое число представлений каждого документа (см. главу 27);

Q в функции Initlnstance объекта-приложения создать объекты-шаблоны документов и добавить их к его списку;

Q создать необходимые ресурсы для каждого из них;

Q переопределить функцию CFrameWnd::OnCreateClient, в которой присоединить к фрейму документа необходимые представления;

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

Документ и его представления

Как мы уже неоднократно отмечали, одним из основных достоинств архитектуры "документ/представление" является то, что в ней данные отделены от их изображения.1 Любые изменения данных осуществляются

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