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\n");
            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\n");
        nRetCode = 1;
    }

    return nRetCode;
}
View Code

 

OK.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM