MapObejcts组件应用设计(地图数据的创建与编辑)

时间:2022-02-25 23:58:54

2.6.1 Recordset对象

RecordsetMapObjects中的一个对象,它为图层(MapLayer)提供地图数据,又是地图数据的管理者与操作者,因此,地图数据的创建和编辑在Recordset上进行。每个MapLayer对应一个Recordset,仅对应一个Recordset,Recordset的可视化。从数据库的观点看,Recordset是一个数据表,概念与数据表一致,图形数据储存在表的一个字段(shape)中。Recordset是记录的集合,提供了对记录及字段的操作方法。

ShapeFileESRI公司定义的一种无拓扑关系的地理信息文件格式,是MapObjects固有数据格式,在这种格式上实现了读写、修改、编辑功能。ShapeFile用一组文件储存一个图层数据,同一图层各文件的主名相同,用作图层名。扩展名标识文件的内容,分别是:

.shp   储存几何要素

.shx   储存几何要素索引

.dbf  储存几何要素的属性数据,是dBase文件,可用FoxPro软件操作

这一组文件映射成一个Recordset表。表中含有.dbf文件的全部字段,还有两个由Recordset对象添加的字段:ShapeFeatureID。两个添加字段的值来自于文件.shp.shx

例如,china图层的三个组成文件是:china.shp,china.shx,china.dbfchina.dbf的字段名是:name , gdp1990 , gdp1995 ,那么,Recordset形成的表是:

Shape

FeatureID

Name

gdp1990

gdp1995

Polygon

1

*

121

190

Polygon

3

河北

221

440

Recordset对象封装了表及在表上的操作,在Recordset中,表的一行称为一个记录,表的一列称为一个字段,列的名称称为字段名。在这个例子中,有5个字段,2个记录。第一行是字段名行,不是记录。

shape字段的每一个值是一个几何图形元素,用几何对象定义。FeatureID是图形元素的索引号。

Shape FeatureIdRecordset对象生成的标准字段,对于CoverageSDECADVPF等格式数据形成的Recordset表也是如此。

1 Recordset表的记录指针

Recordset表从概念上看,是记录的集合。记录是集合中的成员,用指针确定在表中的位置。在表中移动指针可以定位记录。

1  Map1中含有china图层,属性如前表所示。编程显示属性表中的数据(完整程序见recordPointer目录)。

Private Sub Command1_Click() ‘记录指针定位

Dim recs As MapObjects2.Recordset

Set recs = Map1.Layers(“china”).Records

recs.MoveFirst  指针指向记录1

Debug.Print recs.Fields(“name”).Value, recs.Fields(“gdp 1995” ).Value ‘输出: *190

recs.MoveNext  指针指向记录2

recs.MoveNext  指针指向记录3

Debug.Print recs.Fields(“name”).Value, recs.Fields(“gdp 1995” ).Value ‘输出:河北  440

End Sub

  Recordset的指针定位方法:

recs.MoveFirst     指针指向记录1开始位置

recs.MoveNext     指针指向下一条记录开始位置

recs.MovePrevious  指针指向前一条记录开始位置

recs.EOF          指针指向最后一条记录的末端时返回TRUE,否则返回FALSE

2编辑属性表已有数据

编辑记录在Recordeset对象上进行,每次编辑一条记录,程序设计顺序依次是:

(1) 移动记录指针到要编辑的记录

(2) 读取当前记录到缓冲区中

(3) 编辑修改当前记录字段的值

(4) 更新当前记录

(5) 全部记录编辑完后,停止编辑

2 编辑China属性表,将gdp1995字段的值增加1(完整程序见recordPointer目录)。

Private Sub Command2_Click() ‘编辑记录中的属性数据

Dim recs As MapObjects2.Recordset

Dim fld As MapObjects2.Field

Set recs = Map1.Layers(“china”).Records

Set fld = recs.Fields.Item(“gdp 1995” )     引用记录的字段

recs.MoveFirst                        定位到记录1

If recs.Updatable Then                  ‘recs是可编辑的吗?

   Do Until recs.EOF                  记录指针指向最后记录的末尾了吗?

     recs.Edit                        读取一条记录到缓冲区中

     fld.Value = fld.Value + 1           修改缓冲区中记录的的一个字段值

     recs.Update                      更新修改的记录

     recs.MoveNext                    记录指针移到下一条记录

   Loop

   recs.StopEditing                    停止编辑

End If

End Sub

将上面的recs.Update语句替换成recs.CancelUpdate ,则记录编辑无效。

3添加新记录

添加新记录在MapLayer.Rcords属性上进行,此属性的数据类型是Recordset,实际是在Recordset对象上进行。使用Recordset.Add方法每次编辑一条记录,程序设计顺序依次是:

(1) 移动记录指针到给定的记录。

(3) 添加一条新记录,这时记录在内存记录缓冲区中。

(2) 为新记录字段赋值。

(3) Update方法更新数据表,这时缓冲区的数据写入文件缓冲区。

(4) 全部添加完后,用StopEding方法停止编辑。这时文件缓冲区的数据写入文件。

3手工将Chian图层的文件复制成EditData图层。设计程序,用鼠标输入一个Polygon,EditData图层中添加一个新记录,将新记录的shape字段值设置成输入的Polygon,name字段值设置成新记录。完整程序见NewDelRd目录,重要代码如下:

Private Sub Command1_Click() ‘添加新记录

Dim recs As MapObjects2.Recordset

Dim fld As MapObjects2.Field

Set recs = Map1.Layers.Item(“EditData”).Records ‘获得记录集的引用

Set fld = recs.Fields(“Shape”)                  获得图形字段的引用

Dim poly As MapObjects2.Polygon

Set poly = Map1.TrackPolygon                    用鼠标画一个多边形

If recs.Updatable Then

  recs.MoveFirst

  recs.AddNew                                  添加一个新记录

  Set fld.Value = poly               将新记录的图形字段设置为画的多边形

  recs.Fields.Item(“Name”).Value = “新记录     设置新记录Name字段的值

  recs.Update                                  更新数据表

  recs.StopEditing                             编辑结束

  Map1.Refresh                                 地图窗口刷新

End If

End Sub

4删除记录

   4删除上例中添加的记录(完整程序在NewDelRd目录中)

Private Sub Command2_Click()  删除name = “新记录的记录

Dim recs As MapObjects2.Recordset

Set recs = Map1.Layers.Item(“EditData”).Records  获得记录集的引用

If recs.Updatable Then

  recs.MoveFirst             移动记录指针到第一个记录

  Do Until recs.EOF          遍历记录集

    If recs.Fields.Item(“Name”).Value = “新记录” Then  判断删除条件

      recs.Edit               使当前记录可编辑

      recs.Delete             删除当前记录

    End If

    recs.MoveNext             移动记录指针到下一个记录

  Loop

    recs.StopEditing         编辑结束

    Map1.Refresh             地图窗口刷新

End If

End Sub

5 FeatureID

FeatureIDRecordset表的字段名,是shape字段中几何图形元素的编号,编号是从1开始的自然数。在Recordset表中,可以读出FeatureID的值,例如:

recs.MoveFirst

Debug.Print recs.Fileds.Item(“FeatureID”).Value   输出:   1

2.6.2 创建数据库表

1定义并创建一个新表

1Form_Load中建立了dc与数据库”china 2” 的连接。创建一个数据库表,命名为MyTable,除了两个标准字段以外,表中还含有三个附加字段,字段定义如下:

字段名

类型

宽度

小数位数

Name

字符型

16

 

Area

数值型

15

3

Perimeter

数值型

15

13

在表中添加两个记录,给三个属性字段赋值。用鼠标绘制两个Polygon, 赋给表的Shape字段。最后将MyTable保存在China2数据库中(完整程序见CreatTable目录中工程)

Dim dc As MapObjects2.DataConnection

Private Sub Command1_Click() ‘创建数据库表

  Dim gds As MapObjects2.GeoDataset

  Dim desc As New TableDesc     数据库表字段描述

  Dim lyr As New MapObjects2.MapLayer

  Dim poly As MapObjects2.Polygon

  With 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     字符串的长度

    .FieldPrecision(1) = 15  数字的位数

    .FieldPrecision(2) = 15

    .FieldScale(1) = 3       小数点之后的位数

    .FieldScale(2) = 3

  End With

  Set gds = dc.AddGeoDataset(“MyTable”, moPolygon, desc) ‘在数据源中加入表

  If gds Is Nothing Then Exit Sub   文件非法,则退出

  Set lyr.GeoDataset = gds          设置图层的地理数据集

  Map1.MousePointer = moCross

  For i = 1 To 2

    Set poly = Map1.TrackPolygon    用鼠标在地图窗口中画一个多边形

    With lyr.Records

      .AddNew                       添加一个记录

      .Fields(“Shape”).Value = poly  为图形字段赋值

      .Fields(“Name”).Value = “多边形 “ & i

      .Fields(“Area”).Value = poly.Area

      .Fields(“Perimeter”).Value = poly.Perimeter

      .Update

    End With

  Next

  lyr.Records.StopEditing       记录集修改完毕,保存表记录的数据

  Map1.MousePointer = moDefault

  Map1.Layers.Add lyr      

  Map1.Refresh            在地图窗口中显示绘制的两个多边形

End Sub

从上段程序中摘取的语句:

Set gds = dc.AddGeoDataset(“MyTable”, moPolygon, desc)

Set lyr.GeoDataset = gds 

lyr.Records .AddNew

lyr.Records.StopEditing

代表了完成这个例题的基本步骤。注意其中揭示的GeoDatasetRecordset之间的关系。

2创建子集数据库表

2用鼠标画一个矩形,从China图层上提取位于矩形区中的记录集,保存提取的记录集,形成一个数据库表(完整程序见SubTable目录中的工程)

Private Sub Command1_Click() ‘创建子集数据库表

  Dim gds As MapObjects2.GeoDataset

  Dim rect As MapObjects2.Rectangle

  Dim recs As MapObjects2.Recordset

  Dim lyr As New MapObjects2.MapLayer

  Map1.MousePointer = moCross

  Set rect = Map1.TrackRectangle  用鼠标拖拉出一个矩形

  Map1.MousePointer = moDefault

  Set recs = Map1.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 TrackingLayer图层与GeoEvent对象

1 TrackingLayer图层

与前面讲述的MapLayerImageLayer不同,跟踪图层TrackingLayer不属于Layers集合。在绘制完Layers集合中的全部图层后,才绘制TrackingLayer图层中的内容。TrackingLayer图层是Map控件的属性,可在其中动态显示不断改变位置的的图形,每个图形是一个GeoEvent实例,不必重绘Layers集合中的图层,即可实现GeoEvent实例在图上移动,因此具有很高的更新速度。通过TrackingLayer.Refresh方法可以触发跟踪层的重绘,同时还触发BeforeTrackingLayerdrawAferTrackingLayerDraw事件。

跟踪层中的GeoEvent实例没有保存在数据文件中,程序退出后立即消失。

2 GeoEvent对象

保存在TrackingLayer图层中的图形元素是GeoEvent对象的实例。MapObjects Shape的实例均可作为TrackingLayer上的GeoEvent实例,因此TrackingLayer图层可以同时储存显示多种类型的图元。GeoEvent实例绘图使用TrackingLayer中自定义的Symbol属性数组中的符号,每个GeoEvent实例可以储存一个标记,用来在运行时与其它GeoEvent实例区别。这个标记还可以用于连接外部数据库中的记录。

GeoEvent实例在TrackingLayer层中显示,位置可以快速动态改变而不影响地图窗口中的其它图层,特别适用于在地图窗口中显示汽车、飞机、GPS接收机等的动态位置。

3 TrackingLayer图层的属性和方法

以下描述中的例句假设Map1VB窗体上的MapObjects2.Map实例

(1) Function Trackinglayer.AddEvent(Object As Object,SymbolIndex As Long) As GeoEvent

函数向跟踪层中加入一个几何要素。

下面的语句在TrackingLayer层中加入一个点,创建GeoEven点事件。

Dim pt As MapObjects2.Point

Map1.TackingLager.AddEvent pt , 0

AddEvent方法加入一个事件时,同时指定了事件使用的数组TrackingLayer.Symbol中的符号,如上面的代码所示,AddEvent的第二个参数SymbolIndexpt指定了显示用的符号TrackingLayer.Sybmol(0)

(2)  Property Event(Index As Long) As GeoEvect

只读属性,返回跟踪层中GeoEvent的引用。

Event数组中的元素是GeoEvet实例,使用GeoEvent的方法编程,例如:

Map1.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 Symbol(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  删除索引号为2GeoEvent

Map1.TackingLayer.ClearEvents      删除全部GeoEvent

 

1创建两个点符号,储存在跟踪层的Symbol数组中,在鼠标光标点击位置创建GeoEvent点实例,用Symbol(0)显示。

1) 创建Symbol数组

Private Sub SetTrackingLayerSymbol() '建立跟踪层显示符号

'设置PointEvents在跟踪层中得显示符号

Map1.TrackingLayer.SymbolCount = 2  '定义Symbol数组为2个元素,下标从 0 开始

Map1.TrackingLayer.Symbol(0).Color = moRed

  Map1.TrackingLayer.Symbol(0).Style = moCircleMarker

  Map1.TrackingLayer.Symbol(0).SymbolType = moPointSymbol

  Map1.TrackingLayer.Symbol(0).Size = 6

 

  Map1.TrackingLayer.Symbol(1).Color = moDark

  Map1.TrackingLayer.Symbol(1).Style = moCircleMarker

  Map1.TrackingLayer.Symbol(1).SymbolType = moPointSymbol

  Map1.TrackingLayer.Symbol(1).Size = 6

End Sub

2) 创建GeoEvent点事件

Sub AddEvent(x As Single, y As Single) '在跟踪层中加入一个点

  Set pt = Map1.ToMapPoint(x, y)      '屏幕坐标变成地图坐标点

  Map1.TrackingLayer.AddEvent pt, 0   '在跟踪层中加入一点,显示符号使用Symbol(0)

End Sub

3) 调用顺序

Form_Load() 中调用

       SetTrackingLayerSymbol()

Map1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)中调用

       SelectEvents x, y

2 利用上例中形成的点事件及TrackingLayer.Symbol数组TackingLayer图层中,找出距离鼠标点击位置小于55000的点事件,用Symbol(1)显示找出的点事件。

Sub SelectEvents(x, y)  '在当前鼠标位置查找距离< 55000 的点事件

  Dim pt As MapObjects2.Point

  Set pt = Map1.ToMapPoint(x, y)

  nEventCount = Map1.TrackingLayer.EventCount  '跟踪层中的事件总数

  Dim testPt As New Point

  For i = 0 To nEventCount - 1                '遍历跟踪层事件

    Set evt = Map1.TrackingLayer.Event(i)

    testPt.x = evt.x

    testPt.y = evt.y

    If pt.DistanceTo(testPt) < 55000 Then '距离使用地图坐标单位,若找到

      evt.SymbolIndex = 1                 '则使用Symbol(1)显示

    End If

  Next i

End Sub

3创建两个线符号,储存在跟踪层的Symbol数组中,在Map1地图窗口中用鼠标光标画折线,将折线加入到跟踪层中(称为LineEvent),用Map1.Tracklayer.Symbol(3)显示。程序语句如下:

1) 在跟踪层中建立Symbol(2)

  Map1.TrackingLayer.Symbol(2).Color = moDark

  Map1.TrackingLayer.Symbol(2).Style = moSolidLine

  Map1.TrackingLayer.Symbol(2).SymbolType = moLineSymbol

  Map1.TrackingLayer.Symbol(2).Size = 3

2) Map1窗口中画线并加入跟踪层中

Private Sub Map1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)

      AddLineEventA   '在地图窗口中添加线事件

End Sub

 

Sub AddLineEventA()                     '在跟踪层中加入一条线

  Dim oLine As MapObjects2.Line

  Set oLine = Map1.TrackLine             '画一条线

If oLine Is Nothing Then Exit Sub

'在跟踪层中加入一以条线,显示符号使用Symbol(2)

Map1.TrackingLayer.AddEvent oLine, 2 

End Sub

 

4 Map1窗口中用鼠标选择例3加入的线,用绿色显示选中的线。程序语句如下:

1) 在跟踪层中建立显示用的Symbol

  Map1.TrackingLayer.Symbol(3).Color = moGreen  绿色

  Map1.TrackingLayer.Symbol(3).Style = moSolidLine

  Map1.TrackingLayer.Symbol(3).SymbolType = moLineSymbol

      Map1.TrackingLayer.Symbol(3).Size = 3

2) Map1.TrackingLayer中查找距离鼠标点<55000的线,用绿色显示查到的线。

Private Sub Map1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)

      SelectLineEvents x, y   '查找与点(x,y)距离 < 55000的线事件

End Sub

 

Sub SelectLineEvents(x, y)  '在当前鼠标位置查找距离< 55000 的线事件

  Dim pt As MapObjects2.Point

  Set pt = Map1.ToMapPoint(x, y)              '距离使用地图数据坐标单位,

  nEventCount = Map1.TrackingLayer.EventCount  '跟踪层中的事件总数

  Dim eventLine As MapObjects2.Line

  For i = 0 To nEventCount - 1                '遍历跟踪层事件

    Set eventLine = Map1.TrackingLayer.Event(i).Shape

    If eventLine.shapeType = moShapeTypeLine Then     '图形是线吗?

      If eventLine.DistanceTo(pt) < 55000 Then     '线离鼠标点的距离 < 55000吗?

        Map1.TrackingLayer.Event(i).SymbolIndex = 3   '则使用Symbol(3)显示

      End If

    End If

  Next i

End Sub

上述4例的完整程序见GeoEvent目录中的工程。