2.6.1
Recordset对象
Recordset是MapObjects中的一个对象,它为图层(MapLayer)提供地图数据,又是地图数据的管理者与操作者,因此,地图数据的创建和编辑在Recordset上进行。每个MapLayer对应一个Recordset,仅对应一个Recordset,是Recordset的可视化。从数据库的观点看,Recordset是一个数据表,概念与数据表一致,图形数据储存在表的一个字段(shape)中。Recordset是记录的集合,提供了对记录及字段的操作方法。
ShapeFile是ESRI公司定义的一种无拓扑关系的地理信息文件格式,是MapObjects固有数据格式,在这种格式上实现了读写、修改、编辑功能。ShapeFile用一组文件储存一个图层数据,同一图层各文件的主名相同,用作图层名。扩展名标识文件的内容,分别是:
.shp 储存几何要素
.shx 储存几何要素索引
.dbf 储存几何要素的属性数据,是dBase文件,可用FoxPro软件操作
这一组文件映射成一个Recordset表。表中含有.dbf文件的全部字段,还有两个由Recordset对象添加的字段:Shape和FeatureID。两个添加字段的值来自于文件.shp和.shx。
例如,china图层的三个组成文件是:china.shp,china.shx,china.dbf。china.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 、FeatureId是Recordset对象生成的标准字段,对于Coverage、SDE、CAD、VPF等格式数据形成的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
recs.MoveNext ‘指针指向记录2
recs.MoveNext ‘指针指向记录3
Debug.Print recs.Fields(“name”).Value, recs.Fields(“gdp
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
recs.MoveFirst ‘定位到记录1
If recs.Updatable Then ‘recs是可编辑的吗?
Do Until recs.EOF ‘记录指针指向最后记录的末尾了吗?
recs.Edit ‘读取一条记录到缓冲区中
fld.Value = fld.Value + 1 ‘修改缓冲区中记录的的一个字段值
recs.Update ‘更新修改的记录
recs.MoveNext ‘记录指针移到下一条记录
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 ‘移动记录指针到下一个记录
recs.StopEditing ‘编辑结束
Map1.Refresh ‘地图窗口刷新
End If
End Sub
5 FeatureID
FeatureID是Recordset表的字段名,是shape字段中几何图形元素的编号,编号是从1开始的自然数。在Recordset表中,可以读出FeatureID的值,例如:
recs.MoveFirst
Debug.Print recs.Fileds.Item(“FeatureID”).Value ‘输出: 1
2.6.2
创建数据库表
1定义并创建一个新表
例1在Form_Load中建立了dc与数据库”china
字段名 |
类型 |
宽度 |
小数位数 |
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
代表了完成这个例题的基本步骤。注意其中揭示的GeoDataset与Recordset之间的关系。
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图层
与前面讲述的MapLayer及ImageLayer不同,跟踪图层TrackingLayer不属于Layers集合。在绘制完Layers集合中的全部图层后,才绘制TrackingLayer图层中的内容。TrackingLayer图层是Map控件的属性,可在其中动态显示不断改变位置的的图形,每个图形是一个GeoEvent实例,不必重绘Layers集合中的图层,即可实现GeoEvent实例在图上移动,因此具有很高的更新速度。通过TrackingLayer.Refresh方法可以触发跟踪层的重绘,同时还触发BeforeTrackingLayerdraw和AferTrackingLayerDraw事件。
跟踪层中的GeoEvent实例没有保存在数据文件中,程序退出后立即消失。
2 GeoEvent对象
保存在TrackingLayer图层中的图形元素是GeoEvent对象的实例。MapObjects Shape的实例均可作为TrackingLayer上的GeoEvent实例,因此TrackingLayer图层可以同时储存显示多种类型的图元。GeoEvent实例绘图使用TrackingLayer中自定义的Symbol属性数组中的符号,每个GeoEvent实例可以储存一个标记,用来在运行时与其它GeoEvent实例区别。这个标记还可以用于连接外部数据库中的记录。
GeoEvent实例在TrackingLayer层中显示,位置可以快速动态改变而不影响地图窗口中的其它图层,特别适用于在地图窗口中显示汽车、飞机、GPS接收机等的动态位置。
3 TrackingLayer图层的属性和方法
以下描述中的例句假设Map1是VB窗体上的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的第二个参数SymbolIndex为pt指定了显示用的符号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 ‘删除索引号为2的GeoEvent
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目录中的工程。