自己寫的MFC曲線控件類

之前因爲實驗室做的一個項目中需要進行實時動態的曲線顯示,在mfc上本來就沒有多少可用的高級控件。負責這部分的學長用了mschart來做實時的曲線顯示,但是效果基本還可以,但是因爲重繪導致的閃爍還是很讓客戶覺得不是很好。所以後來我接手這部分後,就決定開始重新寫一個曲線控件。從實現的效果來看,基本還是滿足要求的。

主要的思想就是重繪,所有的東西都是畫出來的。windows的所有控件都是畫出來的,譬如按鈕,簡單來說就是一個方塊。只是檢測鼠標位置以及鼠標事件,當鼠標點擊以及鼠標位置在方塊位置上時,就表示這個按鈕被點擊了。所以自己模擬就可以了。這個也是現在windows下主流的一種客戶端程序編程方法directUI。例如QQ的客戶端、360的客戶端等等都是利用這種方法完成的。不說這些,直接給出代碼吧。

先給效果圖吧!


#pragma once

#include <math.h>
#include <vector>
using namespace std;

struct LinePoint //ÕÛÏßµãÊýŸÝ
{
	float x;
	float y;

	LinePoint(float a, float b)
	{
		x = a;
		y = b;
	}
};

struct LineChartData
{
	vector<LinePoint> vecPoint; //µãÊýŸÝ

	CString strLegend;       //ÕÛÏß±êÇ©£¬Íš¹ýžÃ±êǩΚһȷ¶šÒ»ÌõÕÛÏß

	bool bIsShow;            //ÊÇ·ñÏÔÊŸ

	//ÓÃÓÚ¹¹œšÕÛÏß»­±Ê
	int nLineStyle;          //ÕÛÏß·çžñ
	int nLineWidth;          //ÕÛÏß¿í¶È
	COLORREF cfLineColor;    //ÕÛÏßÑÕÉ«
};

// CLineChart
class CLineChart : public CWnd
{
	DECLARE_DYNAMIC(CLineChart)
private:
	COLORREF m_cfBkColor;  //ÕÛÏßÍŒ±³Ÿ°ÑÕÉ«

	CRect m_rectLine;    //ÕÛÏßÇøÓòλÖ㬻æÖÆÕÛÏßÇøÓò
	CRect m_rectClient;  //¿Í»§ÇøÇøÓòλÖÃ

	int m_nTitleHeight;  //±êÌâžß¶È
	CString m_strTitle;  //±êÌâÎÄ×Ö
	CFont* m_pTitleFont; //±êÌâÎÄ×Ö×ÖÌå
	int m_nLegendWidth;  //ÕÛÏß±êÇ©ÎıŸ¿í¶È
	CFont* m_pLegendFont; //±êÇ©ÎıŸ×ÖÌå

	bool m_bIsXShowGrid; //XÖáÏÔÊŸÍøžñ±êÖŸ
	float m_fXAxisStart; //XÖῪʌµã
	float m_fXAxisStop;  //XÖáœáÊøµã
	float m_fXAxisStep;  //XÖᲜ³€
	CFont* m_pXAxisPointFont; //XÖá×ø±êµã×ÖÌå
	CString m_strXAxisLegend; //XÖá±êÇ©ÎıŸ
	CFont* m_pXAxisLegendFont; //XÖá±êÇ©ÎıŸ×ÖÌå
	int m_nXAxisHeight;  //XÖá±êÇ©Óë×ø±êµãžß¶È

	bool m_bIsYShowGrid; //YÖáÏÔÊŸÍøžñ±êÖŸ
	float m_fYAxisStart; //YÖῪʌµã
	float m_fYAxisStop;  //YÖáœáÊøµã
	float m_fYAxisStep;  //YÖᲜ³€
	CString m_strYAxisLegend; //YÖá±êÇ©ÎıŸ
	CFont* m_pYAxisPointFont; //YÖá×ø±êµã×ÖÌå
	CFont* m_pYAxisLegendFont; //YÖá±êÇ©ÎıŸ×ÖÌå
	int m_nYAxisWidth;  //YÖá±êÇ©Óë×ø±êµãžß¶È

	CPen* m_pPenGrid;//Íøžñ»­±Ê
	CPen* m_pPenAxis;//×ø±êÖá»­±Ê

	vector<LineChartData> m_vecChartData;

public:
	CLineChart();
	virtual ~CLineChart();
	virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);

	bool AddLine(CString strLegend, COLORREF cfColor, bool bIsShow = true);//ÌíŒÓÖ±Ïß
	bool AddLine(CString strLegend, COLORREF cfColor, int nLineStyle, int nLineWidth, bool bIsShow = true);//ÌíŒÓÖ±Ïß
	bool AddLineData(CString strLegend, LinePoint point);//ΪֱÏßÌíŒÓÒ»žöÊýŸÝµã
	bool AddLineData(CString strLegend, vector<LinePoint> vecPoint);//ΪֱÏßÌíŒÓһϵÁÐÊýŸÝµã

	void SetBkColor(COLORREF cfColor);//ÉèÖñ³Ÿ°ÑÕÉ«
	void SetTitleText(CString strTitle);//ÉèÖñêÌâÀžÎıŸ
	void SetXAxisText(CString strText);//ÉèÖÃXÖá±êÇ©
	void SetYAxisText(CString strText);//ÉèÖÃYÖá±êÇ©
	void SetXAxisData(float fStart, float fStop, float fStep);//ÉèÖÃXÖáµÄÊýŸÝÊôÐÔ£¬°üÀš¿ªÊŒ×ø±ê£¬œáÊø×ø±êÓ벜³€
	void SetYAxisData(float fStart, float fStop, float fStep);//ÉèÖÃYÖáµÄÊýŸÝÊôÐÔ£¬°üÀš¿ªÊŒ×ø±ê£¬œáÊø×ø±êÓ벜³€
	void ShowXAxisGrid(bool bIsShow);//ÏÔÊŸXÖáµÄÍøžñ
	void ShowYAxisGrid(bool bIsShow);//ÏÔÊŸYÖáµÄÍøžñ


protected:
	DECLARE_MESSAGE_MAP()
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnPaint();

	void DrawLine(vector<LineChartData>::iterator itor, CDC* pDC);//»æÖÆÕÛÏß
	void DrawTitle(CDC* pDC);//»æÖƱêÌâÀž
	void DrawLegend(CDC* pDC);//»æÖƱêÇ©ÎıŸ
	void DrawXAxis(CDC* pDC);//»æÖÆXÖá±êÇ©ÎıŸÍøžñ
	void DrawYAxis(CDC* pDC);//»æÖÆXÖá±êÇ©ÎıŸÍøžñ
};

// LineChart.cpp : ʵÏÖÎÄŒþ
//

#include "stdafx.h"
#include "ChartTest.h"
#include "LineChart.h"


// CLineChart

IMPLEMENT_DYNAMIC(CLineChart, CWnd)

CLineChart::CLineChart()
{
	m_cfBkColor = RGB(236, 233, 216);

	m_nTitleHeight = 20;
	m_strTitle = _T("ÎÒÊÇÒ»žö±êÌâÀž");
	m_pTitleFont = new CFont();
	m_pTitleFont->CreatePointFont(120, _T("ËÎÌå"));
	m_nLegendWidth = 30;
	m_pLegendFont = new CFont();
	m_pLegendFont->CreatePointFont(100, _T("ËÎÌå"));

	m_bIsXShowGrid = true;
	m_fXAxisStart = 0;
	m_fXAxisStop = 10;
	m_fXAxisStep = 1;
	m_pXAxisPointFont = new CFont();
	m_pXAxisPointFont->CreatePointFont(90, _T("ËÎÌå"));
	m_strXAxisLegend = _T("XÖá±êÇ©±êÇ©");
	m_pXAxisLegendFont = new CFont();
	m_pXAxisLegendFont->CreatePointFont(120, _T("ËÎÌå"));
	m_nXAxisHeight = 20;

	m_bIsYShowGrid = true;
	m_fYAxisStart = 0;
	m_fYAxisStop = 10;
	m_fYAxisStep = 1;
	m_pYAxisPointFont = new CFont();
	m_pYAxisPointFont->CreatePointFont(90, _T("ËÎÌå"));
	m_strYAxisLegend = _T("YÖá");
	m_pYAxisLegendFont = new CFont();
	m_pYAxisLegendFont->CreateFontW(18, 0, 900, 900, FW_NORMAL,
		0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
		DEFAULT_PITCH, _T("Arial")); 
//	m_pYAxisLegendFont->CreatePointFont(120, _T("ËÎÌå"));

	m_pPenGrid = new CPen();
	m_pPenGrid->CreatePen(PS_DOT, 1, RGB(0, 0, 0));
	m_pPenAxis = new CPen();
	m_pPenAxis->CreatePen(PS_SOLID, 1, RGB(0, 0, 0));

	m_nYAxisWidth = 20;
}

CLineChart::~CLineChart()
{
	if (NULL != m_pPenAxis)
	{
		m_pPenAxis->DeleteObject();
	}
	if (NULL != m_pPenGrid)
	{
		m_pPenGrid->DeleteObject();
	}
	if (NULL != m_pLegendFont)
	{
		m_pLegendFont->DeleteObject();
	}
	if (NULL != m_pTitleFont)
	{
		m_pTitleFont->DeleteObject();
	}
	if (NULL != m_pXAxisLegendFont)
	{
		m_pXAxisLegendFont->DeleteObject();
	}
	if (NULL != m_pXAxisPointFont)
	{
		m_pXAxisPointFont->DeleteObject();
	}
	if (NULL != m_pYAxisLegendFont)
	{
		m_pYAxisLegendFont->DeleteObject();
	}
	if (NULL != m_pYAxisPointFont)
	{
		m_pYAxisPointFont->DeleteObject();
	}
}


BEGIN_MESSAGE_MAP(CLineChart, CWnd)
	ON_WM_CREATE()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
END_MESSAGE_MAP()



// CLineChart ÏûÏ¢ŽŠÀí³ÌÐò


BOOL CLineChart::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
	// TODO: ÔÚŽËÌíŒÓךÓÃŽúÂëºÍ/»òµ÷ÓûùÀà
	return CWnd::Create(NULL, _T(""), WS_CHILD | WS_VISIBLE, rect, pParentWnd, nID);
}

int CLineChart::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	return 0;
}

void CLineChart::SetBkColor(COLORREF cfColor)
{
	m_cfBkColor = cfColor;
}

BOOL CLineChart::OnEraseBkgnd(CDC* pDC)
{
	// TODO: ÔÚŽËÌíŒÓÏûÏ¢ŽŠÀí³ÌÐòŽúÂëºÍ/»òµ÷ÓÃĬÈÏÖµ
	return true;
}


void CLineChart::OnPaint()
{
	CPaintDC dc(this);
	CDC* pMemDC = new CDC();
	CBitmap* pBmp = new CBitmap();
	CSize szExent;

	//»ñÈ¡¿Í»§ÇøλÖÃ
	GetClientRect(m_rectClient);

	pMemDC->CreateCompatibleDC(&dc);
	pBmp->CreateCompatibleBitmap(&dc, m_rectClient.Width(), m_rectClient.Height());
	pMemDC->SelectObject(pBmp);
	pMemDC->SetBkMode(TRANSPARENT);

	//»æÖƱ³Ÿ°
	pMemDC->FillSolidRect(m_rectClient, m_cfBkColor);

	DrawTitle(pMemDC);//»æÖƱêÌâÀž
	DrawLegend(pMemDC);//»æÖƱêÇ©Àž

	//ÐÞžÄXÖá±êÇ©Àžžß¶È
	pMemDC->SelectObject(m_pXAxisLegendFont);
	szExent = pMemDC->GetTextExtent(m_strXAxisLegend);
	m_nXAxisHeight = szExent.cy + 10;
	pMemDC->SelectObject(m_pXAxisPointFont);
	szExent = pMemDC->GetTextExtent(m_strXAxisLegend);
	m_nXAxisHeight += szExent.cy + 5;


	//»æÖÆYÖá
	DrawYAxis(pMemDC);

	//»æÖÆXÖá
	DrawXAxis(pMemDC);

	//É趚ÕÛÏß»æÖÆÇøÓòŽóС
	m_rectLine.top = m_nTitleHeight;
	m_rectLine.bottom = m_rectClient.bottom - m_nXAxisHeight;
	m_rectLine.left = m_nYAxisWidth;
	m_rectLine.right = m_rectClient.right - m_nLegendWidth;

	//»æÖÆÕÛÏß
	for (vector<LineChartData>::iterator itor = m_vecChartData.begin(); itor != m_vecChartData.end(); itor++)
	{
		if ((*itor).bIsShow)
		{
			DrawLine(itor, pMemDC);
		}
	}

	dc.BitBlt(0, 0, m_rectClient.Width(), m_rectClient.Height(), pMemDC, 0, 0, SRCCOPY);

	pBmp->DeleteObject();
	ReleaseDC(pMemDC);
	ReleaseDC(&dc);
}

void CLineChart::DrawTitle(CDC* pDC)
{
	//È·¶š±êÌâÀžžß¶È
	pDC->SelectObject(m_pTitleFont);
	CSize szExent = pDC->GetTextExtent(m_strTitle);
	CPoint pt;
	m_nTitleHeight = szExent.cy + 20;

	//»æÖƱêÌâ
	szExent = pDC->GetTextExtent(m_strTitle);
	pt.x = (m_rectClient.Width() - szExent.cx) / 2;
	pt.y = (m_nTitleHeight - szExent.cy) / 2;
	pDC->TextOutW(pt.x, pt.y, m_strTitle);
}

void CLineChart::DrawLegend(CDC* pDC)
{
	CSize szExent;
	CPoint pt;
	
	pDC->SelectObject(m_pLegendFont);
	m_nLegendWidth = -1;
	//»ñÈ¡×îŽóµÄ±êÇ©ÎıŸ³€¶ÈÓÃÓÚÈ·¶š±êÇ©ÀžµÄ¿í¶È
	for (vector<LineChartData>::iterator itor = m_vecChartData.begin(); itor != m_vecChartData.end(); itor++)
	{
		if ((*itor).bIsShow)
		{
			szExent = pDC->GetTextExtent((*itor).strLegend);
			if (szExent.cx > m_nLegendWidth)
			{
				m_nLegendWidth = szExent.cx;
			}
		}
	}
	m_nLegendWidth += 40;

	//»æÖƱêÇ©ÀžÎıŸÓëÑÕÉ«±êʶÏß
	pt.x = m_rectClient.right - m_nLegendWidth + 40;
	pt.y = m_rectClient.top + m_nTitleHeight + 10;
	for (vector<LineChartData>::iterator itor = m_vecChartData.begin(); itor != m_vecChartData.end(); itor++)
	{
		if ((*itor).bIsShow)
		{
			CPen* pPen = new CPen();
			pPen->CreatePen(PS_SOLID, 2, (*itor).cfLineColor);
			pDC->SelectObject(pPen);
			pDC->MoveTo(pt.x - 30, pt.y + szExent.cy / 2);
			pDC->LineTo(pt.x - 5, pt.y + szExent.cy / 2);

			pDC->TextOutW(pt.x, pt.y, (*itor).strLegend);
			pt.y += 10 + szExent.cy;
			pPen->DeleteObject();
		}
	}
}

void CLineChart::DrawYAxis(CDC* pDC)
{
	//»æÖÆYÖá±êÇ©
	CPoint pt;
	int nMaxWidth = 0; //×ø±êÖµµÄ×îŽó¿í¶È
	CString str;
	int nStep ;//×ø±êÖµÖ®Œä»æÖƵĿí¶ÈÏñËØŒäžô

	pDC->SelectObject(m_pYAxisLegendFont);
	CSize szExent = pDC->GetTextExtent(m_strYAxisLegend);
	pt.x = 5;
	pt.y = (m_rectClient.Height() - m_nTitleHeight - szExent.cy) / 2;
	pDC->TextOutW(pt.x, pt.y, m_strYAxisLegend);

	//»æÖÆYÖá×ø±ê
	pDC->SelectObject(m_pYAxisPointFont);
	m_nYAxisWidth = pt.x + szExent.cy + 10;
	//»ñÈ¡×îŽóµÄYÖá×ø±êÖµ¿í¶È
	for (float i = m_fYAxisStart; i <= m_fYAxisStop; i += m_fYAxisStep) //»ñÈ¡YÖá×ø±ê×îŽó¿í¶È
	{
		str.Format(_T("%.2f"), i);
		szExent = pDC->GetTextExtent(str);
		if (nMaxWidth < szExent.cx)
		{
			nMaxWidth = szExent.cx;
		}
	}
	m_nYAxisWidth += nMaxWidth;


	//»æÖÆYÖá×ø±êÖá,°üÀšŒýÍ·ÓëÖ±ÏßÖá
	pDC->SelectObject(m_pPenAxis);
	pDC->MoveTo(m_nYAxisWidth - 3, m_rectClient.top + m_nTitleHeight - 7);
	pDC->LineTo(m_nYAxisWidth, m_rectClient.top + m_nTitleHeight - 15);
	pDC->LineTo(m_nYAxisWidth + 3, m_rectClient.top + m_nTitleHeight - 7);
	pDC->MoveTo(m_nYAxisWidth, m_rectClient.top + m_nTitleHeight - 15);
	pDC->LineTo(m_nYAxisWidth, m_rectClient.bottom - m_nXAxisHeight);


	nStep = (m_rectClient.Height() - m_nTitleHeight - m_nXAxisHeight) / ((m_fYAxisStop - m_fYAxisStart) / m_fYAxisStep);

	if (nStep < 40) //µ÷ÕûYÖᲜ³€
	{
		m_fYAxisStep *= 2;
		m_fYAxisStop = ceil((m_fYAxisStop - m_fYAxisStart) / m_fYAxisStep) * m_fYAxisStep + m_fYAxisStart;
		Invalidate();
		return;
	}

	//»æÖÆYÖá×ø±êµã£¬×ø±êλÖÃÓëÍøžñ
	for (float i = m_fYAxisStart; i <= m_fYAxisStop; i += m_fYAxisStep)
	{
		//»æÖÆYÖá×ø±êµã
		str.Format(_T("%.2f"), i);
		szExent = pDC->GetTextExtent(str);
		pt.x = m_nYAxisWidth - szExent.cx - 5;
		pt.y = m_rectClient.bottom - m_nXAxisHeight - (i - m_fYAxisStart) / m_fYAxisStep * nStep - szExent.cy / 2;
		pDC->TextOutW(pt.x, pt.y, str);

		//»æÖÆYÖá×ø±êµãλÖÃ
		pDC->SelectObject(m_pPenAxis);
		pDC->MoveTo(m_nYAxisWidth, pt.y + szExent.cy / 2);
		pDC->LineTo(m_nYAxisWidth + 5, pt.y + szExent.cy / 2);

		//»æÖÆYÖáÍøžñ
		if (m_bIsYShowGrid)
		{
			pDC->SelectObject(m_pPenGrid);
			pDC->LineTo(m_rectClient.right - m_nLegendWidth, pt.y + szExent.cy / 2);
		}
	}

	//ŒÆËã×îÓÒ±ßXÖáÍøžñÏßλÖÃ
	pDC->SelectObject(m_pXAxisPointFont);
	str.Format(_T("%.0f"), m_fXAxisStop);
	szExent = pDC->GetTextExtent(str);

	//XÖá×ø±êµãλÖòœ³€
	nStep = (m_rectClient.Width() - m_nYAxisWidth - m_nLegendWidth) / ((m_fXAxisStop - m_fXAxisStart) / m_fXAxisStep);
	if (nStep < 40) //µ÷ÕûXÖᲜ³€
	{
		m_fXAxisStep *= 2;

		m_fXAxisStop = ceil((m_fXAxisStop - m_fXAxisStart) / m_fXAxisStep) * m_fXAxisStep + m_fXAxisStart;

		Invalidate();
		return;
	}

	pt.x = m_rectClient.left + m_nYAxisWidth + (m_fXAxisStop - m_fXAxisStart) / m_fXAxisStep * nStep - szExent.cx / 2;
	pt.y = m_rectClient.bottom - m_nXAxisHeight + 5;


	//Èô»æÖÆYÖáÍøžñ,µ«²»»æÖÆXÖáÍøžñÏߣ¬Ôò»æÖÆ×îÓÒ±ßXÖáÍøžñÏß
	if (m_bIsYShowGrid && !m_bIsXShowGrid)
	{
		pDC->MoveTo(pt.x  + szExent.cx / 2, m_rectClient.bottom - m_nXAxisHeight - 5);
		pDC->LineTo(pt.x  + szExent.cx / 2, m_rectClient.top + m_nTitleHeight);
	}
	
	if (m_bIsYShowGrid)
	{
		//È¥³ý×îÓÒ±ßXÖáÍøžñÏßÓұߵĶàÓàÍøžñÏß
		CRect rectClear;
		rectClear.left = pt.x  + szExent.cx / 2 + 1;
		rectClear.right = m_rectClient.right - m_nLegendWidth;
		rectClear.bottom = m_rectClient.bottom - m_nXAxisHeight - 1;
		rectClear.top = m_rectClient.top + m_nTitleHeight + 1;

		pDC->FillSolidRect(rectClear, m_cfBkColor);
	}
}

void CLineChart::DrawXAxis(CDC* pDC)
{
	//»æÖÆXÖá±êÇ©
	CPoint pt;
	int nStep; //XÖá×ø±êŒäµÄÏñËØŒäžô
	CString str;
	pDC->SelectObject(m_pXAxisLegendFont);
	CSize szExent = pDC->GetTextExtent(m_strXAxisLegend);
	pt.x = (m_rectClient.Width() - m_nYAxisWidth - m_nLegendWidth - szExent.cx) / 2 + m_nYAxisWidth;
	pt.y = m_rectClient.bottom - szExent.cy - 5;
	pDC->TextOutW(pt.x, pt.y, m_strXAxisLegend);

	//»æÖÆXÖá×ø±êÖᣬ°üÀšŒýÍ·ÓëÖ±ÏßÖá
	pDC->SelectObject(m_pPenAxis);
	pDC->MoveTo(m_rectClient.right - m_nLegendWidth + 7, m_rectClient.bottom - m_nXAxisHeight - 3);
	pDC->LineTo(m_rectClient.right - m_nLegendWidth + 15, m_rectClient.bottom - m_nXAxisHeight);
	pDC->LineTo(m_rectClient.right - m_nLegendWidth + 7, m_rectClient.bottom - m_nXAxisHeight + 3);
	pDC->MoveTo(m_nYAxisWidth, m_rectClient.bottom - m_nXAxisHeight);
	pDC->LineTo(m_rectClient.right - m_nLegendWidth + 15, m_rectClient.bottom - m_nXAxisHeight);

	pDC->SelectObject(m_pXAxisPointFont);
	nStep = (m_rectClient.Width() - m_nYAxisWidth - m_nLegendWidth) / ((m_fXAxisStop - m_fXAxisStart) / m_fXAxisStep);

	if (nStep < 40) //µ÷ÕûXÖᲜ³€
	{
		m_fXAxisStep *= 2;

		m_fXAxisStop = ceil((m_fXAxisStop - m_fXAxisStart) / m_fXAxisStep) * m_fXAxisStep + m_fXAxisStart;

		Invalidate();
		return;
	}

	for (float i = m_fXAxisStart; i <= m_fXAxisStop; i += m_fXAxisStep)
	{
		//»æÖÆXÖá×ø±êµã
		str.Format(_T("%.0f"), i);
		szExent = pDC->GetTextExtent(str);
		pt.x = m_rectClient.left + m_nYAxisWidth + (i - m_fXAxisStart) / m_fXAxisStep * nStep - szExent.cx / 2;
		pt.y = m_rectClient.bottom - m_nXAxisHeight + 5;
		pDC->TextOutW(pt.x, pt.y, str);

		//»æÖÆXÖá×ø±êµãλÖÃ
		pDC->SelectObject(m_pPenAxis);
		pDC->MoveTo(pt.x + szExent.cx / 2, m_rectClient.bottom - m_nXAxisHeight);
		pDC->LineTo(pt.x  + szExent.cx / 2, m_rectClient.bottom - m_nXAxisHeight - 5);


		//»æÖÆXÖá±ížñ
		if (m_bIsXShowGrid)
		{
			pDC->SelectObject(m_pPenGrid);
			pDC->LineTo(pt.x  + szExent.cx / 2, m_rectClient.top + m_nTitleHeight);
		}
	}


	//ŒÆËãYÖá×îÉÏÃæÍøžñÏßλÖÃ
	pDC->SelectObject(m_pYAxisPointFont);
	str.Format(_T("%.2f"), m_fYAxisStop);
	szExent = pDC->GetTextExtent(str);

	//YÖá×ø±êµãÏñËØλÖòœ³€
	nStep = (m_rectClient.Height() - m_nTitleHeight - m_nXAxisHeight) / ((m_fYAxisStop - m_fYAxisStart) / m_fYAxisStep);

	if (nStep < 40) //µ÷ÕûYÖᲜ³€
	{
		m_fYAxisStep *= 2;
		m_fYAxisStop = ceil((m_fYAxisStop - m_fYAxisStart) / m_fYAxisStep) * m_fYAxisStep + m_fYAxisStart;
		Invalidate();
		return;
	}

	pt.x = m_nYAxisWidth - szExent.cx - 5;
	pt.y = m_rectClient.bottom - m_nXAxisHeight - (m_fYAxisStop - m_fYAxisStart) / m_fYAxisStep * nStep - szExent.cy / 2;

	//Èô»æÖÆXÖáÍøžñ,µ«²»»æÖÆYÖáÍøžñÏߣ¬Ôò»æÖÆ×îÉÏÃæYÖáÍøžñÏß
	if (!m_bIsYShowGrid && m_bIsXShowGrid)
	{
		pDC->MoveTo(m_nYAxisWidth + 5, pt.y + szExent.cy / 2);
		pDC->LineTo(m_rectClient.right - m_nLegendWidth, pt.y + szExent.cy / 2);
	}
	
	if (m_bIsXShowGrid)
	{
		//È¥³ý×îÉÏÃæYÖáÍøžñÏßÉϱߵĶàÓàÍøžñÏß
		CRect rectClear;
		rectClear.left = m_rectClient.left + m_nYAxisWidth + 1;
		rectClear.right = m_rectClient.right - m_nLegendWidth;
		rectClear.bottom = pt.y + szExent.cy / 2;
		rectClear.top = m_rectClient.top + m_nTitleHeight + 1;

		pDC->FillSolidRect(rectClear, m_cfBkColor);
	}

}

void CLineChart::DrawLine(vector<LineChartData>::iterator itor, CDC* pDC)
{
	//ŽŽœšÕÛÏß»­±Ê
	CPen* pPen = new CPen();
	CPoint pt;
	int nXStep = m_rectLine.Width() / ((m_fXAxisStop - m_fXAxisStart) / m_fXAxisStep);
	int nYStep = m_rectLine.Height() / ((m_fYAxisStop - m_fYAxisStart) / m_fYAxisStep);

	pPen->CreatePen((*itor).nLineStyle, (*itor).nLineWidth, (*itor).cfLineColor);
	pDC->SelectObject(pPen);

	vector<LinePoint>::iterator ptItor = (*itor).vecPoint.begin();

	while (ptItor != (*itor).vecPoint.end())
	{
		if ((*ptItor).x < m_fXAxisStart && (*ptItor).x > m_fXAxisStop)
		{
			continue;
		}
		
		if ((*ptItor).y < m_fYAxisStart)
		{
			m_fYAxisStart -= (int)((m_fYAxisStart - (*ptItor).y) / m_fYAxisStep + 1) * m_fYAxisStep;
			Invalidate();
			return;
		}
		else if ((*ptItor).y > m_fYAxisStop)
		{
			m_fYAxisStop += (int)(((*ptItor).y - m_fYAxisStop) / m_fYAxisStep + 1) * m_fYAxisStep;
			Invalidate();
			return;
		}
		else
		{
			//È·¶šÕÛÏßµãλÖÃ
			pt.x = m_rectLine.left + ((*ptItor).x - m_fXAxisStart) / m_fXAxisStep * nXStep;
			pt.y = m_rectLine.bottom - ((*ptItor).y - m_fYAxisStart) / m_fYAxisStep * nYStep;

			//»æÖÆÕÛÏß
			if (ptItor == (*itor).vecPoint.begin())
			{
				pDC->MoveTo(pt.x, pt.y);
			}
			else
			{
				pDC->LineTo(pt.x, pt.y);
			}
		}
		ptItor++;
	}

	pPen->DeleteObject();
}

bool CLineChart::AddLine(CString strLegend, COLORREF cfColor, bool bIsShow)
{
	vector<LineChartData>::iterator itor = m_vecChartData.begin();
	bool bIsExist = false; //ÅжÏÕÛÏßÊÇ·ñÒÑŸ­ŽæÔÚ

	while (itor != m_vecChartData.end())
	{
		if ((*itor).strLegend == strLegend)
		{
			bIsExist = true;
			break;
		}
		itor++;
	}

	if (bIsExist) //žÃÕÛÏßÒÑŸ­ŽæÔÚ£¬žü»»±êÇ©ÎıŸºóÖØÐÂÌíŒÓ
	{
		return false;
	}
	else
	{
		//ÌíŒÓžÃÕÛÏß
		LineChartData line;
		line.strLegend = strLegend;
		line.cfLineColor = cfColor;
		line.nLineStyle = PS_SOLID;
		line.nLineWidth = 1;
		line.bIsShow = bIsShow;
		m_vecChartData.push_back(line);

		return true;
	}
}

bool CLineChart::AddLine(CString strLegend, COLORREF cfColor, int nLineStyle, int nLineWidth, bool bIsShow)
{
	vector<LineChartData>::iterator itor = m_vecChartData.begin();
	bool bIsExist = false; //ÅжÏÕÛÏßÊÇ·ñÒÑŸ­ŽæÔÚ

	while (itor != m_vecChartData.end())
	{
		if ((*itor).strLegend == strLegend)
		{
			bIsExist = true;
			break;
		}
		itor++;
	}

	if (bIsExist) //žÃÕÛÏßÒÑŸ­ŽæÔÚ£¬žü»»±êÇ©ÎıŸºóÖØÐÂÌíŒÓ
	{
		return false;
	}
	else
	{
		//ÌíŒÓžÃÕÛÏß
		LineChartData line;
		line.strLegend = strLegend;
		line.cfLineColor = cfColor;
		line.nLineStyle = nLineStyle;
		line.nLineWidth = nLineWidth;
		line.bIsShow = bIsShow;
		m_vecChartData.push_back(line);

		return true;
	}
}

bool CLineChart::AddLineData(CString strLegend, LinePoint point)
{
	vector<LineChartData>::iterator itor = m_vecChartData.begin();

	for (;itor != m_vecChartData.end(); itor++)
	{
		if ((*itor).strLegend == strLegend)
		{
			(*itor).vecPoint.push_back(point);

			if (point.x > m_fXAxisStop)
			{
				m_fXAxisStop += ceil((point.x - m_fXAxisStop) / m_fXAxisStep) * m_fXAxisStep; 
			}
			else if (point.x < m_fXAxisStart)
			{
				m_fXAxisStart -= ceil((m_fXAxisStart - point.x) / m_fXAxisStep) * m_fXAxisStep; 
			}

			return true;
		}
	}
	return false;
}

bool CLineChart::AddLineData(CString strLegend, vector<LinePoint> vecPoint)
{
	vector<LineChartData>::iterator itor = m_vecChartData.begin();
	vector<LinePoint>::iterator ptItor = vecPoint.begin();

	for (;itor != m_vecChartData.end(); itor++)
	{
		if ((*itor).strLegend == strLegend)
		{
			for (; ptItor != vecPoint.end(); ptItor++)
			{
				(*itor).vecPoint.push_back((*ptItor));

				if ((*ptItor).x > m_fXAxisStop)
				{
					m_fXAxisStop += ceil(((*ptItor).x - m_fXAxisStop) / m_fXAxisStep) * m_fXAxisStep; 
				}
				else if ((*ptItor).x < m_fXAxisStart)
				{
					m_fXAxisStart -= ceil((m_fXAxisStart - (*ptItor).x) / m_fXAxisStep) * m_fXAxisStep; 
				}
			}

			return true;
		}
	}
	return false;
}

void CLineChart::SetTitleText(CString strTitle)
{
	m_strTitle = strTitle;
}

void CLineChart::SetXAxisText(CString strText)
{
	m_strXAxisLegend = strText;
}

void CLineChart::SetYAxisText(CString strText)
{
	m_strYAxisLegend = strText;
}

void CLineChart::SetXAxisData(float fStart, float fStop, float fStep)
{
	m_fXAxisStart = fStart;
	m_fXAxisStop = fStop;
	m_fXAxisStep = fStep;
}

void CLineChart::SetYAxisData(float fStart, float fStop, float fStep)
{
	m_fYAxisStart = fStart;
	m_fYAxisStop = fStop;
	m_fYAxisStep = fStep;
}

void CLineChart::ShowXAxisGrid(bool bIsShow)
{
	m_bIsXShowGrid = bIsShow;
}

void CLineChart::ShowYAxisGrid(bool bIsShow)
{
	m_bIsYShowGrid = bIsShow;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章