利用MFC绘制Excel数据的波形

利用MFC绘制Excel数据的波形

工具:VS2015、Excel2013

  • 项目的创建
  • 创建文件对话框
  • 打开并读取Excel文件
  • 绘制波形

项目的创建

打开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);
    }

}

Excel表格的读取

添加类
点击项目—添加类—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编程入门》

你可能感兴趣的:(c++代码练习)