Раскройте элемент дерева классов под именем CMyView. Класс CMyView происходит от MFC-класса cview и дает вам возможность управлять обликами (views) документов в рамках модели программирования архитектуры «документ — представление», считающейся стандартной технологией разработки MFC-приложений. О ней достаточно много сказано. (См., например, Круглински Д. Основы Visual C++, М: «Русская редакция», 1997; Черносвитов A. Visual C++ и MFC, СПб.: «Питер», 2000.) Здесь мы также будем рассматривать особенности технологии, по позднее. А пока попробуем изменить коды нашего приложения так, чтобы оно умело отображать данные документа. Выполнив двойной щелчок над элементом дерева OnDraw (CDC *pDC), вы увидите новое окно-страницу, управляемое вкладкой MyView.cpp. Так именуется файл реализации (implementation file) класса CMyView. Курсор должен находиться на теле метода перерисовки:
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
Здесь вместо подсказки // TODO: мы должны вставить код, отображающий данные документа. Функция OnDraw(CDC *pDC) входит в состав класса CMyView, являсь методом этого класса, и вызывается каркасом приложения в тех случаях, когда необходимо перерисовать окно, обслуживаемое классом CMyView.
Примечание
Каркасом приложения (Application Framework) называется совокупность классов и других структур библиотеки MFC, которые присутствуют в вашем приложении неявно. Дело в том, что классы вашего приложения произведены (с помощью механизма наследования ООП) от классов MFC. Данные и методы этих классов компилятор включил в исполняемый модуль, и они работают на вас. (Данные используются, методы вызываются.) Но вы можете и не знать об этом.
Представлением документа называется клиентская область одного из окон-рамок, обслуживаемых классом CChildFrame и живущих внутри главного окна приложения. В MDI приложении их может быть много. Это те окна, которые можно видеть по очереди, все сразу, каскадом или рядом, не перекрывая друг друга (Cascade или Tile).
Перед тем как начать отображение данных, надо эти данные создать или добыть из класса, обслуживающего документ. В соответствии с концепцией архитектуры «документ — представление» все стратегические данные приложения должны храниться в классе документа, то есть в классе CMyDoc. Метод GetDocument (он вызывается в заготовке OnDraw) класса CMyView позволяет добыть указатель на объект класса CMyDoc, который управляет активным в данный момент документом.
Примечание
Макроподстановка ASSERT_VALID в отладочной (Debug) версии проекта проверяет на осмысленность полученный указатель и дает сообщение об ошибке, в случае когда указатель равен нулю или в действительности не является адресом объекта класса, производного от класса CObject. Если вы просмотрите иерархию классов MFC, то увидите, что CObject является отцом-прародителем всех классов, потомки которых использованы в нашем приложении.
Итак, имея адрес документа, мы можем начинать отображение его данных в окне представления. В системе, поддерживающей графический интерфейс пользователя, все данные не просто выводятся на экран, они скорее «рисуются» в контексте устройства, связанном с окном. Подсистема Windows GDI (Graphics Device Interface) дает вам набор средств для рисования, среди которых одним из главных является контекст устройства, управляемый классом CDC (Device Context). Указатель на используемый системой в данный момент объект класса CDC мы получили в качестве параметра функции OnDraw.
Концепция такова: рисование производится в специальной области памяти, управляемой этим классом, с помощью графических примитивов (точек, прямоугольников и т. д.) и логической системы координат. Далее Windows производит преобразование логических координат примитивов в систему физических или аппаратных (device) координат. Идея в том, что программист отображает данные в контексте устройства, не задумываясь о том, где они будут реально воспроизведены (на экране хорошего или плохого монитора, на принтере или на графопостроителе).Программист стремится наиболее точно отобразить данные документа в произвольно выбранной им логической системе координат, а система с помощью драйверов устройств стремится наиболее точно преобразовать все точки рисунка в физическую или аппаратную, то есть связанную с конкретным устройством, систему координат.
Сеанс работы в Studio.Net начинается с открытия существующего или создания нового решения (solution). В дальнейшем вместо термина решение я иногда буду использовать термин рабочее пространство, так как буквальный перевод — решение — не всегда точен. Файлы с расширением sin используются IDE (Integrated Development Environment) для хранения настроек и начальных установок конкретных решений. Концепция решений помогает объединить проекты и другие элементы в одном рабочем пространстве. Множество файлов разного типа, в рамках одного решения составляют приложение (application) Visual Studio.Net 7.0. Рабочее пространство может содержать несколько проектов, быть пустым или содержать файлы, которые имеют смысл и вне контекста решений. В любом случае, вы должны начинать работу в студии с открытия существующего или создания нового рабочего пространства.
Проект как часть решения состоит из отдельных компонентов, например файлов, описывающих форму окна или шаблон диалога (re-файл), файлов с исходными кодами программных модулей (.срр, .cs) и/или файлов, представляющих собой описание запроса к базе данных (database script), HTML-документов и, т. д. Настройки проектов хранятся в специальных файлах проектов. Они могут иметь разные расширения, так как в одном пространстве можно объединять проекты совершенно разных типов. Например, проект MFC-приложения хранит свои установки в файле с расширением vcproj, а файл проекта, реализованного на языке
С#, имеет расширение csproj. Такой файл является читаемым, его можно открыть вне рамок Studio.Net (например, с помощью Notepad) и увидеть описание установок проекта на еще одном из «секретных» языков. Например, проект типа MFC Application с именем MyProj содержит файл MyProj.vcproj, начальный фрагмент которого мы приведем здесь:
<?xml version="1.0"?>
<VisualStudioProject ProjectType="Visual C++" Version="7.00" Name="MyProj" Keyword="mfc">
<Build>
<Settings>
<Platform Name="Win32"/>
Зададимся целью нарисовать в логической системе координат плоский многоугольник (Polygon), координаты точек которого будем хранить в динамической структуре данных. Специалисты советуют в таких случаях пользоваться одним из множества шаблонов, реализующих поведение фундаментальных структур данных и присутствующих в рамках STL (Standard Template Library). Библиотека шаблонов STL доступна на любой платформе, так как является стандартом. Она станет доступной и нам, если мы подключим необходимый файл заголовков. Для хранения точек многоугольника мы выберем шаблон стандартного контейнера, который называется vector. Это динамическая структура данных, которая ведет себя как «умный» массив элементов произвольного типа. Любой контейнер удобно представлять себе в виде резиновой сумки с одинаковыми объектами любой природы, которая почти всегда полна и в которую всегда можно положить еще разумное количество объектов того же типа. Это возможно, потому что она растягивается, то есть способна динамически (на этапе выполнения) изменять свои размеры как в сторону увеличения, так и в сторону уменьшения.
Подробнее о контейнерах будет сказано позже, а сейчас надо решить, что должно в нем храниться. Так как многоугольник определяется координатами точек, то контейнер целесообразно «скроить» (по шаблону vector) так, чтобы в нем можно было хранить объекты класса CPoint. Этот класс является вспомогательным в MFC (не происходит от CObject). Найдите этот класс в иерархии классов библиотеки MFC. Для этого:
Дайте команду Help > Index.
В появившемся окне Index (Look for:) задайте CPoint.
В окне Index Results for CPoints — 3 topics found выберите строку CPoint Class (MFC).
Внизу появившегося окна CPoint Class найдите ссылку Hierarchy Chart и щелкните ее мышью.
Класс CPoint находится в правой части карты под заголовком Simple Value Types. После этого отыщите классы: CObject, CDocument, cview, cwnd, которые так или иначе присутствуют в каркасе нашего приложения. Закройте окна Index, Index Results и Hierarchy Chart.
Концепция решений и проектов
Создание нового проекта
Классы приложения
Контейнер точек
Рисование в контексте устройства
Реакция на ошибки
Итак, вы успешно преодолели все трудности установки Microsoft Visual Studio. Net 7.0 (если они были, а они в изобилии присутствовали в бета-версии продукта, с которой я имел дело в момент написания книги) и готовы покорить определенные высоты с помощью вашей неудержимой фантазии программиста и возможностей студии. Инструменты Studio.Net, несомненно, помогут воплотить ваши идеи в реальные проекты, которые теперь принято называть решениями (solutions) — термин, обозначающий новую концепцию логического хранилища проектов.
Если вы имеете опыт работы в среде Microsoft Visual Studio 6.0, то, открыв Studio.Net, вы сразу отметите значительные изменения в интерфейсе. Общий облик вызывает ассоциации с пультом управления летательного аппарата или какого-то другого сложного технического объекта. Задача одна — в небольшом пространстве разместить множество инструментов контроля и управления за состоянием объекта. Но в отличие от осязаемого пульта управления самолетом ваш иллюзорный пульт на экране может динамично изменяться, отчасти благодаря сравнительно новым элементам управления — tabbed windows — окнам с вкладками. Открыв Studio.Net, вы увидите такое окно на самом видном месте. Это окно самое большое по площади. В начальный момент оно имеет только одну страницу (page), открываемую с помощью вкладки (tab) VS Home Page. Далее в этой группе будут появляться другие вкладки, позволяющие открывать другие страницы составного окна. В случае если вы «потеряете» начальное окно, то его можно вернуть на свое место, дав команду View > Web Browser. Вот другой способ сделать это:
открыть контекстное меню, щелкнув правой клавишей мыши над пустым местом планки обычного меню или над пустым местом стандартной инструментальной панели;
выбрать панель под именем Web;
нажать кнопку Ноmе на новой панели.
При поиске кнопок используйте всплывающие подсказки (tooltips).
Обозревая окна Studio.Net, отметьте усовершенствования косметического характера: пункты меню теперь имеют значки, изменились цвета элементов интерфейса в разных состояниях, нарушив тем самым рекомендации Microsoft по созданию UI-элементов (User Interface).
Примечание
Visual C++, Microsoft Developer Network (MSDN), fj, Visual Basic и другие компоненты составляют интегрированную среду разработки приложений — Visual Studio Integrated Development Environment (IDE). Совместное использование одной и той же среды имеет очевидные преимущества, так как в процессе разработки приложений на разных языках можно пользоваться одними и теми же или сходными инструментами Studio.Net: Web Browser, Command Window, Tabbed Documents, редакторами кодов, HTML-страниц,XML-схем и редакторами ресурсов.
Полезно откомпилировать и запустить приложение в незавершенном состоянии, так как это позволит увидеть, как проявляются ошибки и недомолвки. Процесс компиляции и сборки совместно называется построением (Build) проекта. Самым быстрым способом построить и запустить проект является ввод Ctrl+F5 и согласие с необходимостью повторения всего процесса.
Ход процесса компиляции и сборки проекта освещается и комментируется Studio.Net в окне Output. Сообщения об ошибках, выявленных на стадии построения, также выводятся в этом окне, но по завершении процесса появится диалоговое окно с сообщением о наличии ошибок. Теперь вы должны выбрать: продолжать ли компоновку или нет. Разумным выбором будет No. Теперь сообщения об ошибках в более подробном виде появляются в окне Task List, которое имеет универсальный характер, но в нашем частном случае используется для отображения ошибок компиляции. Окно имеет вид списка, который помогает идентифицировать и локализовать ошибки.
Выделив ошибку в списке, вы можете нажать F1 и получить по ней более подробную справку. В нашем случае, если не было ошибок ввода, вероятно, появятся более 10 ошибок, первую из которых приведем здесь:
error C2143: syntax error : missing ';' before '<' C:\My Projects\My\MyDoc.h(38)
Здесь мне хочется поговорить о том, как выудить из этих сообщений более или менее точное указание на истинное местоположение и причину ошибки или ошибок. Прежде всего надо психологически подготовиться к тому, что ошибки всегда и неизбежно будут преследовать вас. Если код содержит более 20 операторов, то он не может быть создан и введен без ошибок. Если же код содержит более 5000 операторов, то он всегда будет содержать их. Это почти аксиома (с долей иронии). Разработчик программного обеспечения вынужден большую часть жизни проводить за компьютером, бесконечно повторяя цепочку одних и тех же действий, которые составляют суть процесса отладки приложения. Чем спокойнее вы относитесь к своим ошибкам, тем быстрее вы с ними расправитесь.
Сейчас важно понять следующее. Пример моделирует ситуацию, когда мы имеем реальные World-координаты (термин, принятый в GDI) какого-то объекта, например разрез корабля, и хотим начертить его детали, которые всегда можно аппроксимировать многоугольниками в некоторой логической системе координат (например, листе ватмана размером 1000x1000 мм). При этом мы преобразуем реальные вещественные координаты корабля в логические, то есть целого типа, так как мы не можем чертить с погрешностью менее 1 мм. В соответствии с концепцией рисования в контексте устройства именно эти (логические) координаты мы и должны использовать в функциях рисования. При последующем выводе рисунка на экран или принтер операционная система автоматически преобразовывает каждую его точку в аппаратные (device) координаты, зависящие от типа и возможностей устройства вывода. Таким образом, мы имеем дело с тремя системами координат и двумя их преобразованиями.
Примечание
Если вы посмотрите справку по теме Coordinate Spaces and Transformations (Пространства и преобразования координат), то вы увидите, что в GDI рассматриваются четыре координатных пространства: World, Page, Device и Physical device, однако часто можно использовать только два (Page и Device). При этом пространства World и Page считаются одним логическим координатным пространством, а пространства Device в Physical device — физическим. Преобразование из пространства Device в Physical device ограничивается только подстройкой начала координат при отображении рисунка на каком-то конкретном устройстве вывода.
Вызовите в окно редактора функцию On Draw. Для этого снова щелкните вкладку MyView.cpp группы окон, вероятно, слева и введите изменения в соответствии со следующим фрагментом:
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc) ;
//======= Узнаем размер контейнера точек
UINT nPoints = pDoc->m_Points.size() ;
//======= Уходим, если он пуст
if (InPoints)
return;
//=== Сохраняем текущее состояние контекста
//=== (инструменты GDI)
pDC->SaveDC () ;
//=== Создаем перо Windows для прорисовки контура
CPen pen (PS_SOLID,2,RGB(0,96,0));
//=== Выбираем его в контекст устройства
pDC->SelectObject (Spen);
//===Создаем кисть Windows для закраски внутренности
CBrush brush (RGB(240,255,250));
pDC->SelectObject (&brush);
//===== Изображаем полигон
pDC->Polygon (spDoc->m_Poihts[0], nPoints);
//Восстанавливаем контекст (предыдущие инструменты GDI)
pDC->RestoreDC(-l);
}
При создании нового проекта Studio.Net автоматически создает рабочее пространство и помещает в него этот проект. Вот перечень шагов для создания нового проекта и нового рабочего пространства (solution), его содержащего.
В меню File > New выберите команду Project.
В появившемся окне диалога New Project, в окне Project Type раскройте узел дерева под именем Visual C++ Projects и выберите узел Win32 Projects.
В окне Templates выберите тип проекта MFC Application.
В окне Name задайте имя проекта My.
В окне Location задайте или оставьте без изменения местоположение новой папки с файлами рабочего пространства.
Рис. 1.2. Окно диалога New Project
Рис. 1.3. Окно мастера MFC Application Wizard
Нажмите ОК и проанализируйте предлагаемые по умолчанию настройки проекта, которые определены в появившемся окне диалога, обслуживаемом инструментом Studio.Net под именем MFC Application Wizard.
Нажмите кнопку Finish.
Мы отложим разговор о различных типах шаблонов (стартовых заготовках) MFC-приложений в предположении, что читатель имеет представление о них по опыту работы в Visual Studio б.0. Если это не так, то все равно не прерывайте процесс чтения и исследования Studio.Net. Примиритесь, временно, с дискомфортом недопонимания. Итак, Application Wizard потрудился и создал стартовую заготовку нового Windows-приложения, которое поддерживает многодокументный интерфейс (MDI). Вы можете немедленно его запустить, дав команду Debug > Start Without Debugging и согласившись с сообщением о том, что конфигурация проекта устарела (подразумевается, ехе-файл либо отсутствует, либо старше, чем какой-либо из исходных файлов проекта). После этого вы имеете возможность наблюдать за процессом компиляции и компоновки в окне Output, которое, скорее всего, появится внизу главного окна Studio.Net. Далее вы увидите окно нового приложения My, поддерживающего стандарт MDI. Опробуйте команды File > New и все команды меню Window этого приложения, следя за заголовками новых дочерних окоп. Закройте стартовое приложение и сосредоточьте внимание на окне Studio.Net с заголовком Solution Explorer, которое, скорее всего, расположено справа от окна VS Home Page.
Примечание
Неуверенность относительно местоположения окон объясняется тем, что окна Studio.Net проявляют удивительную подвижность. При желании вы можете разместить их в разных группах tabbed-окон или сделать их свободными (floating), причаливаемыми (docable) или скрыть (hide). Поэкспериментируйте с командами (Docable, Hide, Floating, Auto Hide контекстного меню, которое появляется при щелчке правой клавишей мыши над заголовками окон.
Опробуйте также команды меню Window. Например, выберите произвольное окно и дайте команду Window > Docable. Отыщите выбранное окно, затем повторите ту же команду и вновь отыщите окно. При работе с кодами в окне редактора наиболее удобным режимом для вспомогательных окон представляется Auto Hide. Studio.Net позволяет очень гибко управлять местоположением своих окон. Отметьте, что вышеупомянутое контекстное меню динамически изменяется в зависимости от текущего состава группы tabbed-окон. В нем появляются другие команды, которые расширяют ваши возможности по управлению интерфейсом Studio.Net. Окно Solution Explorer дает возможность управлять проектами и файлами проектов. Оно является аналогом окна File View в Visual Studio 6 и теперь по умолчанию входит в группу окон, составляющих блок очень полезных страниц (pages), которыми вы будете часто пользоваться. Сейчас активизируйте страницу Class View из этого блока, для того чтобы увидеть состав классов библиотеки MFC, использованный в новом приложении. При поиске вкладки Class View в блоке используйте всплывающие подсказки. Раскройте дерево классов. Отметьте, что теперь кроме шести классов(CAboutDlg, CChildFrame, CMainFrame, CMyApp, CMyDoc, CMyView) в дерево входят и другие элементы, также являющиеся логическими компонентами MFC-приложения. Это глобальные функции и переменные (Global Functions and Variables), макроподстановки И константы (Macros and Constants).