zoukankan      html  css  js  c++  java
  • vc mfc 写excel文件,包括数据和图表

    我的需求是根据数据画柏拉图

    1.参考

    [MFC]MFC输出到EXCEL表格并画图表

    MSDN 上只有VBA的代码,vc的资料都是别人写的代码做参考

    Excel VBA 参考

    这些.h文件是通过excel.exe导入到项目中的,我的office是2016 目录是

    C:Program Files (x86)Microsoft Office ootOffice16excel.exe

    导入方法可以参考 MFC vc++ 写 word 文件,使用MSWORD.OLB 导入方法

    向excel中写数据并画图

      1 #include "CApplication.h"
      2 #include "CChart.h"
      3 #include "CChartObject.h"
      4 #include "CChartObjects.h"
      5 #include "CCharts.h"
      6 #include "CRange.h"
      7 #include "CWorkbook.h"
      8 #include "CWorkbooks.h"
      9 #include "CWorksheet.h"
     10 #include "CWorksheets.h"
     11 
     12 void CMFCApplication1Dlg::OnBnClickedOk()
     13 {
     14     COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
     15     CApplication app;
     16     if (!app.CreateDispatch(_T("Excel.Application"), NULL))
     17     {
     18         AfxMessageBox(_T("创建Excel服务失败!"));
     19         return;
     20     }
     21     app.put_Visible(FALSE);//不显示EXCEL表
     22 
     23     CWorkbooks books;
     24     CWorkbook book;
     25     books = app.get_Workbooks();//获取一个工作簿集合
     26     book = books.Add(covOptional);//添加一个工作簿
     27 
     28     CWorksheets sheets;
     29     CWorksheet sheet;
     30     sheets = book.get_Sheets();//获取一个工作表集合
     31     sheet = sheets.get_Item(COleVariant((short)1));//获取一个工作表
     32 
     33     CRange range;
     34     range.AttachDispatch(sheet.get_Cells(), TRUE);//加载所有单元格
     35     range.put_Item(_variant_t((long)1), _variant_t((long)1), _variant_t("失败测试项"));//横坐标 纵坐标 内容
     36     range.put_ColumnWidth(_variant_t((long)10));//所有列的宽度
     37     range.put_Item(_variant_t((long)1), _variant_t((long)2), _variant_t("频次"));
     38     range.put_Item(_variant_t((long)1), _variant_t((long)3), _variant_t("累计百分比"));
     39     range.put_Item(_variant_t((long)1), _variant_t((long)4), _variant_t("频率"));
     40 
     41     range.put_Item(_variant_t((long)2), _variant_t((long)1), _variant_t("失败1"));
     42     range.put_Item(_variant_t((long)3), _variant_t((long)1), _variant_t("失败2"));
     43     range.put_Item(_variant_t((long)4), _variant_t((long)1), _variant_t("失败3"));
     44     range.put_Item(_variant_t((long)5), _variant_t((long)1), _variant_t("失败4"));
     45     range.put_Item(_variant_t((long)6), _variant_t((long)1), _variant_t("失败5"));
     46 
     47     range.put_Item(_variant_t((long)2), _variant_t((long)2), _variant_t(20));
     48     range.put_Item(_variant_t((long)3), _variant_t((long)2), _variant_t(20));
     49     range.put_Item(_variant_t((long)4), _variant_t((long)2), _variant_t(20));
     50     range.put_Item(_variant_t((long)5), _variant_t((long)2), _variant_t(20));
     51     range.put_Item(_variant_t((long)6), _variant_t((long)2), _variant_t(20));
     52 
     53     range.put_Item(_variant_t((long)2), _variant_t((long)3), _variant_t("20%"));
     54     range.put_Item(_variant_t((long)3), _variant_t((long)3), _variant_t("40%"));
     55     range.put_Item(_variant_t((long)4), _variant_t((long)3), _variant_t("60%"));
     56     range.put_Item(_variant_t((long)5), _variant_t((long)3), _variant_t("80%"));
     57     range.put_Item(_variant_t((long)6), _variant_t((long)3), _variant_t("100%"));
     58 
     59     range.put_Item(_variant_t((long)2), _variant_t((long)4), _variant_t("20%"));
     60     range.put_Item(_variant_t((long)3), _variant_t((long)4), _variant_t("20%"));
     61     range.put_Item(_variant_t((long)4), _variant_t((long)4), _variant_t("20%"));
     62     range.put_Item(_variant_t((long)5), _variant_t((long)4), _variant_t("20%"));
     63     range.put_Item(_variant_t((long)6), _variant_t((long)4), _variant_t("20%"));
     64 
     65     long left, top, width, height;
     66     left = 100;
     67     top = 10;
     68     width = 350;
     69     height = 250;
     70 
     71     CChartObjects excel_charts;
     72     CChartObject excle_chart;
     73     CChart chart;
     74     LPDISPATCH lpDisp;
     75     lpDisp = sheet.ChartObjects(covOptional);
     76     ASSERT(lpDisp);
     77     excel_charts.AttachDispatch(lpDisp);
     78 
     79     excle_chart = excel_charts.Add(left, top, width, height);
     80     chart.AttachDispatch(excle_chart.get_Chart());
     81 
     82     lpDisp = sheet.get_Range(_variant_t("A1"), _variant_t("C6"));//图标数据范围
     83     ASSERT(lpDisp);
     84     range.AttachDispatch(lpDisp);
     85 
     86     VARIANT var;
     87     var.vt = VT_DISPATCH;
     88     var.pdispVal = lpDisp;
     89 
     90     chart.ChartWizard(var,
     91         COleVariant((short)65),//图表类型折线图
     92         covOptional,//不知道有啥用
     93         COleVariant((short)2),
     94         COleVariant((short)1),
     95         COleVariant((short)1),//"系列1"用的个数
     96         COleVariant((short)TRUE),
     97         _variant_t("失败项柏拉图"),//图表标题
     98         _variant_t(""),//横坐标标题
     99         _variant_t(""),//纵坐标标题
    100         _variant_t("")//此纵坐标标题
    101     );
    102     //保存
    103     CString strExcelPath = _T("柏拉图.xlsx");//创建在我的文档中
    104     book.SaveAs(_variant_t(strExcelPath), vtMissing, vtMissing, vtMissing, vtMissing,
    105         vtMissing, 0, vtMissing, vtMissing, vtMissing,
    106         vtMissing, vtMissing);
    107 
    chart.ReleaseDispatch();
    chartObject.ReleaseDispatch(); 108 range.ReleaseDispatch(); 109 sheet.ReleaseDispatch(); 110 sheets.ReleaseDispatch(); 111 book.ReleaseDispatch();
    books.Close();
    112 books.ReleaseDispatch(); 113 app.Quit(); 114 app.ReleaseDispatch(); 115 //退出程序 116 }

    这时生成的excel.xlsx文件是这样的

     但此时这个图离要求还要调整图表

    1.“累计百分比”的坐标轴,次坐标

    2.设置“频数”的图表类型为柱形图

    3.设置图表显示数据标签

    4.移动图表位置

    此时,用office excel 的 视图 ->录制宏,生成的各个步骤的VBA代码是

     1 Sub 宏1()
     2 '
     3 ' 宏1 宏
     4 '
     5 
     6 '
     7     ActiveSheet.ChartObjects("图表 1").Activate
     8     ActiveChart.FullSeriesCollection(2).AxisGroup = 2
     9 End Sub
    10 
    11 Sub 宏2()
    12 '
    13 ' 宏2 宏
    14 '
    15 
    16 '
    17     ActiveSheet.ChartObjects("图表 1").Activate
    18     ActiveChart.FullSeriesCollection(1).ChartType = xlColumnClustered
    19 End Sub
    20 Sub 宏3()
    21 '
    22 ' 宏3 宏
    23 '
    24 
    25 '
    26     ActiveChart.SetElement (msoElementDataLabelShow)
    27 End Sub
    28 Sub 宏4()
    29 '
    30 ' 宏4 宏
    31 '
    32 
    33 '
    34     ActiveChart.ChartArea.Select
    35     ActiveSheet.Shapes("图表 1").IncrementLeft 155
    36     ActiveSheet.Shapes("图表 1").IncrementTop -7
    37 End Sub

    这个代码转换成vc 的代码就ok了,但是查了半天MSDN 一些步骤找不到对应的函数,所以这个代码画简单图还是有点用,复杂的查msdn太煎熬了

    这时又有另一个方法是

    1.先把.xlsx文件做出来,图画好 如图

      

     2.写代码修改单元格的数据,再修改图表对应的单元格范围 这样就可以比较灵活的生成一个柏拉图了

     1 void CMFCApplication2Dlg::OnBnClickedOk()
     2 {
     3     COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
     4     CApplication excel_app; //Excel应用程序
     5     if (!excel_app.CreateDispatch(_T("Excel.Application"), NULL))
     6     {
     7         AfxMessageBox(_T("创建Excel服务失败!"));
     8         return;
     9     }
    10     excel_app.put_Visible(FALSE);//不显示EXCEL表
    11     excel_app.put_UserControl(FALSE);//不允许其他用户控制Excel
    12     //得到工作簿容器
    13     CWorkbooks books;
    14     books.AttachDispatch(excel_app.get_Workbooks());
    15     //打开一个工作簿,如不存在,则新增一个工作簿
    16     CWorkbook book;
    17     LPDISPATCH lpDisp;
    18     lpDisp = books.Open(_T("柏拉图Format.xlsx"),
    19     vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
    20     vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
    21     vtMissing, vtMissing, vtMissing, vtMissing);
    22     book.AttachDispatch(lpDisp);
    23 
    24     //得到工作簿中的Sheet的容器
    25     CWorksheets sheets;
    26     CWorksheet sheet;
    27     sheets.AttachDispatch(book.get_Sheets());
    28     sheet = sheets.get_Item(_variant_t((long)1));//获取一个工作表
    29 
    30     //修改一个单元格表示正确打开了这个文件
    31     CRange range;
    32     range.AttachDispatch(sheet.get_Cells(), TRUE);//加载所有单元格
    33     range.put_Item(_variant_t((long)7), _variant_t((long)1), _variant_t("失败6"));//横坐标 纵坐标 内容
    34     range.put_Item(_variant_t((long)7), _variant_t((long)2), _variant_t("10"));//横坐标 纵坐标 内容
    35     range.put_Item(_variant_t((long)7), _variant_t((long)3), _variant_t("110%"));//横坐标 纵坐标 内容
    36     range.put_Item(_variant_t((long)7), _variant_t((long)4), _variant_t("10%"));//横坐标 纵坐标 内容
    37     CChartObject chartObject;
    38     CChart chart;
    39     lpDisp = sheet.ChartObjects(_variant_t((long)1));//第一个图表
    40     ASSERT(lpDisp);
    41     chartObject.AttachDispatch(lpDisp);
    42     chart = chartObject.get_Chart();
    43     LPDISPATCH lpRange;
    44     lpRange = sheet.get_Range(_variant_t("A1"), _variant_t("C7"));//图标数据范围
    45 
    46     chart.SetSourceData(lpRange, _variant_t((long)2));
    47 
    48     //保存
    49     //book.Save();
    50     //另存为
    51     CString strExcelPath = _T("柏拉图1.xlsx");//创建在我的文档中
    52     book.SaveAs(_variant_t(strExcelPath), vtMissing, vtMissing, vtMissing, vtMissing,
    53         vtMissing, 0, vtMissing, vtMissing, vtMissing,
    54         vtMissing, vtMissing);
    55     //关闭文件释放资源
    chart.ReleaseDispatch();
    lpRange->Release();//这个东西要释放掉
    chartObject.ReleaseDispatch(); 56 range.ReleaseDispatch(); 57 sheet.ReleaseDispatch(); 58 sheets.ReleaseDispatch(); 59 book.ReleaseDispatch();
    books.Close();
    60 books.ReleaseDispatch(); 61 excel_app.Quit(); 62 excel_app.ReleaseDispatch(); 63 }

    结果如图

     这个方法的缺点是图表的2个“系列”频次和累计百分比的单元格必须是挨着的2列数据,不然需要再从图表类得到“系列”的类,再修改“系列”的数据范围,那就不知道能不能行的通了

     这里只对如何画柏拉图做讨论,不对举例的数据合理性做讨论,参考 【工具】柏拉图的正确制作方法             Excel柏拉图怎么制作

    延申问题:

    1.在线程中写excel文件,Range::put_Item这个函数有中断,不知道啥原因,那就不要用了吧

    2.可以在表格中写公式例如,range.put_Item(_variant_t((long)2), _variant_t((long)1), _variant_t("=C2"));

    结果如图

    设置字体和对齐方式

    CFont0 excelFont;
    CRange rangeFont;

    1                 strRange.Format(_T("%s%d"), strTemp, stuTempFormat.iRow);// A1
    2                 rangeFont.AttachDispatch(sheet.get_Range(_variant_t(strRange), _variant_t(strRange)), TRUE);//这里可以用一个范围
    3                 excelFont.AttachDispatch(rangeFont.get_Font());
    4                 excelFont.put_Name(_variant_t(strFontName)); //字体
    5                 excelFont.put_Size(_variant_t((long)m_iFontSize)); //大小
    6                 rangeFont.put_HorizontalAlignment(_variant_t((long)m_ExcelAlignment));//对齐方式

     获取行数列数

    在MFC中怎么获得Excel文档中已经使用了的行数和列数

        CRange range;
        range = sheet.get_UsedRange();
        range = range.get_Rows();
        long lCountRow = range.get_Count();
        range = range.get_Columns();
        long lCountCol = range.get_Count();
  • 相关阅读:
    关于SQL Server系统数据库详解
    如何删除发布服务器distribution
    SQL Server如何删除多余tempDB文件
    SQL Server 中用While循环替代游标Cursor的解决方案
    理解性能的奥秘——应用程序中慢,SSMS中快(4)收集解决参数嗅探问题的信息
    第十六章——处理锁、阻塞和死锁(3)——使用SQLServer Profiler侦测死锁
    第十六章——处理锁、阻塞和死锁(2)——侦测阻塞和阻塞查询
    降级与熔断
    浅淡缓存
    小P的架构生活(下)
  • 原文地址:https://www.cnblogs.com/ckrgd/p/14520399.html
Copyright © 2011-2022 走看看