视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
C++第四十四篇--MFC使用ChartCtrl绘制动态曲线
2025-10-05 01:21:15 责编:小OO
文档
C++第四⼗四篇--MFC使⽤ChartCtrl绘制动态曲线前⾔

⽬的:使⽤控制台程序带MFC类库画⼀个动态曲线图

参考链接:

操作步骤

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(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 constructorvirtual ~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

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

}

}

else

{

// TODO: change error code to suit your needs

wprintf(L"Fatal Error: GetModuleHandle failed\\n");

nRetCode = 1;

}

return nRetCode;

}

View Code

OK.下载本文

显示全文
专题