用VC++实现通用的报表控件
生活随笔
收集整理的這篇文章主要介紹了
用VC++实现通用的报表控件
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
摘 要: 常用開發(fā)工具的報表設計工具操作繁瑣,專業(yè)性強,難滿足用戶自己隨時定制
報表格式的要求。本文基于Word模板,用VC建立一個通用的ActiveX報表控件,用以補充開
發(fā)工具中報表處理功能的不足。
關鍵詞:報表控件,OLE自動化,定制報表,ActiveX控件
1 引言
信息管理系統(tǒng)的常用開發(fā)工具(如VFP、DELPHI、POWERBULID等)的報表設計工具操作
繁瑣,專業(yè)性強,當用戶對報表的需求有所變化時,需重新修該應用程序。特別對一些突
發(fā)性的臨時報表的需求,更是無能為力。
為了制作復雜報表及賦予用戶定制報表的能力,就需要對常用的開發(fā)工具擴充以提供一
種靈活的報表設計工具,當前ActiveX控件可用于大多數(shù)開發(fā)環(huán)境,是擴充開發(fā)工具報表
開發(fā)能力的首選。本文介紹一種基于WORD模板的報表ActiveX控件,該控件基于報表模板生
成WORD文檔形式的報表,以供用戶或應用程序打印或預覽。用戶可通過修改報表模板以改
變報表格式。
本文介紹本控件所實現(xiàn)三類報表中第一類報表(即數(shù)據(jù)源中每行數(shù)據(jù)生成一個報表)
的實現(xiàn)。報表的數(shù)據(jù)源采用EXCEL,當然為了擴充,我把對數(shù)據(jù)源的訪問封裝在兩個函數(shù)
上即取屬性名函數(shù)及取數(shù)據(jù)源特定行的函數(shù)內,這樣能通過ADO方便的轉換到其他數(shù)據(jù)源。
2 報表模板的設計
2.1 根據(jù)要求在WORD中設計好報表的格式 。
2.2 在設計好報表中,添加數(shù)據(jù)項的描述。
數(shù)據(jù)項的描述定義采用WORD標簽,即在報表中需要輸出數(shù)據(jù)源中的數(shù)據(jù)的位置插入標簽。
標簽名即數(shù)據(jù)源的屬性名(對EXCEL第一行上各列單元格的值即為屬性名)。
3 控件的實現(xiàn)
在VC++ 6.0下創(chuàng)建Activex控件
3.1建立工程
MFC Activex ControlWizard新建一個名為report的工程,在向導過程中選取
invisible at runtime 的特征。打開ClassWizard ---Add Class---From a type library
選擇本機的Word9.olb(本機裝Word2000,Word98中為Word8.olb 具體根據(jù)本機word的
版本)。選擇_Application (類名改為_Applicationword),_Document,Documents ,
Bookmark,Bookmarks,Cell,Cells,Column,Columns ,Range(類名改成Rangeword),
Row,Rows,Selection,Table,Tables,Window,Characters,Paragraph,Paragraph,
View。加入新類。用同樣方法選擇本機的EXCEL9.OLB,選擇_Application,_Workbook,
Workbooks ,_Worksheet,Sheets,Range加入新類。
在ReportCtl.h中加入
#include "excel9.h"
#include<comdef.h>
#include "msword9.h"
3.2增加ActiveX控件屬性:
1.文檔模板文件名:ReportTemplateFileName類型Cstring 內部名 m_reportTemplateFileName
2.數(shù)據(jù)源名: DateSourceName 類型 BSTR 內部名 m_DateSourceName;
3. 添加報表種類屬性
(1)定義枚舉類型:在CreportCtrl類的定義中加入
enum ReportType {OneRecordOneReport=1,OneGroupRecordOneReport, OneTableOneReport};
//每條記錄一張報表,每組記錄一張報表,所有記錄一張報表
(2)添加報表種類屬性 ReportType 類型 short 內部名 m_ReportType
4.添加報表文件名屬性ReportFileName 類型 Cstring 內部名稱 m_reportFileName
5.添加報表特征屬性
(1)定義枚舉類型enum ReportCharacter
{EveryReportPageAlone=0x0001,VerticalAjacentCellUnite=0x0002,Group=0x0004,
EveryPageHasHeadTail=0x0008 ,EveryPageHasTailNoHead=0x0010 };
//對第一類報表僅第一個用到,即一頁能不能包含多張報表
(2)定義報表特征屬性 ReportCharacter 類型 short 內部名稱 m_ReportCharact
6.添加文件路徑屬性 FilePath 類型 Cstring 內部名m_filePath
7.添加數(shù)據(jù)源主屬性屬性 DataSourceKey 類 Cstring 內部名m_DateSourceName
多個主屬性以,分開。
3.3 添加報表控件的報表制作方法及相關的私有函數(shù)及數(shù)據(jù)
3.3.1報表制作方法MakeReport
short CReportCtrl::MakeReport()
{
/*檢查 數(shù)據(jù)源文件、報表文件、報表模板文件文件名的合法性及數(shù)據(jù)源文件、報表
模板文件及文件路徑是否存在------從略*/
int pronum=GetDataSourceProperty(DataSourceProperty); /*啟動excel服務,
讀數(shù)據(jù)源的屬性名到數(shù)組DataSourceProperty 返回 –1表示 啟動EXCEL服務失敗*/
if(pronum==-1){m_ErrorinformationCode=7; EndExcel();return 7;}
/* m_ErrorinformationCode是類的私有成員,保存制表后的錯誤代碼 錯誤信息
在類的一個常量字符串數(shù)組中-----從略*/
if(!DataSourceKeyIsExist()){m_ErrorinformationCode=6; return 6;}
//檢查關鍵字屬性存在否
switch(m_ReportType) //報表類型
{ case OneRecordOneReport:if(OneRecordOneReportMakeReport()==-1)
{m_ErrorinformationCode=11; return 11; };
break; }
//對DataSourceProperty 等字符串數(shù)組刪除數(shù)組內的所有串
/對pDataSourcePropertyKeySN等指針變量釋放空間-----從略
EndExcel(); //結束Excel服務
return 0;
}
3.3.2添加私有數(shù)據(jù)
_Application excel;Workbooks books;_Workbook book;Sheets sheets;
_Worksheet worksheet;
CstringArray DataSourceProperty ,DataSourcePropertyKey ;
/*存放數(shù)據(jù)源的屬性名,數(shù)據(jù)源的關鍵字 */
int * pDataSourcePropertyKeySN;//關鍵字屬性對應的excel表的列數(shù)從一開始
3.3.3 添加的CreportCtr類的部分私有函數(shù)
1.從串中分解出子串(以,為分界)同時去除空格,返回子串數(shù)
int ExtractSubtring(Cstring &str,CstringArray &strarr)//實現(xiàn)從略
2.取excel指定行 返回false表示全空 n 表示第幾行 SpaceEndOrAppointCol=0
表示該行從左到右查找,如碰到屬性為空則表示該行結束 否則SpaceEndOrAppointCol
表示該行的列數(shù)*/
bool CReportCtrl::GetExcelRowToArray(int n, CStringArray &prostrarr,
int SpaceEndOrAppointCol)
{if(SpaceEndOrAppointCol<0) return false;
?? Range range,cell;range=worksheet.GetRows ();
?? range=range.GetItem (_variant_t((long)n),vtMissing).pdispVal ;
?? // //取當前行
?? range=range.GetCells (); //取當前行所有的單元格
?? int i=1;
?? while(1)
?? { cell=range.GetItem (_variant_t((long)i),vtMissing).pdispVal ;
????? //取出該行的第i列的單元格
????? _variant_t f= cell.GetValue ();
????? f.ChangeType( VT_BSTR ,NULL); //把取出數(shù)據(jù)如short轉換成BSTR類型??
????? BSTR bstr=f.bstrVal ;CString text(bstr); //把BSTR轉換成CString
????? ReMoveChar (text,' '); //刪除text串中的空格
????? if(SpaceEndOrAppointCol==0)
????? {if(!text.GetLength ()) break;} else if(i>SpaceEndOrAppointCol) break;
???????? prostrarr.Add (text); i++;}
???????? if(range.m_lpDispatch !=NULL)range.ReleaseDispatch ();
??????????? int j; i=prostrarr.GetSize ();if(i==0) return false;
???????? for(j=0;j<i;j++)
???????? if(!prostrarr[j].IsEmpty ()) return true;
????? return false;
}
3.取數(shù)據(jù)源的屬性,返回屬性個數(shù) 如返回-1則是啟動excel失敗或其他excel問題
int GetDataSourceProperty(CstringArray &prostrarr)
int CReportCtrl::GetDataSourceProperty(CStringArray &prostrarr)
{ if(excel.m_lpDispatch ==NULL)
{ if(!excel.CreateDispatch ("Excel.Application",NULL)) return -1;
?? books=excel.GetWorkbooks (); if(books.m_lpDispatch ==NULL) return -1;
?? books.Open (m_filePath?m_filePath+'//'+m_DateSourceName:m_DateSourceName,vtMissing,
?? vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,
?? vtMissing,vtMissing,vtMissing,vtMissing,vtMissing);
?? book=books.GetItem (_variant_t((long)1)); if(book.m_lpDispatch ==NULL) return-1;
?? sheets=book.GetSheets ();if(sheets.m_lpDispatch ==NULL) return-1;
?? worksheet=sheets.GetItem (_variant_t((long)1));
?? if(worksheet.m_lpDispatch ==NULL) return-1;}
????? GetExcelRowToArray(1,prostrarr);
?? return prostrarr.GetSize ();}
4.判斷一個串集合是否屬于另一個串集合 如one為空返回false 用p指向的數(shù)組返回one串中的每個元素在another串的位置
bool CReportCtrl::IsOneStrBelongAnotherStr(CStringArray &one, CStringArray &another,int *p ) //實現(xiàn)從略
5.判斷數(shù)據(jù)源關鍵屬性是否存在
bool CReportCtrl::DataSourceKeyIsExist()
{ bool result;
?? if(!m_dataSourceKey.GetLength ()) return false;
?? int grouppropertynum=ExtractSubtring(m_dataSourceKey,DataSourcePropertyKey);
?? pDataSourcePropertyKeySN=new int[ DataSourcePropertyKey.GetSize ()];
?? result=IsOneStrBelongAnotherStr(DataSourcePropertyKey,
?? DataSourceProperty,
?? pDataSourcePropertyKeySN);
?? if(result==false) { delete pDataSourcePropertyKeySN;
????? pDataSourcePropertyKeySN=NULL;}
?? return result;
}
6.在字符數(shù)組中查找字符串
int CReportCtrl:: FindStringInStringArray (CStringArray &x, CString &str) //實現(xiàn)從略
7. 判斷數(shù)組在制定位置是否為空,位置由共n個,由p指針所指
bool IsStringArrSpeciPositionNoEmpty( CStringArray &array , int *p,int n) //實現(xiàn)從略
8.結束word服務
void CReportCtrl::EndWord()
{ word.Quit(&vtMissing,&vtMissing,&vtMissing) ;
? word.ReleaseDispatch ();
? //對CreportCtrl類中所有word類的對象調用ReleaseDispatch () --從略
}
9.結束excel服務 類同結束word服務
void CReportCtrl::EndExcel()
10.制第一類表 返回-1表示制表錯
short CReportCtrl::OneRecordOneReportMakeReport()
{
?? Rangeword range; int exceldatarownum=0; CStringArray excelrow;
?? long count,i,j,colnum; //count 標簽數(shù)量 colnum excel當前行
?? long priorposition_end=0; //粘貼前的文件結尾
?? _variant_t end; long pagenum,priorpagenum; //粘貼前后的頁數(shù)
?? short *point;//標簽所在的列
?? int validbookname=0;
?? if(word.m_lpDispatch !=NULL) return -1;
? ?//*******************啟動word服務
?? if(!word.CreateDispatch ("Word.Application",NULL)) return -1;
?? if(worddoc_ReportFile.m_lpDispatch ==NULL)
?? {
????? word.SetVisible (false); word.SetWindowState (1);
????? worddocs=word.GetDocuments ();
????? worddoc_ReportFile=worddocs.Add(&vtMissing,&vtMissing,&vtMissing,&vtMissing);
????? _variant_t file=m_filePath+'//'+ m_reportTemplateFileName;
????? worddoc_TemplateFile=worddocs.Open (&file,&vtMissing,&vtMissing,
????? &vtMissing,&vtMissing, &vtMissing,&vtMissing,
????? &vtMissing,&vtMissing,&vtMissing,&vtMissing,&vtMissing);
??? ? //*************啟動word服務
????? //*************取出模板文件中的標簽并確定該標簽對應數(shù)據(jù)源的第幾列
????? bookmarks=worddoc_TemplateFile.GetBookmarks ();
????? count=bookmarks.GetCount ();
????? point =new short[count+1];
????? for(i=1;i<=count;i++) //確定標簽對應excel表的列數(shù)
????? {
???????? bookmark=bookmarks.Item (&_variant_t((long)i));
???????? CString str=bookmark.GetName (); //word標簽是不含空格的
???????? point[i]= FindStringInStringArray (DataSourceProperty,str);
???????? if(point[i]>0) validbookname++; }
??????? ?//***********取出數(shù)據(jù)源中的每一行,生成一個報表
???????? colnum=2; //第二列開始放數(shù)據(jù),第一列為屬性名
???????? while(GetExcelRowToArray(colnum,excelrow,DataSourceProperty.GetSize ())&&
???????? IsStringArrSpeciPositionNoEmpty(excelrow,
???????? pDataSourcePropertyKeySN, DataSourcePropertyKey.GetSize ())
???????? ) //取出第colnum列,如關鍵屬性非空即如該行有效
???????? { exceldatarownum++; i=1;
??????????? while(i<=count) //count為標簽的個數(shù)
?????????????? { bookmark=bookmarks.Item (&_variant_t((long)i));
????????????????? range=bookmark.GetRange ();
????????????????? int k=point[i];
????????????????? if(k>0) //如該標簽有效即有對應的數(shù)據(jù)源列
????????????????? range.SetText (excelrow[k]); //用colnum行的對應列的數(shù)據(jù)插入到標簽位置
????????????????? i++;
?????????????? }
??????? ?//************把生成的第colnum-1張報表拷貝到報表文件的文件尾
????? range= worddoc_TemplateFile.GetContent ();
????? range.Copy ();
???? ?/*如報表特性不為一張報表單獨成頁,則判斷把報表拷貝到報表文件的文件尾后,是否會造成該報表在報表文件中跨頁,跨頁則該頁從另一頁開始*/
????? range=worddoc_ReportFile.GetContent(); end=(long) (range.GetEnd ()-1);
????? priorposition_end=end; priorpagenum=(range.GetInformation (4)).lVal ;
????? range=worddoc_ReportFile.Range (&end,&end);range.Paste ();
????? switch(m_ReportCharacter&0x0001?1:2)
????? {
???????? case 1: //每張報表單獨成頁
???????? range=worddoc_ReportFile.GetContent();
?? end=(long) (range.GetEnd ()-1);
?? range=worddoc_ReportFile.Range (&end,&end);
?? range.InsertBreak (&_variant_t((long)7)); //插入分頁符
?? break;
?? case 2: // 每張報表不單獨成頁,但如跨頁則當前報表從另一頁開始
?? range=worddoc_ReportFile.GetContent();
?? end=(long) (range.GetEnd ()-1);
?? pagenum=range.GetInformation (4).lVal;
?? if(pagenum!=priorpagenum)
?? {range=worddoc_ReportFile.Range (&_variant_t((long)(priorposition_end)),&_variant_t((long)?? (priorposition_end)));
?? range.InsertBreak (&_variant_t((long)7)); } //如跨頁則分頁
?? break;
?? } //switch
?? colnum++; excelrow.RemoveAll ();
? ? //取消對worddoc2的修改
?? worddoc_TemplateFile.Undo (&_variant_t((long)validbookname)); } //while
? ?//如模板文件剛好滿頁則結果多一個空頁(一個僅包含回車的段),所以計算頁數(shù),多的減一
?? switch(m_ReportCharacter&0x0001?1:2)
?? { case 2:
???? range= worddoc_ReportFile.GetContent ();
???? j=range.GetInformation (4).lVal;
?? if(j>exceldatarownum) //每張報表不單獨成頁 則最多一頁每條記錄
??? {
????? characters=worddoc_ReportFile.GetCharacters ();
????? range=characters.Item (1);
????? range.Delete (&_variant_t(long(1)),&_variant_t(long(1)));
??? }
?? case 1:
?? range= worddoc_TemplateFile.GetContent ();
?? i=range.GetInformation (4).lVal; //取得頁數(shù)
?? range= worddoc_ReportFile.GetContent ();
?? j=range.GetInformation (4).lVal;
?? if(j>=i* exceldatarownum+1)
??? {
?????? paragraphs=worddoc_ReportFile.GetParagraphs ();
?????? count=paragraphs.GetCount ();
?????? if(count>0)paragraph=paragraphs.Item (count);
?????? range=paragraph.GetRange ();
?????? range.Delete (&_variant_t(long(1)),&_variant_t(long(1)));
???? }
?? break;
? }
window=word.GetActiveWindow ();view=window.GetView ();
view.SetShowBookmarks (FALSE); _variant_t filename= m_filePath+'//'+m_reportFileName;
worddoc_ReportFile.SaveAs(&filename,&vtMissing,&vtMissing,&vtMissing,&vtMissing,
&vtMissing,&vtMissing,&vtMissing,&vtMissing,&vtMissing,&vtMissing);
worddoc_TemplateFile.Close (&_variant_t((long)0),&vtMissing,&vtMissing);
worddoc_ReportFile.Close (&_variant_t((long)0),&vtMissing,&vtMissing);
EndWord(); }
return 0;
}
4 結束語
本控件是在遇到用戶要求一些突發(fā)的臨時報表的時,為解決此類問題開發(fā)的。用戶所要求的臨時報表是對上下級部門之間交換的EXCEL數(shù)據(jù),根據(jù)不同的格式生成報表。由于篇幅的關系,類中很多私有函數(shù)就沒有給出。
報表格式的要求。本文基于Word模板,用VC建立一個通用的ActiveX報表控件,用以補充開
發(fā)工具中報表處理功能的不足。
關鍵詞:報表控件,OLE自動化,定制報表,ActiveX控件
1 引言
信息管理系統(tǒng)的常用開發(fā)工具(如VFP、DELPHI、POWERBULID等)的報表設計工具操作
繁瑣,專業(yè)性強,當用戶對報表的需求有所變化時,需重新修該應用程序。特別對一些突
發(fā)性的臨時報表的需求,更是無能為力。
為了制作復雜報表及賦予用戶定制報表的能力,就需要對常用的開發(fā)工具擴充以提供一
種靈活的報表設計工具,當前ActiveX控件可用于大多數(shù)開發(fā)環(huán)境,是擴充開發(fā)工具報表
開發(fā)能力的首選。本文介紹一種基于WORD模板的報表ActiveX控件,該控件基于報表模板生
成WORD文檔形式的報表,以供用戶或應用程序打印或預覽。用戶可通過修改報表模板以改
變報表格式。
本文介紹本控件所實現(xiàn)三類報表中第一類報表(即數(shù)據(jù)源中每行數(shù)據(jù)生成一個報表)
的實現(xiàn)。報表的數(shù)據(jù)源采用EXCEL,當然為了擴充,我把對數(shù)據(jù)源的訪問封裝在兩個函數(shù)
上即取屬性名函數(shù)及取數(shù)據(jù)源特定行的函數(shù)內,這樣能通過ADO方便的轉換到其他數(shù)據(jù)源。
2 報表模板的設計
2.1 根據(jù)要求在WORD中設計好報表的格式 。
2.2 在設計好報表中,添加數(shù)據(jù)項的描述。
數(shù)據(jù)項的描述定義采用WORD標簽,即在報表中需要輸出數(shù)據(jù)源中的數(shù)據(jù)的位置插入標簽。
標簽名即數(shù)據(jù)源的屬性名(對EXCEL第一行上各列單元格的值即為屬性名)。
3 控件的實現(xiàn)
在VC++ 6.0下創(chuàng)建Activex控件
3.1建立工程
MFC Activex ControlWizard新建一個名為report的工程,在向導過程中選取
invisible at runtime 的特征。打開ClassWizard ---Add Class---From a type library
選擇本機的Word9.olb(本機裝Word2000,Word98中為Word8.olb 具體根據(jù)本機word的
版本)。選擇_Application (類名改為_Applicationword),_Document,Documents ,
Bookmark,Bookmarks,Cell,Cells,Column,Columns ,Range(類名改成Rangeword),
Row,Rows,Selection,Table,Tables,Window,Characters,Paragraph,Paragraph,
View。加入新類。用同樣方法選擇本機的EXCEL9.OLB,選擇_Application,_Workbook,
Workbooks ,_Worksheet,Sheets,Range加入新類。
在ReportCtl.h中加入
#include "excel9.h"
#include<comdef.h>
#include "msword9.h"
3.2增加ActiveX控件屬性:
1.文檔模板文件名:ReportTemplateFileName類型Cstring 內部名 m_reportTemplateFileName
2.數(shù)據(jù)源名: DateSourceName 類型 BSTR 內部名 m_DateSourceName;
3. 添加報表種類屬性
(1)定義枚舉類型:在CreportCtrl類的定義中加入
enum ReportType {OneRecordOneReport=1,OneGroupRecordOneReport, OneTableOneReport};
//每條記錄一張報表,每組記錄一張報表,所有記錄一張報表
(2)添加報表種類屬性 ReportType 類型 short 內部名 m_ReportType
4.添加報表文件名屬性ReportFileName 類型 Cstring 內部名稱 m_reportFileName
5.添加報表特征屬性
(1)定義枚舉類型enum ReportCharacter
{EveryReportPageAlone=0x0001,VerticalAjacentCellUnite=0x0002,Group=0x0004,
EveryPageHasHeadTail=0x0008 ,EveryPageHasTailNoHead=0x0010 };
//對第一類報表僅第一個用到,即一頁能不能包含多張報表
(2)定義報表特征屬性 ReportCharacter 類型 short 內部名稱 m_ReportCharact
6.添加文件路徑屬性 FilePath 類型 Cstring 內部名m_filePath
7.添加數(shù)據(jù)源主屬性屬性 DataSourceKey 類 Cstring 內部名m_DateSourceName
多個主屬性以,分開。
3.3 添加報表控件的報表制作方法及相關的私有函數(shù)及數(shù)據(jù)
3.3.1報表制作方法MakeReport
short CReportCtrl::MakeReport()
{
/*檢查 數(shù)據(jù)源文件、報表文件、報表模板文件文件名的合法性及數(shù)據(jù)源文件、報表
模板文件及文件路徑是否存在------從略*/
int pronum=GetDataSourceProperty(DataSourceProperty); /*啟動excel服務,
讀數(shù)據(jù)源的屬性名到數(shù)組DataSourceProperty 返回 –1表示 啟動EXCEL服務失敗*/
if(pronum==-1){m_ErrorinformationCode=7; EndExcel();return 7;}
/* m_ErrorinformationCode是類的私有成員,保存制表后的錯誤代碼 錯誤信息
在類的一個常量字符串數(shù)組中-----從略*/
if(!DataSourceKeyIsExist()){m_ErrorinformationCode=6; return 6;}
//檢查關鍵字屬性存在否
switch(m_ReportType) //報表類型
{ case OneRecordOneReport:if(OneRecordOneReportMakeReport()==-1)
{m_ErrorinformationCode=11; return 11; };
break; }
//對DataSourceProperty 等字符串數(shù)組刪除數(shù)組內的所有串
/對pDataSourcePropertyKeySN等指針變量釋放空間-----從略
EndExcel(); //結束Excel服務
return 0;
}
3.3.2添加私有數(shù)據(jù)
_Application excel;Workbooks books;_Workbook book;Sheets sheets;
_Worksheet worksheet;
CstringArray DataSourceProperty ,DataSourcePropertyKey ;
/*存放數(shù)據(jù)源的屬性名,數(shù)據(jù)源的關鍵字 */
int * pDataSourcePropertyKeySN;//關鍵字屬性對應的excel表的列數(shù)從一開始
3.3.3 添加的CreportCtr類的部分私有函數(shù)
1.從串中分解出子串(以,為分界)同時去除空格,返回子串數(shù)
int ExtractSubtring(Cstring &str,CstringArray &strarr)//實現(xiàn)從略
2.取excel指定行 返回false表示全空 n 表示第幾行 SpaceEndOrAppointCol=0
表示該行從左到右查找,如碰到屬性為空則表示該行結束 否則SpaceEndOrAppointCol
表示該行的列數(shù)*/
bool CReportCtrl::GetExcelRowToArray(int n, CStringArray &prostrarr,
int SpaceEndOrAppointCol)
{if(SpaceEndOrAppointCol<0) return false;
?? Range range,cell;range=worksheet.GetRows ();
?? range=range.GetItem (_variant_t((long)n),vtMissing).pdispVal ;
?? // //取當前行
?? range=range.GetCells (); //取當前行所有的單元格
?? int i=1;
?? while(1)
?? { cell=range.GetItem (_variant_t((long)i),vtMissing).pdispVal ;
????? //取出該行的第i列的單元格
????? _variant_t f= cell.GetValue ();
????? f.ChangeType( VT_BSTR ,NULL); //把取出數(shù)據(jù)如short轉換成BSTR類型??
????? BSTR bstr=f.bstrVal ;CString text(bstr); //把BSTR轉換成CString
????? ReMoveChar (text,' '); //刪除text串中的空格
????? if(SpaceEndOrAppointCol==0)
????? {if(!text.GetLength ()) break;} else if(i>SpaceEndOrAppointCol) break;
???????? prostrarr.Add (text); i++;}
???????? if(range.m_lpDispatch !=NULL)range.ReleaseDispatch ();
??????????? int j; i=prostrarr.GetSize ();if(i==0) return false;
???????? for(j=0;j<i;j++)
???????? if(!prostrarr[j].IsEmpty ()) return true;
????? return false;
}
3.取數(shù)據(jù)源的屬性,返回屬性個數(shù) 如返回-1則是啟動excel失敗或其他excel問題
int GetDataSourceProperty(CstringArray &prostrarr)
int CReportCtrl::GetDataSourceProperty(CStringArray &prostrarr)
{ if(excel.m_lpDispatch ==NULL)
{ if(!excel.CreateDispatch ("Excel.Application",NULL)) return -1;
?? books=excel.GetWorkbooks (); if(books.m_lpDispatch ==NULL) return -1;
?? books.Open (m_filePath?m_filePath+'//'+m_DateSourceName:m_DateSourceName,vtMissing,
?? vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,
?? vtMissing,vtMissing,vtMissing,vtMissing,vtMissing);
?? book=books.GetItem (_variant_t((long)1)); if(book.m_lpDispatch ==NULL) return-1;
?? sheets=book.GetSheets ();if(sheets.m_lpDispatch ==NULL) return-1;
?? worksheet=sheets.GetItem (_variant_t((long)1));
?? if(worksheet.m_lpDispatch ==NULL) return-1;}
????? GetExcelRowToArray(1,prostrarr);
?? return prostrarr.GetSize ();}
4.判斷一個串集合是否屬于另一個串集合 如one為空返回false 用p指向的數(shù)組返回one串中的每個元素在another串的位置
bool CReportCtrl::IsOneStrBelongAnotherStr(CStringArray &one, CStringArray &another,int *p ) //實現(xiàn)從略
5.判斷數(shù)據(jù)源關鍵屬性是否存在
bool CReportCtrl::DataSourceKeyIsExist()
{ bool result;
?? if(!m_dataSourceKey.GetLength ()) return false;
?? int grouppropertynum=ExtractSubtring(m_dataSourceKey,DataSourcePropertyKey);
?? pDataSourcePropertyKeySN=new int[ DataSourcePropertyKey.GetSize ()];
?? result=IsOneStrBelongAnotherStr(DataSourcePropertyKey,
?? DataSourceProperty,
?? pDataSourcePropertyKeySN);
?? if(result==false) { delete pDataSourcePropertyKeySN;
????? pDataSourcePropertyKeySN=NULL;}
?? return result;
}
6.在字符數(shù)組中查找字符串
int CReportCtrl:: FindStringInStringArray (CStringArray &x, CString &str) //實現(xiàn)從略
7. 判斷數(shù)組在制定位置是否為空,位置由共n個,由p指針所指
bool IsStringArrSpeciPositionNoEmpty( CStringArray &array , int *p,int n) //實現(xiàn)從略
8.結束word服務
void CReportCtrl::EndWord()
{ word.Quit(&vtMissing,&vtMissing,&vtMissing) ;
? word.ReleaseDispatch ();
? //對CreportCtrl類中所有word類的對象調用ReleaseDispatch () --從略
}
9.結束excel服務 類同結束word服務
void CReportCtrl::EndExcel()
10.制第一類表 返回-1表示制表錯
short CReportCtrl::OneRecordOneReportMakeReport()
{
?? Rangeword range; int exceldatarownum=0; CStringArray excelrow;
?? long count,i,j,colnum; //count 標簽數(shù)量 colnum excel當前行
?? long priorposition_end=0; //粘貼前的文件結尾
?? _variant_t end; long pagenum,priorpagenum; //粘貼前后的頁數(shù)
?? short *point;//標簽所在的列
?? int validbookname=0;
?? if(word.m_lpDispatch !=NULL) return -1;
? ?//*******************啟動word服務
?? if(!word.CreateDispatch ("Word.Application",NULL)) return -1;
?? if(worddoc_ReportFile.m_lpDispatch ==NULL)
?? {
????? word.SetVisible (false); word.SetWindowState (1);
????? worddocs=word.GetDocuments ();
????? worddoc_ReportFile=worddocs.Add(&vtMissing,&vtMissing,&vtMissing,&vtMissing);
????? _variant_t file=m_filePath+'//'+ m_reportTemplateFileName;
????? worddoc_TemplateFile=worddocs.Open (&file,&vtMissing,&vtMissing,
????? &vtMissing,&vtMissing, &vtMissing,&vtMissing,
????? &vtMissing,&vtMissing,&vtMissing,&vtMissing,&vtMissing);
??? ? //*************啟動word服務
????? //*************取出模板文件中的標簽并確定該標簽對應數(shù)據(jù)源的第幾列
????? bookmarks=worddoc_TemplateFile.GetBookmarks ();
????? count=bookmarks.GetCount ();
????? point =new short[count+1];
????? for(i=1;i<=count;i++) //確定標簽對應excel表的列數(shù)
????? {
???????? bookmark=bookmarks.Item (&_variant_t((long)i));
???????? CString str=bookmark.GetName (); //word標簽是不含空格的
???????? point[i]= FindStringInStringArray (DataSourceProperty,str);
???????? if(point[i]>0) validbookname++; }
??????? ?//***********取出數(shù)據(jù)源中的每一行,生成一個報表
???????? colnum=2; //第二列開始放數(shù)據(jù),第一列為屬性名
???????? while(GetExcelRowToArray(colnum,excelrow,DataSourceProperty.GetSize ())&&
???????? IsStringArrSpeciPositionNoEmpty(excelrow,
???????? pDataSourcePropertyKeySN, DataSourcePropertyKey.GetSize ())
???????? ) //取出第colnum列,如關鍵屬性非空即如該行有效
???????? { exceldatarownum++; i=1;
??????????? while(i<=count) //count為標簽的個數(shù)
?????????????? { bookmark=bookmarks.Item (&_variant_t((long)i));
????????????????? range=bookmark.GetRange ();
????????????????? int k=point[i];
????????????????? if(k>0) //如該標簽有效即有對應的數(shù)據(jù)源列
????????????????? range.SetText (excelrow[k]); //用colnum行的對應列的數(shù)據(jù)插入到標簽位置
????????????????? i++;
?????????????? }
??????? ?//************把生成的第colnum-1張報表拷貝到報表文件的文件尾
????? range= worddoc_TemplateFile.GetContent ();
????? range.Copy ();
???? ?/*如報表特性不為一張報表單獨成頁,則判斷把報表拷貝到報表文件的文件尾后,是否會造成該報表在報表文件中跨頁,跨頁則該頁從另一頁開始*/
????? range=worddoc_ReportFile.GetContent(); end=(long) (range.GetEnd ()-1);
????? priorposition_end=end; priorpagenum=(range.GetInformation (4)).lVal ;
????? range=worddoc_ReportFile.Range (&end,&end);range.Paste ();
????? switch(m_ReportCharacter&0x0001?1:2)
????? {
???????? case 1: //每張報表單獨成頁
???????? range=worddoc_ReportFile.GetContent();
?? end=(long) (range.GetEnd ()-1);
?? range=worddoc_ReportFile.Range (&end,&end);
?? range.InsertBreak (&_variant_t((long)7)); //插入分頁符
?? break;
?? case 2: // 每張報表不單獨成頁,但如跨頁則當前報表從另一頁開始
?? range=worddoc_ReportFile.GetContent();
?? end=(long) (range.GetEnd ()-1);
?? pagenum=range.GetInformation (4).lVal;
?? if(pagenum!=priorpagenum)
?? {range=worddoc_ReportFile.Range (&_variant_t((long)(priorposition_end)),&_variant_t((long)?? (priorposition_end)));
?? range.InsertBreak (&_variant_t((long)7)); } //如跨頁則分頁
?? break;
?? } //switch
?? colnum++; excelrow.RemoveAll ();
? ? //取消對worddoc2的修改
?? worddoc_TemplateFile.Undo (&_variant_t((long)validbookname)); } //while
? ?//如模板文件剛好滿頁則結果多一個空頁(一個僅包含回車的段),所以計算頁數(shù),多的減一
?? switch(m_ReportCharacter&0x0001?1:2)
?? { case 2:
???? range= worddoc_ReportFile.GetContent ();
???? j=range.GetInformation (4).lVal;
?? if(j>exceldatarownum) //每張報表不單獨成頁 則最多一頁每條記錄
??? {
????? characters=worddoc_ReportFile.GetCharacters ();
????? range=characters.Item (1);
????? range.Delete (&_variant_t(long(1)),&_variant_t(long(1)));
??? }
?? case 1:
?? range= worddoc_TemplateFile.GetContent ();
?? i=range.GetInformation (4).lVal; //取得頁數(shù)
?? range= worddoc_ReportFile.GetContent ();
?? j=range.GetInformation (4).lVal;
?? if(j>=i* exceldatarownum+1)
??? {
?????? paragraphs=worddoc_ReportFile.GetParagraphs ();
?????? count=paragraphs.GetCount ();
?????? if(count>0)paragraph=paragraphs.Item (count);
?????? range=paragraph.GetRange ();
?????? range.Delete (&_variant_t(long(1)),&_variant_t(long(1)));
???? }
?? break;
? }
window=word.GetActiveWindow ();view=window.GetView ();
view.SetShowBookmarks (FALSE); _variant_t filename= m_filePath+'//'+m_reportFileName;
worddoc_ReportFile.SaveAs(&filename,&vtMissing,&vtMissing,&vtMissing,&vtMissing,
&vtMissing,&vtMissing,&vtMissing,&vtMissing,&vtMissing,&vtMissing);
worddoc_TemplateFile.Close (&_variant_t((long)0),&vtMissing,&vtMissing);
worddoc_ReportFile.Close (&_variant_t((long)0),&vtMissing,&vtMissing);
EndWord(); }
return 0;
}
4 結束語
本控件是在遇到用戶要求一些突發(fā)的臨時報表的時,為解決此類問題開發(fā)的。用戶所要求的臨時報表是對上下級部門之間交換的EXCEL數(shù)據(jù),根據(jù)不同的格式生成報表。由于篇幅的關系,類中很多私有函數(shù)就沒有給出。
總結
以上是生活随笔為你收集整理的用VC++实现通用的报表控件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++用库 jsoncpp 解析 JSO
- 下一篇: 初学者如何开发出高质量J2EE系统