SDI -приложения внутри окна представления в точке x=200, y=100 должен появиться круг радиусом 20 пикселов.Приступим к решению поставленной задачи.
Командой меню
Установите вкладку
Состояние остальных вкладок пусть останется установленным по умолчанию, а именно


На последней вкладке цифра 4 означает размер списка последних обработанных документов.
Просмотрите все вкладки мастера и нажмите кнопку Finish, чтобы мастер создал заготовку приложения
В раскрывающемся списке Solution Configurations поменяйте режим работы оболочки с Debug на Release, чтобы отключить генерацию отладочного кода при сборке проекта
Запустите заготовку, созданную мастером, на компиляцию и линковку командой Build/Build Solution, а затем на выполнение командой Debug/Start Debugging (F5) Появится полноценное окно Windows с однодокументным интерфейсом ( )

В классе документа нам нужно добавить поля, в которых будут храниться координаты центра будущего круга.
Вызовите панель View/Solution Explorer и в дереве файлов проекта двойным щелчком откройте на редактирование заголовочный файл CircleDoc.h
Найдите объявление класса CCircleDoc и добавьте в него объявления полей, которые будут хранить координаты центра кругаОбъявления полей в классе документа CCircleDoc
class CCircleDoc : public CDocument
{
protected: // create from serialization only
CCircleDoc();
DECLARE_DYNCREATE(CCircleDoc)
// Attributes
public:
int m_PosX; // координата x (по горизонтали) центра круга
int m_PosY; // координата y (по вертикали) центра круга
// Operations
public:
...................................................
}
В объявлении класса язык C++ не допускает инициализацию членов-данных (кроме перечисления enum ). Поэтому инициализацию поместим в функцию-член класса, которая выполняется при создании нового документа. Для этого
В раскрывающемся списке Functions in CCircleDoc (сведения о CCircleDoc ) выберите функцию-метод OnNewDocument()Именно функция OnNewDocument() срабатывает при создании нового документа.
Внесите в функцию OnNewDocument() код инициализации объявленных координат кругаИнициализация полей в функции OnNewDocument() класса CCircleDoc
BOOL CCircleDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
m_PosX = 200;
m_PosY = 100;
return TRUE;
}
Схема "Документ-Представление" реализует отношение "один ко многим", т.е. одни и те же данные класса Документа можно по разному отображать пользователю в классах Представления. В нашем случае будет только одно представление данных Документа. Класс Представления CCircleView будет выполнять непосредственное взаимодействие с пользователем и в нем тоже понадобятся поля для хранения координат центра круга.
Через панель Solution Explorer откройте заголовочный файл CircleView.h, найдите объявление класса CCircleView и внесите в него объявления переменных-членов, которые будут хранить координаты центра кругаОбъявления полей в классе представления CCircleView
class CCircleView : public CView
{
protected: // create from serialization only
CCircleView();
DECLARE_DYNCREATE(CCircleView)
// Attributes
public:
CCircleDoc* GetDocument() const;
int m_PosX; // координата x (по горизонтали) центра круга
int m_PosY; // координата y (по вертикали) центра круга
// Operations
public:
.....................................................
};
Значения полей, хранящих координаты центра круга, в классе Документа и в классе Представления всегда должны совпадать, поэтому удобнее назначить им одинаковые имена. Обратите внимание на то, что здесь уже имеется прототип функции GetDocument(), которая будет возвращать указатель на объект класса CCircleDoc, чтобы можно было вызывать его члены . Эта функция нам понадобится дальше, чтобы адресоваться из класса-представления CCircleView к данным, хранящимся в документе, представленном классом CCircleDoc. Мастер уже создал и реализацию функции GetDocument(), которая имеет вид
Реализация функции GetDocument()
CCircleDoc* CCircleView::GetDocument() const // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCircleDoc)));
return (CCircleDoc*)m_pDocument;
}
Инициализацию объявленных в классе представления CCircleView переменных поместим в функцию-член OnInitialUpdate() класса представления, которая выполняется один раз при первом отображении документа на экране. В ней мы предусмотрим начальную перекачку данных из класса Документа в класс Представления. Для этого
Откройте панель
В панели Properties нажмем кнопку Overriders и в появившемся списке виртуальных функций класса CCircleView, унаследованных от базового класса CView, выделите функцию OnInitialUpdate()
В появившемся раскрывающемся списке выполните команду Add, чтобы мастер добавил в файл CCircleView.cpp заготовку для переопределения виртуальной функции OnInitialUpdate()
Дополните функцию OnInitialUpdate() кодом, копирующим содержимое переменных из объекта Документ в объект ПредставлениеКопирование координат центра круга из Документа в Представление
void CCircleView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
m_PosX = GetDocument()->m_PosX;
m_PosY = GetDocument()->m_PosY;
}
Для рисования круга на экране в окне Документ нужно поместить соответствующий код в функцию-член OnDraw() класса CCircleView. Эта функция выполняется всякий раз, когда нужно вывести окно документа из-за возникших в нем изменений
В панели Solution Explorer откройте файл CircleView.cpp и через раскрывающийся список в верхней части рабочей области редактора позиционируйтесь на метод OnDraw()
Освободите от комментариев указатель на контекст устройства в аргументах метода OnDraw() и дополните тело кодом рисования кругаКод рисования круга в объекте Документа
void CCircleView::OnDraw(CDC* pDC)
{
CCircleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
// Задать границы описывающего прямоугольника,
// в котором будет нарисован круг
CRect rect;
rect.left = m_PosX - 20;
rect.top = m_PosY - 20;
rect.right = m_PosX + 20;
rect.bottom = m_PosY + 20;
// Нарисовать круг на контексте устройства
pDC->Ellipse(rect);
}
Постройте приложение и убедитесь, что получился примерно такой результат
Результатом предыдущих действий было появление круга в фиксированной точке с программно заданными координатами x=200, y=100. Сделаем так, чтобы по щелчку мыши в произвольном месте клиентской области окна, представленного объектом CCircleView, круг перерисовывался с центром в месте щелчка.
При этом, новое положение центра круга необходимо немедленно продублировать в классе Документа. Это нужно для того, что если пользователь сохранит Документ и закроет приложение, то при следующем открытии документа последнее состояние Представления полностью восстановится.
В панели Class View вызовите контекстное меню для класса CCircleView и выполните команду Properties для вызова одноименной панели
Щелкните на пиктограмме Messages в верхней части панели Properties, найдите событие WM_LBUTTONDOWN, которое генерируется операционной системой всякий раз при щелчке по объекту класса представления CCircleView, и в раскрывающемся списке добавьте обработчик OnLButtonDown()Оболочка сразу внесет необходимые изменения в файлы CCircleView.h и CCircleView.cpp: добавит записи в объявление класса и таблицу сообщений, а также создаст заготовку обработчика. Эти автоматически созданные изменения будут следующими
Объявление обработчика в файле CCircleView.h
class CCircleView : public CView
{
...............................................................
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
public:
virtual void OnInitialUpdate();
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
Регистрация события в таблице сообщений класса CircleView BEGIN_MESSAGE_MAP(CCircleView, CView) // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) ON_WM_LBUTTONDOWN() END_MESSAGE_MAP()
Заготовка обработчика в файле CircleView.cpp
void CCircleView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
}
Дополните обработчик OnLButtonDown() класса CCircleView следующим кодомКод обработчика щелчка мыши на Представлении
void CCircleView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
// Обновить координаты центра круга
// координатами места щелчка курсора
m_PosX = point.x;
m_PosY = point.y;
// Инициировать перерисовку экрана вызовом функции OnDraw()
Invalidate();
// Передать новые координаты щелчка в класс CCircleDoc
CCircleDoc* pDoc = GetDocument();
pDoc->m_PosX = m_PosX; // Через промежуточный указатель
GetDocument()->m_PosY = m_PosY; // Напрямую
// Установить флажок изменения Документа
pDoc->SetModifiedFlag(TRUE);
CView::OnLButtonDown(nFlags, point); // Выполнить базовый метод
}
Постройте приложение и убедитесь, что круг перерисовывается по каждому щелчку мыши на новом местеНапишем код, который будет отвечать за сохранение Документа в файле и загрузку ранее сохраненных Документов. Этот процесс основан на функции Serialize(), которая обеспечивает сериализацию (десериализацию) данных при их сохранении на диске и вызывается автоматически, когда вибирается пункт меню Save, Save As, Open или закрепленные за ними кнопки на панели инструментов. Сериализация и десериализация - это специальные методы упаковки/распаковки данных, чтобы они однозначно восстанавливались в соответствующие значения переменных класса документа.
панели Class View выделите класс CCircleDoc двойным щелчком мышиВ результате таких действий откроется файл CircleDoc.h в редакторе кода, курсор станет на имени класса в его объявлении и вверху появятся два раскрывающихся списка: в левом будет имя класса, а в правом - список его функций-членов.
Раскройте правый список методов класса и двойным щелчком мыши позиционируйтесь на методе Serialize()В результате откроется файл CircleDoc.cpp, где находится этот метод, и курсор установится на реализации метода.
Заготовка функции Serialize() выглядит так
Заготовка функции Serialize() в файле CircleDoc.cpp
void CCircleDoc::Serialize(CArchive ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
// Сюда добавить код сохранения
}
else
{
// TODO: add loading code here
// Сюда добавить код загрузки
}
}
Ссылка ar соответствует потоку (открытому каналу связи), связанному с архивом (файлом), открытым на запись или чтение. Заготовка пока ничего не читает и ничего не сохраняет.
Модифицируйте код заготовки метода Serialize() следующим образомКод функции Serialize() в файле CircleDoc.cpp
void CCircleDoc::Serialize(CArchive ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
// Сюда добавить код сохранения
ar << m_PosX << m_PosY; }
else
{
// TODO: add loading code here
// Сюда добавить код загрузки
ar >> m_PosX >> m_PosY;
}
}
Существует строгое правило сериализации и десериализации: последовательность данных, перечисленных для сохранения, должна строго соответствовать данным, перечисленным для загрузки
Выполните команду В верхней части таблицы редактора ресурсов имеется строка с идентификатором IDR_MAINFRAME

Значением этой строки является
Circle\n\nCircle\n\n\nCircle.Document\nCircle.Document
Символы \n служат разделителями 7 разделов, некоторые из которых обозначают следующее
Circle - определяет заголовок окна приложенияNullCircleNull - определяет наименование фильтра в строке Files of type диалогового окна Save As или OpenNull - определяет фильтр в строке File name диалогового окна Save As или OpenCircle.Document Circle.Document
Измените прямо в таблице или через панель Properties содержимое разделов 1, 4 и 5 как показано ниже1. Программа рисования окружности - лабораторная работа 4. CIR Files (*.cir) 5. .cir
Новое значение строки должно быть таким
Программа рисования окружности - лабораторная работа\n\nCircle\nCIR Files (*.cir)\n.cir\nCircle.Document\nCircle.Document
Постройте приложение и выполните программу. Должно получиться окно со следующим заголовком
Замечание. Возможно, что Ваш проект не настроен на корректное отображение русского языка и может получиться нечто следующее

В этом случае нужно выполнить такие действия:
String Table вызвать контектсное меню PropertiesLanguage выбрать язык РусскийString Table со строкой заголовка, которая может оказаться испорченной после компиляции, и вновь восстановить строку заголовкаПосле таких действий должно получиться окно с нормальным заголовком.
При начальной загрузке документа он безымянный, поэтому имеет в заголовке Untitled. При каждом новом выполнении команды New меню File генерируется безымянный документ. Щелчок мыши в клиентской области окна устанавливается флаг модификации документа в обработчике OnLButtonDown(), поэтому при закрытии документа должно выдаваться стандартное предупреждение

Наши изменения строки ресурсов заметны не только в заголовке окна приложения. Команды File/Save As и File/Open приложения вызывают стандартные диалоговые окна с назначенным нами фильтром

Среда проектирования Visual Studio .NET 2005 при создании нового -проекта генерирует стандартную иконку, которая имеет имя, совпадающее с именем приложения Circle.ico и размещается в папке res каталога проекта. На эту иконку ссылается идентификатор IDR_MAINFRAME. Чтобы убедиться в этом
Через панель Solution Explorer раскройте узел Resource Files и для файла Circle.rc выполните команду View Code контекстного менюМы видим, что в секции Icon содержится код привязки файла иконки к идентификатору ресурсов
Секция Icon в файле ресурсов Circle.rc ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDR_MAINFRAME ICON "res\\Circle.ico" IDR_CircleTYPE ICON "res\\CircleDoc.ico"
Заменить иконку главного окна приложения можно несколькими способами, например:
res проекта приложения и заменить его имя на имя проекта Circle.icores проекта приложения и зарегистрировать ее в файле Circle.rc
В панели
В появившемся диалоговом окне установите тип ресурса Icon и выполните кнопку Import, чтобы зарегистрировать в ресурсах нужный файл иконки
Оболочка присвоит добавленному ресурсу идентификатор по умолчанию IDI_ICON1 и сделает запись в файле ресурсов
Секция Icon в файле ресурсов Circle.rc ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDR_MAINFRAME ICON "res\\Circle.ico" IDR_CircleTYPE ICON "res\\CircleDoc.ico" IDI_ICON1 ICON "res\\2.ICO
В панели Resource View выделите ресурс старой иконки с идентификатором IDR_MAINFRAME и через контекстное меню или клавишей Delete отсоедините его от проекта
В панели Resource View выделите ресурс IDI_ICON1 новой иконки и через панель Properties измените его имя на IDR_MAINFRAME
Постройте приложение и убедитесь в появлении новой иконки
Русифицируем меню приложения и удалим ненужные кнопки и пункты. Это мы сделаем для иллюстрации возможностей среды, а вообще-то английские названия данного приложения уместны и понятны.
В панели Resource View раскройте узел Menu и выделите ресурс IDR_MAINFRAME
Раскройте панель Properties и установите Language=Русский (если он не установлен)
В панели Resource View дважды щелкните по ресурсу IDR_MAINFRAME, чтобы открыть редактор меню
Вызовите и закрепите на экране панель Properties, которая отражает стандартные свойства каждого пункта меню
Последовательно выделяя пункты меню, замените значение свойства Caption (название пункта) и Prompt (длинная подсказка в строке состояния и всплывающая подсказка, отделенные символом новой строки) на русское содержимое, соблюдая синтаксис
Меню верхнего уровня Edit в нашем проекте не используется, как и соответствующие кнопки панели инструментов, поэтому удалите ихПанель инструментов на редактирование можно вызвать двойным щелчком на идентификаторе IDR_MAINFRAME в папке Toolbar панели Resource View, а ненужные пиктограммы для удаления просто стаскивать мышью с этой панели.

Для редактирования текстов можно использовать и другой способ. Поскольку пункты меню и кнопки панели инструментов привязаны к одним и тем же действиям, то они имеют одни и те же идентификаторы ресурсов, хранящиеся в строковом ресурсе String Table. Поэтому через панель Resource View можно вызвать редактор String Table и править названия длинных и всплывающих подсказок прямо в таблице.
Дополним нашу программу выводом текста в центре окна представления документа, которое является клиентской областью окна-рамки всего приложения.
Введите в класс документа объявление новой переменной m_strText
Для быстрого позиционирования вызовите панель Class View и дважды кликните на классе CCircleDoc. В рабочей области откроется файл CircleDoc.h в режиме редактирования. Код объявления переменной класса будет таким
Объявление новой переменной в файле CircleDoc.h
class CCircleDoc : public CDocument
{
protected: // create from serialization only
CCircleDoc();
DECLARE_DYNCREATE(CCircleDoc)
// Attributes
public:
int m_PosX; // координата x (по горизонтали) центра круга
int m_PosY; // координата y (по вертикали) центра круга
CString m_strText; // для хранения текста
........................................
};
В конструктор класса введите инициализацию текстовой переменной. Для этого в правом верхнем раскрывающемся списке выберите имя конструктора CCircleDoc, которое совпадает с именем класса Документа. Откроется файл CCircleDoc.cpp в режиме редактирования, в который внесите свое изменение
Файл CircleDoc.cpp - инициализация новой переменной
CCircleDoc::CCircleDoc() // конструктор класса
{
// TODO: add one-time construction code here
m_strText = "Привет студентам от Снеткова В.М.!!!";
}
В файле CircleView.cpp выберите функцию OnDraw() и поместите в нее код вывода текста в центр клиентской области приложения. Для этого нужно определитьРисование текста в функции OnDraw() файла CircleView.cpp
void CCircleView::OnDraw(CDC* pDC)
{
CCircleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
// Задать границы прямоугольника, в которых
// будет нарисован круг
CRect rect;
rect.left = m_PosX - 20;
rect.top = m_PosY - 20;
rect.right = m_PosX + 20;
rect.bottom = m_PosY + 20;
// Нарисовать круг
pDC->Ellipse(rect);
// Вывод текста в центре клиентской области окна-рамки
GetWindowRect(rect); // определение размеров клиентской области
CSize size = pDC->GetTextExtent(pDoc->m_strText); // размеры текста
int width = rect.right - rect.left; // ширина клиентской области
int height = rect.bottom - rect.top;// высота клиентской области
int x = (width - size.cx) / 2; // позиция вывода по ширине
int y = (height - size.cy) / 2; // позиция вывода по высоте
pDC->TextOut(x, y, pDoc->m_strText); // вывод строки с текстом
}
Запустите приложение и получите окончательный результат
В результате последовательности шагов мы получили вполне работоспособную программу -архитектуры. Особенность такой архитектуры состоит в том, что окно-рамка приложения может включать в себя только один текущий документ. При открытии нового документа содержимое старого документа замещается новым.
Попутно мы познакомились с некоторыми особенностями среды проектирования, существенно облегчающей жизнь разработчика. В центре всего процесса проектирования приложения стоит объектно-ориентированный подход, основанный на работе с классами и широко применяющий свойство наследования классов.
Заготовка приложения генерируется мастерами по предварительным настройкам, запрашиваемым у разработчика. Дальнейшая работа программиста состоит в последовательной модификации заготовки кода в соответствии со спецификацией своей задачи и выбранных методов решения. Это позволяет разработчику больше сосредоточиться на предметной области проекта и не отвлекаться на частные вопросы системной реализации.
Сочетание этапов визуального проектирования и последующего кодирования позволяют представить технологию решения более наглядной и структурированной. Процесс программирования становится более последовательным и более свободным от систематических ошибок. Это существенно сокращает сроки проектирования и делает программный код надежным и легко модифицируемым.
На экране сосуществуют текст и графика потому, что все перед выводом преобразуется в растровую графику.
SDI -приложения внутри окна представления в точке x=200, y=100 должен появиться круг радиусом 20 пикселов.Приступим к решению поставленной задачи.
Командой меню
Установите вкладку
Состояние остальных вкладок пусть останется установленным по умолчанию, а именно


На последней вкладке цифра 4 означает размер списка последних обработанных документов.
Просмотрите все вкладки мастера и нажмите кнопку Finish, чтобы мастер создал заготовку приложения
В раскрывающемся списке Solution Configurations поменяйте режим работы оболочки с Debug на Release, чтобы отключить генерацию отладочного кода при сборке проекта
Запустите заготовку, созданную мастером, на компиляцию и линковку командой Build/Build Solution, а затем на выполнение командой Debug/Start Debugging (F5) Появится полноценное окно Windows с однодокументным интерфейсом ( )

В классе документа нам нужно добавить поля, в которых будут храниться координаты центра будущего круга.
Вызовите панель View/Solution Explorer и в дереве файлов проекта двойным щелчком откройте на редактирование заголовочный файл CircleDoc.h
Найдите объявление класса CCircleDoc и добавьте в него объявления полей, которые будут хранить координаты центра кругаОбъявления полей в классе документа CCircleDoc
class CCircleDoc : public CDocument
{
protected: // create from serialization only
CCircleDoc();
DECLARE_DYNCREATE(CCircleDoc)
// Attributes
public:
int m_PosX; // координата x (по горизонтали) центра круга
int m_PosY; // координата y (по вертикали) центра круга
// Operations
public:
...................................................
}
В объявлении класса язык C++ не допускает инициализацию членов-данных (кроме перечисления enum ). Поэтому инициализацию поместим в функцию-член класса, которая выполняется при создании нового документа. Для этого
В раскрывающемся списке Functions in CCircleDoc (сведения о CCircleDoc ) выберите функцию-метод OnNewDocument()Именно функция OnNewDocument() срабатывает при создании нового документа.
Внесите в функцию OnNewDocument() код инициализации объявленных координат кругаИнициализация полей в функции OnNewDocument() класса CCircleDoc
BOOL CCircleDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
m_PosX = 200;
m_PosY = 100;
return TRUE;
}
Схема "Документ-Представление" реализует отношение "один ко многим", т.е. одни и те же данные класса Документа можно по разному отображать пользователю в классах Представления. В нашем случае будет только одно представление данных Документа. Класс Представления CCircleView будет выполнять непосредственное взаимодействие с пользователем и в нем тоже понадобятся поля для хранения координат центра круга.
Через панель Solution Explorer откройте заголовочный файл CircleView.h, найдите объявление класса CCircleView и внесите в него объявления переменных-членов, которые будут хранить координаты центра кругаОбъявления полей в классе представления CCircleView
class CCircleView : public CView
{
protected: // create from serialization only
CCircleView();
DECLARE_DYNCREATE(CCircleView)
// Attributes
public:
CCircleDoc* GetDocument() const;
int m_PosX; // координата x (по горизонтали) центра круга
int m_PosY; // координата y (по вертикали) центра круга
// Operations
public:
.....................................................
};
Значения полей, хранящих координаты центра круга, в классе Документа и в классе Представления всегда должны совпадать, поэтому удобнее назначить им одинаковые имена. Обратите внимание на то, что здесь уже имеется прототип функции GetDocument(), которая будет возвращать указатель на объект класса CCircleDoc, чтобы можно было вызывать его члены . Эта функция нам понадобится дальше, чтобы адресоваться из класса-представления CCircleView к данным, хранящимся в документе, представленном классом CCircleDoc. Мастер уже создал и реализацию функции GetDocument(), которая имеет вид
Реализация функции GetDocument()
CCircleDoc* CCircleView::GetDocument() const // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCircleDoc)));
return (CCircleDoc*)m_pDocument;
}
Инициализацию объявленных в классе представления CCircleView переменных поместим в функцию-член OnInitialUpdate() класса представления, которая выполняется один раз при первом отображении документа на экране. В ней мы предусмотрим начальную перекачку данных из класса Документа в класс Представления. Для этого
Откройте панель
В панели Properties нажмем кнопку Overriders и в появившемся списке виртуальных функций класса CCircleView, унаследованных от базового класса CView, выделите функцию OnInitialUpdate()
В появившемся раскрывающемся списке выполните команду Add, чтобы мастер добавил в файл CCircleView.cpp заготовку для переопределения виртуальной функции OnInitialUpdate()
Дополните функцию OnInitialUpdate() кодом, копирующим содержимое переменных из объекта Документ в объект ПредставлениеКопирование координат центра круга из Документа в Представление
void CCircleView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
m_PosX = GetDocument()->m_PosX;
m_PosY = GetDocument()->m_PosY;
}
Для рисования круга на экране в окне Документ нужно поместить соответствующий код в функцию-член OnDraw() класса CCircleView. Эта функция выполняется всякий раз, когда нужно вывести окно документа из-за возникших в нем изменений
В панели Solution Explorer откройте файл CircleView.cpp и через раскрывающийся список в верхней части рабочей области редактора позиционируйтесь на метод OnDraw()
Освободите от комментариев указатель на контекст устройства в аргументах метода OnDraw() и дополните тело кодом рисования кругаКод рисования круга в объекте Документа
void CCircleView::OnDraw(CDC* pDC)
{
CCircleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
// Задать границы описывающего прямоугольника,
// в котором будет нарисован круг
CRect rect;
rect.left = m_PosX - 20;
rect.top = m_PosY - 20;
rect.right = m_PosX + 20;
rect.bottom = m_PosY + 20;
// Нарисовать круг на контексте устройства
pDC->Ellipse(rect);
}
Постройте приложение и убедитесь, что получился примерно такой результат
Результатом предыдущих действий было появление круга в фиксированной точке с программно заданными координатами x=200, y=100. Сделаем так, чтобы по щелчку мыши в произвольном месте клиентской области окна, представленного объектом CCircleView, круг перерисовывался с центром в месте щелчка.
При этом, новое положение центра круга необходимо немедленно продублировать в классе Документа. Это нужно для того, что если пользователь сохранит Документ и закроет приложение, то при следующем открытии документа последнее состояние Представления полностью восстановится.
В панели Class View вызовите контекстное меню для класса CCircleView и выполните команду Properties для вызова одноименной панели
Щелкните на пиктограмме Messages в верхней части панели Properties, найдите событие WM_LBUTTONDOWN, которое генерируется операционной системой всякий раз при щелчке по объекту класса представления CCircleView, и в раскрывающемся списке добавьте обработчик OnLButtonDown()Оболочка сразу внесет необходимые изменения в файлы CCircleView.h и CCircleView.cpp: добавит записи в объявление класса и таблицу сообщений, а также создаст заготовку обработчика. Эти автоматически созданные изменения будут следующими
Объявление обработчика в файле CCircleView.h
class CCircleView : public CView
{
...............................................................
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
public:
virtual void OnInitialUpdate();
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
Регистрация события в таблице сообщений класса CircleView BEGIN_MESSAGE_MAP(CCircleView, CView) // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) ON_WM_LBUTTONDOWN() END_MESSAGE_MAP()
Заготовка обработчика в файле CircleView.cpp
void CCircleView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
}
Дополните обработчик OnLButtonDown() класса CCircleView следующим кодомКод обработчика щелчка мыши на Представлении
void CCircleView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
// Обновить координаты центра круга
// координатами места щелчка курсора
m_PosX = point.x;
m_PosY = point.y;
// Инициировать перерисовку экрана вызовом функции OnDraw()
Invalidate();
// Передать новые координаты щелчка в класс CCircleDoc
CCircleDoc* pDoc = GetDocument();
pDoc->m_PosX = m_PosX; // Через промежуточный указатель
GetDocument()->m_PosY = m_PosY; // Напрямую
// Установить флажок изменения Документа
pDoc->SetModifiedFlag(TRUE);
CView::OnLButtonDown(nFlags, point); // Выполнить базовый метод
}
Постройте приложение и убедитесь, что круг перерисовывается по каждому щелчку мыши на новом местеНапишем код, который будет отвечать за сохранение Документа в файле и загрузку ранее сохраненных Документов. Этот процесс основан на функции Serialize(), которая обеспечивает сериализацию (десериализацию) данных при их сохранении на диске и вызывается автоматически, когда вибирается пункт меню Save, Save As, Open или закрепленные за ними кнопки на панели инструментов. Сериализация и десериализация - это специальные методы упаковки/распаковки данных, чтобы они однозначно восстанавливались в соответствующие значения переменных класса документа.
панели Class View выделите класс CCircleDoc двойным щелчком мышиВ результате таких действий откроется файл CircleDoc.h в редакторе кода, курсор станет на имени класса в его объявлении и вверху появятся два раскрывающихся списка: в левом будет имя класса, а в правом - список его функций-членов.
Раскройте правый список методов класса и двойным щелчком мыши позиционируйтесь на методе Serialize()В результате откроется файл CircleDoc.cpp, где находится этот метод, и курсор установится на реализации метода.
Заготовка функции Serialize() выглядит так
Заготовка функции Serialize() в файле CircleDoc.cpp
void CCircleDoc::Serialize(CArchive ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
// Сюда добавить код сохранения
}
else
{
// TODO: add loading code here
// Сюда добавить код загрузки
}
}
Ссылка ar соответствует потоку (открытому каналу связи), связанному с архивом (файлом), открытым на запись или чтение. Заготовка пока ничего не читает и ничего не сохраняет.
Модифицируйте код заготовки метода Serialize() следующим образомКод функции Serialize() в файле CircleDoc.cpp
void CCircleDoc::Serialize(CArchive ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
// Сюда добавить код сохранения
ar << m_PosX << m_PosY; }
else
{
// TODO: add loading code here
// Сюда добавить код загрузки
ar >> m_PosX >> m_PosY;
}
}
Существует строгое правило сериализации и десериализации: последовательность данных, перечисленных для сохранения, должна строго соответствовать данным, перечисленным для загрузки
Выполните команду В верхней части таблицы редактора ресурсов имеется строка с идентификатором IDR_MAINFRAME

Значением этой строки является
Circle\n\nCircle\n\n\nCircle.Document\nCircle.Document
Символы \n служат разделителями 7 разделов, некоторые из которых обозначают следующее
Circle - определяет заголовок окна приложенияNullCircleNull - определяет наименование фильтра в строке Files of type диалогового окна Save As или OpenNull - определяет фильтр в строке File name диалогового окна Save As или OpenCircle.Document Circle.Document
Измените прямо в таблице или через панель Properties содержимое разделов 1, 4 и 5 как показано ниже1. Программа рисования окружности - лабораторная работа 4. CIR Files (*.cir) 5. .cir
Новое значение строки должно быть таким
Программа рисования окружности - лабораторная работа\n\nCircle\nCIR Files (*.cir)\n.cir\nCircle.Document\nCircle.Document
Постройте приложение и выполните программу. Должно получиться окно со следующим заголовком
Замечание. Возможно, что Ваш проект не настроен на корректное отображение русского языка и может получиться нечто следующее

В этом случае нужно выполнить такие действия:
String Table вызвать контектсное меню PropertiesLanguage выбрать язык РусскийString Table со строкой заголовка, которая может оказаться испорченной после компиляции, и вновь восстановить строку заголовкаПосле таких действий должно получиться окно с нормальным заголовком.
При начальной загрузке документа он безымянный, поэтому имеет в заголовке Untitled. При каждом новом выполнении команды New меню File генерируется безымянный документ. Щелчок мыши в клиентской области окна устанавливается флаг модификации документа в обработчике OnLButtonDown(), поэтому при закрытии документа должно выдаваться стандартное предупреждение

Наши изменения строки ресурсов заметны не только в заголовке окна приложения. Команды File/Save As и File/Open приложения вызывают стандартные диалоговые окна с назначенным нами фильтром

Среда проектирования Visual Studio .NET 2005 при создании нового -проекта генерирует стандартную иконку, которая имеет имя, совпадающее с именем приложения Circle.ico и размещается в папке res каталога проекта. На эту иконку ссылается идентификатор IDR_MAINFRAME. Чтобы убедиться в этом
Через панель Solution Explorer раскройте узел Resource Files и для файла Circle.rc выполните команду View Code контекстного менюМы видим, что в секции Icon содержится код привязки файла иконки к идентификатору ресурсов
Секция Icon в файле ресурсов Circle.rc ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDR_MAINFRAME ICON "res\\Circle.ico" IDR_CircleTYPE ICON "res\\CircleDoc.ico"
Заменить иконку главного окна приложения можно несколькими способами, например:
res проекта приложения и заменить его имя на имя проекта Circle.icores проекта приложения и зарегистрировать ее в файле Circle.rc
В панели
В появившемся диалоговом окне установите тип ресурса Icon и выполните кнопку Import, чтобы зарегистрировать в ресурсах нужный файл иконки
Оболочка присвоит добавленному ресурсу идентификатор по умолчанию IDI_ICON1 и сделает запись в файле ресурсов
Секция Icon в файле ресурсов Circle.rc ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDR_MAINFRAME ICON "res\\Circle.ico" IDR_CircleTYPE ICON "res\\CircleDoc.ico" IDI_ICON1 ICON "res\\2.ICO
В панели Resource View выделите ресурс старой иконки с идентификатором IDR_MAINFRAME и через контекстное меню или клавишей Delete отсоедините его от проекта
В панели Resource View выделите ресурс IDI_ICON1 новой иконки и через панель Properties измените его имя на IDR_MAINFRAME
Постройте приложение и убедитесь в появлении новой иконки
Русифицируем меню приложения и удалим ненужные кнопки и пункты. Это мы сделаем для иллюстрации возможностей среды, а вообще-то английские названия данного приложения уместны и понятны.
В панели Resource View раскройте узел Menu и выделите ресурс IDR_MAINFRAME
Раскройте панель Properties и установите Language=Русский (если он не установлен)
В панели Resource View дважды щелкните по ресурсу IDR_MAINFRAME, чтобы открыть редактор меню
Вызовите и закрепите на экране панель Properties, которая отражает стандартные свойства каждого пункта меню
Последовательно выделяя пункты меню, замените значение свойства Caption (название пункта) и Prompt (длинная подсказка в строке состояния и всплывающая подсказка, отделенные символом новой строки) на русское содержимое, соблюдая синтаксис
Меню верхнего уровня Edit в нашем проекте не используется, как и соответствующие кнопки панели инструментов, поэтому удалите ихПанель инструментов на редактирование можно вызвать двойным щелчком на идентификаторе IDR_MAINFRAME в папке Toolbar панели Resource View, а ненужные пиктограммы для удаления просто стаскивать мышью с этой панели.

Для редактирования текстов можно использовать и другой способ. Поскольку пункты меню и кнопки панели инструментов привязаны к одним и тем же действиям, то они имеют одни и те же идентификаторы ресурсов, хранящиеся в строковом ресурсе String Table. Поэтому через панель Resource View можно вызвать редактор String Table и править названия длинных и всплывающих подсказок прямо в таблице.
Дополним нашу программу выводом текста в центре окна представления документа, которое является клиентской областью окна-рамки всего приложения.
Введите в класс документа объявление новой переменной m_strText
Для быстрого позиционирования вызовите панель Class View и дважды кликните на классе CCircleDoc. В рабочей области откроется файл CircleDoc.h в режиме редактирования. Код объявления переменной класса будет таким
Объявление новой переменной в файле CircleDoc.h
class CCircleDoc : public CDocument
{
protected: // create from serialization only
CCircleDoc();
DECLARE_DYNCREATE(CCircleDoc)
// Attributes
public:
int m_PosX; // координата x (по горизонтали) центра круга
int m_PosY; // координата y (по вертикали) центра круга
CString m_strText; // для хранения текста
........................................
};
В конструктор класса введите инициализацию текстовой переменной. Для этого в правом верхнем раскрывающемся списке выберите имя конструктора CCircleDoc, которое совпадает с именем класса Документа. Откроется файл CCircleDoc.cpp в режиме редактирования, в который внесите свое изменение
Файл CircleDoc.cpp - инициализация новой переменной
CCircleDoc::CCircleDoc() // конструктор класса
{
// TODO: add one-time construction code here
m_strText = "Привет студентам от Снеткова В.М.!!!";
}
В файле CircleView.cpp выберите функцию OnDraw() и поместите в нее код вывода текста в центр клиентской области приложения. Для этого нужно определитьРисование текста в функции OnDraw() файла CircleView.cpp
void CCircleView::OnDraw(CDC* pDC)
{
CCircleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
// Задать границы прямоугольника, в которых
// будет нарисован круг
CRect rect;
rect.left = m_PosX - 20;
rect.top = m_PosY - 20;
rect.right = m_PosX + 20;
rect.bottom = m_PosY + 20;
// Нарисовать круг
pDC->Ellipse(rect);
// Вывод текста в центре клиентской области окна-рамки
GetWindowRect(rect); // определение размеров клиентской области
CSize size = pDC->GetTextExtent(pDoc->m_strText); // размеры текста
int width = rect.right - rect.left; // ширина клиентской области
int height = rect.bottom - rect.top;// высота клиентской области
int x = (width - size.cx) / 2; // позиция вывода по ширине
int y = (height - size.cy) / 2; // позиция вывода по высоте
pDC->TextOut(x, y, pDoc->m_strText); // вывод строки с текстом
}
Запустите приложение и получите окончательный результат
В результате последовательности шагов мы получили вполне работоспособную программу -архитектуры. Особенность такой архитектуры состоит в том, что окно-рамка приложения может включать в себя только один текущий документ. При открытии нового документа содержимое старого документа замещается новым.
Попутно мы познакомились с некоторыми особенностями среды проектирования, существенно облегчающей жизнь разработчика. В центре всего процесса проектирования приложения стоит объектно-ориентированный подход, основанный на работе с классами и широко применяющий свойство наследования классов.
Заготовка приложения генерируется мастерами по предварительным настройкам, запрашиваемым у разработчика. Дальнейшая работа программиста состоит в последовательной модификации заготовки кода в соответствии со спецификацией своей задачи и выбранных методов решения. Это позволяет разработчику больше сосредоточиться на предметной области проекта и не отвлекаться на частные вопросы системной реализации.
Сочетание этапов визуального проектирования и последующего кодирования позволяют представить технологию решения более наглядной и структурированной. Процесс программирования становится более последовательным и более свободным от систематических ошибок. Это существенно сокращает сроки проектирования и делает программный код надежным и легко модифицируемым.
На экране сосуществуют текст и графика потому, что все перед выводом преобразуется в растровую графику.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.