前言
目的:使用控制台程序帶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; } }
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); };
4. 控制台調用動態折線圖

chart *chartdialog = new chart; int ReturnValue = chartdialog->DoModal(); // Show the dialog printf("%d", ReturnValue);
效果圖
可能出現的問題
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; }
OK.