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
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
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 claseCPolyCtl
, 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)
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ónshort 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
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
Agregue la declaración de
CalcPoints
a la sección públicaIPolyCtl
de la claseCPolyCtl
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);
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
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
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íneaTRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT );
porTRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT.m_psz );
y la líneaTRACE( "Source Text: %s\n", COLE2CT( bstrSourceLineText ) );
porTRACE( "Source Text: %s\n", bstrSourceLineText );
.
En el caso de los errores relacionados conHMONITOR
, abra StdAfx.h en el proyectoTCProps
y reemplace:#ifndef WINVER #define WINVER 0x0400 #endif
con
#ifndef WINVER #define WINVER 0x0500 #define _WIN32_WINNT 0x0500 #endif
En Test Container, en el menú Edición, haga clic en Insertar nuevo control.
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
En Test Container, haga clic en Invocar métodos en el menú Control.
Se muestra el cuadro de diálogo Invocar método.
Seleccione la versión PropPut de la propiedad Lados en el cuadro de lista desplegable Nombre del método.
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
Actualice PolyCtl.cpp, para lo que debe agregar la llamada a
FireViewChange
al métodoput_Sides
. Cuando termine, el métodoput_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