由于项目的需要,需要画一个折线图。
传统的Teechart、MSChart、HighSpeedChart一般是只能配置在x86系统下,等到使用x64系统下运行就是会报出不知名的错误,这个地方让人很苦恼。
我在进行配置的过程之中,使用Teechart将x86配置好了,可以正常使用,但是嫁接到x64系统下就不可以使用了。HighSpeedChart也是同样在x64系统下使用会出现如下错误,并且在进行设置x轴的时候,x轴类型只能是int类型,贼其难用。配置了半天结果x64位用不了,x64系统真的不建议使用上述控件方式。
经过长时间的思索,还是直接用代码画一个吧,配置环境过于困难。
首先拉出一个Picture Control控件,然后将其ID进行更改为IDC_PIC_CTRL
在自己的.h文件之中进行定义变量
CStatic m_PicCtrl2;
CRect m_rect;
然后在相应的按钮下进行功能的定义(以依次修改按钮为例)
// TODO: 在此添加控件通知处理程序代码
int click = 6;
std::vector<CString> use;
std::vector<std::string> xAxisLabels = { "0"};
std::vector<double> yAxisValues = { 0 };
void CMFCApplication2Dlg::OnBnClickedButton5()
{
CPaintDC dc(this); // 使用设备上下文绘制
// 清空窗口
CRect rect;
GetClientRect(&rect); // 获取绘制区域大小
dc.FillSolidRect(rect, RGB(255, 255, 255)); // 填充白色背景
// 绘制图形的代码
// ...
CWnd* pWnd = GetDlgItem(IDC_PIC_CTRL); // 获取Picture Control的指针
pWnd->GetClientRect(&rect); // 获取绘制区域大小
CDC* pDC = pWnd->GetDC(); // 获取绘图设备上下文
// 绘制背景
pDC->FillSolidRect(rect, RGB(255, 255, 255));
// 设置坐标轴参数
int marginX = rect.Width() / 8.0;
int marginY = rect.Height() / 8.0;
time_t now = time(0);
tm* localTime = localtime(&now);
char buffer[80];
strftime(buffer, 80, "%Y-%m-%d 仰角角度测量试验", localTime);
CString cstringTime(buffer);
CString chartTitle = (cstringTime) ;
CString xAxisTitle = _T("时间(时:分:秒)");
CString yAxisTitle = _T("角度(°)");
// 绘制横轴线和纵轴线
pDC->MoveTo(rect.left + marginX + 3, rect.bottom - marginY * 1.5);
pDC->LineTo(rect.right - marginX, rect.bottom - marginY * 1.5);
pDC->MoveTo(rect.left + marginX, rect.top + marginY * 1.5);
pDC->LineTo(rect.left + marginX, rect.bottom - marginY * 1.5 - 3);
// 绘制箭头线
/*
pDC->MoveTo(rect.right - marginX, rect.bottom - marginY * 1.5);
pDC->LineTo(rect.right - marginX - 6.0, rect.bottom - marginY * 1.5 - 6.0);
pDC->MoveTo(rect.right - marginX, rect.bottom - marginY * 1.5);
pDC->LineTo(rect.right - marginX - 6.0, rect.bottom - marginY * 1.5 + 6.0 );
*/
// 绘制坐标轴标题
pDC->SetBkMode(TRANSPARENT);
// 设置大标题文本颜色
pDC->SetTextColor(RGB(0, 0, 255)); // 深蓝色
// 设置大标题文本粗细
CFont font;
font.CreateFont(16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Arial")); // 创建一个16像素的粗体Arial字体
pDC->SelectObject(&font); // 设置字体
pDC->TextOut(rect.Width() / 2, rect.bottom - marginY * 0.5, chartTitle);//大标题
// 设置大标题文本颜色
pDC->SetTextColor(RGB(0, 0, 0)); // 黑色
pDC->TextOut(rect.left + (double)marginX * 7.2, rect.bottom - marginY * 1.6, xAxisTitle);//x轴标题
pDC->TextOut(rect.left + marginX - 30, rect.top + marginY / 2, yAxisTitle);//Y轴标题
//std::vector<std::string> xAxisLabels = { "0","北京", "上海", "南京" };
//std::vector<double> yAxisValues = { 0,0.2, 0.5, 1.8 };
std::string currentTime = getCurrentTimeAsString();
//点击次数增加
if (yAxisValues.size() == 1)
{
xAxisLabels.push_back(currentTime);
yAxisValues.push_back(2.2);
}
else if (yAxisValues.size() == 2)
{
xAxisLabels.push_back(currentTime);
yAxisValues.push_back(4.2);
}
else if (yAxisValues.size() == 3)
{
xAxisLabels.push_back(currentTime);
yAxisValues.push_back(1.2);
}
else if (yAxisValues.size() == 4)
{
xAxisLabels.push_back(currentTime);
yAxisValues.push_back(2.2);
}
else if (yAxisValues.size() == 5)
{
xAxisLabels.push_back(currentTime);
yAxisValues.push_back(6.2);
}
else if (yAxisValues.size() == 6)
{
xAxisLabels.push_back(currentTime);
yAxisValues.push_back(5.2);
}
else
{
//当点击次数大于六次
xAxisLabels.erase(xAxisLabels.begin());
yAxisValues.erase(yAxisValues.begin());
xAxisLabels.push_back(currentTime);
yAxisValues.push_back(8.2);
}
int numPoints = yAxisValues.size();
int xInterval = (rect.Width() - 2 * marginX) / (numPoints - 1);//x轴间隔
int yInterval = (rect.Height() - 2 * marginY) / (13 - 1);//y轴间隔 这个地方的是纵轴的最大数量
// 绘制横轴标签刻度
for (int i = 0; i < numPoints; i++)
{
int x = rect.left + marginX + i * xInterval;
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 210)); // 创建一个红色的实线画笔
pDC->SelectObject(&pen); // 设置画笔
pDC->MoveTo(x, rect.bottom - marginY * 1.5); //横轴小标记
pDC->LineTo(x, rect.bottom - marginY * 1.5 + 5);
pDC->TextOut(x - 10, rect.bottom - marginY * 1.5 + 10, CString(xAxisLabels[i].c_str()));
}
//将最大的值进行/12操作,
for (int i = 0; i < 13; i++)//重新绘制纵轴 这个地方的8是最大值
{
// 寻找最大值的迭代器
auto maxIt = std::max_element(yAxisValues.begin(), yAxisValues.end());
double maxValue;
// 如果找到了最大值,则打印它
if (maxIt != yAxisValues.end())
{
maxValue = *maxIt;
}
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 210)); // 创建一个红色的实线画笔
pDC->SelectObject(&pen); // 设置画笔
double y = (double)(rect.bottom) - (double)marginY * 1.5 - ((double)10.0 / (double)12.0 * (double)i) * (double)yInterval; //根据实际大小进行设定 这个地方需要注意yInterval变量与
pDC->MoveTo(rect.left + marginX, y); //纵轴小标记
pDC->LineTo(rect.left + marginX - 5, y);
double value = (maxValue / (double)12.0) * (double)i; // 假设i是一个整数变量
std::stringstream ss;
ss << std::fixed << std::setprecision(4) << value;
std::string strValue = ss.str();
CString cstrValue(strValue.c_str());
pDC->TextOut(rect.left + marginX * 0.8 - 30, y - 5, cstrValue);
}
// 绘制折线
for (int i = 0; i < numPoints - 1; i++)
{
int x1 = rect.left + marginX + i * xInterval;
int y1 = rect.bottom - marginY * 1.5 - (yAxisValues[i]*12.0/10.0) * yInterval;
int x2 = rect.left + marginX + (i + 1) * xInterval;
int y2 = rect.bottom - marginY * 1.5 - (yAxisValues[i + 1]*12.0/10.0) * yInterval;
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(125, 0, 0)); // 创建一个红色的实线画笔
pDC->SelectObject(&pen); // 设置画笔
pDC->MoveTo(x1, y1);
pDC->LineTo(x2, y2);
pDC->SetTextColor(RGB(255, 0, 0)); // 深蓝色
//绘制数值
pDC->TextOut(x2 - 8, y2 - 20, CString(std::to_string(yAxisValues[i+1]).c_str()));//这个地方的标记需要变成4个小数点
}
pWnd->ReleaseDC(pDC);
}
在使用上述代码的时候需要进行头文件的引入
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <atlstr.h>
#include <iostream>
#include <ctime>
#include <cstring>
#include <iostream>
#include <sstream>
#include <chrono>
using namespace std;
最后测试的展示情况是如下所示:
上述的依次添加按钮是按下一次,添加一个折现,只是个示例的过程,也可以改为实时动态的过程,只要添加个定时器就可以了,比较简单。关于界面部分,自己进行修改修改,进行美化一下就可以使用了。上述代码比较通俗易懂,按照自己的逻辑写的。