用户注册



邮箱:

密码:

用户登录


邮箱:

密码:
记住登录一个月忘记密码?

发表随想


还能输入:200字
云代码 - c++代码库

函数绘图程序

2016-08-14 作者: 小章举报

[c++]代码库

/*
 *
 *  ChartCtrl.cpp
 *
 *  Written by C閐ric Moonen (cedric_moonen@hotmail.com)
 *
 *
 *
 *  This code may be used for any non-commercial and commercial purposes in a compiled form.
 *  The code may be redistributed as long as it remains unmodified and providing that the
 *  author name and this disclaimer remain intact. The sources can be modified WITH the author
 *  consent only.
 
 *  This code is provided without any garanties. I cannot be held responsible for the damage or
 *  the loss of time it causes. Use it at your own risks
 *
 *  An e-mail to notify me that you are using this code is appreciated also.
 *
 *
 *  History:
 *      - 18/05/2006: Added support for panning
 *      - 28/05/2006: Bug corrected in RemoveAllSeries
 *      - 28/05/2006: Added support for resizing
 *      - 12/06/2006: Added support for manual zoom
 *      - 10/08/2006: Added SetZoomMinMax and UndoZoom
 *      - 24/03/2007: GDI leak corrected
 *      - 24/03/2007: Invisible series are not taken in account for auto axis
 *                    and legend (thanks to jerminator-jp).
 *      - 24/03/2007: possibility to specify a margin for the axis. Needs to be improved
 *      - 05/04/2007: ability to change the text color of the axis.
 *      - 05/04/2007: ability to change the color of the border of the drawing area.
 *      - 05/04/2007: Surface series added.
 *      - 26/08/2007: The clipping area of the series is a bit larger (they will be
 *                    drawn over the bottom and right axes).
 *      - 12/01/2007: Ability to change the color of the zoom rectangle.
 *      - 08/02/2008: Added convenience functions to convert from date to value and
 *                    opposite.
 *      - 21/02/2008: The zoom doesn't do anything if the user only clicks on the control
 *                    (thanks to Eugene Pustovoyt).
 *      - 29/02/2008: The auto axis are now refreshed when a series is removed (thanks to
 *                    Bruno Lavier).
 *      - 08/03/2008: EnableRefresh function added (thanks to Bruno Lavier).
 *      - 21/03/2008: Added support for scrolling.
 *      - 25/03/2008: UndoZoom function added.
 *      - 25/03/2008: A series can now be removed using its pointer.
 *      - 12/08/2008: Performance patch (thanks to Nick Holgate).
 *      - 18/08/2008: Added support for printing.
 *      - 31/10/2008: Fixed a bug for unicode.
 *
 */
 
#include "stdafx.h"
#include "ChartCtrl.h"
 
#include "ChartSerie.h"
#include "ChartGradient.h"
#include "ChartStandardAxis.h"
#include "ChartDateTimeAxis.h"
#include "ChartLogarithmicAxis.h"
#include "ChartCrossHairCursor.h"
#include "ChartDragLineCursor.h"
 
#include "ChartPointsSerie.h"
#include "ChartLineSerie.h"
#include "ChartSurfaceSerie.h"
#include "ChartBarSerie.h"
#include "ChartCandlestickSerie.h"
#include "ChartGanttSerie.h"
 
#if _MFC_VER > 0x0600
#include "atlImage.h"
#endif
 
using namespace std;
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
 
#define CHARTCTRL_CLASSNAME    _T("ChartCtrl")  // Window class name
 
 
COLORREF pSeriesColorTable[] = { RGB(255,0,0), RGB(0,150,0), RGB(0,0,255), RGB(255,255,0), RGB(0,255,255),
                                 RGB(255,128,0), RGB(128,0,128), RGB(128,128,0), RGB(255,0,255), RGB(64,128,128)};
 
/////////////////////////////////////////////////////////////////////////////
// CChartCtrl
 
CChartCtrl::CChartCtrl()
{
    RegisterWindowClass();
 
    m_iEnableRefresh = 1;
    m_bPendingRefresh = false;
    m_BorderColor = RGB(0,0,0);
    m_BackColor = GetSysColor(COLOR_BTNFACE);
    EdgeType = EDGE_RAISED;
    m_BackGradientType = gtVertical;
    m_bBackGradient = false;
    m_BackGradientCol1 = m_BackGradientCol2 = m_BackColor;
 
    for (int i=0;i<4;i++)
        m_pAxes[i] = NULL;
 
    m_pLegend = new CChartLegend(this);
    m_pTitles = new CChartTitle(this);
     
    m_bMemDCCreated = false;
    m_bPanEnabled = true;
    m_bRMouseDown = false;
 
    m_bZoomEnabled = true;
    m_bLMouseDown = false;
    m_ZoomRectColor = RGB(255,255,255);
 
    m_bToolBarCreated = false;
    m_pMouseListener = NULL;
    m_bMouseVisible = true;
}
 
CChartCtrl::~CChartCtrl()
{
    TSeriesMap::iterator seriesIter = m_mapSeries.begin();
    for (seriesIter; seriesIter!=m_mapSeries.end(); seriesIter++)
    {
        delete (seriesIter->second);
    }
    TCursorMap::iterator cursorIter = m_mapCursors.begin();
    for (cursorIter; cursorIter!=m_mapCursors.end(); cursorIter++)
    {
        delete (cursorIter->second);
    }
 
    for (int i=0; i<4 ;i++)
    {
        if (m_pAxes[i])
            delete m_pAxes[i];
    }
 
    if (m_pLegend)
    {
        delete m_pLegend;
        m_pLegend = NULL;
    }
    if (m_pTitles)
    {
        delete m_pTitles;
        m_pTitles = NULL;
    }
}
 
 
BEGIN_MESSAGE_MAP(CChartCtrl, CWnd)
    //{{AFX_MSG_MAP(CChartCtrl)
    ON_WM_PAINT()
    ON_WM_ERASEBKGND()
    ON_WM_MOUSEMOVE()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_LBUTTONDBLCLK()
    ON_WM_RBUTTONDOWN()
    ON_WM_RBUTTONUP()
    ON_WM_RBUTTONDBLCLK()
    ON_WM_SIZE()
    ON_WM_HSCROLL()
    ON_WM_VSCROLL()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
 
/////////////////////////////////////////////////////////////////////////////
// CChartCtrl message handlers
 
void CChartCtrl::OnPaint()
{
    CPaintDC dc(this); // device context for painting
 
    if (!m_bMemDCCreated)
    {
        RefreshCtrl();
        m_bMemDCCreated = true;
    }
 
    // Get Size of Display area
    CRect rect;
    GetClientRect(&rect);
    dc.BitBlt(0, 0, rect.Width(), rect.Height(),
              &m_BackgroundDC, 0, 0, SRCCOPY) ;
 
    // Draw the zoom rectangle
    if (m_bZoomEnabled && m_bLMouseDown)
    {
        CPen NewPen(PS_SOLID,1,m_ZoomRectColor);
        CPen* pOldPen = dc.SelectObject(&NewPen);
 
        dc.MoveTo(m_rectZoomArea.TopLeft());
        dc.LineTo(m_rectZoomArea.right,m_rectZoomArea.top);
        dc.LineTo(m_rectZoomArea.BottomRight());
        dc.LineTo(m_rectZoomArea.left,m_rectZoomArea.bottom);
        dc.LineTo(m_rectZoomArea.TopLeft());
 
        dc.SelectObject(pOldPen);
        DeleteObject(NewPen);
    }
 
    // Draw the cursors.
    TCursorMap::iterator iter = m_mapCursors.begin();
    for (iter; iter!=m_mapCursors.end(); iter++)
        iter->second->Draw(&dc);
}
 
BOOL CChartCtrl::OnEraseBkgnd(CDC* )
{
    // To avoid flickering
//  return CWnd::OnEraseBkgnd(pDC);
    return FALSE;
}
 
CChartCrossHairCursor* CChartCtrl::CreateCrossHairCursor(bool bSecondaryHorizAxis,
                                                         bool bSecondaryVertAxis)
{
    CChartAxis* pHorizAxis = NULL;
    CChartAxis* pVertAxis = NULL;
    if (bSecondaryHorizAxis)
        pHorizAxis = m_pAxes[TopAxis];
    else
        pHorizAxis = m_pAxes[BottomAxis];
    if (bSecondaryVertAxis)
        pVertAxis = m_pAxes[RightAxis];
    else
        pVertAxis = m_pAxes[LeftAxis];
 
    ASSERT(pHorizAxis != NULL);
    ASSERT(pVertAxis != NULL);
 
    CChartCrossHairCursor* pNewCursor = new CChartCrossHairCursor(this, pHorizAxis, pVertAxis);
    m_mapCursors[pNewCursor->GetCursorId()] = pNewCursor;
    return pNewCursor;
}
 
CChartDragLineCursor* CChartCtrl::CreateDragLineCursor(EAxisPos relatedAxis)
{
    ASSERT(m_pAxes[relatedAxis] != NULL);
 
    CChartDragLineCursor* pNewCursor = new CChartDragLineCursor(this, m_pAxes[relatedAxis]);
    m_mapCursors[pNewCursor->GetCursorId()] = pNewCursor;
    return pNewCursor;
}
 
void CChartCtrl::AttachCustomCursor(CChartCursor* pCursor)
{
    m_mapCursors[pCursor->GetCursorId()] = pCursor;
}
 
void CChartCtrl::RemoveCursor(unsigned cursorId)
{
    TCursorMap::iterator iter = m_mapCursors.find(cursorId);
    if (iter != m_mapCursors.end())
    {
        delete iter->second;
        m_mapCursors.erase(iter);
    }
}
 
void CChartCtrl::ShowMouseCursor(bool bShow)
{
    m_bMouseVisible = bShow;
    if (!bShow)
        SetCursor(NULL);
}
 
CChartStandardAxis* CChartCtrl::CreateStandardAxis(EAxisPos axisPos)
{
    CChartStandardAxis* pAxis = new CChartStandardAxis();
    AttachCustomAxis(pAxis, axisPos);
    return pAxis;
}
 
CChartLogarithmicAxis* CChartCtrl::CreateLogarithmicAxis(EAxisPos axisPos)
{
    CChartLogarithmicAxis* pAxis = new CChartLogarithmicAxis();
    AttachCustomAxis(pAxis, axisPos);
    return pAxis;
}
 
CChartDateTimeAxis* CChartCtrl::CreateDateTimeAxis(EAxisPos axisPos)
{
    CChartDateTimeAxis* pAxis = new CChartDateTimeAxis();
    AttachCustomAxis(pAxis, axisPos);
    return pAxis;
}
 
void CChartCtrl::AttachCustomAxis(CChartAxis* pAxis, EAxisPos axisPos)
{
    // The axis should not be already attached to another control
    ASSERT(pAxis->m_pParentCtrl == NULL);
    pAxis->SetParent(this);
 
    if ( (axisPos==RightAxis) || (axisPos==TopAxis) )
        pAxis->SetSecondary(true);
    if (  (axisPos==BottomAxis) || (axisPos==TopAxis) )
        pAxis->SetHorizontal(true);
    else
        pAxis->SetHorizontal(false);
    pAxis->CreateScrollBar();
 
    // Beofre storing the new axis, we should delete the previous one if any
    if (m_pAxes[axisPos])
        delete m_pAxes[axisPos];
    m_pAxes[axisPos] = pAxis;
}
 
bool CChartCtrl::RegisterWindowClass()
{
    WNDCLASS wndcls;
    HINSTANCE hInst = AfxGetInstanceHandle();
 
    if (!(::GetClassInfo(hInst, CHARTCTRL_CLASSNAME, &wndcls)))
    {
        memset(&wndcls, 0, sizeof(WNDCLASS));  
 
        wndcls.hInstance        = hInst;
        wndcls.lpfnWndProc      = ::DefWindowProc;
        wndcls.hCursor          = NULL; //LoadCursor(NULL, IDC_ARROW);
        wndcls.hIcon            = 0;
        wndcls.lpszMenuName     = NULL;
        wndcls.hbrBackground    = (HBRUSH) ::GetStockObject(WHITE_BRUSH);
        wndcls.style            = CS_DBLCLKS;
        wndcls.cbClsExtra       = 0;
        wndcls.cbWndExtra       = 0;
        wndcls.lpszClassName    = CHARTCTRL_CLASSNAME;
 
        if (!RegisterClass(&wndcls))
        {
          //  AfxThrowResourceException();
            return false;
        }
    }
 
    return true;
 
}
 
int CChartCtrl::Create(CWnd *pParentWnd, const RECT &rect, UINT nID, DWORD dwStyle)
{
    dwStyle |= WS_CLIPCHILDREN;
    int Result = CWnd::Create(CHARTCTRL_CLASSNAME, _T(""), dwStyle, rect, pParentWnd, nID);
 
    if (Result)
        RefreshCtrl();
 
    return Result;
}
 
void CChartCtrl::SetBackGradient(COLORREF Col1, COLORREF Col2, EGradientType GradientType)
{
    m_bBackGradient = true;
    m_BackGradientCol1 = Col1;
    m_BackGradientCol2 = Col2;
    m_BackGradientType = GradientType;
    RefreshCtrl();
}
 
void CChartCtrl::EnableRefresh(bool bEnable)
{
    if (bEnable)
        m_iEnableRefresh++;
    else
        m_iEnableRefresh--;
    if (m_iEnableRefresh > 0 && m_bPendingRefresh)
    {
        m_bPendingRefresh = false;
        RefreshCtrl();
    }
}
 
void CChartCtrl::UndoPanZoom()
{
    EnableRefresh(false);
    if (m_pAxes[BottomAxis])
        m_pAxes[BottomAxis]->UndoZoom();
    if (m_pAxes[LeftAxis])
        m_pAxes[LeftAxis]->UndoZoom();
    if (m_pAxes[TopAxis])
        m_pAxes[TopAxis]->UndoZoom();
    if (m_pAxes[RightAxis])
        m_pAxes[RightAxis]->UndoZoom();
    EnableRefresh(true);
}
 
void CChartCtrl::RefreshCtrl()
{
    // Window is not created yet, so skip the refresh.
    if (!GetSafeHwnd())
        return;
    if (m_iEnableRefresh < 1)
    {
        m_bPendingRefresh = true;
        return;
    }
 
    // Retrieve the client rect and initialize the
    // plotting rect
    CClientDC dc(this) ; 
    CRect ClientRect;
    GetClientRect(&ClientRect);
    m_PlottingRect = ClientRect;       
 
    // If the backgroundDC was not created yet, create it (it
    // is used to avoid flickering).
    if (!m_BackgroundDC.GetSafeHdc() )
    {
        CBitmap memBitmap;
        m_BackgroundDC.CreateCompatibleDC(&dc) ;
        memBitmap.CreateCompatibleBitmap(&dc, ClientRect.Width(),ClientRect.Height()) ;
        m_BackgroundDC.SelectObject(&memBitmap) ;
    }
 
    // Draw the chart background, which is not part of
    // the DrawChart function (to avoid a background when
    // printing).
    DrawBackground(&m_BackgroundDC, ClientRect);
    ClientRect.DeflateRect(3,3);
    DrawChart(&m_BackgroundDC,ClientRect);
    for (int i=0; i<4 ;i++)
    {
        if (m_pAxes[i])
            m_pAxes[i]->UpdateScrollBarPos();
    }
    Invalidate();
}
 
void CChartCtrl::DrawChart(CDC* pDC, CRect ChartRect)
{
    m_PlottingRect = ChartRect;
    CSize TitleSize = m_pTitles->GetSize(pDC);
    CRect rcTitle;
    rcTitle = ChartRect;
    rcTitle.bottom = TitleSize.cy;
 
    ChartRect.top += TitleSize.cy;
    m_pTitles->SetTitleRect(rcTitle);
    m_pTitles->Draw(pDC);
 
    m_pLegend->ClipArea(ChartRect,pDC);
 
    //Clip all the margins (axis) of the client rect
    int n=0;
    for (n=0;n<4;n++)
    {
        if (m_pAxes[n])
        {
            m_pAxes[n]->SetAxisSize(ChartRect,m_PlottingRect);
            m_pAxes[n]->Recalculate();
            m_pAxes[n]->ClipMargin(ChartRect,m_PlottingRect,pDC);
        }
    }
    for (n=0;n<4;n++)
    {
        if (m_pAxes[n])
        {
            m_pAxes[n]->SetAxisSize(ChartRect,m_PlottingRect);
            m_pAxes[n]->Recalculate();
            m_pAxes[n]->Draw(pDC);
        }
    }
 
    CPen SolidPen(PS_SOLID,0,m_BorderColor);
    CPen* pOldPen = pDC->SelectObject(&SolidPen);
 
    pDC->MoveTo(m_PlottingRect.left,m_PlottingRect.top);
    pDC->LineTo(m_PlottingRect.right,m_PlottingRect.top);
    pDC->LineTo(m_PlottingRect.right,m_PlottingRect.bottom);
    pDC->LineTo(m_PlottingRect.left,m_PlottingRect.bottom);
    pDC->LineTo(m_PlottingRect.left,m_PlottingRect.top);
 
    pDC->SelectObject(pOldPen);
    DeleteObject(SolidPen);
 
    TSeriesMap::iterator iter = m_mapSeries.begin();
    for (iter; iter!=m_mapSeries.end(); iter++)
    {
        CRect drawingRect = m_PlottingRect;
        drawingRect.bottom += 1;
        drawingRect.right += 1;
        iter->second->SetPlottingRect(drawingRect);
        iter->second->DrawAll(pDC);
    }
 
    pDC->IntersectClipRect(m_PlottingRect);
    // Draw the labels when all series have been drawn
    for (iter=m_mapSeries.begin(); iter!=m_mapSeries.end(); iter++)
    {
        iter->second->DrawLabels(pDC);
    }
    pDC->SelectClipRgn(NULL);
 
    // Draw the legend at the end (when floating it should come over the plotting area).
    m_pLegend->Draw(pDC);
}
 
void CChartCtrl::DrawBackground(CDC* pDC, CRect ChartRect)
{
    CBrush BrushBack;
    BrushBack.CreateSolidBrush(m_BackColor) ;
    if (!m_bBackGradient)
    {
        pDC->SetBkColor(m_BackColor);
        pDC->FillRect(ChartRect,&BrushBack);
    }
    else
    {
        CChartGradient::DrawGradient(pDC,ChartRect,m_BackGradientCol1,
                                     m_BackGradientCol2,m_BackGradientType);
    }
 
    // Draw the edge.
    pDC->DrawEdge(ChartRect,EdgeType,BF_RECT);
}
 
void CChartCtrl::RefreshScreenAutoAxes()
{
    for (int n=0;n<4;n++)
    {
        if (m_pAxes[n])
            m_pAxes[n]->RefreshScreenAutoAxis();
    }
}
 
CChartPointsSerie* CChartCtrl::CreatePointsSerie(bool bSecondaryHorizAxis,
                                               bool bSecondaryVertAxis)
{
    CChartPointsSerie* pNewSerie = new CChartPointsSerie(this);
    AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis);
    return pNewSerie;
}
 
CChartLineSerie* CChartCtrl::CreateLineSerie(bool bSecondaryHorizAxis,
                                             bool bSecondaryVertAxis)
{
    CChartLineSerie* pNewSerie = new CChartLineSerie(this);
    AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis);
    return pNewSerie;
}
 
CChartSurfaceSerie* CChartCtrl::CreateSurfaceSerie(bool bSecondaryHorizAxis,
                                                   bool bSecondaryVertAxis)
{
    CChartSurfaceSerie* pNewSerie = new CChartSurfaceSerie(this);
    AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis);
    return pNewSerie;
}
 
CChartBarSerie* CChartCtrl::CreateBarSerie(bool bSecondaryHorizAxis,
                                           bool bSecondaryVertAxis)
{
    CChartBarSerie* pNewSerie = new CChartBarSerie(this);
    AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis);
    return pNewSerie;
}
 
CChartCandlestickSerie* CChartCtrl::CreateCandlestickSerie(bool bSecondaryHorizAxis,
                                                           bool bSecondaryVertAxis)
{
    CChartCandlestickSerie* pNewSerie = new CChartCandlestickSerie(this);
    AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis);
    return pNewSerie;
}
 
CChartGanttSerie* CChartCtrl::CreateGanttSerie(bool bSecondaryHorizAxis,
                                                     bool bSecondaryVertAxis)
{
    CChartGanttSerie* pNewSerie = new CChartGanttSerie(this);
    AttachCustomSerie(pNewSerie, bSecondaryHorizAxis, bSecondaryVertAxis);
    return pNewSerie;
}
 
void CChartCtrl::AttachCustomSerie(CChartSerie* pNewSeries,
                                   bool bSecondaryHorizAxis,
                                   bool bSecondaryVertAxis)
{
    size_t ColIndex = m_mapSeries.size()%10;
 
    CChartAxis* pHorizAxis = NULL;
    CChartAxis* pVertAxis = NULL;
    if (bSecondaryHorizAxis)
        pHorizAxis = m_pAxes[TopAxis];
    else
        pHorizAxis = m_pAxes[BottomAxis];
    if (bSecondaryVertAxis)
        pVertAxis = m_pAxes[RightAxis];
    else
        pVertAxis = m_pAxes[LeftAxis];
 
    ASSERT(pHorizAxis != NULL);
    ASSERT(pVertAxis != NULL);
 
    if (pNewSeries)
    {
        pNewSeries->SetPlottingRect(m_PlottingRect);
        pNewSeries->SetColor(pSeriesColorTable[ColIndex]);
        pNewSeries->m_pHorizontalAxis = pHorizAxis;
        pNewSeries->m_pVerticalAxis = pVertAxis;
        m_mapSeries[pNewSeries->GetSerieId()] = pNewSeries;
 
        EnableRefresh(false);
        pVertAxis->RegisterSeries(pNewSeries);
        pVertAxis->RefreshAutoAxis();
        pHorizAxis->RegisterSeries(pNewSeries);
        pHorizAxis->RefreshAutoAxis();
 
        // The series will need to be redrawn so we need to refresh the control
        RefreshCtrl();
        EnableRefresh(true);
    }
}
 
CChartSerie* CChartCtrl::GetSerie(size_t uSerieId) const
{
    CChartSerie* pToReturn = NULL;
    TSeriesMap::const_iterator iter = m_mapSeries.find(uSerieId);
    if (iter != m_mapSeries.end())
    {
        pToReturn = iter->second;
    }
 
    return pToReturn;
}
 
void CChartCtrl::RemoveSerie(unsigned uSerieId)
{
    TSeriesMap::iterator iter = m_mapSeries.find(uSerieId);
    if (iter != m_mapSeries.end())
    {
        CChartSerie* pToDelete = iter->second;
        m_mapSeries.erase(iter);
 
        EnableRefresh(false);
        pToDelete->m_pVerticalAxis->UnregisterSeries(pToDelete);
        pToDelete->m_pHorizontalAxis->UnregisterSeries(pToDelete);
        pToDelete->m_pVerticalAxis->RefreshAutoAxis();
        pToDelete->m_pHorizontalAxis->RefreshAutoAxis();
        delete pToDelete;
        RefreshCtrl();
        EnableRefresh(true);
    }
}
 
void CChartCtrl::RemoveAllSeries()
{
    TSeriesMap::iterator iter = m_mapSeries.begin();
    for (iter; iter != m_mapSeries.end(); iter++)
    {
        delete iter->second;
    }
 
    m_mapSeries.clear();
    RefreshCtrl();
}
 
 
CChartAxis* CChartCtrl::GetBottomAxis() const
{
    return (m_pAxes[BottomAxis]);
}
 
CChartAxis* CChartCtrl::GetLeftAxis() const
{
    return (m_pAxes[LeftAxis]);
}
 
CChartAxis* CChartCtrl::GetTopAxis() const
{
    return (m_pAxes[TopAxis]);
}
 
CChartAxis* CChartCtrl::GetRightAxis() const
{
    return (m_pAxes[RightAxis]);
}
 
 
CDC* CChartCtrl::GetDC()
{
    return &m_BackgroundDC;
}
 
 
size_t CChartCtrl::GetSeriesCount() const
{
    return m_mapSeries.size();
}
 
/////////////////////////////////////////////////////////////////////////////
// Mouse events
 
void CChartCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
    if (m_bRMouseDown && m_bPanEnabled)
    {
        if (point != m_PanAnchor)
        {
            EnableRefresh(false);
            if (m_pAxes[LeftAxis])
                m_pAxes[LeftAxis]->PanAxis(m_PanAnchor.y,point.y);
            if (m_pAxes[RightAxis])
                m_pAxes[RightAxis]->PanAxis(m_PanAnchor.y,point.y);
            if (m_pAxes[BottomAxis])
                m_pAxes[BottomAxis]->PanAxis(m_PanAnchor.x,point.x);
            if (m_pAxes[TopAxis])
                m_pAxes[TopAxis]->PanAxis(m_PanAnchor.x,point.x);
            RefreshCtrl();
            EnableRefresh(true);
            // Force an immediate repaint of the window, so that the mouse messages
            // are by passed (this allows for a smooth pan)
            UpdateWindow();
 
            m_PanAnchor = point;
        }
    }
 
    if (m_bLMouseDown && m_bZoomEnabled)
    {
        m_rectZoomArea.BottomRight() = point;
        Invalidate();
    }
 
    for (int i=0; i<4; i++)
    {
        if (m_pAxes[i])
            m_pAxes[i]->m_pScrollBar->OnMouseLeave();
    }
    CWnd* pWnd = ChildWindowFromPoint(point);
    if (pWnd != this)
    {
        CChartScrollBar* pScrollBar = dynamic_cast<CChartScrollBar*>(pWnd);
        if (pScrollBar)
            pScrollBar->OnMouseEnter();
    }
 
    if (m_PlottingRect.PtInRect(point))
    {
        TCursorMap::iterator iter = m_mapCursors.begin();
        for (iter; iter!=m_mapCursors.end(); iter++)
            iter->second->OnMouseMove(point);
         
        Invalidate();
    }
 
    if (!m_bMouseVisible && m_PlottingRect.PtInRect(point))
        SetCursor(NULL);
    else
        SetCursor(::LoadCursor(NULL,IDC_ARROW));
 
    SendMouseEvent(CChartMouseListener::MouseMove, point);
    CWnd::OnMouseMove(nFlags, point);
}
 
void CChartCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
    SetCapture();
    if (m_bZoomEnabled)
    {
        m_bLMouseDown = true;
        m_rectZoomArea.TopLeft() = point;
        m_rectZoomArea.BottomRight() = point;
    }
 
    if (m_PlottingRect.PtInRect(point))
    {
        TCursorMap::iterator iter = m_mapCursors.begin();
        for (iter; iter!=m_mapCursors.end(); iter++)
            iter->second->OnMouseButtonDown(point);
         
        Invalidate();
    }
 
    SendMouseEvent(CChartMouseListener::LButtonDown, point);
    CWnd::OnLButtonDown(nFlags, point);
}
 
void CChartCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
    ReleaseCapture();
    m_bLMouseDown = false;
    if (m_bZoomEnabled)
    {
        if ( (m_rectZoomArea.left > m_rectZoomArea.right) ||
             (m_rectZoomArea.top > m_rectZoomArea.bottom))
        {
            UndoPanZoom();
        }
        else if ( (m_rectZoomArea.left!=m_rectZoomArea.right) &&
                  (m_rectZoomArea.top!=m_rectZoomArea.bottom))
        {
            double MinVal = 0;         
            double MaxVal = 0;
             
            if (m_pAxes[BottomAxis])
            {
                if (m_pAxes[BottomAxis]->IsInverted())
                {
                    MaxVal = m_pAxes[BottomAxis]->ScreenToValue(m_rectZoomArea.left);
                    MinVal = m_pAxes[BottomAxis]->ScreenToValue(m_rectZoomArea.right);
                }
                else
                {
                    MinVal = m_pAxes[BottomAxis]->ScreenToValue(m_rectZoomArea.left);
                    MaxVal = m_pAxes[BottomAxis]->ScreenToValue(m_rectZoomArea.right);
                }
                m_pAxes[BottomAxis]->SetZoomMinMax(MinVal,MaxVal);
            }
 
            if (m_pAxes[LeftAxis])
            {
                if (m_pAxes[LeftAxis]->IsInverted())
                {
                    MaxVal = m_pAxes[LeftAxis]->ScreenToValue(m_rectZoomArea.bottom);
                    MinVal = m_pAxes[LeftAxis]->ScreenToValue(m_rectZoomArea.top);
                }
                else
                {
                    MinVal = m_pAxes[LeftAxis]->ScreenToValue(m_rectZoomArea.bottom);
                    MaxVal = m_pAxes[LeftAxis]->ScreenToValue(m_rectZoomArea.top);
                }
                m_pAxes[LeftAxis]->SetZoomMinMax(MinVal,MaxVal);
            }
 
            if (m_pAxes[TopAxis])
            {
                if (m_pAxes[TopAxis]->IsInverted())
                {
                    MaxVal = m_pAxes[TopAxis]->ScreenToValue(m_rectZoomArea.left);
                    MinVal = m_pAxes[TopAxis]->ScreenToValue(m_rectZoomArea.right);
                }
                else
                {
                    MinVal = m_pAxes[TopAxis]->ScreenToValue(m_rectZoomArea.left);
                    MaxVal = m_pAxes[TopAxis]->ScreenToValue(m_rectZoomArea.right);
                }
                m_pAxes[TopAxis]->SetZoomMinMax(MinVal,MaxVal);
            }
 
            if (m_pAxes[RightAxis])
            {
                if (m_pAxes[RightAxis]->IsInverted())
                {
                    MaxVal = m_pAxes[RightAxis]->ScreenToValue(m_rectZoomArea.bottom);
                    MinVal = m_pAxes[RightAxis]->ScreenToValue(m_rectZoomArea.top);
                }
                else
                {
                    MinVal = m_pAxes[RightAxis]->ScreenToValue(m_rectZoomArea.bottom);
                    MaxVal = m_pAxes[RightAxis]->ScreenToValue(m_rectZoomArea.top);
                }
                m_pAxes[RightAxis]->SetZoomMinMax(MinVal,MaxVal);
            }
 
            RefreshCtrl();
        }
    }
 
    if (m_PlottingRect.PtInRect(point))
    {
        TCursorMap::iterator iter = m_mapCursors.begin();
        for (iter; iter!=m_mapCursors.end(); iter++)
            iter->second->OnMouseButtonUp(point);
         
        Invalidate();
    }
 
    SendMouseEvent(CChartMouseListener::LButtonUp, point);
    CWnd::OnLButtonUp(nFlags, point);
}
 
void CChartCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
    SendMouseEvent(CChartMouseListener::LButtonDoubleClick, point);
    CWnd::OnLButtonDblClk(nFlags, point);
}
 
void CChartCtrl::OnRButtonDown(UINT nFlags, CPoint point)
{
    SetCapture();
    m_bRMouseDown = true;
    if (m_bPanEnabled)
        m_PanAnchor = point;
 
    SendMouseEvent(CChartMouseListener::RButtonDown, point);
    CWnd::OnRButtonDown(nFlags, point);
}
 
void CChartCtrl::OnRButtonUp(UINT nFlags, CPoint point)
{
    ReleaseCapture();
    m_bRMouseDown = false;
 
    SendMouseEvent(CChartMouseListener::RButtonUp, point);
    CWnd::OnRButtonUp(nFlags, point);
}
 
void CChartCtrl::OnRButtonDblClk(UINT nFlags, CPoint point)
{
    SendMouseEvent(CChartMouseListener::RButtonDoubleClick, point);
    CWnd::OnRButtonDblClk(nFlags, point);
}
 
void CChartCtrl::SendMouseEvent(CChartMouseListener::MouseEvent mouseEvent,
                                const CPoint& screenPoint) const
{
    if (m_pMouseListener)
    {
        // Check where the click occured.
        if (m_pTitles->IsPointInside(screenPoint))
            m_pMouseListener->OnMouseEventTitle(mouseEvent,screenPoint);
        if (m_pLegend->IsPointInside(screenPoint))
            m_pMouseListener->OnMouseEventLegend(mouseEvent,screenPoint);
        for (int i=0; i<4; i++)
        {
            if ( m_pAxes[i] && m_pAxes[i]->IsPointInside(screenPoint) )
                m_pMouseListener->OnMouseEventAxis(mouseEvent,screenPoint,m_pAxes[i]);
        }
        if (m_PlottingRect.PtInRect(screenPoint))
            m_pMouseListener->OnMouseEventPlotArea(mouseEvent,screenPoint);
    }
     
    // Check all the series in reverse order (check the series on top first).
    TSeriesMap::const_reverse_iterator rIter = m_mapSeries.rbegin();
    for(rIter; rIter!=m_mapSeries.rend(); rIter++)
    {
        if (rIter->second->OnMouseEvent(mouseEvent, screenPoint))
            break;
    }
}
 
void CChartCtrl::OnSize(UINT nType, int cx, int cy)
{
    CWnd::OnSize(nType, cx, cy);
     
    // Force recreation of background DC
    if (m_BackgroundDC.GetSafeHdc() )
        m_BackgroundDC.DeleteDC();
     
    RefreshCtrl();
}
 
double CChartCtrl::DateToValue(const COleDateTime& Date)
{
    return (DATE)Date;
}
 
COleDateTime CChartCtrl::ValueToDate(double Value)
{
    COleDateTime RetDate((DATE)Value);
    return RetDate;
}
 
void CChartCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    CChartScrollBar* pChartBar = dynamic_cast<CChartScrollBar*>(pScrollBar);
    if (pChartBar)
        pChartBar->OnHScroll(nSBCode, nPos);
 
    CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
    RefreshCtrl();
}
 
void CChartCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    CChartScrollBar* pChartBar = dynamic_cast<CChartScrollBar*>(pScrollBar);
    if (pChartBar)
        pChartBar->OnVScroll(nSBCode, nPos);
 
    CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
    RefreshCtrl();
}
 
void CChartCtrl::Print(const TChartString& strTitle, CPrintDialog* pPrntDialog)
{
    CDC dc;
    if (pPrntDialog == NULL)
    {
        CPrintDialog printDlg(FALSE);
        if (printDlg.DoModal() != IDOK)         // Get printer settings from user
            return;
 
        dc.Attach(printDlg.GetPrinterDC());     // attach a printer DC
    }
    else
        dc.Attach(pPrntDialog->GetPrinterDC()); // attach a printer DC
    dc.m_bPrinting = TRUE;
     
    DOCINFO di;                                 // Initialise print doc details
    memset(&di, 0, sizeof (DOCINFO));
    di.cbSize = sizeof (DOCINFO);
    di.lpszDocName = strTitle.c_str();
 
    BOOL bPrintingOK = dc.StartDoc(&di);        // Begin a new print job
 
    CPrintInfo Info;
    Info.m_rectDraw.SetRect(0,0, dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES));
 
    OnBeginPrinting(&dc, &Info);                // Initialise printing
    for (UINT page = Info.GetMinPage(); page <= Info.GetMaxPage() && bPrintingOK; page++)
    {
        dc.StartPage();                         // begin new page
        Info.m_nCurPage = page;
        OnPrint(&dc, &Info);                    // Print page
        bPrintingOK = (dc.EndPage() > 0);       // end page
    }
    OnEndPrinting(&dc, &Info);                  // Clean up after printing
 
    if (bPrintingOK)
        dc.EndDoc();                            // end a print job
    else
        dc.AbortDoc();                          // abort job.
 
    dc.Detach();                                // detach the printer DC
}
 
void CChartCtrl::OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo)
{
    // OnBeginPrinting() is called after the user has committed to
    // printing by OK'ing the Print dialog, and after the framework
    // has created a CDC object for the printer or the preview view.
 
    // This is the right opportunity to set up the page range.
    // Given the CDC object, we can determine how many rows will
    // fit on a page, so we can in turn determine how many printed
    // pages represent the entire document.
    ASSERT(pDC && pInfo);
 
    // Get a DC for the current window (will be a screen DC for print previewing)
    CDC *pCurrentDC = GetDC();        // will have dimensions of the client area
    if (!pCurrentDC)
        return;
 
    CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
    CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY));
 
    // Create the printer font
    int nFontSize = -10;
    CString strFontName = _T("Arial");
    m_PrinterFont.CreateFont(nFontSize, 0,0,0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET,
                             OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
                             DEFAULT_PITCH | FF_DONTCARE, strFontName);
    CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
 
    // Get the page sizes (physical and logical)
    m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
 
    m_LogicalPageSize.cx = ScreenPixelsPerInch.cx * m_PaperSize.cx / PaperPixelsPerInch.cx * 3 / 4;
    m_LogicalPageSize.cy = ScreenPixelsPerInch.cy * m_PaperSize.cy / PaperPixelsPerInch.cy * 3 / 4;
 
 
    // Set up the print info
    pInfo->SetMaxPage(1);
    pInfo->m_nCurPage = 1;                        // start printing at page# 1
 
    ReleaseDC(pCurrentDC);
    pDC->SelectObject(pOldFont);
}
 
void CChartCtrl::OnPrint(CDC *pDC, CPrintInfo *pInfo)
{
    if (!pDC || !pInfo)
        return;
 
    CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
 
    // Set the page map mode to use GraphCtrl units
    pDC->SetMapMode(MM_ANISOTROPIC);
    pDC->SetWindowExt(m_LogicalPageSize);
    pDC->SetViewportExt(m_PaperSize);
    pDC->SetWindowOrg(0, 0);
 
    // Header
    pInfo->m_rectDraw.top    = 0;
    pInfo->m_rectDraw.left   = 0;
    pInfo->m_rectDraw.right  = m_LogicalPageSize.cx;
    pInfo->m_rectDraw.bottom = m_LogicalPageSize.cy;
 
    DrawChart(pDC, &pInfo->m_rectDraw);
 
    // SetWindowOrg back for next page
    pDC->SetWindowOrg(0,0);
 
    pDC->SelectObject(pOldFont);
}
 
void CChartCtrl::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
    m_PrinterFont.DeleteObject();
    // RefreshCtrl is needed because the print job
    // modifies the chart components (axis, ...)
    RefreshCtrl();
}
 
void CChartCtrl::GoToFirstSerie()
{
    m_currentSeries = m_mapSeries.begin();
}
 
CChartSerie* CChartCtrl::GetNextSerie()
{
    CChartSerie* pSeries = NULL;
    if (m_currentSeries != m_mapSeries.end())
    {
        pSeries = m_currentSeries->second;
        m_currentSeries++;
    }
 
    return pSeries;
}
 
#if _MFC_VER > 0x0600
void CChartCtrl::SaveAsImage(const TChartString& strFilename,
                             const CRect& rect,
                             int nBPP,
                             REFGUID guidFileType)
{
    CImage chartImage;
    CRect chartRect = rect;
    if (chartRect.IsRectEmpty())
    {
        GetClientRect(&chartRect);
    }
     
    chartImage.Create(chartRect.Width(), chartRect.Height(), nBPP);
    CDC newDC;
    newDC.Attach(chartImage.GetDC());
 
    DrawBackground(&newDC, chartRect);
    chartRect.DeflateRect(3,3);
    DrawChart(&newDC, chartRect);
 
    newDC.Detach();
    chartImage.Save(strFilename.c_str(), guidFileType);
    chartImage.ReleaseDC();
}
#endif

[源代码打包下载]




网友评论    (发表评论)


发表评论:

评论须知:

  • 1、评论每次加2分,每天上限为30;
  • 2、请文明用语,共同创建干净的技术交流环境;
  • 3、若被发现提交非法信息,评论将会被删除,并且给予扣分处理,严重者给予封号处理;
  • 4、请勿发布广告信息或其他无关评论,否则将会删除评论并扣分,严重者给予封号处理。


扫码下载

加载中,请稍后...

输入口令后可复制整站源码

加载中,请稍后...