一、ArcObjects简介 软件重用是业界追求的目标,人们一直希望能够像搭积木一样随意地“装配”应用程序;组件对象就充当了积木的角色。所谓组件对象,实际上就是预先定义好的、能完成一定功能的服务或接口。Microsoft'sComponentObjectModel(组件对象模型,简称COM)是组件对象之间互相接口的规范。凡是遵循COM接口规范的对象彼此之间能相互通信和交互,即使这些对象是由不同的厂商用不同的语言编写,在不同的Windows版本甚至在不同的机器上建立。 ArcObjects是ESRI公司提供的一套基于COM技术的组件库。ArcGIS(tm)软件家族中的ArcMap(tm),ArcCatalog(tm),andArcScene(tm)应用程序就是由ArcObjects构建而成的。COM本质上仍然是客户/服务器模式,如“图A”所示,客户(通常是应用程序)请求创建COM对象并通过COM对象的接口操纵COM对象,服务器根据客户的请求创建并管理COM对象。COM是个二进制规范,它与源代码无关,我们可以使用任何支持COM的编程语言(如VisualBasic、VisualC++、Delpi等)做ArcObjects的应用开发。不过,目前的ArcObjects不是独立的SDK,所以要用ArcObjects开发独立的应用系统,必须要在已装有ArcInfo(tm),ArcEditor(tm)或ArcView(tm)的环境下进行,以获取软件使用的许可。 二、Delphi编程环境下ArcObjects的开发过程 由于随机带的ArcObjects开发帮助手册(ArcObjectsDeveloperHelp)以及ESRI 公司主页上的ArcScripts里提供的大部分编程指导和例程都是用VisualBasic和VisualC++编写的,为了让习惯于用Delphi工作的程序员们能方便地使用ArcObjects进行独立的应用开发,下面我们用Delphi5+ArcObjects来构造一个简单的GIS应用程序作为示例,以供参考。这个应用程序会实现一些如:图形数据的加载,地图的放大、缩小、漫游、全景显示及在地图上添加点状图形标记的功能。 说明:如过以前已做过第一、二步的工作可以跳过,直接从第三步入手。 第一步:引入ArcObjects类型库文件 使用Delphi5.0“Project|ImportTypeLibrary……”菜单项打开“ImportTypeLibrary”对话框,从其类型库文件列表框中找到“ESRIObjectLibrary(Version1.0)”,即为“%ARCHOME%/bin/esriCore.olb”文件。接下来操作需要注意,这时在“ClassName”列表里罗列了所有esriCore.olb实现类的类名,由于其中的部分类名与Delphi的VCL组件库里定义的类名有重复,为了避免产生冲突,建议把上述列表里罗列的所有类名由原来的以“T”开头改为以“Tesri”开头,最后按“CreateUnit”,这样在“Unitdirname”编辑栏处指定的目录里会生成一个名为“esriCore_TLB.pas”的该类型库的ObjectPascal外套文件,从中可以看出该类型库中的所有GUID常量、类型、接口和CoClass组件类。 第二步:引入ArcObjects地图控件 使用“Component|ImportActiveXControl……”菜单项打开“ImportActiveX”对话框,从其ActiveX控件列表框中找到“ESRIArcObjectsControls8.1(Version1.0)”并按“Install……”按钮,然后一路“确认”。这样在Palette控件面板的ActiveX页面上就会出现一个“TMapControl”类型的ActiveX控件。 第三步:功能实现 1.准备工作 先使用“File|NewApplication……”菜单项建立一个新的工程,然后选中Palette控件面板的ActiveX页面上“MapControl”控件,用鼠标拖放到新建工程的窗体上,MapControl的Name属性设为MapControl,Align属性设为alClient,ShowScrollbars属性设为False。最后在unit1单元interface部分的uses字句后添加上对“esriCore_TLB”的引用,这很关键,否则编译器找不到相关的Interface和CoClass的声明。2.往MapControl控件上加载图层 这里介绍使用的是shapefile格式的数据。给Form1窗体添加一个加载shapefile文件的全局方法AddShpLayer,实现代码如下: functionTForm1.AddShpLayer(FilePath,FileName:String):String; var pWFactory:IWorkspaceFactory; pPropertySet:IPropertySet; pWorkspace:IWorkspace; pFWorkspace:IFeatureWorkspace; pFClass:IFeatureClass; pFLayer:IFeatureLayer; begin try pWFactory:=CoShapefileWorkspaceFactory.CreateasIWorkspaceFactory; pPropertySet:=CoPropertySet.CreateasIPropertySet; pPropertySet.SetProperty('DATABASE',FilePath); pWFactory.Open(pPropertySet,self.Handle,pWorkspace); pFWorkspace:=pWorkspaceasIFeatureWorkspace; Delete(FileName,Length(FileName)-3,4); pFWorkspace.OpenFeatureClass(FileName,pFClass); pFLayer:=coFeatureLayer.CreateasIFeatureLayer; pFLayer.Set_FeatureClass(pFClass); pFLayer.Set_Name(FileName); MapControl1.AddLayer(pFLayer); result:=FileName; except onE:Exceptiondoresult:=''; end; end; 然后在窗体Form1的OnCreate事件里加入以下的代码: AddShpLayer('D:/GISData/','STATES.shp'); 这时按F9运行程序(此前确保D:/GISData/STATES.shp图层文件存在,即至少包括D:/GISData/STATES.shp、D:/GISData/STATES.shx、D:/GISData/STATES.dbf三个文件),就会发现STATES图层已经加入到了Mapcontrol控件里。 3.地图的放大、缩小、漫游和全景显示 在Mapcontrol控件的onMouseDown事件里加入以下的代码: procedureTForm1.MapControlMouseDown(Sender:TObject;button,shift,x, y:Integer;mapX,mapY:Double); var envlp:IEnvelope; bIsEmpty:wordbool; begin //在Mapcontrol上按下鼠标左键后做拉框操作,实现地图放大功能 if(Button=1)and(Shift=0)then begin MapControl.MousePointer:=esriPointerZoomIn; envlp:=MapControl.TrackRectangle; envlp.Get_IsEmpty(bIsEmpty); ifnotbIsEmptythen MapControl.Extent:=envlp exit end; //按下Shift键的同时在Mapcontrol上按下鼠标左键在做点击操作,实现地图缩小功能 if(Button=1)and(Shift=1)then begin MapControl.MousePointer:=esriPointerZoomOut; envlp:=MapControl.Extent; envlp.Expand(2,2,False); MapControl.Extent:=envlp; exit; end; //在Mapcontrol上按下鼠标右键键后做拖动操作,实现地图漫游功能 if(Button=2)and(Shift=0)then begin MapControl.MousePointer:=esriPointerPanning; MapControl.Pan; MapControl.MousePointer:=esriPointerPan; exit; end; end; 在Mapcontrol控件的OnDoubleClick事件里加入以下的代码: procedureTForm1.MapControl1DoubleClick(Sender:TObject;button,shift,x, y:Integer;mapX,mapY:Double); begin //在Mapcontrol上双击,实现地图全景显示功能 MapControl1.Extent:=MapControl1.FullExtent; end; 4.地图上添加点状图形标记的功能 先声明两个窗体Form1的私有变量: F_MultiPoint:IMultiPoint; F_Pts:IPointCollection; 再在窗体Form1的OnCreate事件里加入以下的代码: F_MultiPoint:=CoMultiPoint.CreateasIMultiPoint; F_Pts:=F_MultiPointasIPointCollection; 然后给Form1窗体添加一个的用于添加点状图形标记的全局的方法DrawPoint, 实现代码如下: procedureTForm1.DrawPoint; var pt_cnt,i:integer; sym:ICharacterMarkerSymbol; pt:IPoint; ft:TFont; oleft:variant; ScreenDisplay:IScreenDisplay; ActiveView:IActiveView; begin ActiveView:=MapControl.ActiveView; ActiveView.Get_ScreenDisplay(ScreenDisplay); F_Pts.Get_PointCount(pt_cnt); ifpt_cnt>0then begin ScreenDisplay.StartDrawing(0,0); fori:=0topt_cnt-1do begin F_Pts.Get_Point(i,pt); sym:=coCharacterMarkerSymbol.CreateasICharacterMarkerSymbol; sym.Set_Size(30); ft:=TFont.Create; ft.Size:=40; ft.Name:='Wingdings'; oleft:=FontToOleFont(ft); sym.Set_Font(IFontDisp(IDispatch(oleft))); sym.Set_CharacterIndex(i+33); ScreenDisplay.SetSymbol(symasISymbol); ScreenDisplay.DrawPoint(pt); end; ScreenDisplay.FinishDrawing; end; end; 然后在Mapcontrol控件的onMouseDown事件里加入以下的代码: //按下Shift键的同时在Mapcontrol上按下鼠标右键在做点击操作, //实现在地图上添加点状图形标记的功能 if(Button=2)and(Shift=1)then begin pt:=mapcontrol1.ToMapPoint(x,y); F_Pts.AddPoint(pt,EmptyParam,EmptyParam); DrawPoint; exit; end; 最后,在Mapcontrol控件的OnAfterDraw事件里加入以下的代码: procedureTForm1.MapControlAfterDraw(Sender:TObject;const display:IDisplay;phase:TOleEnum); begin DrawPoint;//用于刷新添加在地图上的点状图形标 end; 这样,一个包含了一些简单的GIS功能的应用程序就完成了(按F9可以运行)。 三、结束语 希望以上的这个小例程能给习惯于用Delphi工作的ArcObjects程序开发者一点启发,从而开发出各种强大的GIS应用系统来。
|