In the drawing code you will use sin and cos functions to calculate the polygon points, so add include math.h at the top of PolyCtl.h:
Note for Release builds only When the ATL COM AppWizard generates the default project, it defines the macro _ATL_MIN_CRT. This macro is defined so that you don't bring the C Run-Time Library into your code if you don't need it. The polygon control needs the C Run-Time Library start-up code to initialize the floating-point functions. Therefore, you need to remove the _ATL_MIN_CRT macro if you want to build a Release version. To remove the macro, click Settings on the Project menu. In the Settings For: drop-down list, choose Multiple Configurations. In the Select project configuration(s) to modify dialog box that appears, click the check boxes for all four Release versions, then click OK. On the C/C++ tab, choose the General category, then remove _ATL_MIN_CRT from the Preprocessor definitions edit box.
Once the polygon points are calculated, you store the points by adding an array of type POINT to the end of the class definition in PolyCtl.h:
Now change the
The completed
You now need to add a function, called
The public section of the IPolyCtl class should now look like this:
Next, add the implementation of the
Now, initialize
The constructor now looks like this:
Now rebuild the control and try it again. Open ActiveX Control Test Container and insert the control. You should see a green triangle within a circle. Try changing the number of sides by following the steps below. To modify properties on a dual interface from within Test Container, use Invoke Methods:
Notice that the control doesn't change. What is wrong? Although you changed the number of sides internally by setting the
To correct this problem, you need to add a call to the FireViewChange function, which is defined in IViewObjectExImpl, after you set the number of sides. If the control is running in its own window, FireViewChange will call the InvalidateRect API directly. If the control is running windowless, the InvalidateRect method will be called on the container's site interface. This forces the control to repaint itself.
The new
After you've added FireViewChange, rebuild and try the control again. This time when you change the number of sides and click Invoke, you should see the control change immediately.
Next, you will add an event to the control. Send feedback to MSDN. Look here for MSDN Online Resources. © 1999 Microsoft Corporation. All rights reserved. Terms of use.Step 4: Changing the Drawing Code
#include <math.h>
#include "resource.h" // main symbols
OLE_COLOR m_clrFillColor;
short m_nSides;
POINT m_arrPoint[100];
OnDraw
function in PolyCtl.h to match the one below. Note that you remove the calls to the Rectangle and DrawText functions. You also explicitly get and select a black pen and white brush. You need to do this in case your control is running windowless. If you don't have your own window, you can't make assumptions about the device context you'll be drawing in.OnDraw
looks like this: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
, that will calculate the coordinates of line intersections. These calculations will be based on the RECT variable that is passed into the function. First you should add the definition of CalcPoints to the public section for the IPolyCtl class in PolyCtl.h:void CalcPoints(const RECT& rc);
// IPolyCtl
public:
STDMETHOD(get_Sides)(/*[out, retval]*/ short *newVal);
STDMETHOD(put_Sides)(/*[in]*/ short newVal);
void CalcPoints(const RECT& rc);
CalcPoints
function to the end of the PolyCtl.cpp file: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
. Choose green as the default color and add this line to the CPolyCtl
constructor in PolyCtl.h: m_clrFillColor = RGB(0, 0xFF, 0);
CPolyCtl()
{
m_nSides = 3;
m_clrFillColor = RGB(0, 0xFF, 0);
}
The Invoke Method dialog box is displayed. m_nSides
variable, you didn't cause the control to repaint. If you switch to another application and then switch back to Test Container you will find that the control is repainted and now has the correct number of sides.put_Sides
method is as follows:STDMETHODIMP CPolyCtl::put_Sides(short newVal)
{
if (newVal > 2 && newVal < 101)
{
m_nSides = newVal;
FireViewChange();
return S_OK;
}
else
return Error(_T("Shape must have between 3 and 100 sides"));
}