Иллюстрированный самоучитель по Visual Studio .NET

Двойственные интерфейсы

Стандартные свойства

Возвращаясь к нашему проекту, отметим, что интерфейс предоставляет своим пользователям два одноименных метода FillColor. Первый метод позволяет пользователю изменить (propput) стандартное или встроенное (stock property) свойство: "цвет заливки". Второй – узнать (propget) текущее значение этого свойства. Этот интерфейс был вставлен мастером потому, что при создании элемента мы указали на – необходимость введения в него одного из стандартных свойств. С этой же целью мастер ввел в состав класса переменную:

OLE_COLOR m_clrFillColor;

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

COpenGL()
{
m_clrFillColor = RGB (255.230.255);
}

Но этого мало. Для того чтобы увидеть результат, надо изменить коды функции рисования, которую вы найдете в том же файле OpenGLh.

Примечание
Вступив в царство ATL, придется отречься от многих привычек, приобретенных в MFC. Вы уже заметили, что мы теперь вместо char* или CString пользуемся OLESTR, а вместо COLORREF– OLE_COLOR. Это еще не так отвлекает, но вот теперь надо рисовать без помощи привычного класса CDC и вернуться к описателю НОС контекста устройства, которым мы пользовались при разработке традиционного Windows-приложения на основе функций API. Также придется привыкнуть к тому, что описатель HOC hdcDraw упрятан в структуру типа ATL_DRAWINFO, ссылку на которую мы получаем в параметре метода OnDraw класса CComControl
.

Напомню, что вся функциональность класса CComControl унаследована нашим классом COpenGL, который, кроме него, имеет еще 17 родителей. Состав полей структуры ATL_DRAWINFO не будем приводить здесь, чтобы не усугублять головокружение, а вместо этого предложим убедиться в том, что можно влиять на облик СОМ-объекта. Особенностью перерисовки СОМ-объекта является то, что он изображает себя в чужом окне. Поэтому, получив контекст устройства, связанный с этим окном, он должен постараться не рисовать вне пределов прямоугольника, отведенного для него.

В Windows существует понятие поврежденной области окна (clip region). Это обычно прямоугольная область, в пределах которой система позволяет приложению рисовать. Если рисующие функции GDI попробуют выйти за границы этой области, то система не отобразит этих изменений. Следующий код интенсивно работает с clip region, поэтому для понимания алгоритма рекомендуем получить справку о функциях GetClipRgn и SelectClipRgn. Введите изменения в уже существующее тело функции OnDraw так, чтобы она приобрела вид:

HRESULT OnDraw(ATL_DRAWINFO& di)
{
//===== Преобразование RECTL в RECT
RECT& r = *(RECT*)di.prcBounds;
//===== Запоминаем текущую поврежденную область
HRGN hRgnOld = 0;
//== Функция GetClipRgn может возвратить: 0, 1 или – 1
if (GetClipRgn(di.hdcDraw, hRgnOld)!= 1) hRgnOld = 0;
//====== Создание новой области
HRGN hRgnNew = CreateRectRgn(r.left,r.top, r.right,r.bottom);
// Оптимистический прогноз (новая область воспринята)
bool bSelectOldRgn = false;
//=== Устанавливаем поврежденную область равной г
if (hRgnNew)
{
bSelectOldRgn = SelectClipRgn(di.hdcDraw,hRgnNew) == ERROR;
}
//=== Изменяем цвет фона и обрамляем объект
::rSelectObject(di.hdcDraw,
::CreateSolidBrush(m_clrFillColor)); Rectangle(di.hdcDraw, r.left, r.top,r.right,r.bottom);
//=== Параметры выравнивания текста и сам текст
SetTextAlign(di.hdcDraw, TA_CENTER | TA_BASELINE);
LPCTSTR pszText = _T("ATL 4.0: OpenGL");
//=== Вывод текста в центр прямоугольника
TextOut(di.hdcDraw, (r.left + r.right)/2,
(r.top + r.bottom)/2,
pszText,Istrlen(pszText));
//=== Если был сбой, то устанавливаем старую область
if (bSelectOldRgn)
SelectClipRgn(di.hdcDraw, hRgnOld);
return S_OK;
}

В этой реализации функции OnDraw мы намеренно пошли на поводу у схемы, предложенной в заготовке. Структура RECTL, на которую указывает prcBounds, идентична структуре RECT, но при заливке она ведет себя на один пиксел лучше (см. справку). Здесь это никак не используется. Автору фрагмента не хотелось много раз писать выражение di .prcBounds ›, поэтому он завел ссылку на объект типа RECTL, приведя ее к типу RECT.

Здесь хочется "взять в руки" CRect, cstring и переписать фрагмент заново в более компактной форме, однако если вы попробуете это сделать, то получите сообщения о том, что CRect и cstring – неизвестные сущности. Они из другого царства MFC. Мы можем подключить поддержку MFC, но при этом многое потеряем. Одной из причин создания ATL была неповоротливость объектов на основе MFC в условиях web-страниц. Мы не можем себе этого позволить, так как собираемся работать с трехмерной графикой. Поэтому надо привыкать работать по правилам Win32-API и классов СОМ.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.