Учебник по Visual C++ .Net

         

Классы приложения Раскройте элемент


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"/>


<Configuration

Name="Debug|Win32"

InterraediateDirectory="Debug"

OutputDirectory="Debug"

ConfigurationType="l"

UseOfMFC="2"

CharacterSet="2">

<Tool Name="VCBscMakeTool"/>

<Tool

Name="VCCLCorapilerTool"

Optimization="0"

Нет необходимости углубляться в анализ языка описания проекта. Поверхностного взгляда достаточно, чтобы понять, что мы имеем дело с последовательностью <предложений>, описывающих тип проекта, настройки и перечень инструментов Studio.Net для его обработки. То же самое можно сказать про sin-файл. Он читаем, и если открыть его в текстовом режиме, то можно увидеть предложения некоего служебного языка, описывающие состав и настройки рабочего пространства.


Контейнер точек Зададимся целью


Окно мастера Add Variable

Просмотрите описание класса CMyDoc, дважды щелкнув на имени класса в окне Class View. В конце файла вы должны увидеть строку

vector<CPoint> m Points;

Теперь просмотрите тело конструктора класса. Для этого раскройте элемент дерева CMyDoc и дважды щелкните на имени конструктора CMyDoc (void). Вы должны увидеть такой заголовок и тело конструктора:

CMyDoc::CMyDoc()

: m Points (0)

{

}

Обратите внимание на инициализатор m_Points (0), который был автоматически вставлен мастером Add Variable. Инициализатор вызывает один из конструкторов шаблона классов vector и сообщает ему, что перед тем, как создать объект класса CMyDoc, надо создать объект m_Points типа vector и задать ему нулевой размер. Нам не нужен этот инициализатор, так как мы собираемся записать в контейнер m_Points координаты тестового многоугольника. Тело конструктора документа пока пусто. Наполним его кодами, вычисляющими точки многоугольника, так чтобы он имел вид пятиконечной звезды. Звезда удобна тем, что позволяет продемонстрировать способы закраски самопересекающихся многоугольников. Измените коды конструктора:

CMyDoc: : CMyDoc ()

//====== Вспомогательные переменные

double pi = 4 . * atari (1.),

al = pi / 10. , // Углы

a2 = 3. * al,

// ====== 2 характерные точки

x1 = cos (al) ,

yl = sin (al) ,

x2 = cos (a2) ,

y2 = sin(a2) ,

x[5], у [5];

//===== Вещественные (World) координаты углов звезды

//===== Считаем, что начало координат находится

//===== в геометрическом центре звезды

х [ 0 ] = 0 . ; у [ 0 ] = 1 . ; // Макушка звезды

х[1] = -х2; у[1] = -у2; // Нижний левый угол

х[2] = xl; У [2] = yl; // Верхний правый угол

х[3] = -xl; y[3] = yl; // Верхний левый угол

х[4] = х2; У [4] = -у2; // Нижний правый угол

//===== Логические координаты углов звезды

//===== запоминаем в контейнере

for (int i=0; i<5; i++)

//===== Точка в логической системе координат

// Увеличиваем в 100 раз, переводим в целые

// и сдвигаем

CPoint pt(200 + int(100. * x[i]), 150 - int(100. * y[i]));

//===== Записываем в конец контейнера

m_Points.push_back(pt);

}

}



Начало работы с Visual Studio.Net


Концепция решений и проектов

Создание нового проекта

Классы приложения

Контейнер точек

Рисование в контексте устройства

Реакция на ошибки

Итак, вы успешно преодолели все трудности установки 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-схем и редакторами ресурсов.



Рис. 1.1. Общий вид Studio.Net


Реакция на ошибки Полезно откомпилировать


Окно Task List со списком ошибок

Воспользуйтесь контекстным меню окна Task List и выберите команду Sort by > Category. В результате ее выполнения на первое место попадает сообщение:

error C2238: unexpected token (s) preceding ";" ...

Это примерно значит: «Неизвестная лексема предшествует точке с запятой». Такое сообщение, на мой взгляд, значительно более точно определяет причину. Вот она: компилятор не знает, что такое vectoro. Причина: мы забыли подключить файл с заголовками библиотеки STL Это легко исправить, вставив в нужное место строки:

//====== Подключает часть определений STL

#include <vector>

//====== Задает область видимости имен STL

using namespace std;

Теперь надо решить, куда вставить эти строки. Их можно вставить в начало файла MyDoc.h, по это будет расточительно. Дело в том, что для подключения файлов заголовков различных библиотек существует специальное место — файл Stdafx.h. Этот файл (совместно с файлом StdAfx.cpp) используется для построения файла скомпилированных заголовков My.pch (precompiled header) и файла скомпилированных типов StdAfx.obj.

Они расположены в папке Debug вашего проекта и служат для ускорения повторных компиляций файлов проекта после внесенных вами изменений, если они незначительны. Таким образом, подключаемые файлы библиотек, а они внушительны по размерам и компилируются только при необходимости. Сейчас настала такая необходимость, так как исправления затрагивают файл Stdafx.h. Вставьте две вышеуказанные строки в конец файла Stdafx.h и запустите музыку (Ctrl+F5).

Отметьте, что все файлы проекта компилируются заново, так как все файлы типа .срр имеют в качестве первой строку:

#include "stdafx.h"

Мы изменили stdafx.h, и компилятор заново проходит по всем зависящим (dependent) от него файлам. После построения и запуска изображение звезды должно появиться в клиентской области дочернего окна-рамки, то есть в окне, управляемом классом CMyView.

Рис. 1.7. Окно приложения My

Обратите внимание на характер заливки внутренних частей полигона, который принят по умолчанию. Он идентифицируется символьной константой ALTERNATING, но есть еще один вариант заливки — WINDING. Вставьте в функцию OnDraw, перед выводом полигона, строку.


pDC->SetPolyFillMode(WINDING);

и нажмите Ctrl+F5. Характер заливки изменился. Объяснение этого факта (и многих других) надо научиться искать в документации, сопровождающей Studio.Net. Дайте команду Help > Index, в окно Look for введите SetPolyFillMode и нажмите Enter. Появится окно Index Results for..., в котором следует сделать выбор между API-функцией SetPolyFillMode и одноименным методом класса CDC. Так как мы работаем с библиотекой MFC, то выбор почти всегда падает на методы классов, а не на одноименные функции API. Текст справки появится в окне Web Browser (многовато окон), и если вы действительно хотите понять алгоритм закрашивания кистью внутренних частей полигона, то вам придется немного потрудиться, даже имея хороший английский. К таким ситуациям тоже надо выработать правильное отношение. Программист должен быть кропотлив и терпелив.

Подведем итог:

мы слегка затронули концепцию решений (solutions);

научились создавать начальную заготовку MFC-приложения;

немного привыкли к скользким как мыло окнам Visual Studio.Net;

вспомнили (или узнали) об архитектуре документ — представление;

ввели в документ фундаментальную структуру данных — контейнер точек, скроенный по шаблону (template) vector;

узнали кое-что о выводе в контекст устройства и координатных пространствах Windows;

получили первый опыт сражений с ошибками.


Рисование в контексте устройства


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);

}



Создание нового проекта При создании


Окно диалога 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).

Рис. 1.4. Представление классов в окне Class View