VC6.0讀取Excel文件數據


  啰嗦一下:本人所在公司從事碟式斯特林太陽能發電設備的研發與銷售。單台設備圖如下:

  工作原理如下:整個設備大致可分為五個部分,

    1、服務器,負責氣象、發電等數據存取,電、網連接等處理;

    2、氣象站,通過光感應器實時獲取氣象數據,傳送至服務器

    3、碟型鏡面,反射陽光熱量,均勻聚焦到350mm直徑的圓形范圍內——發動機熱頭大小;

    4、斯特林發動機,吸收鏡面反射熱量,通過內部氣體膨脹、收縮帶動發動機發電;

    5、通信線,連接系統各個部分,使其運行正常。

  對於這樣一台設備,要使其高效發電,出氣象條件要好之外,對每塊鏡片的最終安裝位置要求極高。因為所有的支撐架子、鏡片的形狀、曲率等參數不可能做到一模一樣,所以每台設備在鏡片初步安裝之后都必須進行精細的調整。具體技術問題這里暫不討論。

  而對於一個電站,由幾十或成百上千台碟子組成,除了鏡片調試以外,還有一個重要的問題需要解決:所有碟子的布局。因為,若碟子之間的距離過小,會有遮擋,造成部分鏡面沒有陽光照射,發動機吸收熱量減少,影響發電效率,嚴重的話會使其停止工作;而若距離過大,解決遮擋的同時,會造成整個電站面積過大,意味着通信線與土地的代價增加。因此,在這之間尋求一種折中的解決方案至關重要,做到盡量高效,低成本。

  針對斯特林碟式太陽能發電站的碟子位置布局問題,公司要求做一個軟件,主要功能是分析歷史電站的發電、氣象、電價、布線等數據,並結合擬定的碟子布局模型,比較實際與模擬結果,選擇最佳方案。

  回歸正題:文件存儲在Excel文件中,因此第一步是能夠在程序中方便地讀取表格數據,這里用的是VC6.0 MFC。

  1、電腦上安裝VC6.0,Excel2007,其他Office版本亦可(WPS盡量避免);

  2、建立一個MFC基於對話框的應用程序工程,名稱自己定,這里取名為"Solar",添加一個按鈕、一個列表控件,分別取名為"Model2","List1",並為后者添加成員變量"m_ExcelData"。

  3、在程序入口處CXXXApp:: InitInstance()函數AfxEnableControlContainer();語句之后加入下面幾行:

1 if (CoInitialize(NULL) != 0)
2 {
3        AfxMessageBox(“初始化COM支持庫失敗!”);
4        exit(1);
5 }

假如這個條件不通過就不能運行起程序。在程序的出口處CSolarApp:: ExitInstance()函數return語句之前加入下面這句話:

1 CoUninitialize();

來釋放COM支持庫,這樣對COM庫的支持就已完成。

  4、下面要從Office的安裝目錄中找到對VC操作excel文件的動態庫,在某些版本下這個文件是Excel8.olb或Excel9.olb,在我的版本中是excel.exe這個exe也是動態庫的形式,是微軟公司主要的文件結果之一。選擇VC的View(查看)菜單里面的類向導ClassWizad命令,會彈出一個對話框;然后點擊Add Class…按鈕選擇From a type library,會彈出一個打開對話框,從這里打開Office安裝目錄下D:\Program Files\Microsoft Office\Office12\EXCEL.EXE文件,從里面選擇幾個要用到的類:_Application, Workbooks, _Wrokbook, Worksheets, _WorkSheet, Range,點擊OK按鈕。會在程序中生成一個excel.h和excel.cpp文件,這些文件中包含了剛才我們選擇的幾個類的代碼。下面介紹一下這幾個類:

  在VC操縱excel的exe動態庫里面有好多個對象模型,就是剛才在創建過程中看到的那個列表,但是經常用到的有這么幾個:_Application, Workbooks, _Wrokbook, Worksheets, _WorkSheet, Range,Charts和_Chart,最后面的兩個是用來操作圖表的,這里沒有用到所以這里也就不記錄了。

  1>_Application:這里的Application就是Excel本身,眾所周知,一個Excel可以包含多個工作簿,每個工作簿又可以包含多個工作表,而每個工作表又可以包含多個區域或者圖表,所以這里他們是樹型的結構關系,而application最基本的一個功能就是找到它的子項工作簿。果然,我們在引入我們程序的Application類中看到了這樣的成員函數:GetWorkbooks()。

  2> Workbooks:這個對象是一個容器對象,它里面存放着所有打開的工作簿。因此,我們可以猜測它一定有添加,查找,打開/關閉工作簿的功能。(本程序中使用excel的一個xlt模板來生成一個xls文件就是使用了這個容器對象的添加功能。)

  3> _Workbook:這是一個工作簿,也就相當於一個xls文件。Excel可以同時打開多個工作簿,所以工作簿之間必定能夠互相切換,每個工作簿可以關聯工作表容器並獲得工作表的索引。

  4> Worksheets:也是一個容器對象,和Workbooks類似。

  5> _Worksheet:這個就是我們看到的工作表,比如Sheet1,sheet2等等。

  6> Rang:就是我們看到的能選中的方框的大小。而我們所要作的操作基本上是以區域為單位進行的。

  5、准備工作做好之后,接下來開始實現按鈕功能:按下之后讀取Excel表格數據,並顯示在列表控件中。這里只是進行簡單地顯示,沒有給出具體的處理過程及結果圖像。目標Excel文件數據如下,行、列分別為30、9(包括序號)。

  在頭文件"afxstd.h"中添加以下幾個頭文件(有些電腦環境可能不必全部加),注意別重復添加某些頭文件。

1 #include <comdef.h>
2 #include <comutil.h>
3 #include <OAIDL.H>
4 #include <afxdisp.h>
5 #include "excel.h"

  若編譯報重定義錯誤,解決方法是在"excel.h"頭文件中的頭部添加:

1 #if !defined _HEAD_FILE_EXCEL9_ 
2 #define _HEAD_FILE_EXCEL9_

  在其尾部添加:

#endif

  在對話框初始化函數BOOL CSolarDlg::OnInitDialog()中添加列表控件風格設置語句:

1 m_Exceldata.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);

  OK,在函數BOOL CSolarDlg::OnModel2()中添加數據讀取及顯示代碼:

  1   _Application m_oExcelApp;
  2     Worksheets m_oWorkSheets;
  3     _Worksheet m_oWorkSheet;
  4     Workbooks m_oWorkBooks;
  5     _Workbook m_oWorkBook;
  6     Range m_oCurrRange;
  7     if (!m_oExcelApp.CreateDispatch( _T( "Excel.Application" ), NULL ) ) 
  8     {
  9         ::MessageBox( NULL, _T( "創建Excel服務失敗!" ), _T( "錯誤提示!" ), MB_OK | MB_ICONERROR); 
 10         exit(1); 
 11     }
 12 
 13     //設置為顯示
 14     m_oExcelApp.SetVisible(FALSE);
 15     m_oWorkBooks.AttachDispatch( m_oExcelApp.GetWorkbooks(), TRUE ); //沒有這條語句,下面打開文件返回失敗。
 16 
 17     LPDISPATCH  lpDisp = NULL;
 18     COleVariant covTrue((short)TRUE);
 19     COleVariant covFalse((short)FALSE);
 20     COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 
 21     Range       oCurCell;
 22 
 23     CString FilePathName;
 24     CFileDialog dlg(TRUE);///TRUE為OPEN對話框,FALSE為SAVE AS對話框
 25     if(dlg.DoModal() == IDOK)
 26     {
 27         FilePathName = dlg.GetPathName();
 28         /*
 29         (1)GetPathName();取文件名全稱,包括完整路徑。取回C:\\WINDOWS\\TEST.EXE
 30         (2)GetFileTitle();取回TEST
 31         (3)GetFileName();取文件全名:TEST.EXE
 32         (4)GetFileExt();取擴展名EXE
 33         */
 34     }
 35     else
 36     {
 37         AfxMessageBox("Open file opetation has been canceled.");
 38         return;
 39     }
 40     
 41     // 打開文件
 42     lpDisp = m_oWorkBooks.Open( FilePathName, 
 43                               _variant_t(vtMissing), 
 44                               _variant_t(vtMissing),
 45                               _variant_t(vtMissing),
 46                               _variant_t(vtMissing),
 47                               _variant_t(vtMissing),
 48                               _variant_t(vtMissing),
 49                               _variant_t(vtMissing),
 50                               _variant_t(vtMissing),
 51                               _variant_t(vtMissing),
 52                               _variant_t(vtMissing),
 53                               _variant_t(vtMissing),
 54                               _variant_t(vtMissing),
 55                               _variant_t(vtMissing),
 56                               _variant_t(vtMissing) );
 57     // 獲得活動的WorkBook( 工作簿 )
 58     m_oWorkBook.AttachDispatch( lpDisp, TRUE );
 59     // 獲得活動的WorkSheet( 工作表 )
 60     m_oWorkSheet.AttachDispatch( m_oWorkBook.GetActiveSheet(), TRUE );
 61     // 獲得使用的區域Range( 區域 )
 62     m_oCurrRange.AttachDispatch( m_oWorkSheet.GetUsedRange(), TRUE );
 63 
 64     // 獲得使用的行數
 65     long lgUsedRowNum = 0;
 66     m_oCurrRange.AttachDispatch( m_oCurrRange.GetRows(), TRUE );
 67     lgUsedRowNum = m_oCurrRange.GetCount();
 68     // 獲得使用的列數
 69     long lgUsedColumnNum = 0;
 70     m_oCurrRange.AttachDispatch( m_oCurrRange.GetColumns(), TRUE );
 71     lgUsedColumnNum = m_oCurrRange.GetCount();
 72     // 讀取Sheet的名稱
 73     CString strSheetName = m_oWorkSheet.GetName();
 74 
 75     //得到全部Cells,此時,CurrRange是cells的集合 
 76     m_oCurrRange.AttachDispatch( m_oWorkSheet.GetCells(), TRUE ); 
 77 
 78     // 更新列表控件數據
 79     for ( int j = 0; j < lgUsedColumnNum; ++j)
 80     {
 81         if(j == 9)
 82         {
 83             m_Exceldata.InsertColumn(j,"Index",LVCFMT_CENTER);
 84             m_Exceldata.SetColumnWidth(j,40);
 85             continue;
 86         }
 87         oCurCell.AttachDispatch( m_oCurrRange.GetItem( COleVariant( (long)(0 + 1)), COleVariant( (long)j ) ).pdispVal, TRUE );
 88         VARIANT varItemName = oCurCell.GetText();
 89         strItemName = varItemName.bstrVal;
 90         m_Exceldata.InsertColumn(j,strItemName,LVCFMT_CENTER);
 91         m_Exceldata.SetColumnWidth(j,80);
 92     }
 93 
 94     for ( int i = 1; i < lgUsedRowNum; ++i) //標題欄0+1行已經取出,從1+1開始獲取數據到29+1
 95     {
 96         strItemName.Format("%d",i);
 97         m_Exceldata.InsertItem(i-1,strItemName);
 98         m_Exceldata.SetItemText(i-1,0,strItemName);
 99         for ( int j = 1; j < lgUsedColumnNum; ++j) //1-8
100         {
101             oCurCell.AttachDispatch( m_oCurrRange.GetItem( COleVariant( (long)(i + 1)), COleVariant( (long)j ) ).pdispVal, TRUE );
102             VARIANT varItemName = oCurCell.GetText();
103             strItemName = varItemName.bstrVal;
104 
105             // 判斷是否是合並的單元格
106             VARIANT varMerge = oCurCell.GetMergeCells();
107             if ( varMerge.boolVal == -1 )
108             {
109                  AfxMessageBox( _T( "是合並的單元格!" ) );
110             }
111             else if ( varMerge.boolVal == 0 )
112             {
113                  AfxMessageBox( _T( "不是合並的單元格!" ) );
114             }
115             
116             m_Exceldata.SetItemText(i-1,j,strItemName);
117         }
118     }
119 
120     // 關閉
121     m_oWorkBook.Close( covOptional, COleVariant( FilePathName ), covOptional );
122     m_oWorkBooks.Close();
123     // 釋放
124     m_oCurrRange.ReleaseDispatch();
125     m_oWorkSheet.ReleaseDispatch();
126     m_oWorkSheets.ReleaseDispatch();
127     m_oWorkBook.ReleaseDispatch();
128     m_oWorkBooks.ReleaseDispatch();
129     m_oExcelApp.ReleaseDispatch();
130     m_oExcelApp.Quit();    // 這條語句是推出Excel程序,任務管理器中的EXCEL進程會自動結束

 

 代碼中字符串變量strItemName是全局變量,在文件開頭聲明:

1 CString strItemName = " ";

  須注意的是:

  1> 代碼中79-92行是為列表添加屬性列及名稱,第一個屬性序號("Index")是人為命名並添加,不是必須的;從第二個屬性列開始為表格屬性;

  2> 代碼中23-39行是文件打開過程,選擇Excel文件后,下面代碼會根據完整文件名進行數據讀取;

  3> 在VC數組及列表控件中,下標從0開始,而讀取Excel表格數據時,索引從1開始。

 至此,簡單的編程過程已完成,重新生成解決方案,編譯、運行,結果如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM