1、MapObejcts组件应用设计(地图数据的创建与编辑)1. Recordset表的记录指针2. 编辑属性表已有数据3. 添加新记录4. 删除记录5. FeatureID6. 创建数据库表1. 定义并创建一个新表2. 创建子集数据库表7. TrackingLayer图层与GeoEvent对象1. TrackingLayer图层2. GeoEvent对象3. TrackingLayer图层的属性和方法2.6.1 Recordset对象Recordset是MapObjects中的一个对象,它为图层(MapLayer)提供地图数据,又是地图数据的管理者与操作者,因此,地图数据的创建和编辑在Recor
2、dset上进行。每个MapLayer对应一个Recordset,仅对应一个Recordset,是Recordset的可视化。从数据库的观点看,Recordset是一个数据表,概念与数据表一致,图形数据储存在表的一个字段(shape)中。Recordset是记录的集合,提供了对记录及字段的操作方法。ShapeFile是ESRI公司定义的一种无拓扑关系的地理信息文件格式,是MapObjects固有数据格式,在这种格式上实现了读写、修改、编辑功能。ShapeFile用一组文件储存一个图层数据,同一图层各文件的主名相同,用作图层名。扩展名标识文件的内容,分别是:.shp 储存几何要素.shx 储存几何
3、要素索引.dbf 储存几何要素的属性数据,是dBase文件,可用FoxPro软件操作这一组文件映射成一个Recordset表。表中含有.dbf文件的全部字段,还有两个由Recordset对象添加的字段:Shape和FeatureID。两个添加字段的值来自于文件.shp和.shx。例如,china图层的三个组成文件是:china.shp,china.shx,china.dbf。china.dbf的字段名是:name , gdp1990 , gdp1995 ,那么,Recordset形成的表是:ShapeFeatureIDNamegdp1990gdp1995Polygon1新疆121190Poly
4、gon3河北221440Recordset对象封装了表及在表上的操作,在Recordset中,表的一行称为一个记录,表的一列称为一个字段,列的名称称为字段名。在这个例子中,有5个字段,2个记录。第一行是字段名行,不是记录。shape字段的每一个值是一个几何图形元素,用几何对象定义。FeatureID是图形元素的索引号。Shape 、FeatureId是Recordset对象生成的标准字段,对于Coverage、SDE、CAD、VPF等格式数据形成的Recordset表也是如此。1 Recordset表的记录指针Recordset表从概念上看,是记录的集合。记录是集合中的成员,用指针确定在表中的
5、位置。在表中移动指针可以定位记录。例1 Map1中含有china图层,属性如前表所示。编程显示属性表中的数据(完整程序见recordPointer目录)。Private Sub Command1_Click() 记录指针定位Dim recs As MapObjects2.RecordsetSet recs = Map1.Layers(“china”).Recordsrecs.MoveFirst 指针指向记录1Debug.Print recs.Fields(“name”).Value, recs.Fields(“gdp1995”).Value 输出: 新疆190recs.MoveNext 指针指
6、向记录2recs.MoveNext 指针指向记录3Debug.Print recs.Fields(“name”).Value, recs.Fields(“gdp1995”).Value 输出:河北 440End SubRecordset的指针定位方法:recs.MoveFirst 指针指向记录1开始位置recs.MoveNext 指针指向下一条记录开始位置recs.MovePrevious 指针指向前一条记录开始位置recs.EOF 指针指向最后一条记录的末端时返回TRUE,否则返回FALSE2编辑属性表已有数据编辑记录在Recordeset对象上进行,每次编辑一条记录,程序设计顺序依次是:(
7、1) 移动记录指针到要编辑的记录(2) 读取当前记录到缓冲区中(3) 编辑修改当前记录字段的值(4) 更新当前记录(5) 全部记录编辑完后,停止编辑例2 编辑China属性表,将gdp1995字段的值增加1(完整程序见recordPointer目录)。Private Sub Command2_Click() 编辑记录中的属性数据Dim recs As MapObjects2.RecordsetDim fld As MapObjects2.FieldSet recs = Map1.Layers(“china”).RecordsSet fld = recs.Fields.Item(“gdp1995
8、”) 引用记录的字段recs.MoveFirst 定位到记录1If recs.Updatable Then recs是可编辑的吗?Do Until recs.EOF 记录指针指向最后记录的末尾了吗?recs.Edit 读取一条记录到缓冲区中fld.Value = fld.Value + 1 修改缓冲区中记录的的一个字段值recs.Update 更新修改的记录recs.MoveNext 记录指针移到下一条记录Looprecs.StopEditing 停止编辑End IfEnd Sub将上面的recs.Update语句替换成recs.CancelUpdate ,则记录编辑无效。3添加新记录添加新记
9、录在MapLayer.Rcords属性上进行,此属性的数据类型是Recordset,实际是在Recordset对象上进行。使用Recordset.Add方法每次编辑一条记录,程序设计顺序依次是:(1) 移动记录指针到给定的记录。(3) 添加一条新记录,这时记录在内存记录缓冲区中。(2) 为新记录字段赋值。(3) 用Update方法更新数据表,这时缓冲区的数据写入文件缓冲区。(4) 全部添加完后,用StopEding方法停止编辑。这时文件缓冲区的数据写入文件。例3手工将Chian图层的文件复制成EditData图层。设计程序,用鼠标输入一个Polygon,在EditData图层中添加一个新记录,
10、将新记录的shape字段值设置成输入的Polygon,将name字段值设置成”新记录”。完整程序见NewDelRd目录,重要代码如下:Private Sub Command1_Click() 添加新记录Dim recs As MapObjects2.RecordsetDim fld As MapObjects2.FieldSet recs = Map1.Layers.Item(“EditData”).Records 获得记录集的引用Set fld = recs.Fields(“Shape”) 获得图形字段的引用Dim poly As MapObjects2.PolygonSet poly =
11、Map1.TrackPolygon 用鼠标画一个多边形If recs.Updatable Thenrecs.MoveFirstrecs.AddNew 添加一个新记录Set fld.Value = poly 将新记录的图形字段设置为画的多边形recs.Fields.Item(“Name”).Value = “新记录” 设置新记录Name字段的值recs.Update 更新数据表recs.StopEditing 编辑结束Map1.Refresh 地图窗口刷新End IfEnd Sub4删除记录例4删除上例中添加的记录(完整程序在NewDelRd目录中)。Private Sub Command2_C
12、lick() 删除name = “新记录” 的记录Dim recs As MapObjects2.RecordsetSet recs = Map1.Layers.Item(“EditData”).Records 获得记录集的引用If recs.Updatable Thenrecs.MoveFirst 移动记录指针到第一个记录Do Until recs.EOF 遍历记录集If recs.Fields.Item(“Name”).Value = “新记录” Then 判断删除条件recs.Edit 使当前记录可编辑recs.Delete 删除当前记录End Ifrecs.MoveNext 移动记录指
13、针到下一个记录Looprecs.StopEditing 编辑结束Map1.Refresh 地图窗口刷新End IfEnd Sub5 FeatureIDFeatureID是Recordset表的字段名,是shape字段中几何图形元素的编号,编号是从1开始的自然数。在Recordset表中,可以读出FeatureID的值,例如:recs.MoveFirstDebug.Print recs.Fileds.Item(“FeatureID”).Value 输出: 12.6.2创建数据库表1定义并创建一个新表例1在Form_Load中建立了dc与数据库”china2”的连接。创建一个数据库表,命名为MyT
14、able,除了两个标准字段以外,表中还含有三个附加字段,字段定义如下:字段名类型宽度小数位数Name字符型16Area数值型153Perimeter数值型1513在表中添加两个记录,给三个属性字段赋值。用鼠标绘制两个Polygon, 赋给表的Shape字段。最后将MyTable保存在China2数据库中(完整程序见CreatTable目录中工程)。Dim dc As MapObjects2.DataConnectionPrivate Sub Command1_Click() 创建数据库表Dim gds As MapObjects2.GeoDatasetDim desc As New Table
15、Desc 数据库表字段描述Dim lyr As New MapObjects2.MapLayerDim poly As MapObjects2.PolygonWith desc 定义表的三个附加属性域.FieldCount = 3.FieldName(0) = “Name” 分别设置3个域的名称.FieldName(1) = “Area”.FieldName(2) = “Perimeter”.FieldType(0) = moString 域的数据类型.FieldType(1) = moDouble.FieldType(2) = moDouble.FieldLength(0) = 16 字符串
16、的长度.FieldPrecision(1) = 15 数字的位数.FieldPrecision(2) = 15.FieldScale(1) = 3 小数点之后的位数.FieldScale(2) = 3End WithSet gds = dc.AddGeoDataset(“MyTable”, moPolygon, desc) 在数据源中加入表If gds Is Nothing Then Exit Sub 文件非法,则退出Set lyr.GeoDataset = gds 设置图层的地理数据集Map1.MousePointer = moCrossFor i = 1 To 2Set poly = Ma
17、p1.TrackPolygon 用鼠标在地图窗口中画一个多边形With lyr.Records.AddNew 添加一个记录.Fields(“Shape”).Value = poly 为图形字段赋值.Fields(“Name”).Value = “多边形 “ & i.Fields(“Area”).Value = poly.Area.Fields(“Perimeter”).Value = poly.Perimeter.UpdateEnd WithNextlyr.Records.StopEditing 记录集修改完毕,保存表记录的数据Map1.MousePointer = moDefaultMap1
18、.Layers.Add lyr Map1.Refresh 在地图窗口中显示绘制的两个多边形End Sub从上段程序中摘取的语句:Set gds = dc.AddGeoDataset(“MyTable”, moPolygon, desc) Set lyr.GeoDataset = gds lyr.Records .AddNew lyr.Records.StopEditing 代表了完成这个例题的基本步骤。注意其中揭示的GeoDataset与Recordset之间的关系。2创建子集数据库表例2用鼠标画一个矩形,从China图层上提取位于矩形区中的记录集,保存提取的记录集,形成一个数据库表(完整程序
19、见SubTable目录中的工程)。Private Sub Command1_Click() 创建子集数据库表Dim gds As MapObjects2.GeoDatasetDim rect As MapObjects2.RectangleDim recs As MapObjects2.RecordsetDim lyr As New MapObjects2.MapLayerMap1.MousePointer = moCrossSet rect = Map1.TrackRectangle 用鼠标拖拉出一个矩形Map1.MousePointer = moDefaultSet recs = Map1
20、.Layers.Item(“Province”).SearchShape(rect, moAreaInTersectt, “”) 提取矩形区中的记录集Set gds = recs.Export(“c:/temp/SubTable”) 保存,形成子集数据库表(ShapeFile格式)Set lyr.GeoDataset = gds 图层引用地理数据集lyr.Symbol.Color = moRed 用红颜色显示此图层Map1.Layers.Add lyr 图层添加到地图窗口中Map1.Refresh 地图窗口刷新End Sub习题1 编写程序实现例1、例2的功能2.6.3 TrackingLay
21、er图层与GeoEvent对象1 TrackingLayer图层与前面讲述的MapLayer及ImageLayer不同,跟踪图层TrackingLayer不属于Layers集合。在绘制完Layers集合中的全部图层后,才绘制TrackingLayer图层中的内容。TrackingLayer图层是Map控件的属性,可在其中动态显示不断改变位置的的图形,每个图形是一个GeoEvent实例,不必重绘Layers集合中的图层,即可实现GeoEvent实例在图上移动,因此具有很高的更新速度。通过TrackingLayer.Refresh方法可以触发跟踪层的重绘,同时还触发BeforeTrackingLa
22、yerdraw和AferTrackingLayerDraw事件。跟踪层中的GeoEvent实例没有保存在数据文件中,程序退出后立即消失。2 GeoEvent对象保存在TrackingLayer图层中的图形元素是GeoEvent对象的实例。MapObjects Shape的实例均可作为TrackingLayer上的GeoEvent实例,因此TrackingLayer图层可以同时储存显示多种类型的图元。GeoEvent实例绘图使用TrackingLayer中自定义的Symbol属性数组中的符号,每个GeoEvent实例可以储存一个标记,用来在运行时与其它GeoEvent实例区别。这个标记还可以用于
23、连接外部数据库中的记录。GeoEvent实例在TrackingLayer层中显示,位置可以快速动态改变而不影响地图窗口中的其它图层,特别适用于在地图窗口中显示汽车、飞机、GPS接收机等的动态位置。3 TrackingLayer图层的属性和方法以下描述中的例句假设Map1是VB窗体上的MapObjects2.Map实例(1) Function Trackinglayer.AddEvent(Object As Object,SymbolIndex As Long) As GeoEvent函数向跟踪层中加入一个几何要素。下面的语句在TrackingLayer层中加入一个点,创建GeoEven点事件。
24、Dim pt As MapObjects2.PointMap1.TackingLager.AddEvent pt , 0 用AddEvent方法加入一个事件时,同时指定了事件使用的数组TrackingLayer.Symbol中的符号,如上面的代码所示,AddEvent的第二个参数SymbolIndex为pt指定了显示用的符号TrackingLayer.Sybmol(0)。(2) Property Event(Index As Long) As GeoEvect只读属性,返回跟踪层中GeoEvent的引用。Event数组中的元素是GeoEvet实例,使用GeoEvent的方法编程,例如:Map1
25、.TrackLingLayer.Event(3).Move x,y 使用相对坐标移动Map1.TrackLingLayer.Event(2).MoveTo x ,y 使用绝对坐标移动Map1.TrackLingLayer.Event(3).SymbolIndex = 1 设置使用的绘图符号在Symbo数组中的索引Geoevents存储在TrackingLayer.Event(n)数组中,n的值是属性TrackingLayer.EventCount,数组索引从0开始。GeoEvent在数中的索引号按加入跟踪层的顺序从小到大排列,删除一个之后,后续元素的索引号全部减1。(1) Property S
26、ymbol(Index As Long) As Symbol只读属性,返回Symbol实例的引用,(4) SymbolCout As Long属性SymbolCout表示Symbol数组中元素的个数。执行语句Map1.TrackingLayer.SymbolCount = 10将为跟踪层创建含有10个元素的Symbol数组,在使用Symbol数组之前,必须执行此语句。(5) 删除跟踪层中的GeoEvent实例Map1.TrackingLayer.RemoveEvent 2 删除索引号为2的GeoEventMap1.TackingLayer.ClearEvents 删除全部GeoEvent例1:
27、创建两个点符号,储存在跟踪层的Symbol数组中,在鼠标光标点击位置创建GeoEvent点实例,用Symbol(0)显示。1) 创建Symbol数组Private Sub SetTrackingLayerSymbol() 建立跟踪层显示符号设置PointEvents在跟踪层中得显示符号Map1.TrackingLayer.SymbolCount = 2 定义Symbol数组为2个元素,下标从 0 开始Map1.TrackingLayer.Symbol(0).Color = moRedMap1.TrackingLayer.Symbol(0).Style = moCircleMarkerMap1.
28、TrackingLayer.Symbol(0).SymbolType = moPointSymbolMap1.TrackingLayer.Symbol(0).Size = 6Map1.TrackingLayer.Symbol(1).Color = moDarkMap1.TrackingLayer.Symbol(1).Style = moCircleMarkerMap1.TrackingLayer.Symbol(1).SymbolType = moPointSymbolMap1.TrackingLayer.Symbol(1).Size = 6End Sub2) 创建GeoEvent点事件Sub
29、AddEvent(x As Single, y As Single) 在跟踪层中加入一个点Set pt = Map1.ToMapPoint(x, y) 屏幕坐标变成地图坐标点Map1.TrackingLayer.AddEvent pt, 0 在跟踪层中加入一点,显示符号使用Symbol(0)End Sub3) 调用顺序在Form_Load() 中调用SetTrackingLayerSymbol()在Map1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)中调用SelectEvents x, y例2
30、 利用上例中形成的点事件及TrackingLayer.Symbol数组,在TackingLayer图层中,找出距离鼠标点击位置小于55000的点事件,用Symbol(1)显示找出的点事件。Sub SelectEvents(x, y) 在当前鼠标位置查找距离 55000 的点事件Dim pt As MapObjects2.PointSet pt = Map1.ToMapPoint(x, y)nEventCount = Map1.TrackingLayer.EventCount 跟踪层中的事件总数Dim testPt As New PointFor i = 0 To nEventCount - 1
31、 遍历跟踪层事件Set evt = Map1.TrackingLayer.Event(i)testPt.x = evt.xtestPt.y = evt.yIf pt.DistanceTo(testPt) 55000 Then 距离使用地图坐标单位,若找到evt.SymbolIndex = 1 则使用Symbol(1)显示End IfNext iEnd Sub例3创建两个线符号,储存在跟踪层的Symbol数组中,在Map1地图窗口中用鼠标光标画折线,将折线加入到跟踪层中(称为LineEvent),用Map1.Tracklayer.Symbol(3)显示。程序语句如下:1) 在跟踪层中建立Symb
32、ol(2)Map1.TrackingLayer.Symbol(2).Color = moDarkMap1.TrackingLayer.Symbol(2).Style = moSolidLineMap1.TrackingLayer.Symbol(2).SymbolType = moLineSymbolMap1.TrackingLayer.Symbol(2).Size = 32) 在Map1窗口中画线并加入跟踪层中Private Sub Map1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)AddL
33、ineEventA 在地图窗口中添加线事件End SubSub AddLineEventA() 在跟踪层中加入一条线Dim oLine As MapObjects2.LineSet oLine = Map1.TrackLine 画一条线If oLine Is Nothing Then Exit Sub在跟踪层中加入一以条线,显示符号使用Symbol(2)Map1.TrackingLayer.AddEvent oLine, 2 End Sub例4 在Map1窗口中用鼠标选择例3加入的线,用绿色显示选中的线。程序语句如下:1) 在跟踪层中建立显示用的SymbolMap1.TrackingLayer
34、.Symbol(3).Color = moGreen 绿色Map1.TrackingLayer.Symbol(3).Style = moSolidLineMap1.TrackingLayer.Symbol(3).SymbolType = moLineSymbolMap1.TrackingLayer.Symbol(3).Size = 32) 在Map1.TrackingLayer中查找距离鼠标点55000的线,用绿色显示查到的线。Private Sub Map1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Si
35、ngle)SelectLineEvents x, y 查找与点(x,y)距离 55000的线事件End SubSub SelectLineEvents(x, y) 在当前鼠标位置查找距离 55000 的线事件Dim pt As MapObjects2.PointSet pt = Map1.ToMapPoint(x, y) 距离使用地图数据坐标单位,nEventCount = Map1.TrackingLayer.EventCount 跟踪层中的事件总数Dim eventLine As MapObjects2.LineFor i = 0 To nEventCount - 1 遍历跟踪层事件Set eventLine = Map1.TrackingLayer.Event(i).ShapeIf eventLine.shapeType = moShapeTypeLine Then 图形是线吗?If eventLine.DistanceTo(pt) 55000 Then 线离鼠标点的距离 55000吗?Map1.TrackingLayer.Event(i).SymbolIndex = 3 则使用Symbol(3)显示End IfEnd IfNext iEnd Sub上述4例的完整程序见GeoEvent目录中的工程。