C++Builder 6中开拓Office措施心得(一)
副标题#e#
一、用控件照旧用OLEAutomation?
这个问题应该说很常见。我也在任何大概的环境下僵持我的主张:用BCB 6提供的Server控件组。假如你是用Delphi 6/7版本开拓,那么用Delphi提供的Server控件组。
这样做有什么长处?我小我私家认为至少有如下两个:
第一,维护布局化+OO的措施设计气势气魄。譬喻:
ExcelApplication1->set_DisplayAlerts(0,false);
ExcelApplication1->Quit();
又如:
int SheetCount=ExcelWorkbook1->Worksheets->Count;
这些代码都照旧较量直观的。并且很具有OO的美感。
第二,强范例查抄胜于弱范例查抄。
假如利用OleGetProperty可能OleSetProperty函数,那么对通报给这两个函数的参数,是没有步伐节制的。譬喻,我完全可以随心配置一个单位格的属性FOO为100。可是这样的函数挪用在运行期必然会堕落。而利用Server控件就不会有这个问题——编译期就不能通过。可以在编译期发明并更正的错误,不要留到运行期去办理。这是我的主张。
二、须要的帮助手段
利用BCB编写节制Excel的措施,是很繁琐的。因为有时编译通事后会呈现难以琢磨的异常!又有一种很无助的感受:BCB在这上面的辅佐的确是BS。CodeInsight的速度又是相当的慢,无法忍受!
不外,我们不要等闲放弃。按照我的履历,在BCB下要想好好把握Excel编程,必需把握三个得到辅佐的途径。这三个得到辅佐的途径就是(以我小我私家爱好的水平降序分列):
Excel自己的宏呼吁。我此刻的习惯是,假如我要在BCB中实现一个成果,可是却不知道相应的要领和参数,我就会打开Excel,在随便一个Sheet顶用宏记录下我要举办的操纵,然后研究宏代码。这样做,必定能得到正确的要领名,可是对参数的数量和范例却不敢担保:这是因为VBA可以选择不PASS一些缺省参数。按照我的小我私家履历,这样做的有效性应该在80%阁下,浅易性在100%。
Office自带的VBA辅佐。这个辅佐在Office安装进程中一般不是缺省安装的。对付Office 2003中文版的用户,应该查抄C:\Program Files\Microsoft Office\OFFICE11\2052\下是否有雷同VBAxxnn.chm文件。个中xx应该是如下字符串之一:AC(Access),GR(Microsoft Graphics),OF(Office),OL(Outlook),OWS(Office Web Service),PB(Publisher),PP(PowerPoint),WD(Word),XL(Excel)。而nn是对应的Office应用的版本号。假如没有这些文件,请运行Office安装措施,在自界说安装中将这些文件安装即可。这些文件,对付我们领略Office应用中的DOM模子长短常有用的。其有效性为85%,浅易性约为80%。
BCB6中关于Server的头文件。这些头文件的位置应该是在:C:\Program Files\Borland\CBuilder6\Include\Vcl\下。我这里只截一张图。从这张图中,我们也可以看到,BCB6对Office的支持只到Office 2000。Delphi 7可以支持到Office XP。不外它们都能很好的在Office 2003下事情。自Delphi 8之后,我们应该用Interop来操纵Office了。这个要领的有效性是100%——因为你必然可以在内里找到BCB支持的要领,可是浅易性只有10%——因为这些头文件都相当的大:excel_2k.h的巨细是8M+!
这三个手段应该相互帮衬,才气在更短的时间内找到正确的要领。并且通过这三个途径找到的要领、参数应该是相互对应、相互一致的。譬喻,移动一个Sheet到另一个Sheet的Move要领,其在上述三个辅佐途径中的界说别离如下:
在Excel的VBA宏里:Sheets("Sheet2").Move After:=Sheets(3)
Excel的VBA辅佐:见下图
BCB的Excel头文件:
// *********************************************************************//
// Interface: IWorksheets
// Flags: (4112) Hidden Dispatchable
// GUID: {000208B1-0001-0000-C000-000000000046}
// *********************************************************************//
interface IWorksheets : public IDispatch
{
public:
… …
HRESULT STDMETHODCALLTYPE Copy(VARIANT Before/*[in,opt]*/= TNoParam(),
VARIANT After/*[in,opt]*/= TNoParam(),
… …
HRESULT STDMETHODCALLTYPE Move(VARIANT Before/*[in,opt]*/= TNoParam(),
VARIANT After/*[in,opt]*/= TNoParam(),
long lcid/*[in]*/= TDefLCID()); // [637]
… …
#p#副标题#e#
三、编程指南
(一) ExcelApplication的启动、退出
我们平时所说的启动/退出Excel,在BCB6中应该被确切的说成是ExcelApplication的启动/退出。对应的控件是。用来启动、退出的代码别离如下:
#p#分页标题#e#
void __fastcall TMainForm::EABtnClick(TObject *Sender)
{
try
{
EA->Connect();
}
catch(…)
{
ShowMessage("Can not launch server");
}
EA->set_Caption((WideString)"Excel Server Invoked by BCB");
EA->set_Visible(0,true);
}
__fastcall TMainForm::~TMainForm()
{
EA->set_DisplayAlerts(0,false);
EA->Quit();
}
留意,Office控件多以接口形式相互关联,所以毗连的要领也被贯之以Connect的名称。由于Excel Application必然是顶层工具,所以它的Connect要领不需要指定参数。
set_Caption是用来配置Excel Application的标题。请留意要用WideString,而不是String。
set_Visible(0, true)是使Excel Application可见。这里参数0是Locale ID。
Excel控件的封装是很奇怪的——也许是因为BCB 6只支持到Office 2000而今朝我们根基都是要操纵Office 2003而引起的版本兼容问题。一般来说,我们但愿直接利用雷同属性的操纵要领来修改。可是,有些属性,如Visible,就必需用“set_属性/get_属性 ”的方法举办操纵。这不是说Excel Application控件中没有Visible这个属性。这个属性确实存在于Excel Application控件中,可是假如你想直接操纵Visible属性,那么无论你写成:“EA->Visible=true;”照旧“EA->Visible[0]=true;”,编译时城市堕落!提示“TExcelApplication::Visible is not accessible. ”。而更奇怪的是,假如我们直接操纵属性,那么纵然编译可以或许通过,也大概没有实际效用!有乐趣的读者可以测试一下Caption属性的操纵。
一般而言,用set_属性/get_属性的方法,必然可以操纵一个属性。可是,有些Set要领的定名也不遵守这个纪律,后文即将涉及。
退出时,可以按照小我私家的爱好,配置DisplayAlerts属性。假如配置为true,那么在退出时,假如对Sheet或Workbook举办了一些需要存盘的操纵,会有一个确认框呈现。
以前曾经有一种说法,说是这样启动并正常退出的Excel Application,退出后会在内存中留下一个Excel历程。在我的呆板上,没有这样的景象。
需要增补的是ExcelApplication控件的ConnectKind属性。它一共有五个可选值:ckAttachToInterface/ckNewInstance/ckRunningOrNew/ckRemote/ckRunning。一般我城市用ckRunningOrNew。其它的选项我倒没有举办过测试。
(三) ExcelWorksheet的操纵
在上文毗连Workbook的代码中,我也同时毗连了TExcelWorksheet,其控件图标是。所以完整的代码段如下:
void __fastcall TMainForm::EWBBtnClick(TObject *Sender)
{
EWB->ConnectTo(EA->Workbooks->Add(TNP, 0));
// Connect to worksheet as well
EWS1->ConnectTo(EWB->Worksheets->get_Item(V("Sheet1")));
EWS2->ConnectTo(EWB->Worksheets->get_Item(V(2)));
EWS3P=EWB->Worksheets->get_Item(V("Sheet3"));
EWS3->ConnectTo(EWS3P);
EWS3->Activate();
}
我们知道,缺省环境下,一个空缺的Excel Workbook有三个空缺的Worksheet,所以上文中我用三个ExcelWorksheet控件来毗连这三个Worksheet。
我们既可以用表的名字(如“Sheet1”),也可以用表的序号(如“2”)来作为一个表的索引号。请留意V要领,它也是我界说的一个宏:
#define V TVariant
所以,它只是一个用来结构TVariant参数的宏。它和上面的TNP宏都是蛮有用的界说。
下面是一些针对Excel Worksheet的操纵,不再一一具体说明。
void __fastcall TMainForm::MoveSheetBtnClick(TObject *Sender)
{
EWS1->Move(TNP, V(EWB->Worksheets->get_Item(V("Sheet3"))), 0);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::RenameBtnClick(TObject *Sender)
{
String NewName;
InputQuery("Rename Excel Worksheet", "Input a new name", NewName);
EWS1->set_Name((WideString)NewName);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::CreateBtnClick(TObject *Sender)
{
EWS4->ConnectTo(EWB->Sheets->
Add(TNP,V(EWB->Worksheets->get_Item(V("Sheet3"))),V(1),V(xlWorksheet)));
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DelSheetBtnClick(TObject *Sender)
{
EWS2->Delete(0);
}
我们已经操纵到了Worksheet级别,可是在我们日常操纵中,打仗最多的是Range(范畴)和Cell(单位格),在后文我们将继承深入接头,并接头如何毗连数据库、如何画数据图,以及如何用TExcelQueryTable加快数据导入的要领。
这样生成的Excel Application只是一个空架子。我们要增加Workbook(事情簿)。
(二) ExcelWorkbook的建设和相关操纵
#p#分页标题#e#
假如我们把ExcelWorkbook简朴的领略为等价于一个xls文件,应该不会不同太大,并且应该对我们有辅佐。它的控件图标是。我们来看如何建设Workbook,代码如下:
void __fastcall TMainForm::EWBBtnClick(TObject *Sender)
// 本文转自 C++Builder研究 - http://www.ccrun.com/article.asp?i=1044&d=xr3888
{
EWB->ConnectTo(EA->Workbooks->Add(TNP, 0));
... ...
}
首先,我们要毗连到一个Workbook的接口上去,这里我们用的是新增一个Workbook的方法。留意TNP参数,我们会在许多场所利用它。它是我本身措施中界说的一个宏:
#define TNP TNoParam()
而第二个参数0,则又是Locale ID(简称LID)。
ExcelWorkbook还可以用来毗连——可能说“打开”更得当——一个现有的Workbook(一个xls文件),详细代码如下:
EWB->ConnectTo(EA->Workbooks->Open((WideString)"c:\\temp\\test.xls",
TNP, TNP, TNP, TNP,
TNP, TNP, TNP, TNP,
TNP, TNP, TNP, TNP, 0));
上述代码中打开了位于c:\temp下的test.xls文件。这个要领有许多参数,一般我城市通报TNP给它。详细参数的寄义,可以参考相关文档。
(三) ExcelWorksheet的操纵
在上文毗连Workbook的代码中,我也同时毗连了TExcelWorksheet,其控件图标是。所以完整的代码段如下:
void __fastcall TMainForm::EWBBtnClick(TObject *Sender)
{
EWB->ConnectTo(EA->Workbooks->Add(TNP, 0));
// Connect to worksheet as well
EWS1->ConnectTo(EWB->Worksheets->get_Item(V("Sheet1")));
EWS2->ConnectTo(EWB->Worksheets->get_Item(V(2)));
EWS3P=EWB->Worksheets->get_Item(V("Sheet3"));
EWS3->ConnectTo(EWS3P);
EWS3->Activate();
}
我们知道,缺省环境下,一个空缺的Excel Workbook有三个空缺的Worksheet,所以上文中我用三个ExcelWorksheet控件来毗连这三个Worksheet。
我们既可以用表的名字(如“Sheet1”),也可以用表的序号(如“2”)来作为一个表的索引号。请留意V要领,它也是我界说的一个宏:
#define V TVariant
所以,它只是一个用来结构TVariant参数的宏。它和上面的TNP宏都是蛮有用的界说。
下面是一些针对Excel Worksheet的操纵,不再一一具体说明。
void __fastcall TMainForm::MoveSheetBtnClick(TObject *Sender)
{
EWS1->Move(TNP, V(EWB->Worksheets->get_Item(V("Sheet3"))), 0);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::RenameBtnClick(TObject *Sender)
{
String NewName;
InputQuery("Rename Excel Worksheet", "Input a new name", NewName);
EWS1->set_Name((WideString)NewName);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::CreateBtnClick(TObject *Sender)
{
EWS4->ConnectTo(EWB->Sheets->
Add(TNP,V(EWB->Worksheets->get_Item(V("Sheet3"))),V(1),V(xlWorksheet)));
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DelSheetBtnClick(TObject *Sender)
{
EWS2->Delete(0);
}
我们已经操纵到了Worksheet级别,可是在我们日常操纵中,打仗最多的是Range(范畴)和Cell(单位格),在后文我们将继承深入接头,并接头如何毗连数据库、如何画数据图,以及如何用TExcelQueryTable加快数据导入的要领。