пользователей: 30398
предметов: 12406
вопросов: 234839
Конспект-online
РЕГИСТРАЦИЯ ЭКСКУРСИЯ

Архитектура «Документ-представление». Классы документа и представления.

Что такое класс документа

Формируя текст программы приложения с помощью AppWizard, вы имеете возможность оснастить свое детище всеми модными аксессуарами коммерческого продукта для Windows 95 — панелью инструментов, строкой состояния, контекстным окном указателя, разнообразными меню и даже окном сообщения об авторских правах. Однако несмотря на все эти "примочки" полезность такого приложения равна нулю. Для того чтобы создать приложение, которое не только хорошо выглядит на экране, но и делает что-то полезное, вам волей-неволей придется вмешаться в текст программы, которую подготовил AppWizard. Это может быть просто или не очень просто, или даже очень сложно — все зависит от того, что же в действительности должно делать приложение и как оно должно при этом выглядеть.

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

Создавая SDI- и MDI-приложения, AppWizard изначально закладывает в них средства, ориентированные на реализацию концепции документ/представление. Это означает, что AppWizard формирует класс, производный от CDocument, и передает ему определенные задачи. Он также формирует класс представления, производный от CView, которому передает другие задачи. Давайте закажем AppWizard простейшее приложение и посмотрим, что он нам выдаст.

Выберите File--New, затем вкладку Projects. Установите имя проекта Арр1 и соответствующие каталоги для файлов проекта. Проверьте, чтобы был выбран вариант MFC AppWizard (ехе) в левом окне. Щелкните на ОК.

Пройдитесь по всем диалоговом окнам AppWizard, заказывая параметры в соответствии с приведенным ниже списком и каждый раз щелкая на Next.

Этап 1. Выберите Multiple documents.

Этап 2. Не меняйте настроек, предлагаемых AppWizard по умолчанию.

Этап 3. Не меняйте настроек, предлагаемых AppWizard по умолчанию.

Этап 4. Сбросьте все флажки, кроме Printing and print preview (Печать и предварительный просмотр распечатки).

Этап 5. Не меняйте настроек, предлагаемых AppWizard по умолчанию.

Этап 6. Не меняйте настроек, предлагаемых AppWizard по умолчанию.

На последнем этапе щелкните на кнопке Finish, и параметры выполненной настройки будут выведены в окне New Project Information (Информация о новом проекте). После щелчка на кнопке OK ClassWizard сформирует проект. В окне ClassView просмотрите список классов приложения. Создано шесть классов: CAboutDIg, CApp1App, CApp1Doc, CApp1View, CChiIdFrame и СМаinFrame.

Класс САрp1Doc представляет документ и содержит структуру данных, которыми может оперировать приложение. Организовать хранение данных в классе можно включением в него соответствующих членов-переменных. Текст файла заголовка, который AppWizard сформировал для класса CApp1 Doc, представлен в листинге 4.1.

 

Листинг4.1

// App1Doc.h : интерфейс класса СApplDoc

#if !defined(AFX_APP1DOC_H__528CF70C_0F96_11D7_BBD4_00C0F6B2220A__INCLUDED_)

#define AFX_APP1DOC_H__528CF70C_0F96_11D7_BBD4_00C0F6B2220A__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

 

class CApp1Doc : public CDocument

зн

protected: // Создаются только в случае сохранения-восстановления.

          CApp1Doc();

          DECLARE_DYNCREATE(CApp1Doc)

public:

public:

// Перегрузка.

// Перегрузка виртуальных функций, сформированная ClassWizard.

          //знзн AFX_VIRTUAL(CApp1Doc)

          public:

          virtual BOOL OnNewDocument();

          virtual void Serialize(CArchive& ar);

          //знзнAFX_VIRTUAL

// Реализация

public:

          virtual ~CApp1Doc();

#ifdef _DEBUG

          virtual void AssertValid() const;

          virtual void Dump(CDumpContext& dc) const;

#endif

protected:

// Карта сообщений

protected:

          //знзнAFX_MSG(CApp1Doc)

                    // ВНИМАНИЕ! ! Здесь ClassWizard будет добавлять и

//   удалять функции-члены.

//   НЕ РЕДАКТИРУЙТЕ текст в этих блоках!

          //знзнAFX_MSG

          DECLARE_MESSAGE_MAP()

зн;

 

Почти в самом начале листинга есть секция Атрибуты, за которой следует ключевое слово  public. Именно здесь вам и нужно будет вставить объявления членов-переменных, в которых планируется хранить данные приложения. В приложении, которое будет рассмотрено дальше  нужно будет сохранять массив объектов класса СРоint. Этот массив объявляется как член класса документа:

 

// Attributes

public:

CPoint m_points [100];

 

CPoint— это класс MFC, который инкапсулирует информацию, имеющую отношение к точке на экране, в частности — координаты этой точки х и у.

В тексте файла заголовка обратите внимание также на то, что класс САрр1Doc имеет две виртуальные функции-члены— OnNewDocument() и Serialize(). MFC вызывает функцию OnNewDocument(), как только пользователь выберет команду File=>New (или соответствующую пиктограмму на панели инструментов, если таковая присутствует в приложении). Эту функцию можно использовать для выполнения всех инициализаций, необходимых новой порции данных. В SDI-приложении в таком случае закрывается открытый документ и новый пустой документ загружается в тот же самый объект класса. В MDI-приложении открывается новый пустой документ (создается новый экземпляр класса документа) в дополнение к уже существующему. Функция Serialize() используется для загрузки в файл и выгрузки из него данных, хранящихся в членах-переменных объекта класса документа.

Рассмотрим файл App1Doc.cpp:

// App1Doc.cpp : implementation of the CApp1Doc class

//

#include "stdafx.h"

#include "App1.h"

 

#include "App1Doc.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

/////////////////////////////////////////////////////////////////////////////

// CApp1Doc

 

IMPLEMENT_DYNCREATE(CApp1Doc, CDocument)

 

BEGIN_MESSAGE_MAP(CApp1Doc, CDocument)

          //знзнAFX_MSG_MAP(CApp1Doc)

// NOTE - the ClassWizard will add and remove mapping macros here.

//    DO NOT EDIT what you see in these blocks of generated code!

          //знзнAFX_MSG_MAP

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// CApp1Doc construction/destruction

 

CApp1Doc::CApp1Doc()

знзно

CApp1Doc::~CApp1Doc()знзно

BOOL CApp1Doc::OnNewDocument()

зн       if (!CDocument::OnNewDocument())

                    return FALSE;

                    return TRUE;зн

/////////////////////////////////////////////////////////////////////////////

// CApp1Doc serialization

void CApp1Doc::Serialize(CArchive& ar)

зн        if (ar.IsStoring())

          зн                             зн

          else

          зн                            зн

зн

#ifdef _DEBUG

void CApp1Doc::AssertValid() const

зн

          CDocument::AssertValid();

зн

 

void CApp1Doc::Dump(CDumpContext& dc) const

зн

          CDocument::Dump(dc);

зн

#endif //_DEBUG

 

/////////////////////////////////////////////////////////////////////////////

// CApp1Doc commands

 

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

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

Большинство программистов, имеющих дело с MFC, включают в класс документа открытые (public) члены с тем, чтобы не затруднять доступ к ним из объекта класса представления. Классический объектно-ориентированный подход, однако, требует включать в класс закрытые (private) или защищенные (protected) члены-переменные и открытые члены-функции считывания и модификации этих переменных.

 

// App1View.h : interface of the CApp1View class

//

/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_APP1VIEW_H__528CF70E_0F96_11D7_BBD4_00C0F6B2220A

__INCLUDED_)

#define AFX_APP1VIEW_H__528CF70E_0F96_11D7_BBD4_00C0F6B2220A__INCLUDED_

 

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

 

class CApp1View : public CView

зн

protected: // create from serialization only

          CApp1View();

          DECLARE_DYNCREATE(CApp1View)

 

// Attributes

public:

          CApp1Doc* GetDocument();

// Operations

public:

 

// Перегрузка.

// ClassWizard генерирует перегрузку виртуальных функций

          //знзнAFX_VIRTUAL(CApp1View)

          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 ~CApp1View();

#ifdef _DEBUG

          virtual void AssertValid() const;

          virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

 

// Сформированные функции карты сообщений

protected:

          //знзнAFX_MSG(CApp1View)

          // NOTE - the ClassWizard will add and remove member functions here.

          //    DO NOT EDIT what you see in these blocks of generated code !

          //знзнAFX_MSG

          DECLARE_MESSAGE_MAP()

зн;

 

#ifndef _DEBUG  // debug version in App1View.cpp

inline CApp1Doc* CApp1View::GetDocument()

  зн return (CApp1Doc*)m_pDocument; зн

#endif

 

/////////////////////////////////////////////////////////////////////////////

 

//знзнAFX_INSERT_LOCATIONзнзн

// Microsoft Visual C++ будет вставлять дополнительные объявления

//    непосредственно перед предыдущей строкой

 

#endif // !defined(AFX_APP1VIEW_H__528CF70E_0F96_11D7_BBD4_

00C0F6B2220A__INCLUDED_)

 

Почти в самом начале текста имеется секция открытых атрибутов, в которой объявлена функция GetDocument(), возвращающая указатель на объект класса CApplDoc. Если, работая с классом представления, вы пожелаете получить указатель на объект класса документа, нужно будет вызвать эту функцию и она вернет вам требуемый указатель. Например, для того чтобы добавить объект класса СРоint в массив таких объектов, который является членом класса документа, можно использовать следующий оператор:

 

GetDocument()->m_points[x] = point;

Можно сделать то же самое, запомнив указатель, возвращаемый GetDocument(), в локальной переменной, а затем уже использовать ее для доступа к данным документа:

 

pDoc = GetDocument();

pDoc-> m_points[x] = point;

 

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

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

Обратите внимание на то, что как класс представления, так и класс документа перегружают часть функций-членов своих базовых классов. Функция OnDraw() является одной из важнейших среди всех виртуальных функций, она является именно тем инструментом, с помощью которого производится рисование в окне приложения. Что касается других функций, то MFC вызывает PreCreateWindow() перед тем, как создается и присоединяется к объекту класса окон MFC окно Windows. Эта функция дает возможность модифицировать такие атрибуты окна, как положение и размер. Функция OnPreparePrinting() используется для модификации диалогового окна Print перед его выводом на экран. Функция OnBeginPrinting() дает шанс создать GDI-объект, такой как кисть или перо, который необходим для выполнения некоторых задач в процессе печати. И наконец, в функции OnEndPrinting() можно уничтожить любой объект, созданный функцией OnBeginPri nting().

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

В классе документа (Doc.cpp) за перерисовку окна отвечает функция

 

UpdateAllViews()

 

В классе представления (View.cpp) за перерисовку окна отвечает функция

 

Invalidate()

 

Вызов функции Invalidate() приводит к тому, что МFС обращается к функции OnDraw(), которая, в свою очередь, перерисовывает изображение на экране. Invalidate() принимает единственный аргумент (его значение по умолчанию— TRUE), который указывает, нужно ли стирать прежнее изображение перед прорисовкой нового функцией OnDraw(). Хотя и редко, но бывают случаи, когда удобнее вызывать Invalidate() с аргументом FALSE, и тогда OnDraw() будет рисовать поверх прежнего изображения.


18.01.2020; 20:10
хиты: 46
рейтинг:0
для добавления комментариев необходимо авторизироваться.
  Copyright © 2013-2024. All Rights Reserved. помощь