Работа с Visual Studio.Net



 

Развитие класса документа


Теперь, когда мы имеем вспомогательные классы (CDPoint и CPolygon), можно подумать о структуре данных класса CTreeDoc. Нам понадобятся:

  • массив (контейнер) полигонов, которые соответствуют файлам документов, обнаруженных в текущем каталоге;
  • массив строк текста с файловыми путями этих документов;
  • один «дежурный» полигон, который в данный момент редактируется, то есть выбран для демонстрации в окне третьего представления (CDrawView);
  • размеры документа в логической системе координат (Page space);
  • коэффициент увеличения размеров при переходе из World в Page-пространство.
Кроме этого, нам понадобятся методы для управления тремя окнами: CLef tview, CRightView и CDrawView. Последний класс будет управлять окном, в котором полигон может быть отредактирован. Этот класс надо еще создать. Замените существующий интерфейс класса CTreeDoc на тот, который приведен ниже. Здесь мы также провели упрощение начальной заготовки по схеме, обсуждавшейся выше:

class CTreeDoc : public CDocument {

//==== Все 3 представления имеют право доступа

//==== к данным документа

friend class CLeftView;

friend class CRightView;

friend class CDrawView;

protected:

virtual ~CTreeDoc ();

CTreeDoc () ;

DECLARE_DYNCREATE(CTreeDoc) public:

//========== Данные документа============

//

CPolygon m_Poly; // Дежурный полигон VECPOLY m_Shapes;

// Контейнер полигонов

// ====== Контейнер имен файлов

vector<CString> m_sFiles;

//====== Размер документа в Page space

CSize m_szDoc;

//== Коэффициент увеличения при переходе World->Page

OINT m_nLogZoom;

//====== Флаг: открыто окно типа CTreeFrame

bool m_bTreeExist;

//=====Флаг: открыто окно типа CDrawFrame

bool m_bDrawExist;

//====== Новые методы класса документ =====//

//====== Поиск нужного представления

CView* GetViewfconst CRuntimeClass* pClass);

//====== Создание нужного представления

bool MakeViewO ;

//====== Преобразование координат World -> Page

CPoint MapToLogPt(CDPointS pt);

//====== Преобразование координат Page -> World

CDPoint MapToWorldPt(CPolntS pt) ;

//===== Перерисовка окна редактирования

void UpdateDrawView();

// Чтение найденных документов и их демонстрация

void ProcessDocs();

//====== Освобождение контейнеров

void FreeDocs();

//====== Поиск выбранной точки

int FindPoint(CDPointS pt) ;

// Overrides

public:

virtual BOOL OnNewDocument();

virtual void Serialize(CArchiveS ar) ;

// Generated message map functions

protected:

DECLARE_MESSAGE_MAP()

);

Некоторым из данных документа можно присвоить значения по умолчанию. Обычно это делается в конструкторе класса. Зададимся неким произвольным размером (2000 х 2000) документа в логической (Page) системе координат. Чем больше эта область, тем точнее будут отражены детали конструкции, так как вещественные (World) координаты претерпят округление при приведении к целым (Page) координатам. Вспоминая, что две из наших тестовых фигур имеют габариты в 2 единицы в пространстве World, определяем коэффициент увеличения m_nLogZoom = 700. В этом случае габариты фигур в пространстве Page будут равны 1400 единиц, то есть они целиком поместятся в области документа. Выбрав произвольные начальные цвета фигуры и учтя соображения относительно установки обратного указателя, получим следующую версию конструктора класса CTreeDoc:

CTreeDoc::CTreeDoc() : m_szDoc(2000,2000), m_Poly()

{

//====== Установка обратного указателя и

//====== атрибутов дежурного полигона

m_Poly.Set(this, RGB(240,255,250), RGB(0,96,0), 2);

m_nLogZoom = 700;

}

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

CTreeDoc::~CTreeDoc()

{

FreeDocs () ;

m_Poly .m_Points . clear () ;

}

Устойчивость данных документа обеспечивается функцией Serialize, и в стартовой заготовке класса уже есть этот метод. Его тело содержит схему сериализа-ции, но не имеет конкретных кодов записи или чтения данных из архива. Мы должны наполнить заготовку кодами так, чтобы документ мог полностью сохранить или восстановить свое состояние. Нет необходимости сохранять абсолютно все данные документа, так как некоторые из них носят тактический (временный) характер. Они заданы по умолчанию и не будут изменяться, например m_szDoc или m_nLogZoom. С долговременными данными документа мы отождествляем текущий или дежурный полигон m_Poly, который по легенде отражает выбранную и редактируемую в данный момент конструкцию. Он должен полностью изменить свои данные при выборе пользователем одной из картинок в окне правого представления. С этим окном мы связываем контейнер полигонов m_Shapes, который тоже носит временный характер, так как уничтожается и вновь создается при переходе из одной папки в другую и лишь помогает пользователю осуществить выбор. Таким образом, сериализацию документа мы отождествляем с сериали-зацией дежурного полигона. Поэтому тело функции Serialize выглядит весьма просто:

void CTreeDoc: : Serialize (CArchivei ar) {

// Просим объект выполнить сериализацию самостоятельно

m_Poly. Serialize (ar) ;

if (ar.IsStoringO ) {

// Здесь помещается код записи "обычных" данных }

else {

// Здесь помещается код чтения "обычных" данных

Мы могли бы поместить в ветви условного оператора такой код: ar « m_szDoc « m_nLogZoom; ar » m_szDoc » m_nLogZoom; но тогда для обработки документов, расположенных в текущей папке, было бы необходимо поддерживать динамический контейнер объектов CTreeDoc. Чтение документов сводилось бы к вызову Serialize для каждого из них. Такое решение будет более громоздким, чем поддержка контейнера полигонов. Поэтому мы оставляем ветви условного оператора пустыми.

Продолжая развитие темы преобразования координат, создадим тело функции MapToLogPt, которая, получив на входе точку с вещественными World-координатами, возвращает точку с целыми координатами в пространстве Page. В коде этой функции мы помещаем центр симметрии фигуры (точку с координатами

CDPoint(0,0)) в центр логической области, отведенной для документа, увеличиваем координаты и преобразуем их к целому типу:

CPoint CTreeDoc::MapToLogPt(CDPointS pt) {

{

//====== Растяжение и сдвиг

int x = m_szDoc.cx/2 +

int(m_nLogZoom * pt.x), у = m_szDoc.cy/2 +

int(m_nLogZoom * pt.y);

return CPoint(x,y);

+}

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

CDPoint CTreeDoc::MapToWorldPt(CPointS pt)

{

//====== Обратные операции

double x = double(pt.x - m_szDoc.cx/2) / m_nLogZoom,

у = double(pt.y - m_szDoc.cy/2) / m_nLogZoom;

return CDPoint(x, y);

}

В настоящий момент, если закомментировать вызовы FreeDocs и ProcessDocs в теле деструктора и функции OnSelchanged класса CLef tview, то вы можете запустить приложение, с тем чтобы устранить возможные ошибки. Но пока никакой новой функциональности оно не обнаружит, так как мы еще не занимались созданием и управлением других представлений его документа. Нам вновь придется вернуться к классу документ, но только после того, как будут разработаны классы связанных с ним представлений.

 

Назад Начало Вперед