Compartir a través de


Cambiar el código de dibujo (Tutorial de ATL, Parte 4)

De forma predeterminada, el código de dibujo del control muestra un cuadrado y el texto PolyCtl. En este paso, cambiará el código para que muestre algo más interesante. Estas son las tareas implicadas:

  • Modificar el archivo de encabezado

  • Modificar la función OnDraw

  • Agregar un método para calcular los puntos del polígono

  • Inicializar el color de relleno

Modificar el archivo de encabezado

Comience por agregar compatibilidad con las funciones matemáticas sin y cos, que se usarán para calcular los puntos del polígono y por crear una matriz para almacenar las posiciones.

Para modificar el archivo de encabezado

  1. Agregue la línea #include <math.h> a la parte superior de PolyCtl.h. La parte superior del archivo debe ser como esta:

    #include <math.h>
    #include "resource.h"       // main symbols
    
  2. Implemente la interfaz IProvideClassInfo para proporcionar información de método para el control, para lo que se agrega el siguiente código a PolyCtl.h. En la clase CPolyCtl, reemplace la línea:

    public CComControl<CPolyCtl>
    

    con

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

    y en BEGIN_COM_MAP(CPolyCtl), agregue las líneas:

    COM_INTERFACE_ENTRY(IProvideClassInfo)
    COM_INTERFACE_ENTRY(IProvideClassInfo2)
    
  3. Una vez calculados los puntos del polígono, se almacenarán en una matriz del tipo POINT, así que agregue la matriz después de la instrucción de definición short m_nSides; a PolyCtl.h:

    POINT m_arrPoint[100];
    

Modificación del método OnDraw

Ahora debe modificar el método OnDraw en PolyCtl.h. El código que agregará crea un lápiz y pincel con el que dibujar el polígono y, después, llama a las funciones Ellipse y Polygon de API Win32 para realizar el dibujo real.

Para modificar la función OnDraw

  1. Reemplace el método OnDraw existente en PolyCtl.h por el código siguiente:

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

Agregar un método para calcular los puntos del polígono

Agregue un método, denominado CalcPoints, que calculará las coordenadas de los puntos que componen el perímetro del polígono. Estos cálculos se basarán en la variable RECT que se pasa a la función.

Para agregar el método CalcPoints

  1. Agregue la declaración de CalcPoints a la sección pública IPolyCtl de la clase CPolyCtl en PolyCtl.h:

    void CalcPoints(const RECT& rc);
    

    La última parte de la sección pública de la clase CPolyCtl tendrá este aspecto:

       void FinalRelease()
       {
       }
    public:
       void CalcPoints(const RECT& rc);
    
  2. Agregue esta implementación de la función CalcPoints al final de 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;
       }
    }
    

Inicializar el color de relleno

Inicialice m_clrFillColor con un color predeterminado.

Para inicializar el color de relleno

  1. Use el verde como color predeterminado agregando esta línea al constructor CPolyCtl en PolyCtl.h:

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

El constructor ahora se parece a este:

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

Compilar y probar el control

Recompile el componente. Asegúrese de que el archivo PolyCtl.htm está cerrado, en caso de que siga abierto y, después, haga clic en Compilar polígono en el menú Compilar. Puede volver a ver el control desde la página PolyCtl.htm, pero esta vez use ActiveX Control Test Container.

Para usar ActiveX Control Test Container

  1. Compile ActiveX Control Test Container e inícielo. El ejemplo de TSTCON: ActiveX Control Test Container se puede encontrar en GitHub.

    Nota:

    Para los errores relacionados con ATL::CW2AEX, en Script.Cpp, reemplace la línea TRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT ); por TRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT.m_psz ); y la línea TRACE( "Source Text: %s\n", COLE2CT( bstrSourceLineText ) ); por TRACE( "Source Text: %s\n", bstrSourceLineText );.
    En el caso de los errores relacionados con HMONITOR, abra StdAfx.h en el proyecto TCProps y reemplace:

    #ifndef WINVER
    #define WINVER 0x0400
    #endif
    

    con

    #ifndef WINVER
    #define WINVER 0x0500
    #define _WIN32_WINNT 0x0500
    #endif
    
  2. En Test Container, en el menú Edición, haga clic en Insertar nuevo control.

  3. Busque el control al que se llamará PolyCtl class y haga clic en Aceptar. Verá un triángulo verde dentro de un círculo.

Intente cambiar el número de lados siguiendo el procedimiento que se indica a continuación. Para modificar las propiedades en una interfaz dual desde Test Container, use Invocar métodos.

Para modificar la propiedad de un control desde Test Container

  1. En Test Container, haga clic en Invocar métodos en el menú Control.

    Se muestra el cuadro de diálogo Invocar método.

  2. Seleccione la versión PropPut de la propiedad Lados en el cuadro de lista desplegable Nombre del método.

  3. Escriba 5 en el cuadro Valor de parámetro, haga clic en Establecer valor y después en Invocar.

Tenga en cuenta que el control no cambia. Aunque cambió internamente el número de lados estableciendo la variable m_nSides, ello no provocó que el control se volviera a pintar. Si cambia a otra aplicación y, después, vuelve a Test Container, verá que el control se ha vuelto a pintar y tiene el número correcto de lados.

Para corregir este problema, agregue una llamada a la función FireViewChange, definida en IViewObjectExImpl, después de establecer el número de lados. Si el control se ejecuta en su propia ventana, FireViewChange llamará directamente al método InvalidateRect. Si el control se ejecuta sin ventanas, se llamará al método InvalidateRect en la interfaz del sitio del contenedor. Esto obliga al control a volver a pintarse.

Para agregar una llamada a FireViewChange

  1. Actualice PolyCtl.cpp, para lo que debe agregar la llamada a FireViewChange al método put_Sides. Cuando termine, el método put_Sides debería ser como el siguiente:

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

Después de agregar FireViewChange, recompile e intente el control de nuevo en ActiveX Control Test Container. Esta vez, cuando cambie el número de lados y haga clic en Invoke, debería ver el cambio de control inmediatamente.

En el paso siguiente, agregará un evento.

Volver al Paso 3 | Avanzar al Paso 5

Consulte también

Tutorial
Prueba de propiedades y eventos con un contenedor de prueba