首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ Builder 利用 OLE 自動化產生 Excel 報表完整實作

     編輯:關於C++

專案架構

  • trpt/:存放報表樣板 table.xls (標題、表頭、格式預設)
  • report/:輸出填好資料的報表供使用者開啟
  • 介面:SaveButton (產生報表)、ReadButton (開啟報表)

必要標頭與連結


// Form1.h
#include "Excel_2K_SRVR.h"  // Office 2000 類型庫產生的標頭
#pragma link "Excel_2K_SRVR" // 連結類型庫

private:
    Variant Ex, Wb, Sheet, ERange, EBorders;

SaveButtonClick:資料寫入與儲存


void __fastcall TForm1::SaveButtonClick(TObject *Sender) {
    try {
        SaveButton->Enabled = false;
        ReadButton->Enabled = false;

        AnsiString ExcelFileName = GetCurrentDir() + "\\trpt\\table.xls";
        if (!FileExists(ExcelFileName)) {
            MessageBox("報表樣板不存在", "錯誤", MB_ICONSTOP|MB_OK);
            return;
        }

        // 建立 Excel 物件
        try { Ex = Variant::CreateObject("Excel.Application"); }
        catch(...) { MessageBox("無法啟動 Excel", "錯誤", MB_ICONSTOP|MB_OK); return; }

        Ex.OlePropertySet("Visible", false);
        Ex.OlePropertyGet("WorkBooks").OleProcedure("Open", ExcelFileName.c_str());
        Wb = Ex.OlePropertyGet("ActiveWorkBook");
        Sheet = Wb.OlePropertyGet("ActiveSheet");

        // 清空舊資料 (第 3~300 列,6 欄)
        for (int r = 3; r < 300; r++) {
            for (int c = 1; c < 7; c++)
                Sheet.OlePropertyGet("Cells", r, c).OlePropertySet("Value", "");
            // 移除框線
            AnsiString rng = "A" + IntToStr(r) + ":F" + IntToStr(r);
            ERange = Sheet.OlePropertyGet("Range", rng.c_str());
            EBorders = ERange.OlePropertyGet("Borders");
            EBorders.OlePropertySet("LineStyle", xlNone);
        }

        // 表頭:標題、日期
        AnsiString title = "報表標題";
        Sheet.OlePropertyGet("Cells", 1, 1).OlePropertySet("Value", title.c_str());

        DateSeparator = '-'; ShortDateFormat = "yyyy/m/d";
        AnsiString dt = DateToStr(Date());
        AnsiString yr = dt.SubString(1,4);
        AnsiString md = dt.SubString(6, dt.Length()-5);
        AnsiString mon = md.SubString(1, md.Pos("-")-1);
        AnsiString day = md.SubString(md.Pos("-")+1, md.Length()-md.Pos("-"));
        AnsiString dtStr = yr + "年" + mon + "月" + day + "日";
        Sheet.OlePropertyGet("Cells", 2, 5).OlePropertySet("Value", dtStr.c_str());

        // 欄位名稱 (第 3 列)
        const char* cols[6] = {"欄位1","欄位2","欄位3","欄位4","欄位5","欄位6"};
        for (int c = 0; c < 6; c++)
            Sheet.OlePropertyGet("Cells", 3, c+1).OlePropertySet("Value", cols[c]);
        // 畫表頭框線
        AnsiString hdrRng = "A3:F3";
        ERange = Sheet.OlePropertyGet("Range", hdrRng.c_str());
        EBorders = ERange.OlePropertyGet("Borders");
        EBorders.OlePropertySet("LineStyle", xlContinuous);
        EBorders.OlePropertySet("Weight", xlThin);
        EBorders.OlePropertySet("ColorIndex", xlAutomatic);

        // 從資料庫讀取並填入 (示範 Query1)
        int row = 4;
        Query1->Open();
        while (!Query1->Eof) {
            for (int c = 1; c < 7; c++) {
                AnsiString val = Query1->Fields->Fields[c-1]->AsString;
                Sheet.OlePropertyGet("Cells", row, c).OlePropertySet("Value", val.c_str());
            }
            // 畫每列框線
            AnsiString dRng = "A" + IntToStr(row) + ":F" + IntToStr(row);
            ERange = Sheet.OlePropertyGet("Range", dRng.c_str());
            EBorders = ERange.OlePropertyGet("Borders");
            EBorders.OlePropertySet("LineStyle", xlContinuous);
            EBorders.OlePropertySet("Weight", xlThin);
            EBorders.OlePropertySet("ColorIndex", xlAutomatic);
            row++; Query1->Next();
        }

        // 儲存、關閉、釋放
        Wb.OleProcedure("Save");
        Wb.OleProcedure("Close");
        Ex.OleFunction("Quit");

        // 複製到 report 目錄供使用者操作
        AnsiString dest = GetCurrentDir() + "\\report\\table.xls";
        if (!CopyFile(ExcelFileName.c_str(), dest.c_str(), false))
            MessageBox("複製失敗,檔案可能被佔用", "錯誤", MB_ICONSTOP|MB_OK);
        else
            MessageBox("報表產生完成", "提示", MB_ICONINFORMATION|MB_OK);

    } catch(...) {
        MessageBox("操作 Excel 失敗", "錯誤", MB_ICONSTOP|MB_OK);
        if (Wb) Wb.OleProcedure("Close");
        if (Ex) Ex.OleFunction("Quit");
    }
    SaveButton->Enabled = true;
    ReadButton->Enabled = true;
}

ReadButtonClick:開啟報表供編輯


void __fastcall TForm1::ReadButtonClick(TObject *Sender) {
    try {
        AnsiString fn = GetCurrentDir() + "\\report\\table.xls";
        if (!FileExists(fn)) { MessageBox("檔案不存在", "錯誤", MB_ICONSTOP|MB_OK); return; }

        try { Ex = Variant::CreateObject("Excel.Application"); }
        catch(...) { MessageBox("無法啟動 Excel", "錯誤", MB_ICONSTOP|MB_OK); return; }

        Ex.OlePropertySet("Visible", true);
        Ex.OlePropertyGet("WorkBooks").OleProcedure("Open", fn.c_str());
    } catch(...) {
        MessageBox("開啟失敗", "錯誤", MB_ICONSTOP|MB_OK);
        if (Ex) Ex.OleFunction("Quit");
    }
}

關鍵技術要點

  1. 樣板分離:版面設計在 Excel 完成,程式只負責填資料,維護容易。
  2. Visible = false:背景產生報表不干擾使用者,速度較快。
  3. 清空策略:固定範圍清值+移除框線,避免舊資料殘留。
  4. 框線繪製:透過 Range.Borders 設定 LineStyle/Weight/ColorIndex。
  5. 資源釋放:Workbook.Close → App.Quit → Variant = Unassigned (隱含於離開作用域)。
  6. 檔案複製:產生完成後複製到 report/,保護樣板不被異動。
  7. 錯誤處理:try...catch 確保 Excel 進程一定會被關閉。

擴充建議

  • 使用 ADOQuery 直接連接資料庫,避免 Query1 元件依賴。
  • 支援多工作表報表:依 Sheet.Name 切換。
  • 匯出 PDF:Workbook.Exec(PR("ExportAsFixedFormat") << xlTypePDF << pdfPath) (Office 2007+)。
  • 非同步產生:放入執行緒避免 UI 凍結。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved