zoukankan      html  css  js  c++  java
  • C++第四十四篇 -- MFC使用ChartCtrl绘制动态曲线

    前言

    目的:使用控制台程序带MFC类库画一个动态曲线图

    参考链接:

    https://blog.csdn.net/sinat_29890433/article/details/105360032

    https://github.com/jobschu/waveDisplayUseChartCtrl

    操作步骤

    1. 创建一个勾选MFC类库的控制台程序

    上一章讲过,此处不做赘述。

    2. 新建一个窗口程序

    3. 编写动态折线图

    chart.cpp

    // chart.cpp : implementation file
    //
    #include "pch.h"
    #include "stdafx.h"
    #include "CPUUsage.h"
    #include "chart.h"
    #include "afxdialogex.h"
    
    // chart dialog
    
    IMPLEMENT_DYNAMIC(chart, CDialog)
    
    chart::chart(CWnd* pParent /*=nullptr*/)
        : CDialog(IDD_chart, pParent)
    {
    }
    
    chart::~chart()
    {
    }
    
    void chart::DoDataExchange(CDataExchange* pDX)
    {
        CDialog::DoDataExchange(pDX);
        DDX_Control(pDX, IDC_CUSTOM_CHART, m_ChartCtrl);
    }
    
    BEGIN_MESSAGE_MAP(chart, CDialog)
        ON_WM_SIZE()
        ON_WM_TIMER()
        ON_WM_PAINT()
    END_MESSAGE_MAP()
    
    #define DATA_SHOW_LENGHT 2000 //总共显示的点个数
    #define DATA_UPDATE_LENGHT 10 //每次更新的点个数
    #define DATA_SHOW_X_AXIS 2000 //X轴显示的点最大值
    #define DATA_SHOW_Y_AXIS 1000 //Y轴显示的点最大值
    //要显示点的缓冲数据
    static double xBuff[DATA_SHOW_LENGHT] = { 0 };
    static double yBuff[DATA_SHOW_LENGHT] = { 0 };
    
    //显示点数据包初始化
    void chart::DataBuffInit(void)
    {
        for (int i = 0; i < DATA_SHOW_LENGHT; i++) {
            xBuff[i] = i;
            yBuff[i] = 50;// cos((i)) * 10 + 50;
        }
    }
    
    //初始化画图界面窗口
    void chart::ChartCtrlInit(void) {
        //手动创建显示窗口
        //CRect rect, rectChart;
        //GetDlgItem(IDC_CUSTOM_SHOW)->GetWindowRect(&rect);
        //ScreenToClient(rect);
        //rectChart = rect;
        //rectChart.top = rect.bottom + 3;
        //rectChart.bottom = rectChart.top + rect.Height();
        //m_ChartCtrl2.Create(this, rectChart, IDC_CUSTOM_SHOW2);
        //m_ChartCtrl2.ShowWindow(SW_SHOWNORMAL);
        ///////////////////////显示主题/////////////////////////////
        m_ChartCtrl.GetTitle()->AddString(_T("CPU Usage"));
        ///////////////////////创建坐标xy标识/////////////////////////////
        //m_ChartCtrl.GetBottomAxis()->GetLabel()->SetText(_T("强度"));
        //m_ChartCtrl.GetLeftAxis()->GetLabel()->SetText(_T("采样点"));
        ///////////////////////创建坐标显示范围/////////////////////////////
        CChartAxis *pAxis = NULL;
        pAxis = m_ChartCtrl.CreateStandardAxis(CChartCtrl::BottomAxis);
        pAxis->SetMinMax(0, DATA_SHOW_X_AXIS);
        pAxis = m_ChartCtrl.CreateStandardAxis(CChartCtrl::LeftAxis);
        pAxis->SetMinMax(0, DATA_SHOW_Y_AXIS);
    }
    
    
    // CmyApplicationDlg 消息处理程序
    BOOL chart::OnInitDialog()
    {
        CDialog::OnInitDialog();
        //获取显示的对话框大小
        CRect rect;
        GetClientRect(&rect);
        oldPiont.x = rect.right - rect.left;
        oldPiont.y = rect.bottom - rect.top;
        // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
        //  执行此操作
    
        // TODO: 在此添加额外的初始化代码
        DataBuffInit();
        ChartCtrlInit();
    
        SetTimer(0, 100, NULL);
        return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
    }
    
    // 如果向对话框添加最小化按钮,则需要下面的代码
    //  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
    //  这将由框架自动完成。
    
    void chart::OnPaint()
    {
        if (IsIconic())
        {
            CPaintDC dc(this); // 用于绘制的设备上下文
    
            SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    
            // 使图标在工作区矩形中居中
            int cxIcon = GetSystemMetrics(SM_CXICON);
            int cyIcon = GetSystemMetrics(SM_CYICON);
            CRect rect;
            GetClientRect(&rect);
            int x = (rect.Width() - cxIcon + 1) / 2;
            int y = (rect.Height() - cyIcon + 1) / 2;
    
        }
        else
        {
            CDialog::OnPaint();
        }
    }
    
    void chart::Resize(void) {
        float fsp[2];
        POINT newPoint;//获取当前对话框大小
        CRect newRect;//获取当前对话框的坐标
        GetClientRect(&newRect);
        newPoint.x = newRect.right - newRect.left;
        newPoint.y = newRect.bottom - newRect.top;
        fsp[0] = (float)newPoint.x / oldPiont.x;
        fsp[1] = (float)newPoint.y / oldPiont.y;
    
        int woc;
        CRect rect;
        CPoint oldTLPoint, newTLPoint;//左上角
        CPoint oldBRPoint, newBRPoint;//右下角
                                      //列出所有的子空间
        HWND hwndChild = ::GetWindow(m_hWnd, GW_CHILD);
        while (hwndChild) {
            woc = ::GetDlgCtrlID(hwndChild);//取得ID
            GetDlgItem(woc)->GetWindowRect(rect);
            ScreenToClient(rect);
    
            oldTLPoint = rect.TopLeft();
            newTLPoint.x = long(oldTLPoint.x*fsp[0]);
            newTLPoint.y = long(oldTLPoint.y*fsp[1]);
            oldBRPoint = rect.BottomRight();
            newBRPoint.x = long(oldBRPoint.x*fsp[0]);
            newBRPoint.y = long(oldBRPoint.y*fsp[1]);
    
            rect.SetRect(newTLPoint, newBRPoint);
            GetDlgItem(woc)->MoveWindow(rect, TRUE);
            hwndChild = ::GetWindow(hwndChild, GW_HWNDNEXT);
        }
        oldPiont = newPoint;
        return;
    }
    void chart::OnSize(UINT nType, int cx, int cy) {
        //窗体大小发生变动。处理函数resize
        if (nType == SIZE_RESTORED || nType == SIZE_MAXIMIZED)
        {
            Resize();
        }
    }
    void chart::DataShow(double *xb, double *yb, int len) {
        m_ChartCtrl.EnableRefresh(false);
        CChartLineSerie *pLineSerie;
        m_ChartCtrl.RemoveAllSeries();
        pLineSerie = m_ChartCtrl.CreateLineSerie();
        pLineSerie->SetSeriesOrdering(poNoOrdering);//设置为无序
        pLineSerie->AddPoints(xb, yb, len);
        UpdateWindow();
        m_ChartCtrl.EnableRefresh(true);
    }
    void chart::OnTimer(UINT nIDEvent) {
        static int offset = 0;
        for (int m = 0; m < DATA_SHOW_LENGHT - DATA_UPDATE_LENGHT; m++)
        {
            //xd[m] = xd[DATA_UPDATE_LENGHT + m];
            yBuff[m] = yBuff[DATA_UPDATE_LENGHT + m];
        }
        int index = DATA_SHOW_LENGHT - DATA_UPDATE_LENGHT;
        for (int i = 0; i < DATA_UPDATE_LENGHT; i++)
        {
            //yd[index + i] = cos((index + i + w)/5) * 50 + 100+rand() / 1000;
            yBuff[index + i] = cos((i + offset) / 5) * DATA_SHOW_Y_AXIS / 4 + rand() / 1000 + DATA_SHOW_Y_AXIS / 2;
        }
        DataShow(xBuff, yBuff, DATA_SHOW_LENGHT);
        offset++;
        if (offset > 10000) {
            offset = 0;
        }
    }
    View Code

    chart.h

    #pragma once
    #include "ChartCtrl/ChartCtrl.h"
    #include "ChartCtrl/ChartTitle.h"
    #include "ChartCtrl/ChartLineSerie.h"
    #include "ChartCtrl/ChartAxisLabel.h"
    
    // chart dialog
    
    class chart : public  CDialog
    {
        DECLARE_DYNAMIC(chart)
    
    public:
        chart(CWnd* pParent = nullptr);   // standard constructor
        virtual ~chart();
    
    // Dialog Data
    #ifdef AFX_DESIGN_TIME
        enum { IDD = IDD_chart };
    #endif
    
    protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    
            // 实现
    protected:
    
        // 生成的消息映射函数
        virtual BOOL OnInitDialog();
        afx_msg void OnPaint();
        afx_msg HCURSOR OnQueryDragIcon();
        afx_msg void OnSize(UINT nType, int cx, int cy);
        afx_msg void OnTimer(UINT nIDEvent);
        DECLARE_MESSAGE_MAP()
    
    public:
        POINT oldPiont;
        void Resize(void);
        CChartCtrl m_ChartCtrl;
        void ChartCtrlInit(void);
        void DataBuffInit(void);
        void DataShow(double *xb, double *yb, int len);
    };
    View Code

    4. 控制台调用动态折线图

    chart *chartdialog = new chart;
    int ReturnValue = chartdialog->DoModal(); // Show the dialog
    printf("%d", ReturnValue);
    View Code

    效果图

    可能出现的问题

    1. 在编译的时候,ChartCtrl里面的cpp老是出现没有"pch.h"即预编译头的问题,所以干脆取消了预编译头进行编译。

    2. 将ChartCtrl库放到项目里。添加之后取名为ChartCtrl,然后将文件都已Add --> Existing Item的方式加进项目里。ChartCtrl文件夹的存放路径与控制台的cpp文件同目录。

    源码:

    CPUUsage.cpp

    // CPUUsage.cpp : This file contains the 'main' function. Program execution begins and ends there.
    //
    
    #include "pch.h"
    #include "framework.h"
    #include "chart.h"
    #include "CPUUsage.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    
    // The one and only application object
    
    CWinApp theApp;
    
    using namespace std;
    
    int main()
    {
        int nRetCode = 0;
    
        HMODULE hModule = ::GetModuleHandle(nullptr);
    
        if (hModule != nullptr)
        {
            // initialize MFC and print and error on failure
            if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
            {
                // TODO: code your application's behavior here.
                wprintf(L"Fatal Error: MFC initialization failed
    ");
                nRetCode = 1;
            }
            else
            {
                // TODO: code your application's behavior here.
                chart *chartdialog = new chart;
                int ReturnValue = chartdialog->DoModal(); // Show the dialog
                printf("%d", ReturnValue);
            }
        }
        else
        {
            // TODO: change error code to suit your needs
            wprintf(L"Fatal Error: GetModuleHandle failed
    ");
            nRetCode = 1;
        }
    
        return nRetCode;
    }
    View Code

    OK.

  • 相关阅读:
    BOM-DOM
    JavaScript
    CSS(2)
    CSS(1)
    HTML5
    索引
    数据库多表查询
    数据操作
    数据库表操作
    初识Java
  • 原文地址:https://www.cnblogs.com/smart-zihan/p/13100239.html
Copyright © 2011-2022 走看看