1. 程式人生 > >VC匯出資料到EXCEL

VC匯出資料到EXCEL

我們製作應用軟體的時候,經常要把結果以報表的形式輸出,當前使用較為廣泛的當然是Excel表格,本文簡略介紹在VC++6.0中如何使用Excel2003的庫函式並對其進行程式設計。先建立一個對話方塊工程,命名為VCExcel。在對話方塊中新增一個按鈕,控制元件ID為ID_RUNEXCEL,介面如下(是不是很搞笑哇,不過沒關係,它照樣能實現強大的功能!)。 
    再在該按鈕上新增訊息BN_CLICKED,其訊息對映函式為OnRunexcel(),下面我們的工作就是要完成這個OnRunexcel()函式。在這裡我們通過一個例項來說明VC是如何呼叫Excel2003的介面程式設計的。 
我們要程式設計輸出一個如下表格。 

格式如下: 
     1、表頭的字型為宋體,加粗,顏色為白色,底色為深藍,垂直水平居中對齊; 
     2、表中正文內容字型為宋體,顏色為深藍,底色為灰色,垂直水平居中對齊;   
     3、全部邊框,文字自動換行。 
在BOOL CVCExcelApp::InitInstance()之中,int nResponse = dlg.DoModal()語句之後加入如下程式碼: 
if(!AfxOleInit())///初始化COM庫
         {
                   AfxMessageBox("初始化COM失敗");
                   return FALSE;
         } 
  為了能呼叫Excel的介面我們開啟MFC ClassWizard->Automation->Add Class->From a type library,選擇[Excel的安裝路徑]\EXCEL.exe,然後把所有的類都新增進去,標頭檔案為excel.h,原始檔為excel.cpp。當然,你也可以只把一些比較常用的類如_Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range加進去,因為網上流傳的絕大部分教程都只新增這幾個類,這完全根據你個人的需要。但在本例中我們至少還要用到Interior類(設定底色),Font類(設定字型),而且這樣做又簡單又方便擴充套件功能,不管三七二十一全部弄進去吧!但這樣做會有一個問題,有可能產生類的名字衝突,例如本來你自己寫了一個類叫Font,當你全部新增時又再次加入了Font類,這樣就重複定義了,不過可以通過名字空間來解決這個問題。再在VCExcelDlg.cpp檔案的頭部新增(如果系統已經自動新增就不要重複添加了): 
#include "VCExcel.h" 
#include "comdef.h" 
這樣一來我們的程式就可以自由呼叫EXCEL了,一切準備就緒。 

   下面先在CVCExcelDlg中新增如下成員變數,用來操控Excel應用程式、工作簿和單元格。 
       Range m_ExlRge; 
       _Worksheet m_ExlSheet; 
       Worksheets m_ExlSheets; 
       _Workbook m_ExlBook; 
       Workbooks m_ExlBooks; 
       _Application m_ExlApp; 
我們利用載入Excel模板來生成要求的表格,在本工程Debug資料夾中建立一個Excel檔案,命名為Template.xls。我們的OnRunexcel()程式碼如下(詳見註釋): 
void CVCExcelDlg::OnRunexcel() 

       // TODO: Add your control notification handler code here 

       //用m_ExlApp物件建立Excel2003程序 

       if(!m_ExlApp.CreateDispatch("Excel.Application",NULL)) 
       { 
              AfxMessageBox("建立Excel服務失敗!"); 
              return; 
       } 

       //設定為可見 
       m_ExlApp.SetVisible(TRUE); 

       ///////////////////下面得到應用程式所在的路徑/////////////////// 
       CString theAppPath,theAppName; 
       char Path[MAX_PATH]; 

       GetModuleFileName(NULL,Path,MAX_PATH);//得到應用程式的全路徑 
       theAppPath=(CString)Path; 

       theAppName=AfxGetApp()->m_pszAppName; 
       theAppName+=".exe"; 

       //把最後的檔名去掉 
       int length1,length2; 

       length1=theAppPath.GetLength(); 
       length2=theAppName.GetLength(); 

       theAppPath.Delete(length1-length2,length2); 
    //////////////////////////////////////////////////////////////// 


       CString TempPath=""; 

       TempPath=theAppPath+"Template.xls";//EXCEL模板的路徑 

       m_ExlBooks.AttachDispatch(m_ExlApp.GetWorkbooks(),TRUE); 

       m_ExlBook.AttachDispatch(m_ExlBooks.Add((_variant_t)TempPath),TRUE);//載入EXCEL模板 

       m_ExlSheets.AttachDispatch(m_ExlBook.GetSheets(),TRUE);//載入Sheet頁面 

       //新增新的Sheet頁面 
       m_ExlSheets.Add(vtMissing,vtMissing,_variant_t((long)1),vtMissing); 

       //刪除第二個Sheet頁面 
       m_ExlSheet.AttachDispatch(m_ExlSheets.GetItem(_variant_t((long)2)),TRUE); 
       m_ExlSheet.Delete(); 

       //把第一個Sheet頁面的名字改變為TestSheet 
       m_ExlSheet.AttachDispatch(m_ExlSheets.GetItem(_variant_t((long)1)),TRUE); 
       m_ExlSheet.SetName("TestSheet"); 


       ///////合併第一行單元格A1至D1////// 

       //載入要合併的單元格 
       m_ExlRge.AttachDispatch(m_ExlSheet.GetRange(_variant_t("A1"),_variant_t("D1")),TRUE); 

       m_ExlRge.Merge(_variant_t((long)0)); 

       ////////設定表格內容//////// 

       m_ExlRge.AttachDispatch(m_ExlSheet.GetCells(),TRUE);//載入所有單元格 

       m_ExlRge.SetItem(_variant_t((long)1),_variant_t((long)1),_variant_t("數學系研究生課程統計")); 

       m_ExlRge.SetItem(_variant_t((long)2),_variant_t((long)1),_variant_t("課程名")); 
       m_ExlRge.SetItem(_variant_t((long)2),_variant_t((long)2),_variant_t("課時")); 
       m_ExlRge.SetItem(_variant_t((long)2),_variant_t((long)3),_variant_t("難度")); 
       m_ExlRge.SetItem(_variant_t((long)2),_variant_t((long)4),_variant_t("教學方式")); 

       m_ExlRge.SetItem(_variant_t((long)3),_variant_t((long)1),_variant_t("泛函分析")); 
       m_ExlRge.SetItem(_variant_t((long)3),_variant_t((long)2),_variant_t("60")); 
       m_ExlRge.SetItem(_variant_t((long)3),_variant_t((long)3),_variant_t("普通")); 
       m_ExlRge.SetItem(_variant_t((long)3),_variant_t((long)4),_variant_t("老師講課")); 

       m_ExlRge.SetItem(_variant_t((long)4),_variant_t((long)1),_variant_t("微分流形")); 
       m_ExlRge.SetItem(_variant_t((long)4),_variant_t((long)2),_variant_t("40")); 
       m_ExlRge.SetItem(_variant_t((long)4),_variant_t((long)3),_variant_t("變態難")); 
       m_ExlRge.SetItem(_variant_t((long)4),_variant_t((long)4),_variant_t("自學")); 

       m_ExlRge.SetItem(_variant_t((long)5),_variant_t((long)1),_variant_t("二階橢圓型方程與方程組")); 
       m_ExlRge.SetItem(_variant_t((long)5),_variant_t((long)2),_variant_t("60")); 
       m_ExlRge.SetItem(_variant_t((long)5),_variant_t((long)3),_variant_t("很難")); 
       m_ExlRge.SetItem(_variant_t((long)5),_variant_t((long)4),_variant_t("討論")); 


       m_ExlRge.AttachDispatch(m_ExlSheet.GetUsedRange());//載入已使用的單元格 

       m_ExlRge.SetWrapText(_variant_t((long)1));//設定單元格內的文字為自動換行 

       //設定齊方式為水平垂直居中 
       //水平對齊:預設=1,居中=-4108,左=-4131,右=-4152 
       //垂直對齊:預設=2,居中=-4108,左=-4160,右=-4107 
       m_ExlRge.SetHorizontalAlignment(_variant_t((long)-4108)); 
       m_ExlRge.SetVerticalAlignment(_variant_t((long)-4108)); 

       ///////設定整體的字型、字號及顏色////// 

       Font ft; 

       ft.AttachDispatch(m_ExlRge.GetFont()); 

       ft.SetName(_variant_t("宋體"));//字型 
       ft.SetColorIndex(_variant_t((long)11));//字的顏色 
       ft.SetSize(_variant_t((long)12));//字號 

       ///////////設定標題字型及顏色////////// 

       m_ExlRge.AttachDispatch(m_ExlSheet.GetRange(_variant_t("A1"),_variant_t("D1"))); 

       ft.AttachDispatch(m_ExlRge.GetFont()); 

       ft.SetBold(_variant_t((long)1));//粗體 
       ft.SetSize(_variant_t((long)13)); 
       ft.SetColorIndex(_variant_t((long)2)); 

       CellFormat cf; 
       cf.AttachDispatch(m_ExlRge.GetCells()); 

       //////////////設定底色///////////////// 

       Interior it; 

       it.AttachDispatch(m_ExlRge.GetInterior()); 

       it.SetColorIndex(_variant_t((long)11));//標題底色 

       ////表格內容的底色//// 

       m_ExlRge.AttachDispatch(m_ExlSheet.GetRange(_variant_t("A2"),_variant_t("D5"))); 

       it.AttachDispatch(m_ExlRge.GetInterior()); 

       it.SetColorIndex(_variant_t((long)15)); 


       //////////////為表格設定邊框///////////// 

       Range UnitRge; 
       CString CellName; 

       for(int i=1;i<=4;i++) 
       { 
              for(int j=1;j<=4;j++) 
              {     
                     CellName.Format("%c%d",j+64,i);//單元格的名稱 

                     UnitRge.AttachDispatch(m_ExlRge.GetRange(_variant_t(CellName),_variant_t(CellName)));//載入單元格 

                     //LineStyle=線型 Weight=線寬 ColorIndex=線的顏色(-4105為自動) 
                     UnitRge.BorderAround(_variant_t((long)1),_variant_t((long)2),_variant_t((long)-4105),vtMissing);//設定邊框 
              } 
       } 


       //釋放物件(相當重要!) 
       m_ExlRge.ReleaseDispatch(); 
       m_ExlSheet.ReleaseDispatch(); 
       m_ExlSheets.ReleaseDispatch(); 
       m_ExlBook.ReleaseDispatch(); 
       m_ExlBooks.ReleaseDispatch(); 
       //m_ExlApp一定要釋放,否則程式結束後還會有一個Excel程序駐留在記憶體中,而且程式重複執行的時候會出錯 
       m_ExlApp.ReleaseDispatch(); 

       //退出程式 m_ExlApp.Quit(); 


小結:一年前就想寫這個東西了,因為網上講VC與Office程式設計的資料實在是太少了,即使有也很片面(VB講這方面的東西卻又多又全,鬱悶~),想當初做這個東西的時候上網查資料快查瘋掉了,最後還是一堆問題沒有解決。哈哈,現在無聊靜下心來一研究發現原來VC蹂躪Excel也不是一件難事啊,在這個例子裡面包含了很多常用的功能,相信做一般的報表是沒什麼問題的。要是做更復雜的報表怎麼辦呢?一個例子也不可能包括方方面面呀,那確實,因此有很多東西是需要讀者自己探討的。下面我告訴大家一個方法,細心的讀者可能已經發現有些引數不知道是從哪裡蹦出來的,例如:水平對齊:預設=1,居中=-4108,左=-4131,右=-4152。這就要用到Office的巨集錄製功能(什麼?你沒聽過?網上去查吧^__^),把你要的操作用巨集錄製下來,然後用VB開啟,單步除錯的時候就能發現這些祕密了!上面例子中的引數都是DoDo在巨集裡面找到滴,哈哈,是不是很簡單?快去試試吧~


Range   range   =   mWorkSheet.GetRange(COleVariant( "A1 "),COleVariant( "C4 "));//設定待操作的單元格範圍 

range.SetNumberFormatLocal(COleVariant( "@ "));   //設定你的巨集中實現的單元格格式設定 為文字格式