Изменение кода отрисовки (учебник ATL, часть 4)

По умолчанию код рисования элемента управления отображает квадрат и текст PolyCtl. На этом шаге вы измените код, чтобы отобразить что-то более интересное. К этим задачам относятся следующие задачи:

  • Изменение файла заголовка

  • OnDraw Изменение функции

  • Добавление метода для вычисления точек многоугольника

  • Инициализация цвета заливки

Изменение файла заголовка

Начните с добавления поддержки математических функций sin и cos, которые будут использоваться для вычисления точек многоугольника, и путем создания массива для хранения позиций.

Изменение файла заголовка

  1. Добавьте строку #include <math.h> в верхнюю часть PolyCtl.h. Верхняя часть файла должна выглядеть следующим образом:

    #include <math.h>
    #include "resource.h"       // main symbols
    
  2. IProvideClassInfo Реализуйте интерфейс для предоставления сведений о методе для элемента управления, добавив следующий код в PolyCtl.h. В классе замените CPolyCtl строку:

    public CComControl<CPolyCtl>
    

    на

    public CComControl<CPolyCtl>,
    public IProvideClassInfo2Impl<&CLSID_PolyCtl, &DIID__IPolyCtlEvents, &LIBID_PolygonLib>
    

    и в BEGIN_COM_MAP(CPolyCtl), добавьте строки:

    COM_INTERFACE_ENTRY(IProvideClassInfo)
    COM_INTERFACE_ENTRY(IProvideClassInfo2)
    
  3. После вычисления точек многоугольника они будут храниться в массиве типа POINT, поэтому добавьте массив после инструкции short m_nSides; определения в PolyCtl.h:

    POINT m_arrPoint[100];
    

Изменение метода OnDraw

Теперь необходимо изменить OnDraw метод в PolyCtl.h. Добавленный код создает новое перо и кисть, с помощью которого нарисовывается многоугольник, а затем вызывает EllipsePolygon функции API Win32 для выполнения фактического рисования.

Изменение функции OnDraw

  1. Замените существующий OnDraw метод в PolyCtl.h следующим кодом:

    HRESULT CPolyCtl::OnDraw(ATL_DRAWINFO& di)
    {
       RECT& rc = *(RECT*)di.prcBounds;
       HDC hdc  = di.hdcDraw;
    
       COLORREF    colFore;
       HBRUSH      hOldBrush, hBrush;
       HPEN        hOldPen, hPen;
    
       // Translate m_colFore into a COLORREF type
       OleTranslateColor(m_clrFillColor, NULL, &colFore);
    
       // Create and select the colors to draw the circle
       hPen = (HPEN)GetStockObject(BLACK_PEN);
       hOldPen = (HPEN)SelectObject(hdc, hPen);
       hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
       hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
    
       Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
    
       // Create and select the brush that will be used to fill the polygon
       hBrush    = CreateSolidBrush(colFore);
       SelectObject(hdc, hBrush);
    
       CalcPoints(rc);
       Polygon(hdc, &m_arrPoint[0], m_nSides);
    
       // Select back the old pen and brush and delete the brush we created
       SelectObject(hdc, hOldPen);
       SelectObject(hdc, hOldBrush);
       DeleteObject(hBrush);
    
       return S_OK;
    }
    

Добавление метода для вычисления точек многоугольника

Добавьте метод, вызываемый CalcPoints, который вычисляет координаты точек, составляющих периметр многоугольника. Эти вычисления будут основаны на переменной RECT, передаваемой в функцию.

Добавление метода CalcPoints

  1. Добавьте объявление CalcPoints в общедоступный IPolyCtl раздел CPolyCtl класса в PolyCtl.h:

    void CalcPoints(const RECT& rc);
    

    Последняя часть общедоступного CPolyCtl раздела класса будет выглядеть следующим образом:

       void FinalRelease()
       {
       }
    public:
       void CalcPoints(const RECT& rc);
    
  2. Добавьте эту реализацию CalcPoints функции в конец PolyCtl.cpp:

    void CPolyCtl::CalcPoints(const RECT& rc)
    {
       const double pi = 3.14159265358979;
       POINT   ptCenter;
       double  dblRadiusx = (rc.right - rc.left) / 2;
       double  dblRadiusy = (rc.bottom - rc.top) / 2;
       double  dblAngle = 3 * pi / 2;          // Start at the top
       double  dblDiff  = 2 * pi / m_nSides;   // Angle each side will make
       ptCenter.x = (rc.left + rc.right) / 2;
       ptCenter.y = (rc.top + rc.bottom) / 2;
    
       // Calculate the points for each side
       for (int i = 0; i < m_nSides; i++)
       {
          m_arrPoint[i].x = (long)(dblRadiusx * cos(dblAngle) + ptCenter.x + 0.5);
          m_arrPoint[i].y = (long)(dblRadiusy * sin(dblAngle) + ptCenter.y + 0.5);
          dblAngle += dblDiff;
       }
    }
    

Инициализация цвета заливки

Инициализация m_clrFillColor с цветом по умолчанию.

Инициализация цвета заливки

  1. Используйте зеленый цвет в качестве цвета по умолчанию, добавив эту строку в CPolyCtl конструктор в PolyCtl.h:

    m_clrFillColor = RGB(0, 0xFF, 0);
    

Конструктор теперь выглядит следующим образом:

CPolyCtl()
{
   m_nSides = 3;
   m_clrFillColor = RGB(0, 0xFF, 0);
}

Сборка и тестирование элемента управления

Перестройте элемент управления. Убедитесь, что файл PolyCtl.htm закрыт, если он по-прежнему открыт, а затем нажмите кнопку "Создать многоугольник " в меню "Сборка ". Вы можете снова просмотреть элемент управления на странице PolyCtl.htm, но на этот раз используйте контейнер тестов activeX.

Использование контейнера тестов activeX

  1. Создайте и запустите контейнер тестов activeX. Пример TSTCON: контейнер тестов activeX можно найти на сайте GitHub.

    Примечание.

    Для ошибок, связанных ATL::CW2AEXс скриптом Cpp, замените строку TRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT );TRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT.m_psz );строкой и строкойTRACE( "Source Text: %s\n", bstrSourceLineText );TRACE( "Source Text: %s\n", COLE2CT( bstrSourceLineText ) );.
    Для ошибок, связанных с HMONITORэтим, откройте StdAfx.h в TCProps проекте и замените:

    #ifndef WINVER
    #define WINVER 0x0400
    #endif
    

    на

    #ifndef WINVER
    #define WINVER 0x0500
    #define _WIN32_WINNT 0x0500
    #endif
    
  2. В меню "Изменить" в меню "Тестовый контейнер" нажмите кнопку "Вставить новый элемент управления".

  3. Найдите элемент управления, который будет вызываться PolyCtl class, и нажмите кнопку "ОК". В круге появится зеленый треугольник.

Попробуйте изменить количество сторон, выполнив следующую процедуру. Чтобы изменить свойства в двойном интерфейсе из тестового контейнера, используйте методы Invoke.

Изменение свойства элемента управления из контейнера тестирования

  1. В тестовом контейнере щелкните "Вызвать методы " в меню "Элемент управления ".

    Откроется диалоговое окно "Метод invoke".

  2. Выберите версию свойства "Стороны" в раскрывающемся списке "Имя метода".

  3. Введите 5 поле "Значение параметра", нажмите кнопку "Задать значение" и нажмите кнопку "Вызвать".

Обратите внимание, что элемент управления не изменяется. Хотя количество сторон было изменено внутренне, задав m_nSides переменную, это не привело к повторной настройке элемента управления. Если переключиться на другое приложение, а затем вернуться к тестовой контейнере, вы увидите, что элемент управления переопределен и имеет правильное количество сторон.

Чтобы устранить эту проблему, добавьте вызов FireViewChange функции, определенный в IViewObjectExImpl, после установки количества сторон. Если элемент управления выполняется в собственном окне, FireViewChange вызовет метод напрямую InvalidateRect . Если элемент управления работает без окна, InvalidateRect метод будет вызываться в интерфейсе сайта контейнера. Это заставляет элемент управления перезапугать себя.

Добавление вызова в FireViewChange

  1. Обновите PolyCtl.cpp, добавив вызов FireViewChange к методу put_Sides . По завершении put_Sides метод должен выглядеть следующим образом:

    STDMETHODIMP CPolyCtl::put_Sides(short newVal)
    {
       if (2 < newVal && newVal < 101)
       {
          m_nSides = newVal;
          FireViewChange();
          return S_OK;
       }
       else
       {
          return Error(_T("Shape must have between 3 and 100 sides"));
       }
    }
    

После добавления FireViewChange, перестройте и повторите попытку элемента управления в контейнере тестов ActiveX. На этот раз при изменении количества сторон и нажатия кнопки вы Invokeувидите изменение элемента управления немедленно.

На следующем шаге вы добавите событие.

Вернуться к шагу 3 | Вкл. Шаг 5

См. также

Руководство
Тестирование свойств и событий с использованием тестового контейнера