筆者在實際工作中經常用Excel表做數據報表,大多數表格的數據都要從數據庫中讀取,這樣我就用C++Builder做了一個報表程序,方便了很多,現在把它共享給C++Builder愛好者們,就算為豐富C++Builder的文檔資料做點事情吧。
首先把Excel報表文件保存到一個指定目錄下,最好放在可執行程序的子目錄下,作為模板文件。可以把報表標題、表頭等設置好。這裡是保存在trpt子目錄下。
然後建一個report目錄,作為報表目標文件夾,存放填好數據的報表,可以由用戶直接操作。
首先確定在你的機器中裝有Office。這裡一Office2000為例。
在C++Builder中新建一個工程,在窗體Form1上面放一個兩個按鈕SaveButton和ReadButton,分別用來保存數據到Excel表和顯示剛剛保存的Excel表。
在SaveButton按鈕的單擊事件中把從數據庫中取到的數據放入到指定的Excel表中並將改文件拷貝到report目錄下。在ReadButto按鈕的單擊事件中顯示report目錄下的報表文件,方便用戶修改和另外保存。
在Form1.h頭文件中定義幾個變量:
private:
Variant Ex,Wb,Sheet,ERange,EBorders;
並在文件頭中包含如下語句:
#include "Excel_2K_SRVR.h"
#include
在Form1.cpp的文件頭中加入
#pragma link "Excel_2K_SRVR"
主要代碼如下:
void __fastcall TForm1:: SaveButtonClick(TObject *Sender)
{
try
{
SaveButton->Enabled = false;
ReadButton->Enabled = false;//使兩個按鈕無效
file://取報表文件CardSend.xls的完整目錄名
AnsiString ExcelFileName = GetCurrentDir()+"\\trpt\\table.xls";
if(!FileExists(ExcelFileName))
{
Application->MessageBox("報表模板文件不存在,無法打開!",
"錯誤",MB_ICONSTOP|MB_OK);
return;
}
file://建立Excel的Ole對象Ex
try
{
Ex = Variant::CreateObject("Excel.Application");
}
catch(...)
{
Application->MessageBox("無法啟動Excel","錯誤",MB_ICONSTOP|MB_OK);
return;
}
file://設置Excel為不可見
Ex.OlePropertySet("Visible",false);
file://打開指定的Excel報表文件。報表文件中最好設定只有一個Sheet。
Ex.OlePropertyGet("WorkBooks").OleProcedure("Open",ExcelFileName.c_str());
Wb = Ex.OlePropertyGet("ActiveWorkBook");
Sheet = Wb.OlePropertyGet("ActiveSheet");//獲得當前默認的Sheet
file://清空Excel表,這裡是用循環清空到第300行。對於一般的表格已經足夠了。
AnsiString strRowTemp;
AnsiString strRange;
int iCols,iRows;//記錄列數和行數
/*從第三行開始,到第300行止。一般第一行是表標題,第二行是副標題或者制表日期。*/
for(iRows=3;iRows<300;iRows++)
{ file://假設只有6列。
for (iCols = 1;iCols < 7; iCols++)
{
file://清空行
Sheet.OlePropertyGet("Cells",iRows,iCols).OlePropertySet("Value","");
}
file://去掉表格邊框
strRange = "A"+IntToStr(iRows)+":F"+IntToStr(iRows);//獲取操作范圍
ERange = Sheet.OlePropertyGet("Range",strRange.c_str());
EBorders = ERange.OlePropertyGet("Borders");//獲取邊框對象
EBorders.OlePropertySet("linestyle",xlNone);
}
AnsiString strPtrDate; file://存放當前日期,作為制表日期
DateSeparator = '-';
ShortDateFormat = "yyyy/m/d";//設置為年/月/日格式
strPtrDate = DateToStr(Date());//取當前日期
AnsiString strYear = strPtrDate.SubString(1,4);
strPtrDate = strPtrDate.SubString(6,strPtrDate.Length()-5);
AnsiString strMonth = strPtrDate.SubString(1,strPtrDate.Pos("-")-1);
AnsiString strDay =
strPtrDate.SubString(strPtrDate.Pos("-")+1,
strPtrDate.Length()-strPtrDate.Pos("-"));
strPtrDate = strYear+"年"+strMonth+"月"+strDay+"日";
AnsiString strData = "報表標題";//報表標題
file://將報表標題置於第一行第一列。在此之前,應將報表文件的標題格式設定好。
Sheet.OlePropertyGet("Cells",1,1).OlePropertySet("Value",
strData.c_str());
file://將制表日期置於表格第二行的右側。
Sheet.OlePropertyGet("Cells",2,5).OlePropertySet("Value",
strPtrDate.c_str());
iRows = 3;//在第三行放置表格的列名
Sheet.OlePropertyGet("Cells",iRows,1).OlePropertySet("Value","列名1");
Sheet.OlePropertyGet("Cells",iRows,2).OlePropertySet("Value","列名2");
Sheet.OlePropertyGet("Cells",iRows,3).OlePropertySet("Value","列名3");
Sheet.OlePropertyGet("Cells",iRows,4).OlePropertySet("Value","列名4");
Sheet.OlePropertyGet("Cells",iRows,5).OlePropertySet("Value","列名5");
Sheet.OlePropertyGet("Cells",iRows,6).OlePropertySet("Value","列名6");
file://畫表格邊框,在A3:F3之間取范圍
strRange = "A"+IntToStr(iRows)+":F"+IntToStr(iRows);
ERange = Sheet.OlePropertyGet("Range",strRange.c_str());
EBorders = ERange.OlePropertyGet("Borders");
EBorders.OlePropertySet("linestyle",xlContinuous);
EBorders.OlePropertySet("weight",xlThin);
EBorders.OlePropertySet("colorindex",xlAutomatic);
iRows++;
file://從數據庫中取數據(略),假設數據集放入Query1中。
Query1->Open();//打開數據集
file://循環取數
while(!Query1->Eof)
{
file://循環取字段的數據放到Excel表對應的行列中
for(iCols=1;iCols<7;iCols++)
{
strRowTemp = Query1->Fields->Fields[iCols-1]->AsString;
Sheet.OlePropertyGet("Cells",iRows,iCols).OlePropertySet("Value",
strRowTemp.c_str());
}
file://畫該行的表格邊框
strRange = "A"+IntToStr(iRows)+":F"+IntToStr(iRows);
ERange = Sheet.OlePropertyGet("Range",strRange.c_str());
EBorders = ERange.OlePropertyGet("Borders");
EBorders.OlePropertySet("linestyle",xlContinuous);
EBorders.OlePropertySet("weight",xlThin);
EBorders.OlePropertySet("colorindex",xlAutomatic);
iRows++;
Query1->Next();
}//while結束
Wb.OleProcedure("Save");//保存表格
Wb.OleProcedure("Close");關閉表格
Ex.OleFunction("Quit");退出Excel
file://定義目標文件名
AnsiString DestinationFile =
GetCurrentDir()+"\\report\\table.xls";
file://將剛剛修改的Excel表格文件table.xls拷貝到report目錄下
if(!CopyFile(ExcelFileName.c_str(),DestinationFile.c_str(),false))
{
Application->MessageBox("復制文件操作失敗,Excel文件可能正在使用中!",
"錯誤",MB_ICONSTOP|MB_OK);
return;
}
Application->MessageBox("成功完成報表保存!\n可以按\'打開Excel文件\'
按鈕進行報表工作","提示",MB_ICONINFORMATION|MB_OK);
SaveButton ->Enabled = true;
ReadButton ->Enabled=true;
}//try結束
catch(...)
{
Application->MessageBox("操作Excel表格失敗!",
"錯誤",MB_ICONSTOP|MB_OK);
Wb.OleProcedure("Close");
Ex.OleFunction("Quit");
SaveButton ->Enabled = true;
ReadButton ->Enabled=false;
}
}
至此,完成報表數據的寫入工作。如果要對完成的Excel表進行操作,可以點擊"打開Excel表文件按鈕"(ReadButton),進行修改,保存,打印等操作。ReadButton的單擊事件如下實現:
void __fastcall TForm1:: ReadButtonClick(TObject *Sender)
{
try
{
file://指定report目錄下的報表文件用於用戶操作
AnsiString ExcelFileName =
GetCurrentDir();+"\\report\\table.xls";
if(!FileExists(ExcelFileName))
{
Application->MessageBox("Excel表文件不存在,無法打開!",
"錯誤",MB_ICONSTOP|MB_OK);
return;
}
try
{
Ex = Variant::CreateObject("Excel.Application");
}
catch(...)
{
Application->MessageBox("無法啟動Excel","錯誤",MB_ICONSTOP|MB_OK);
return;
}
file://使Excel可見
Ex.OlePropertySet("Visible",true);
file://打開Excel表格文件Table.xls
Ex.OlePropertyGet("WorkBooks").OleProcedure("Open",ExcelFileName.c_str());
}
catch(...)
{
Application->MessageBox("操作Excel表格錯誤!","錯誤",MB_ICONSTOP|MB_OK);
Ex.OleFunction("Quit");
}
}
以上關於C++BuilderExcel表格的操作僅作為個人觀點和水平呈獻給關心此問題的讀者,如果有更好的方式方法,敬請指教,不勝感激。