Click here to Skip to main content
Click here to Skip to main content
Articles » Multimedia » GDI+ » Applications » Downloads
 
Add your own
alternative version

GDI+ Plot ActiveX Control

, 5 Sep 2013 LGPL3
GDI+ 2D plot ActiveX control
// (C) Copyright 2009 by CCTEC ENGINEERING CO., LTD
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted, 
// provided that the above copyright notice appears in all copies and 
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting 
// documentation.
//

// GDIPlusPlotCtl.cpp : Implementation of the CGDIPlusPlotCtrl ActiveX Control class.

#include "stdafx.h"
#include "GDIPlusPlot.h"
#include "GDIPlusPlotCtl.h"
#include "GDIPlusPlotPpg.h"

#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define XTIME_TIMER 1							        // X axis timer X���ʱ����ʶ	
#define XTIME_TIMER_INTERVAL 100				        // X axis timer interval X���Զ���ʱ���
#define RED_RGB Gdiplus::Color(255, 255, 0, 0)	        // Red RGB ��ɫ
#define BLACK_RGB Gdiplus::Color(255, 0, 0, 0)	        // Black RGB ��ɫ
#define GREEN_RGB Gdiplus::Color(255, 0, 255, 0)        // Green RGB ��ɫ
#define WHITE_RGB Gdiplus::Color(255, 255, 255, 255)    // White RGB ��ɫ
#define YELLOW_RGB Gdiplus::Color(255, 255, 255, 0)     // Yellow RGB ��ɫ
#define BLUE_RGB Gdiplus::Color(255, 0, 0, 255)			// Blue RGB ��ɫ
#define WHITE_ARGB(X) Gdiplus::Color(X, 255, 255, 255)  // Alpha white RGB
#define LIGHT_WHITE_RGB WHITE_ARGB(86)					// Light white dz��ɫ
#define CAPTION_SIZE 16							        // Caption font size ���������С
#define MARGIN 0								        // Margin font size �߽������С
#define LABEL_SIZE 12							        // Label font size ��ǩ�����С
#define SCALE_SIZE 10                                   // Scale font size �̶������С
#define X_UNIT_ONE 10								    // X axis unit one length X�ᵥλ1����
#define Y_UNIT_ONE 5                                    // Y axis unit one length Y�ᵥλ1����
#define BUFFER_SIZE 1024                                // 1KB
#define CURVE_POINTS_SIZE 1024
#define X_CURSOR_STEP 20
#define MAX_RANGE_Y 40
#define MIN_RANGE_Y 10
#define DEBUG_MSGBOX(X) MessageBox(X, "DEBUG", MB_OK | MB_ICONINFORMATION)

IMPLEMENT_DYNCREATE(CGDIPlusPlotCtrl, COleControl)


/////////////////////////////////////////////////////////////////////////////
// Message map

BEGIN_MESSAGE_MAP(CGDIPlusPlotCtrl, COleControl)
	//{{AFX_MSG_MAP(CGDIPlusPlotCtrl)
	ON_WM_TIMER()
	ON_WM_SIZE()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_RBUTTONDOWN()
	//}}AFX_MSG_MAP
	ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
	ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// Dispatch map

BEGIN_DISPATCH_MAP(CGDIPlusPlotCtrl, COleControl)
	//{{AFX_DISPATCH_MAP(CGDIPlusPlotCtrl)
	DISP_PROPERTY_EX(CGDIPlusPlotCtrl, "caption", GetCaption, SetCaption, VT_BSTR)
	DISP_PROPERTY_EX(CGDIPlusPlotCtrl, "xTime", GetXTime, SetXTime, VT_BOOL)
	DISP_PROPERTY_EX(CGDIPlusPlotCtrl, "xLabel", GetXLabel, SetXLabel, VT_BSTR)
	DISP_PROPERTY_EX(CGDIPlusPlotCtrl, "yLabel", GetYLabel, SetYLabel, VT_BSTR)
	DISP_PROPERTY_EX(CGDIPlusPlotCtrl, "interval", GetInterval, SetInterval, VT_I2)
	DISP_PROPERTY_EX(CGDIPlusPlotCtrl, "annolabel", GetAnnolabel, SetAnnolabel, VT_BSTR)
	DISP_PROPERTY_EX(CGDIPlusPlotCtrl, "xTrack", GetXTrack, SetXTrack, VT_BOOL)
	DISP_FUNCTION(CGDIPlusPlotCtrl, "PlotXY", PlotXY, VT_EMPTY, VTS_R8 VTS_R8 VTS_I2)
	DISP_FUNCTION(CGDIPlusPlotCtrl, "SetRange", SetRange, VT_EMPTY, VTS_R8 VTS_R8 VTS_R8 VTS_R8)
	DISP_FUNCTION(CGDIPlusPlotCtrl, "PlotY", PlotY, VT_EMPTY, VTS_R8 VTS_I2)
	DISP_FUNCTION(CGDIPlusPlotCtrl, "ClearGraph", ClearGraph, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION(CGDIPlusPlotCtrl, "AddElement", AddElement, VT_EMPTY, VTS_I2)
	DISP_FUNCTION(CGDIPlusPlotCtrl, "IsElementVisible", IsElementVisible, VT_EMPTY, VTS_I2 VTS_BOOL)
	DISP_FUNCTION(CGDIPlusPlotCtrl, "SetXCursorPos", SetXCursorPos, VT_EMPTY, VTS_R8)
	DISP_FUNCTION(CGDIPlusPlotCtrl, "GetQuadrantWidth", GetQuadrantWidth, VT_R8, VTS_NONE)
	//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()


/////////////////////////////////////////////////////////////////////////////
// Event map

BEGIN_EVENT_MAP(CGDIPlusPlotCtrl, COleControl)
	//{{AFX_EVENT_MAP(CGDIPlusPlotCtrl)
	// NOTE - ClassWizard will add and remove event map entries
	//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_EVENT_MAP
END_EVENT_MAP()


/////////////////////////////////////////////////////////////////////////////
// Property pages

// TODO: Add more property pages as needed.  Remember to increase the count!
BEGIN_PROPPAGEIDS(CGDIPlusPlotCtrl, 1)
	PROPPAGEID(CGDIPlusPlotPropPage::guid)
END_PROPPAGEIDS(CGDIPlusPlotCtrl)


/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CGDIPlusPlotCtrl, "GDIPLUSPLOT.GDIPlusPlotCtrl.1",
	0xdcd24674, 0xd4a1, 0x4ece, 0xb6, 0xa0, 0xd8, 0x54, 0xdb, 0x5a, 0xd6, 0x92)


/////////////////////////////////////////////////////////////////////////////
// Type library ID and version

IMPLEMENT_OLETYPELIB(CGDIPlusPlotCtrl, _tlid, _wVerMajor, _wVerMinor)


/////////////////////////////////////////////////////////////////////////////
// Interface IDs

const IID BASED_CODE IID_DGDIPlusPlot =
		{ 0x6bb19a9a, 0x4f5, 0x42de, { 0x94, 0x95, 0xec, 0xc3, 0x19, 0xd4, 0x9e, 0x81 } };
const IID BASED_CODE IID_DGDIPlusPlotEvents =
		{ 0xd60098a8, 0x5b4e, 0x4b86, { 0x91, 0x1a, 0xf2, 0xc6, 0xb5, 0x41, 0x1c, 0xb3 } };


/////////////////////////////////////////////////////////////////////////////
// Control type information

static const DWORD BASED_CODE _dwGDIPlusPlotOleMisc =
	OLEMISC_ACTIVATEWHENVISIBLE |
	OLEMISC_SETCLIENTSITEFIRST |
	OLEMISC_INSIDEOUT |
	OLEMISC_CANTLINKINSIDE |
	OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CGDIPlusPlotCtrl, IDS_GDIPLUSPLOT, _dwGDIPlusPlotOleMisc)


/////////////////////////////////////////////////////////////////////////////
// CGDIPlusPlotCtrl::CGDIPlusPlotCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CGDIPlusPlotCtrl

BOOL CGDIPlusPlotCtrl::CGDIPlusPlotCtrlFactory::UpdateRegistry(BOOL bRegister)
{
	// TODO: Verify that your control follows apartment-model threading rules.
	// Refer to MFC TechNote 64 for more information.
	// If your control does not conform to the apartment-model rules, then
	// you must modify the code below, changing the 6th parameter from
	// afxRegApartmentThreading to 0.

	if (bRegister)
		return AfxOleRegisterControlClass(
			AfxGetInstanceHandle(),
			m_clsid,
			m_lpszProgID,
			IDS_GDIPLUSPLOT,
			IDB_GDIPLUSPLOT,
			afxRegApartmentThreading,
			_dwGDIPlusPlotOleMisc,
			_tlid,
			_wVerMajor,
			_wVerMinor);
	else
		return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}


/////////////////////////////////////////////////////////////////////////////
// CGDIPlusPlotCtrl::CGDIPlusPlotCtrl - Constructor

CGDIPlusPlotCtrl::CGDIPlusPlotCtrl()
{
	Gdiplus::GdiplusStartupInput gdiplusStartupInput;

	InitializeIIDs(&IID_DGDIPlusPlot, &IID_DGDIPlusPlotEvents);

	// TODO: Initial GDI+ related handler ��ʼ��GDI+��ؾ��
	Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
	m_MemoryGraphics = NULL;

	m_caption	    = L"GDIPlusPlot";	    // Default caption Ĭ�ϱ���
	m_xLabel	    = L"X AXIS";		    // Default X axis label Ĭ��X���ǩ
	m_yLabel	    = L"Y AXIS";		    // Default Y axis label Ĭ��Y���ǩ
	m_annolabel		= L"";					// Default anno label Ĭ��anno��ǩ
	m_xTime		    = FALSE;			    // Disable auto-timer for X axis X��Ĭ�ϲ��Զ���ʱ
	m_xTrack		= FALSE;				// Disable track on X axis Ĭ��X�᲻����
    m_xMin		    = 0;                    // Default x min range Ĭ��X����Сֵ
	m_xMax		    = 100;                  // Default x max range Ĭ��X�����ֵ
	m_yMin		    = -10;                  // Default y min range Ĭ��Y����Сֵ
	m_yMax		    = 10;                   // Default y max range Ĭ��Y�����ֵ
	m_CursorX		= 0;
	m_ElementCount	= 0;
}


/////////////////////////////////////////////////////////////////////////////
// CGDIPlusPlotCtrl::~CGDIPlusPlotCtrl - Destructor

CGDIPlusPlotCtrl::~CGDIPlusPlotCtrl()
{
	// TODO: Release GDI+ related handler �ͷ�GDI+��ؾ��
	if (m_MemoryGraphics) delete m_MemoryGraphics; m_MemoryGraphics = NULL;
	Gdiplus::GdiplusShutdown(m_gdiplusToken);
}

// TODO: Draw caption ������
void CGDIPlusPlotCtrl::m_DrawCaption(CRect rcBounds) 
{
    // NOTE: See the example of DrawString section of GDI+ in MSDN
    // �鿴MSDN����GDI+��DrawString����
    
	Gdiplus::FontFamily		fontFamily(L"Courier New");
	Gdiplus::Font			font(&fontFamily, CAPTION_SIZE, Gdiplus::FontStyleBold, 
            Gdiplus::UnitPixel);
	Gdiplus::RectF			layoutRect(0.0f, MARGIN, rcBounds.Width(), CAPTION_SIZE);
	Gdiplus::StringFormat	format;
	Gdiplus::SolidBrush		solidBrush(BLACK_RGB);

	format.SetAlignment(Gdiplus::StringAlignmentCenter);
	m_MemoryGraphics->DrawString(m_caption, -1, &font, layoutRect, &format, &solidBrush);
}

// TODO: Draw X axis label ��X���ǩ
void CGDIPlusPlotCtrl::m_DrawXLabel(CRect rcBounds) 
{
	Gdiplus::FontFamily		fontFamily(L"Courier New");
	Gdiplus::Font			font(&fontFamily, LABEL_SIZE, Gdiplus::FontStyleRegular, 
            Gdiplus::UnitPixel);
	Gdiplus::RectF			layoutRect(0.0f, rcBounds.Height() - LABEL_SIZE - MARGIN, 
            rcBounds.Width(), LABEL_SIZE);
	Gdiplus::StringFormat	format;
	Gdiplus::SolidBrush		solidBrush(BLACK_RGB);

	format.SetAlignment(Gdiplus::StringAlignmentCenter);
	m_MemoryGraphics->DrawString(m_xLabel, -1, &font, layoutRect, &format, &solidBrush);
}

// TODO: Draw Y axis label ��Y���ǩ
void CGDIPlusPlotCtrl::m_DrawYLabel(CRect rcBounds) 
{
	Gdiplus::FontFamily		fontFamily(L"Courier New");
	Gdiplus::Font			font(&fontFamily, LABEL_SIZE, Gdiplus::FontStyleRegular, 
            Gdiplus::UnitPixel);
	Gdiplus::RectF			layoutRect(0.0f, 0.0f, LABEL_SIZE, rcBounds.Height());
	Gdiplus::StringFormat	format;
	Gdiplus::SolidBrush		solidBrush(BLACK_RGB);

	// FIXME: *BUG* fail to vertical �޷���ֱ
	format.SetFormatFlags(Gdiplus::StringFormatFlagsDirectionVertical | 
		Gdiplus::StringFormatFlagsDirectionRightToLeft);
	format.SetAlignment(Gdiplus::StringAlignmentCenter);
	m_MemoryGraphics->DrawString(m_yLabel, -1, &font, layoutRect, &format, &solidBrush);
}

int CGDIPlusPlotCtrl::m_GetPointY(int PointX, std::list<point_t> pointlist) 
{
    std::list<point_t>::iterator point;

    for (point = pointlist.begin(); point != pointlist.end(); point++) 
    {
        // FIXME: Big number eat small one
        if ((*point).x == PointX) return ((*point).y - m_QuadrantHeight) / (m_yMax - m_yMin);
    }
    return 0;
}

void CGDIPlusPlotCtrl::m_DrawCurve(short index) 
{
    Gdiplus::Point                  curvePoints[CURVE_POINTS_SIZE];
	std::list<element_t>::iterator	EleIter;
	std::list<point_t>::iterator    PointIter;
    Gdiplus::FontFamily		        fontFamily(L"Courier New");
	Gdiplus::Font			        font(&fontFamily, SCALE_SIZE, Gdiplus::FontStyleRegular, 
                                        Gdiplus::UnitPixel);
    Gdiplus::StringFormat	        format;
	Gdiplus::SolidBrush		        solidBrush(WHITE_RGB);
    wchar_t                         xTrack[BUFFER_SIZE];
	unsigned int					i, j;
	
    format.SetAlignment(Gdiplus::StringAlignmentNear);

	for (EleIter = m_ElementList.begin(), j = 0; 
            EleIter != m_ElementList.end(); EleIter++, j++) 
	{
		// TODO: Find the element with the index if it is visible ���������ӣ�ʹ������Ѱ����
		if (index == (*EleIter).index && (*EleIter).visible) 
		{
			Gdiplus::Pen pen((*EleIter).color);

			// TODO: Cleanup curve points array ������ߵ�
			memset(curvePoints, 0, CURVE_POINTS_SIZE);
			for (PointIter = (*EleIter).pointlist.begin(), i = 0; 
				PointIter != (*EleIter).pointlist.end(); PointIter++, i++) 
			{
                // TODO: Make the original point
				if (i == 0) 
                {
                    Gdiplus::Point point(m_QuadrantX, m_QuadrantHeight / 2);
                    curvePoints[i] = point; 
                    continue;
                }
                Gdiplus::Point point((*PointIter).x, (*PointIter).y);
				curvePoints[i] = point;
			}
			m_MemoryGraphics->DrawCurve(&pen, curvePoints, i);
            
            // TODO: Draw track cursor value �������α��ֵ
            if (m_xTrack) 
            {
                Gdiplus::RectF layoutRect(m_TrackX, m_QuadrantY + SCALE_SIZE * j, 
                    Y_UNIT_ONE * 16, SCALE_SIZE);

                memset(xTrack, 0, BUFFER_SIZE);
                swprintf( xTrack, L"%d", m_GetPointY(m_TrackX, (*EleIter).pointlist) );
                m_MemoryGraphics->DrawString(xTrack, -1, &font, layoutRect, 
                    &format, &solidBrush);
            }
			break;
		}
	}
}

void CGDIPlusPlotCtrl::m_DrawPlotXY() 
{
    unsigned int e;

    if (m_xTrack && m_QuadrantX < m_TrackX) m_DrawCursor(m_TrackX);

	// TODO: Draw multi curve ����������
	for (e = 0; e < m_ElementCount; e++) 
	{
		m_DrawCurve(e);
	}
}

void CGDIPlusPlotCtrl::m_DrawCursor(int x) 
{
    Gdiplus::Pen pen(RED_RGB);

    m_MemoryGraphics->DrawLine(&pen, x, m_QuadrantY, x, m_QuadrantY + m_QuadrantHeight);
}

// TODO: Draw the cursor flying with the timer for X axis ��X���ϻ���ʱ�����ŵ��α�
void CGDIPlusPlotCtrl::m_DrawXTimeCursor() 
{
	// TODO: Cleanup when out of range ��������Χ�����ƺ���
    if (m_QuadrantWidth < m_CursorX) ClearGraph();
    
    m_DrawCursor(m_QuadrantX + m_CursorX);
    // TODO: Draw Y axis depending on the value via PlotY ����PlotY����ֵ��Y��
    m_DrawPlotXY();

    // TODO: Move the X axis cursor �ƶ�X����α�
    m_CursorX += X_CURSOR_STEP;
}

// TODO: Draw the scale for X axis ��X��̶�
void CGDIPlusPlotCtrl::m_DrawXScale() 
{
    Gdiplus::FontFamily		fontFamily(L"Courier New");
	Gdiplus::Font			font(&fontFamily, SCALE_SIZE, Gdiplus::FontStyleRegular, 
            Gdiplus::UnitPixel);
    Gdiplus::StringFormat	format;
	Gdiplus::SolidBrush		solidBrush(LIGHT_WHITE_RGB);
    wchar_t                 pScale[BUFFER_SIZE];
    Gdiplus::Pen            pen(LIGHT_WHITE_RGB);
    int                     x1, x2;
    int                     y1 = m_QuadrantY, y2 = m_QuadrantY + m_QuadrantHeight;
    unsigned int            i, pCount = (m_xMax - m_xMin) / X_UNIT_ONE;
    SYSTEMTIME              st;

    GetLocalTime(&st);
    format.SetAlignment(Gdiplus::StringAlignmentNear);

    // TODO: At least there are 3 scales ������3���̶�
    if (pCount == 0) pCount = 2;
    for (i = 0; i < pCount + 1; i++) 
    {
        x1 = x2 = m_QuadrantX + (m_QuadrantWidth / pCount) * i;
        if (X_UNIT_ONE < m_QuadrantWidth - x1) m_MemoryGraphics->DrawLine(&pen, x1, y1, x2, y2);
        // FIXME: Is the width suitable ����Ƿ����
        Gdiplus::RectF layoutRect(x1, y2 - SCALE_SIZE, X_UNIT_ONE * 16, SCALE_SIZE);
	    memset(pScale, 0, BUFFER_SIZE);
        if (m_xTime) 
        {
            swprintf(pScale, L"%d:%d:%d:%d", st.wHour, st.wMinute, st.wSecond, 
                    st.wMilliseconds / 100 + i);
        } 
        else 
        {
            swprintf(pScale, L"%d", m_xMin + X_UNIT_ONE * i);
        }
        if (i != 0 && i != pCount) m_MemoryGraphics->DrawString(pScale, -1, &font, layoutRect, &format, &solidBrush);
    }
}

// TODO: Draw Y axis scale ��Y��̶�
void CGDIPlusPlotCtrl::m_DrawYScale() 
{
    Gdiplus::FontFamily		fontFamily(L"Courier New");
	Gdiplus::Font			font(&fontFamily, SCALE_SIZE, Gdiplus::FontStyleRegular, 
            Gdiplus::UnitPixel);
    Gdiplus::StringFormat	format;
	Gdiplus::SolidBrush		solidBrush(WHITE_RGB), lightBrush(LIGHT_WHITE_RGB);
    wchar_t                 pScale[BUFFER_SIZE];
    Gdiplus::Pen            pen(LIGHT_WHITE_RGB);
    int                     x1 = m_QuadrantX, x2 = m_QuadrantX + m_QuadrantWidth;
    int                     y1, y2;
    unsigned int            i, pCount = (m_yMax - m_yMin) / Y_UNIT_ONE;

    format.SetAlignment(Gdiplus::StringAlignmentNear);

    // TODO: At least there are 3 scales ������3���̶�
    if (pCount == 0) pCount = 2;
    for (i = 0; i < pCount + 1; i++) 
    {
        y1 = y2 = m_QuadrantY + (m_QuadrantHeight / pCount) * i;
        if (Y_UNIT_ONE < m_QuadrantHeight - y1) 
        {
            m_MemoryGraphics->DrawLine(&pen, x1, y1, x2, y2);
        }
	    memset(pScale, 0, BUFFER_SIZE);
        // TODO: Draw Y min and max only ֻ��Y����С����ֵ
        if (i == 0) 
        {
            Gdiplus::RectF layoutRect(x1, y2, Y_UNIT_ONE * 6, SCALE_SIZE);
            swprintf(pScale, L"%d", m_yMin);
			m_MemoryGraphics->DrawString(pScale, -1, &font, layoutRect, &format, &lightBrush);
        }
        // TODO: Draw Y max here
        if (i == pCount) 
        {
            Gdiplus::RectF layoutRect(x1, y2 - SCALE_SIZE, Y_UNIT_ONE * 6, SCALE_SIZE);
            swprintf(pScale, L"%d", m_yMax);
			m_MemoryGraphics->DrawString(pScale, -1, &font, layoutRect, &format, &lightBrush);
        }
    }
	if (m_xTime) 
	{
		Gdiplus::RectF layoutRect(x1, m_QuadrantY + m_QuadrantHeight / 2 - SCALE_SIZE, 
			Y_UNIT_ONE * 6, SCALE_SIZE);
		m_MemoryGraphics->DrawString(m_annolabel, -1, &font, layoutRect, &format, &solidBrush);
	}
}

// TODO: Draw quadrant ������
void CGDIPlusPlotCtrl::m_DrawQuadrant(CRect rcBounds) 
{
	Gdiplus::SolidBrush	solidBrush(BLACK_RGB);

	//m_QuadrantX = LABEL_SIZE; 
    m_QuadrantX = 0;
    //m_QuadrantY = CAPTION_SIZE + MARGIN;
    m_QuadrantY = 0; 
    //m_QuadrantWidth = rcBounds.Width() - LABEL_SIZE - MARGIN; 
    m_QuadrantWidth = rcBounds.Width();
    //m_QuadrantHeight = rcBounds.Height() - CAPTION_SIZE - LABEL_SIZE - MARGIN * 2;
    m_QuadrantHeight = rcBounds.Height();

    // TODO: Draw each layer ���ղ��ѭ��
    m_MemoryGraphics->FillRectangle(&solidBrush, m_QuadrantX, m_QuadrantY, m_QuadrantWidth, 
            m_QuadrantHeight);

    // TODO: Draw X axis related thing ��X�����
    m_DrawXScale();

    // TODO: Draw Y axis related thing ��Y�����
    m_DrawYScale();

    // TODO: Draw XTime cursor ��XTimeʱ���α�
    if (m_xTime) m_DrawXTimeCursor();
    else m_DrawPlotXY();
}

/////////////////////////////////////////////////////////////////////////////
// CGDIPlusPlotCtrl::OnDraw - Drawing function

void CGDIPlusPlotCtrl::OnDraw(
			CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
	Gdiplus::Graphics pGraphics(pdc->m_hDC);
	Gdiplus::Bitmap pBitmap(rcBounds.Width(), rcBounds.Height());

	// TODO: Cache the GDI+ Graphics object handler ��Graphics���󻺴�
	m_MemoryGraphics = Gdiplus::Graphics::FromImage(&pBitmap);

	// TODO: Anti alias �����
	m_MemoryGraphics->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);

	// TODO: Fill the background color with the parent hWnd`s ���ؼ��ı���ɫ���ΪhWnd����ɫ
	OLE_COLOR pWndBkColor = AmbientBackColor();
	Gdiplus::Rect pWndRect(0, 0, rcBounds.Width(), rcBounds.Height());
	COLORREF pWndRGB = TranslateColor(pWndBkColor);
	Gdiplus::SolidBrush pWndBg(Gdiplus::Color(255, GetRValue(pWndRGB), 
		GetGValue(pWndRGB), GetBValue(pWndRGB)));
	m_MemoryGraphics->FillRectangle(&pWndBg, pWndRect);

	// TODO: Draw caption ������
	m_DrawCaption(rcBounds);
	
	// TODO: Draw X axis label ��X���ǩ
	//m_DrawXLabel(rcBounds);

	// TODO: Draw Y axis label ��Y���ǩ
	//m_DrawYLabel(rcBounds);

	// TODO: Draw quadrant ������
	m_DrawQuadrant(rcBounds);

    // TODO: Multi framebuffer
	pGraphics.DrawImage(&pBitmap, rcBounds.left, rcBounds.top);

	// TODO: Cleanup Gdiplus::Graphics object �ͷ�Graphics����ָ��
	if (m_MemoryGraphics) delete m_MemoryGraphics; m_MemoryGraphics = NULL;
}


/////////////////////////////////////////////////////////////////////////////
// CGDIPlusPlotCtrl::DoPropExchange - Persistence support

void CGDIPlusPlotCtrl::DoPropExchange(CPropExchange* pPX)
{
	ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
	COleControl::DoPropExchange(pPX);

	// TODO: Call PX_ functions for each persistent custom property.

}


/////////////////////////////////////////////////////////////////////////////
// CGDIPlusPlotCtrl::OnResetState - Reset control to default state

void CGDIPlusPlotCtrl::OnResetState()
{
	COleControl::OnResetState();  // Resets defaults found in DoPropExchange

	// TODO: Reset any other control state here.
}


/////////////////////////////////////////////////////////////////////////////
// CGDIPlusPlotCtrl::IsSubclassedControl - This is a subclassed control

BOOL CGDIPlusPlotCtrl::IsSubclassedControl()
{
	return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// CGDIPlusPlotCtrl::OnOcmCommand - Handle command messages

LRESULT CGDIPlusPlotCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam)
{
#ifdef _WIN32
	WORD wNotifyCode = HIWORD(wParam);
#else
	WORD wNotifyCode = HIWORD(lParam);
#endif

	// TODO: Switch on wNotifyCode here.

	return 0;
}


/////////////////////////////////////////////////////////////////////////////
// CGDIPlusPlotCtrl message handlers

void CGDIPlusPlotCtrl::OnTimer(UINT nIDEvent) 
{
	InvalidateControl();

	COleControl::OnTimer(nIDEvent);
}

void CGDIPlusPlotCtrl::PlotXY(double xValue, double yValue, short index) 
{
    point_t                         p;
	std::list<element_t>::iterator  pIter;

	// TODO: index is bigger than element count
	if (m_ElementCount < index) return ;

    p.x = m_QuadrantX + m_QuadrantWidth / (m_xMax - m_xMin) * (xValue - m_xMin);
    p.y = m_QuadrantY + m_QuadrantHeight / (m_yMax - m_yMin) * (yValue - m_yMin);

	for (pIter = m_ElementList.begin(); pIter != m_ElementList.end(); pIter++) 
	{
		if (index == (*pIter).index) 
		{
            (*pIter).pointlist.push_back(p);
			break;
		}
	}
}

BSTR CGDIPlusPlotCtrl::GetCaption() 
{
	return m_caption;
}

void CGDIPlusPlotCtrl::SetCaption(LPCTSTR lpszNewValue) 
{
	CString strTmp;

	strTmp = lpszNewValue;
	m_caption = strTmp.AllocSysString();

	SetModifiedFlag();
}

BOOL CGDIPlusPlotCtrl::GetXTime() 
{
	return m_xTime;
}

void CGDIPlusPlotCtrl::SetXTime(BOOL bNewValue) 
{
	m_xTime = bNewValue;
    if (m_xTime) SetTimer(XTIME_TIMER, XTIME_TIMER_INTERVAL, NULL);
	
    SetModifiedFlag();
}

void CGDIPlusPlotCtrl::SetRange(double xMin, double xMax, double yMin, double yMax) 
{
	m_xMin = xMin; 
	m_xMax = xMax; 
	m_yMin = yMin; 
	m_yMax = yMax;
}

BSTR CGDIPlusPlotCtrl::GetXLabel() 
{
	return m_xLabel;
}

void CGDIPlusPlotCtrl::SetXLabel(LPCTSTR lpszNewValue) 
{
	CString strTmp;

	strTmp = lpszNewValue;
	m_xLabel = strTmp.AllocSysString();

	SetModifiedFlag();
}

BSTR CGDIPlusPlotCtrl::GetYLabel() 
{
	return m_yLabel;
}

void CGDIPlusPlotCtrl::SetYLabel(LPCTSTR lpszNewValue) 
{
	CString strTmp;

	strTmp = lpszNewValue;
	m_yLabel = strTmp.AllocSysString();

	SetModifiedFlag();
}

short CGDIPlusPlotCtrl::GetInterval() 
{
	// TODO: Add your property handler here

	return 0;
}

void CGDIPlusPlotCtrl::SetInterval(short nNewValue) 
{
	// TODO: Add your property handler here

	SetModifiedFlag();
}

void CGDIPlusPlotCtrl::PlotY(double newValue, short index) 
{
	point_t                         p;
	std::list<element_t>::iterator  pIter;

	// TODO: index is bigger than element count
	if (m_ElementCount < index) return ;

    p.x = m_QuadrantX + m_CursorX;
    p.y = m_QuadrantY + m_QuadrantHeight / (m_yMax - m_yMin) * (newValue - m_yMin);

	for (pIter = m_ElementList.begin(); pIter != m_ElementList.end(); pIter++) 
	{
		if (index == (*pIter).index) 
		{
			(*pIter).pointlist.push_back(p);
			break;
		}
	}

	SetModifiedFlag();
}

BSTR CGDIPlusPlotCtrl::GetAnnolabel() 
{
	return m_annolabel;
}

void CGDIPlusPlotCtrl::SetAnnolabel(LPCTSTR lpszNewValue) 
{
	CString strTmp;

	strTmp = lpszNewValue;
	m_annolabel = strTmp.AllocSysString();

	SetModifiedFlag();
}

void CGDIPlusPlotCtrl::AddElement(short color) 
{
	element_t element;

	switch (color) 
	{
	default:
	case 0:
		element.color = GREEN_RGB;
		break;
	case 1:
		element.color = RED_RGB;
		break;
	case 2:
		element.color = BLUE_RGB;
		break;
	case 3:
		element.color = WHITE_RGB;
		break;
	case 4:
		element.color = YELLOW_RGB;
		break;
	}

	element.index = m_ElementCount;
	element.visible = TRUE;
	m_ElementList.push_back(element);
	m_ElementCount++;
}

void CGDIPlusPlotCtrl::ClearGraph() 
{
	std::list<element_t>::iterator pIter;

	m_CursorX = 0;

	for (pIter = m_ElementList.begin(); pIter != m_ElementList.end(); pIter++) 
	{
		(*pIter).pointlist.clear();
	}
}

void CGDIPlusPlotCtrl::IsElementVisible(short index, BOOL visible) 
{
	std::list<element_t>::iterator pIter;

	// TODO: index is bigger than element count
	if (m_ElementCount < index) return ;

	for (pIter = m_ElementList.begin(); pIter != m_ElementList.end(); pIter++) 
	{
		if (index == (*pIter).index) 
		{
			(*pIter).visible = visible;
			break;
		}
	}
}

void CGDIPlusPlotCtrl::OnSize(UINT nType, int cx, int cy) 
{
	COleControl::OnSize(nType, cx, cy);

	m_QuadrantX = LABEL_SIZE; 
    m_QuadrantY = CAPTION_SIZE + MARGIN; 
    m_QuadrantWidth = cx - LABEL_SIZE - MARGIN; 
    m_QuadrantHeight = cy - CAPTION_SIZE - LABEL_SIZE - MARGIN * 2;
}

BOOL CGDIPlusPlotCtrl::GetXTrack() 
{
	return m_xTrack;
}

void CGDIPlusPlotCtrl::SetXTrack(BOOL bNewValue) 
{
	m_xTrack = bNewValue;

	SetModifiedFlag();
}

void CGDIPlusPlotCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
    if (!m_xTrack || point.x < m_QuadrantX) return ;

    m_TrackX = point.x;
    m_TrackY = point.y;

    InvalidateControl();

	COleControl::OnMouseMove(nFlags, point);
}

void CGDIPlusPlotCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
    std::list<element_t>::iterator	EleIter;
	std::list<point_t>::iterator    PointIter;

    if (!m_xTime) return ;

	if (point.x < m_QuadrantWidth && 0 < point.x && 
            point.y < m_QuadrantHeight && 0 < point.y) 
    {
        if (abs(m_yMin) < MAX_RANGE_Y && abs(m_yMax) < MAX_RANGE_Y) 
        {
            m_yMin *= 2;
            m_yMax *= 2;
            if (!m_xTime) 
            {
                for (EleIter = m_ElementList.begin(); 
                        EleIter != m_ElementList.end(); EleIter++) 
                {
                    for (PointIter = (*EleIter).pointlist.begin(); 
                        PointIter != (*EleIter).pointlist.end(); PointIter++) 
                    {
						// FIXME: Relative postion issue but might be suitable 
                        // in realtime mode
                        (*PointIter).y /= 2;
                    }
                }
            }
            InvalidateControl();
        }
    } 
	
	COleControl::OnLButtonDown(nFlags, point);
}

void CGDIPlusPlotCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	std::list<element_t>::iterator	EleIter;
	std::list<point_t>::iterator    PointIter;

    if (!m_xTime) return ;

	if (point.x < m_QuadrantWidth && 0 < point.x && 
            point.y < m_QuadrantHeight && 0 < point.y) 
    {
        if (MIN_RANGE_Y < abs(m_yMin) && MIN_RANGE_Y < abs(m_yMax)) 
        {
            m_yMin /= 2;
            m_yMax /= 2;
            if (!m_xTime) 
            {
                for (EleIter = m_ElementList.begin(); 
                        EleIter != m_ElementList.end(); EleIter++) 
                {
                    for (PointIter = (*EleIter).pointlist.begin(); 
                        PointIter != (*EleIter).pointlist.end(); PointIter++) 
                    {
						(*PointIter).y *= 2;
                    }
                }
            }
            InvalidateControl();
        }
    } 
	
	COleControl::OnRButtonDown(nFlags, point);
}

void CGDIPlusPlotCtrl::SetXCursorPos(double xValue) 
{
	m_CursorX = xValue;
}

double CGDIPlusPlotCtrl::GetQuadrantWidth() 
{
	return m_QuadrantWidth;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author

Leslie Zhai
Engineer
China China
An individual human existence should be like a river - small at first, narrowly contained within its banks, and rushing passionately past boulders and over waterfalls. Gradually the river grows wider, the banks recede, the waters flow more quietly, and in the end, without any visible break, they become merged in the sea, and painlessly lose their individual being.
Follow on   Twitter   Google+   LinkedIn

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 6 Sep 2013
Article Copyright 2009 by Leslie Zhai
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid