工具:VS2015、Excel2013
打开VS2015,文件—新建—项目—MFC应用程序—项目名称改为wavedraw—确定—下一步—选择基于对话框—完成
删除TODO:在此放置对话框控件,添加一个Edit Control控件,ID改为IDC_SLCT_EDIT,添加一个Button控件,ID改为IDC_SLCT_BUTTON,caption改为选择文件,最后添加一个Picture Control控件。
在选择文件控件上添加事件处理程序
void CwavedrawDlg::OnBnClickedSlctButton()
{
// TODO: 在此添加控件通知处理程序代码
//设置过滤器
TCHAR fmtFilter[] = _T("excel文件(*.xlsx*.xls)|*.xlsx;*.xls||");
//构造文件对话框
CFileDialog fileDlg(TRUE, _T("xlsx"), NULL, 0, fmtFilter, this);
CString strFilePath; //文件路径
//打开文件对话框
if (IDOK == fileDlg.DoModal())
{
//点击文件对话框上的打开"按钮
strFilePath = fileDlg.GetPathName();
SetDlgItemText(IDC_SLCT_EDIT, strFilePath);
}
}
添加类
点击项目—添加类—TypeLib中的MFC类—文件—位置为excel.exe路径,添加 _Application,_Workbook,_Worksheet,_Font,_Workbooks,_Worksheets,_Range.在wavedrawDlg.h头文件中添加
#include"CApplication.h"
#include"CFont0.h"
#include"CRange.h"
#include"CWorkbook.h"
#include"CWorkbooks.h"
#include"CWorksheet.h"
#include"CWorksheets.h"
#define COUNT 100
并加入声明
double value[COUNT]={0};
int CT=0;
在 wavedrawDlg.cpp中加入代码
void CwavedrawDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
//导入
COleVariant covOptional((long)DISP_E_PARAMNOTFOUND,VT_ERROR);
if (!app.CreateDispatch(_T("Excel.Application")))
{
this->MessageBox(_T("无法创建Excel应用!"));
//return TRUE;
}
books = app.get_Workbooks();
//打开Excel,其中pathname为Excel表的路径名
UpdateData(TRUE);
lpDisp = books.Open(m_strfilepath, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);
book.AttachDispatch(lpDisp);
sheets = book.get_Worksheets();
sheet = sheets.get_Item(COleVariant((short)1));
_variant_t rValue; //存储获得的单元格内容
//获得坐标为(A,i)的单元格
for (int i = 0; i < 100; i++)
{
CString num;
num.Format(_T("A%d"), i+1);
range = sheet.get_Range(_variant_t(num), _variant_t(num));
//获得单元格的内容
rValue = _variant_t(range.get_Value2());
//转换成double型
rValue.ChangeType(VT_R8);
//转换格式,并输出
value[i]= rValue.dblVal;
}
book.put_Saved(TRUE);
app.Quit();
CDialogEx::OnOK();
}
在wavedrawDlg.cpp的BOOL CwavedrawDlg::OnInitDialog()中加入定时器
插入代码
//启动定时器,ID为1,定时时间为200ms
SetTimer(1,200,NULL);
为CwavedrawDlg类添加波形绘制的成员函数Cwavedraw::DrawWave(CDC*pDC,CRect &rectPicture),参数分别为设备上下指针和绘图的矩形区域
void CwavedrawDlg::DrawWave(CDC *pDC, CRect &rectPicture)
{
float fDeltaX; // x 轴相邻两个绘图点的坐标距离
float fDeltaY; // y 轴每个逻辑单位对应的坐标值
int nX; // 在连线时用于存储绘图点的横坐标
int nY; // 在连线时用于存储绘图点的纵坐标
CPen newPen; // 用于创建新画笔
CPen *pOldPen; // 用于存放旧画笔
CBrush newBrush; // 用于创建新画刷
CBrush *pOldBrush; // 用于存放旧画刷
// 计算 fDeltaX 和 fDeltaY
fDeltaX = (float)rectPicture.Width() / (COUNT - 1);
fDeltaY = (float)rectPicture.Height() / 100;
// 创建白色新画刷
newBrush.CreateSolidBrush(RGB(255, 255, 255));
// 选择新画刷,并将旧画刷的指针保存到 pOldBrush
pOldBrush = pDC->SelectObject(&newBrush);
// 以黑色画刷为绘图控件填充黑色,形成黑色背景
pDC->Rectangle(rectPicture);
// 恢复旧画刷
pDC->SelectObject(pOldBrush);
// 删除新画刷
newBrush.DeleteObject();
// 创建实心画笔,粗度为 1,颜色为黑色
newPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
// 选择新画笔,并将旧画笔的指针保存到 pOldPen
pOldPen = pDC->SelectObject(&newPen);
// 将当前点移动到绘图控件窗口的左下角,以此为波形的起始点
pDC->MoveTo(rectPicture.left, rectPicture.bottom);
// 计算 m_nzValues 数组中每个点对应的坐标位置,并依次连接,最终形成曲线
for (int i = 0; i < CT; i++)
{
nX = rectPicture.left + (int)(i * fDeltaX);
nY = rectPicture.bottom - (double)(value[i] * fDeltaY);
pDC->LineTo(nX, nY);
}
// 恢复旧画笔
pDC->SelectObject(pOldPen);
// 删除新画笔
newPen.DeleteObject();
}
有了定时器和绘图成员函数,我们就可以在 WM_TIMER 消息的响应函数中添加对
波形数据的定时处理和对波形的定时绘制了。修改代码
void CwavedrawDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CRect rectPicture;
// 获取绘图控件的客户区坐标
// (客户区坐标以窗口的左上角为原点,这区别于以屏幕左上角为原点的屏幕坐标)
m_picDraw.GetClientRect(&rectPicture);
// 绘制波形图
DrawWave(m_picDraw.GetDC(), rectPicture);
CT++;
CDialogEx::OnTimer(nIDEvent);
}
在对话框销毁时,定时器应关闭。所以为 CwavadrawDlg 类添加 WM_DESTRO
Y 消息的处理函数,并修改如下:
void CwavedrawDlg::OnDestroy()
{
CDialogEx::OnDestroy();
// TODO :在此处添加消息处理程序代码
//关闭定时器
KillTimer(1);
}
至此本程序功能可实现。本文大部分参考《鸡啄米VS2010/MFC编程入门》