Microsoft Office 2000一个新的令人振奋的特性就是它提供了Office Web Components (OWC,一组用于创建动态Web文档的ActiveX控件)。OWC包括六个控件,实现了Excel的部分功能并提供了数据库存取功能,它们是ChartSpace、Spreadsheet、DataSourceControl、RecordNavigationControl、ExpandControl和Pivot-Table。DataSourceControl和RecordNavigationControl控件提供了数据库存取功能,它们可以用ADOExpress控件来替代。 ExpandControl本文将不涉及,有兴趣的朋友可自行研究。要想使用这些ActiveX控件需要引入相应的类型库(当然如果是后期绑定就不需要),选择菜单命令Project | Import Type Library,然后在弹出的对话框选择Microsoft Office Web Components 9.0 (Version 1.0),确认选中了Generate Component Wrapper选项(Delphi5中支持),然后点击Install按钮,六个组件就被加到了组件面板上。
类型库文件定义在MSOWC.DLL文件中,位于/Program Files/Microsoft Office 2000/Office目录下。帮助文件为MSOWCVBA.CHM,位于/Program Files/Microsoft Office 2000/Office/1033。
ChartSpace组件
ChartSpace是用来创建图表的,它支持46 种图表,从线型到Doughnut Exploded型,详细类型参见帮助中的ChartChartTypeEnum 参数列表。它支持多种数据源,比如其他OWC控件,像Spreadsheet控件,ADO数据源或静态数据。
1. 基于静态数据的图表
在Delphi中我们可以把静态数据储存在Variant数组中,数组可以使用VarArraycreate 函数创建,也可以使用VarArrayOf函数创建动态的Variant数组。下面的代码演示了如何创建并赋值给一个静态Variant数组。
var
XValues : Variant;
...
//创建Variant数组
XValues := VarArraycreate([0,2], varVariant);
//加载X轴数据
XValues[0] := 'Element one';
XValues[1] := 'Element two';
XValues[2] := 'Element two';
VarArraycreate 的两个参数用于指定数组的维数和项目类型,在上面的例子中我们创建了Variant类型的有三个项目的数组。下面的代码则演示了如何用VarArrayOf 函数创建一个一维Variant类型的数组:
VarArrayOf([104737, 50952, 78128, 117797, 52902, 80160, 47491, 62435]);
图1.18
使用ChartSpace控件包括几个步骤:首先,需要清除图表已有的内容;随后,添加一个新的图表对象到图表集合中(集合最多允许有16个图表);然后,就可以为图表提供数据(Series集合),设定标题(Title 属性),指定坐标轴(Axes 集合)和设定插图(Legend 属性)。图1.18显示了一个简单的ChartSpace控件的类体系关系。
下面给出一个例子演示如何使用静态数据创建图表,首先我们需要设定一些变量:
var
Chart : WCChart; // 图表
Series : WCSeries; // Series
XValues : Variant; // X轴值
清空图表原有内容。
ChartSpace1.Clear;
ChartSpace1.Refresh;
创建新的图表,因为这是图表集合中第一个图表,它的索引为0。
Chart := ChartSpace1.Charts.Add(0);
设定图表标题。
Chart.HasTitle := True; //说明图表有标题
Chart.Title.Caption := 'Sales By Category';
然后就是提供数据了,先创建X轴的值,这里使用静态Variant数组作为数据源。
XValues := VarArraycreate([0,7], varVariant);
XValues[0] := 'Beverages';
XValues[1] := 'Condiments';
XValues[2] := 'Confections';
XValues[3] := 'Dairy Products';
XValues[4] := 'Grains & Cereals';
XValues[5] := 'Meat & Poultry';
XValues[6] := 'Produce';
XValues[7] := 'Seafood';
有了数据,现在就需要添加一个新的Series 对象到SeriesCollection 集合中去。
Series := Chart.SeriesCollection.Add(0);
with Series do begin
//设定Series标题...
Caption := '1998';
// ...和数据
SetData(chDimCategories, chDataLiteral, XValues);
// Y轴数据源是一个动态variant数组
SetData(chDimValues, chDataLiteral, VarArrayOf(
[104737, 50952, 78128, 117797,
52902, 80160, 47491, 62435]));
// 设定图表类型,这里为Clustered Column
Type_ := chChartTypeColumnClustered;
end;
下面让我们再添加一个新的series,并创建一个新的图表放在已有图表的顶上。
Series := Chart.SeriesCollection.Add(1);
with Series do begin
Caption := '1999';
SetData(chDimCategories, chDataLiteral, XValues);
SetData(chDimValues, chDataLiteral, VarArrayOf(
[20000, 15000, 36000, 56000,
40000, 18000, 20000, 33000]));
// 设定图表类型为Line Markers.
Type_ := chChartTypeLineMarkers;
end;
我们还需要为图表添加一个坐标轴,并设定它的属性。
Chart.Axes.Add(Chart.Axes[chAxisPositionLeft].Scaling,
chAxisPositionRight, chValueAxis);
Chart.Axes[chAxisPositionLeft ].NumberFormat := '$#,##0';
Chart.Axes[chAxisPositionRight].NumberFormat := '0';
Chart.Axes[chAxisPositionLeft ].MajorUnit := 20000;
Chart.Axes[chAxisPositionRight].MajorUnit := 20000;
接下来要在图表的下边添加一个插图。
Chart.HasLegend := True;
Chart.Legend.Position := chLegendPositionBottom;
图1.19
生成的结果如图1.19所示,随后我们要演示如何使用数据库作为数据源显示图表。
2. 基于数据库的图表
创建基于数据库的图表,有两个选择:一个是使用OWC中的DataSource控件,一个是使用Ado兼容的数据源。 其实两者大同小异,主要区别是如何定义数据源。
(1) 使用OWC的DataSource
首先声明变量:
var
RSD : RecordsetDef; // 数据源DataSource
BarChart : WCChart; // 图表
PieChart : WCChart;
接下来设定数据源及相应的SQL语句来获得数据,这里使用Access带的例子数据库 Northwind.mdb。
begin
DataSourceControl1.ConnectionString :=
'DRIVER={Microsoft Access Driver (*.mdb)};' +
'DBQ=C:/DATA/NORTHWIND.MDB'; //根据自己的路径进行修改
RSD := DataSourceControl1.RecordsetDefs.AddNew(
'select * FROM [Category Sales for 1997]', 3, 'Sales');
然后,清除图表,并指定数据源:
with ChartSpace1 do begin
Clear;
Refresh;
DataSource := DataSourceControl1.DefaultInterface as MSDATASRC _TLB.DataSource;
DataMember := RSD.Name;
end;
因为ChartSpace控件的DataSource 属性声明为IUnknown类型的接口(见MSDATASRC_TLB 单元),所以需要用as操作符查询接口。
(2) 使用ADO数据源
这里使用ADOExpress控件,ADOConnection控件用来设定数据源和游标类型,ADOCommand控件用来提供SQL查询。下面是ADO数据集变量定义:
var
RS : _Recordset; // ADO RecordSet
下面代码执行一个SQL查询,并把返回的数据赋给图表:
RS := ADOCommand1.Execute;
with ChartSpace1 do begin
Clear;
Refresh;
DataSource := RS as MSDATASRC_TLB.DataSource;
DataMember := '';
end;
下面的代码和前面讲过的类似,创建一个新的图表指定数据类型、添加坐标轴等。
// 设定图表水平布局
ChartSpace1.ChartLayout := chChartLayoutHorizontal;
// 添加新的图表
BarChart := ChartSpace1.Charts.Add(0);
with BarChart do begin
//设定图表类型为Bar图
Type_ := chChartTypeBarClustered;
// 第一个字段为categories.
SetData(chDimCategories, 0, 0);
//第二个字段为values.
SetData(chDimValues, 0, 1);
//设定坐标轴格式
with Axes[chAxisPositionBottom] do begin
NumberFormat -:= '0,';
MajorUnit:= 25000;
HasMajorGridlines := False;
end;
end;
现在基于同样的数据创建一个饼图,运行结果显示在图1.20中。
PieChart := ChartSpace1.Charts.Add(1);
with PieChart do begin
//设定图表类型为饼图
Type_ := chChartTypePie;
SetData(chDimCategories, 0, 0);
SetData(chDimValues, 0, 1);
// 设定饼图的"Explode"段数
SeriesCollection.Item[0].Explosion := 20;
// 添加插图...
HasLegend := True;
Legend.Position := chLegendPositionBottom;
// ...和标题
HasTitle := True;
Title.Caption := 'Sales by Category for 1997';
Title.Font.Set_Bold(True);
Title.Font.Set_Size(11);
WidthRatio := 75;
// 数据按百分比显示
with SeriesCollection.Item[0].DataLabelsCollection.Add do
begin
HasValue := False;
HasPercentage := True;
Font.Set_Size(7);
end
图1.20
(3) 基于电子表格(Spreadsheet)数据的图表
在下面这个例子中,我们将创建一个基于OWC Spreadsheet控件数据的图表,当我们修改了电子表格中的数据后,变动会自动反映在电子表格中,先声明变量:
var
Sheet : WorkSheet; // 电子表格
Chart : WCChart; // 图表
用数据填充电子表格
Sheet := Spreadsheet1.ActiveSheet;
with Sheet do begin
Range['A1', 'A10'].Set_Formula('=Row()');
Range['B1', 'B10'].Set_Formula('=A1^2');
Range['A12','A12'].Set_Formula('=Max(A1:A10)');
Range['B12','B12'].Set_Formula('=Max(B1:B10)');
end;
在上面的代码中,我们把行号(从1到10)插到列A中,把行号的平方插到列B中。单元格A12和 B12 设为列A和列B的最大值。正如我们看到的,Spreadsheet控件支持Excel那样的公式表达,它和Excel拥有同样的二进制内核。这项特性使得我们可以利用Spreadsheet控件执行某些无须显示结果于在屏幕上的后台计算。
同前面类似,还是创建图表,连接数据源:
with ChartSpace1 do begin
Clear;
Refresh;
//指定数据源
DataSource := Sheet.Parent as MSDATASRC_TLB.DataSource;
Chart := Charts.Add(0);
// 设定图表类型为Scattered Smooth Line Markers。
Chart.Type_ := chChartTypeScatterSmoothLineMarkers;
// 指定X轴数据...
Chart.SetData(chDimXValues, 0, 'A1:A10');
// ...和Y轴数据
Chart.SetData(chDimYValues, 0, 'B1:B10');
end;
剩下的就是美化我们的图表,比如指定轴标题和类型等
//显示轴的标题
with Chart do begin
with Axes[chAxisPositionBottom] do begin
HasTitle := True;
Title.Caption := 'X';
Title.Font.Set_Size(8);
MajorUnit := 1;
end;
with Axes[chAxisPositionLeft] do begin
HasTitle := True;
Title.Caption := 'X Squared';
Title.Font.Set_Size(8);
MajorUnit := 10;
end;
...
然后指定轴的范围并设定其他的样式:
Scalings[chDimXValues].Maximum :=
Sheet.Range['A12', 'A12'].Value;
Scalings[chDimXValues].Minimum := 1;
Scalings[chDimYValues].Maximum :=
Sheet.Range['B12', 'B12'].Value;
// 设定其他样式
with SeriesCollection.Item[0] do begin
Marker.Style := chMarkerStyleDot;
Marker.Size := 6;
Line.Set_Weight(1);
End
运行结果如图1.21所示。
注意数据可以被动态的显示,当我们改变了电子表格的数据,结果会被自动的反映在图表中。现在我们已经知道如何使用Spreadsheet控件作为图表的数据源,接下来该讲如何使用Spreadsheet控件本身了。
Spreadsheet控件
Spreadsheet控件提供了一个可编程的内核,它有一个巨大的函数库可以进行各种计算。Spreadsheet对象模型(如图1.22)包含ActiveSheet 属性,用于同控件中的活动页面交互,Pane 对象代表电子表格的工作区,Range 用于指定单元格范围,TitleBar 表示电子表格的标题条,而Worksheet 则是电子表格本身。
图1.21 图1.22
向电子表格中加载数据有很多方式,比如手工输入,从剪贴板复制粘贴,从Word或Excel中加载,或从文本文件以及网站读取等。要想从文本文件中读取数据,可以使用Spreadsheet控件的 LoadText 方法,它需要下列参数:
l 字符串形式的文件名;
l 分割符号,比如tab或逗号等;
l 一个布尔值用于确定如何处理连续的分割符;
l 以及文本标识,缺省是双引号。
下面就是一个LoadText 的使用例子,它从Employee.txt文件中加载数据,并使用tab字符(ASCII 8)作为分割符:
SpreadSheet1.LoadText('c:/data/Employee.txt', Chr(9), False, '"');
此外我们还可以通过设定CSVData (逗号分割的数据)属性或是HTMLData (HTML类型数据)属性来指定数据。注意:HTML格式的数据需要是以Excel兼容格式储存的。当前版本的Spreadsheet控件还不支持数据库,但是我们可以很容易的从ADO数据源中引入数据,代码示意如下:
procedure TForm1.Button1Click(Sender: TObject);
var
RS: _RecordSet; // ADO Recordset
I,J: Integer; // 记数
NumRecs : Integer; // 记录数
begin
// 执行SQL查询
RS := ADOCommand1.Execute;
// 移动到第一条记录
RS.MoveFirst;
// 清空spreadsheet
Spreadsheet1.ActiveSheet.Cells.Item[1, 1].select;
Spreadsheet1.ActiveSheet.UsedRange.Clear;
// 设定列标题
J := 0;
for I := 0 to RS.Fields.Count-1 do begin
Inc(J);
Spreadsheet1.ActiveSheet.Cells.Item[1, J].Set_Value(
RS.Fields[I].Name)
end;
// 读入数据
I := 1;
while NOT RS.EOF do begin
for J := 1 to RS.Fields.Count do
Spreadsheet1.ActiveSheet.Cells.Item[I+1, J].
Set_Value(VarToStr(RS.Fields[J-1].Value));
// 移到下一条记录
RS.MoveNext;
Inc(I)
end;
NumRecs := I;
end;
上面我们使用ADOCommand控件从Northwind数据库的Employees表中读取数据,然后遍历记录,并把数据加入Spreadsheet控件的单元格中。读完数据后,我们可以设定单元格的属性,下面的代码可改变第一行单元格的字体:
with Spreadsheet1.Range[Spreadsheet1.Cells.Item[1, 1],
Spreadsheet1.Cells.Item[1, RS.Fields.Count]].Font do
begin
Set_Name('Arial Narrow');
Set_Bold(True);
Set_Size(11);
end;
同时我们还可以设定单元格按内容自动调整尺寸并左对齐数据:
with Spreadsheet1.Range[Spreadsheet1.Cells.Item[1, 1],
Spreadsheet1.Cells.Item[NumRecs, RS.Fields.Count] do
begin
AutoFitColumns;
Set_HAlignment(ssHAlignLeft);
end;
运行结果如图1.23所示。
图1.23
设定颜色
如果我们想修改Chart或Spreadsheet控件中元素的颜色,会发现Color 属性是只读的,这是由于Delphi类型库扫描器的bug引起的,为了绕过这个问题,我们可以直接使用Set_Color 方法,但是它的参数是POleVariant1类型的,这个类型定义为OLEVariant的类型指针,下面代码演示如何使用Set_Color 方法:
var
C : OLEVariant;
...
// 使用预定义的颜色...
C := OLEVariant('CornSilk');
// ...或16位RGB值
C := OLEVariant(RGB($C0, $C0, $C0));
...
Spreadsheet1.ActiveSheet.UsedRange.Interior.Set_Color(@C);
是什么呢?