2023年2月

原贴地址:http://hi.baidu.com/story_of_water/blog/item/e47e90b66556eafc30add19f.html

一、加载地图数据

1、 TAB的数据分为两种数据:地图数据(Layers)、属性数据(Datasets)。关系:不可分割的一个数据集的两部分.
2、 数据加载:GST文件由GeosetManager40.exe程序生成。在程序使用gsT文件:Map1.Geoset=Filepath+FileName
3、 问题:GST文件加载后,只是默认将地图数据加载,属性数据另外需要使用单独的命令进行加载,否则对属性数据的操作全部非法。加载:Map1.Datasets.ADD 属性数据集名称
4、 另一种加载方式:使用LayerInfo 对象,这种方式下加载地图数据源的地图集和属性集均可直接使用。示例:
dim LayerInfo as MapXLib.LayerInfo
dim Lyr as Mpxlib.layer

LayerInfo.Type = miLayerInfoTypeTab ‘加载表的类型
LayerInfo.AddParameter "FileSpec", FilePath + LayerName + ".TAB" ‘加载表的全路径名
LayerInfo.AddParameter "NAME", LayerName ‘地图集的别名
LayerInfo.AddParameter "AutoCreateDataset", 1 ‘是否加载属性数据集
LayerInfo.AddParameter "datasetname", LayerName ‘属性数据集别名

MainMap.Layers.Add LayerInfo ‘加载到指定的MapX对象中,立即可直接使用

5、 第三种加载数据方式:GST文件+ LayerInfo方式。示例:
使用两个MapX对象:MainMap、TempMap
TempMap.Geoset=GST文件
MainMap.geoset=””
TempMap.Refresh

For I=1 to TempMap.Layers.Count
FileName=TempMap.Layers.Item(I).Filespec
‘直接引用LayerInfo方式加载地图数据到MainMap
Next


二、创建地图对象

必要:创建地图对象,必须使用FeatureFactory对象
1、 创建一个点对象
点对象有一个坐标点(X,Y),点对象变量是Point类型,点对象的样式(Style)是符号样式。
Dim Pnt AS MapXLib.Point
Dim FeaFac AS MapXLib.FeatureFactory
Dim Lyr AS MapXLib.Layer
Dim Ftr AS MapXLib.Feature
Dim NewStyle AS MapXLib.Style

‘绑定
SET Lyr=MainMap.Layers.Item(LayerName)
SET FeaFac=mainmap.featurefactory
‘设置点对象样式
With NewStyle
.SymbolType = miSymbolTypeBitmap
.SymbolBitmapSize = 24
.SymbolBitmapTransparent = False
.SymbolBitmapName = "YIEL2-32.BMP"
End With
Mainmap.AutoRedraw=False ‘禁止自动刷新
Lyr.Editable=True ‘置当前图层为可写状态
‘创建点对象
pnt.set X1,Y1
‘添加进当前图层
Set Ftr=FeaFac. CreateSymbol (Pnt,Newstyle) ‘创建符号
‘Set Ftr=FeaFac. CreateSymbol (Pnt,MainMap.DefaultStyle)
‘添加
Lyr.AddFeature Ftr
Lyr.Refresh
Mainmap.AutoRedraw=True
Lyr.Editable=False
‘释放
SET Pnt = Nothing
SET FeaFac = Nothing
SET Lyr = Nothing
SET Ftr = Nothing
‘以上代码放在MapX的ToolUsed事件下

单独修改某个图元的样式:SET Ftr.Style=NewStyle,再用Update 即可
2、 创建一个线矩形
Dim Pnts AS MapXLib.Points

With NewStyle
.LineColor=Rgb(0, 0,255)
End With
‘第一个点
Pnt.Set X1,Y1
Pnts.add Pnt
‘第二个点
Pnt.Set X2,Y1
Pnts.add Pnt
‘第三个点
Pnt.Set X2,Y2
Pnts.add Pnt
‘第四个点
Pnt.Set X1,Y2
Pnts.add Pnt
‘第五个点
Pnt.Set X1,Y1
Pnts.add Pnt

‘创建线矩形
SET Ftr=FeaFac.CreateLine(Pnts,NewStyle)
Lyr.AddFeature Ftr
Lyr.Refresh

3、 上面创建对象中存在的问题:并未对其数据数据进行赋值
创建对象的同时创建其数据集合
Dim Pnt AS MapXLib.Point
Dim FeaFac AS MapXLib.FeatureFactory
Dim Lyr AS MapXLib.Layer
Dim Ftr AS MapXLib.Feature
Dim NewStyle AS MapXLib.Style
Dim ds AS MapXLib.Dataset
Dim Flds AS MapXLib.Fields

‘绑定
SET Lyr=MainMap.Layers.Item(LayerName)
SET ds=Lyr.Datasets.Item(1)
Set Flds=ds.Fields
SET FeaFac=mainmap.featurefactory
‘设置点对象样式
With NewStyle
.SymbolType = miSymbolTypeBitmap
.SymbolBitmapSize = 24
.SymbolBitmapTransparent = False
.SymbolBitmapName = "YIEL2-32.BMP"
End With
Mainmap.AutoRedraw=False ‘禁止自动刷新
Lyr.Editable=True ‘置当前图层为可写状态
‘创建点对象
pnt.set X1,Y1
‘创建图形
Set Ftr=FeaFac. CreateSymbol (Pnt,Newstyle) ‘创建符号
‘Set Ftr=FeaFac. CreateSymbol (Pnt,MainMap.DefaultStyle)
‘设置属性
For I=1 to Flds.Count
Lyr.KeyFields=Flds.Item(i).Name
Ftr.Keyvalue=valueStr(I) ‘这里并没有对字段类型进行判断
Next
‘另外一种方法:使用Rowvalues和Rowvalue对象
‘添加
Lyr.AddFeature Ftr
Lyr.Refresh
Mainmap.AutoRedraw=True
Lyr.Editable=False
‘释放
SET Pnt = Nothing
SET FeaFac = Nothing
SET Lyr = Nothing
SET Ftr = Nothing

SET ds = Nothing
SET Flds = Nothing
4、 创建表
(1) 临时表:
A、用MainMap.Layers.CreateLayer方法创建临时表。但这个临时表只有一个字段:GeoName( Char 24)。程序运行过程中该表存放位置为系统临时文件夹下
B、使用LayerInfo对象创建临时表,可以指定字段。示例:

Dim Lyr As MapXLib.Layer
Dim LayerInfo As New MapXLib.LayerInfo
Dim Flds As New MapXLib.Fields

‘字段定义
Flds.AddStringField "ID", 12
Flds.AddStringField "Name", 50
Flds.AddNumericField "Deptch", 12, 2
Flds.AddIntegerField "Length"


LayerInfo.Type = miLayerInfoTypeTemp
LayerInfo.AddParameter "FileSpec", FileName
LayerInfo.AddParameter "NAME", LayerName
LayerInfo.AddParameter "Fields", Flds

Set Lyr = MainMap.Layers.Add(LayerInfo, 1)

Set Lyr = Nothing
Set LayerInfo = Nothing

(2) 创建永久表
Dim Lyr As MapXLib.Layer
Dim LayerInfo As New MapXLib.LayerInfo
Dim Flds As New MapXLib.Fields

Flds.AddStringField "ID", 12
Flds.AddStringField "Name", 50
Flds.AddNumericField "Deptch", 12, 2
Flds.AddIntegerField "Length"


LayerInfo.Type = miLayerInfoTypeNewTable
LayerInfo.AddParameter "FileSpec", FilePath + "" + FileName
LayerInfo.AddParameter "NAME", LayerName
LayerInfo.AddParameter "Fields", Flds

Set Lyr = MainMap.Layers.Add(LayerInfo, 1)

Set Lyr = Nothing
Set LayerInfo = Nothing


5、 创建工具句柄
系统已经定义工具句柄都以整数(包括16进制)常数存在,句柄号大于1000和小于12基本都为系统使用。
A. 定义常数:必须为全局变量
Global Const CreateSymbolTool = 13 ′创建节点
Global Const CreateLineTool = 15 ′创建管线
Global Const InfoTipTool = 16 ′信息工具
Global Const MoveFeature = 17 ′移动地图
Global Const ScaleDistanceTool = 18 ′测量两点间的距离

B. 使用CreateCustomTool创建新的工具句柄:
MainMap.CreateCustomTool CreateSymbolTool, miToolTypePoint, miSymbolCursor
MainMap.CreateCustomTool CreateLineTool, miToolTypeLine, miCrossCursor
MainMap.CreateCustomTool InfoTipTool, miToolTypePoint, miCrossCursor
MainMap.CreateCustomTool MoveFeature, miToolTypeLine, miPanCursor
MainMap.CreateCustomTool ScaleDistanceTool, miToolTypeLine, miPanCursor
C. 如何使用?
在Map对象的ToolUsed事件的ToolNum参数为当前所激活的工具
使当
前操作指向某行为:MainMap.CurrentTool=工具句柄号,如放大:MainMap.CurrentTool=miZoomInTool,移动图元:MainMap.CurrentTool=MoveFeature
操作具体的工具句柄时,执行该捕捉到的工具句柄的代码:
在ToolUsed事件中:

Select Case ToolNum
Case MoveFeature
‘执行代码
End Select

删除图元:Lyr.DeleteFeature Ftr

三、查询


1、 属性查找。Find、Search方法:注意的是Find方法只支持TAB表文件,不支持空间数据表。
Find :与FoxPro中Locate定位命令想类似。
Search:支持SQL语句。写法:仅指SQL语句的WHERE 部分,且From语句中只能有一个表——仅对单表进行操作:Select * from LayerName WHERE ID LIKE “%北京%”
示例:
A、查找
Dim Ftrs AS MapXlib.Features ‘图元集合

SET Ftrs=Lyr.Search(“ID LIKE ““%北京%”””)
For I=1 to Ftrs.Count
‘执行语句
Next
B、高亮显示
Lyr.Selection.Replace Ftrs ‘将当前查询所得的结果集全部高亮显示(隐含执行:Lyr.ClearSelection语句)——加入selection集合
闪烁:不能用Selection,否则会对整个屏幕进行整个刷新(抖动)。使用更新Style的方法进行选定图元的闪烁。
记载图元的老样式:Set Oldsytle=Ftr.Style

Lyr.Selection.Add Ftrs ‘将当前查询所得的结果集添加到已有的结果集中,再全部高亮显示
C、对查询的结果集进行属性修改
示例程序:完成的是Professional中信息工具功能
Dim ds AS MapXlib.Dataset
Dim Flds AS MapXlib.Fields
Dim Ftr AS MapXlib.Feature

Set Lyr=MainMap.Layers.Item(LayerName)
Set ds=Lyr.Datasets.item(1)
Set Flds=ds.Fields
‘查找
SET Ftrs=Lyr.Search(“ID LIKE ““%北京%”””)
If Ftrs.count=0 then exit sub

‘读取属性值
For I=1 to Ftrs.Count
Set Ftr=Ftrs.Item(I)
For j=1 to Flds.count
FldsName(J)=Flds.Item(J).Name ‘字段列表
Lyr.KeyField=FldsName(J)
valueStr(I,J)=Ftr.Keyvalue ‘值列表
Next
Next

‘修改属性
MainMap.AuyoRedraw=False
Lyr.Editable=True

For j=1 to Flds.count
Lyr.KeyField= Flds.Item(J).Name
Ftrs.Item(j).Keyvalue =valueStr(J) ‘更新值列表
Ftrs.Item(j).Update True
Next

Lyr.Refresh
Lyr.Editable=False
MainMap.AuyoRedraw=True

‘修改样式
Dim NewStyle AS MapXlib.Style

With NewStyle
‘设置样式
End With

MainMap.AuyoRedraw=False
Lyr.Editable=True

For i=1 to Ftrs.count
Set Ftr =Ftrs.Item(I)
SET Ftr.Style=NewStyle ‘更新样式
Ftr.Update True
Next

Lyr.Refresh
Lyr.Editable=False
MainMap.AuyoRedraw=True

2、 空间查找
2 点查找:SearchAtPoint,结果集为Features类型
Dim Pnt AS MapXlib.Point

Pnt.Set X,Y
Set Ftrs=Lyr.SearchAtPoint(Pnt,miSearchResultAll)
For I=1 to Ftrs.Count
‘执行语句
Next
注意:点查找时,一般情况下结果集在一个以上的图层都存在。所以取值时应分别提取

2 园查找:在临时图层上画一个不保存的圆,然后查找被这个圆所包含的所有图层的图元对象。
Dim Pnt AS MapXlib.Point
Dim TempCir AS MapXlib.Feature
Dim FeaFac AS MapXLIB.featurefactory

Pnt.Set X,Y
Set tempcir=FeaFac.CreateCircularRegion(miCircleTypeMap ,Pnt,1, MainMap.MapUnit,,)

‘miSearchTypeCentroidWithin :中心点包含
‘miSearchTypePartiallyWithin :部分包含
‘miSearchTypeEntirelyWithin :全部包含

Set Ftrs=Lyr.

SearchWithinFeature
(TempCir, miSearchTypePartiallyWithin)

For I=1 to Ftrs.Count
‘执行语句
Next

SET Pnt =Nothing
set TempCir =Nothing
set FeaFac =Nothing

3、 相交
判断两个图元是否有交点以及交点坐标信息。
(1)判断是否相交
IF Lyr.IntersectionTest( ftr1, ftr2, miIntersectFeature ) THEN
‘交点
END IF

(2)获取相交点坐标信息
‘交点
Dim Ftr AS MapXlib.Feature

SET Ftr=MainMap.FeatureFactory. IntersectFeatures(Ftr1,Ftr2)
‘交点坐标信息
For J=1 to Ftr.parts.item(1).count
X1= Ftr.parts.item(1).Item(J).X
Y1= Ftr.parts.item(1).Item(J).Y
Next

4、 测距
使用Map对象的Distance方法。如何测量任意多边形的周长?
使用累加的方法,还要使用图元节点集合。
Distancevalue=0
‘第一个点
Pnt.Set Ftr.Parts.Item(1).Item(1).X, Ftr.Parts.Item(1).Item(1).Y
For j=2 TO Ftr.Parts.Item(1).Count
‘累加
X1= Ftr.Parts.Item(1).Item(j-1).X
Y1= Ftr.Parts.Item(1).Item(j-1).Y
X2= Ftr.Parts.Item(1).Item(j).X
Y2= Ftr.Parts.Item(1).Item(j).Y
Distancevalue = Distancevalue +MainMap.Distance(X1, Y1, X2, Y2)
Next
‘多边形周长
Msgbox Distancevalue+” ”+MainMap.MapUnit

四、对象编辑

(1)、对属性的编辑
主要使用Fields对象。示例:
Dim Flds AS MapXlIB.Fields

‘修改当前图层的每一个字段
For J=1 to Flds.Count
Lyr.KeyField= Flds.Item(j).Name ‘使当前图层指向J字段
‘更新当前图元的J字段值
Ftr.Keyvalue=NewvalueStr(J)
Ftr.Update True ‘并未写入硬盘
Next
Lyr.Refresh ‘保存修改到硬盘

(2)、移动地图
首先创建一个移动工具句柄
MainMap.CreateCustomTool MoveFeature, miToolTypeLine, miPanCursor
在Map对象的ToolUsed事件的ToolNum参数为当前所激活的工具
捕捉MoveFeature工具句柄
‘传过来的参数:X1,Y1,X2,Y2
Select case ToolNum
……..
Case MoveFeature
Dim Lyr AS MapXlib.Layer
Dim Ftr AS MapXlib.Feature
Dim Ftrs AS MapXlib.Features

Dim Xe,Ye AS Double ‘坐标偏移量

Xe=X2-X1
Ye=Y2-Y1

Set Lyr=Mainmap.Layers.Item(LayerName)
Set Ftrs=Lyr.Selection.Clone ‘将当前图层中选定的集合复制到Ftrs变量中
MainMap.AutoRedraw=False
Lyr.Editable=True
For J=1 to Ftrs.Count
Set Ftr=Ftrs.Item(J)
Ftr.Offset Xe,Ye
Ftr.Update True
Next
Lyr.Refresh
Lyr.Editable=False
MainMap.AutoRedraw=True

SET lyr=Nothing
SET Ftr=Nothing
End Select
(3)、样式更新
Dim NewStyle AS MapXLib.Style

‘初始赋值
Set Lyr=MainMap.Layers.Item(LayerName)
Set Ftrs=Lyr.AllFeatures
Set NewStyle=Ftrs.Item(1).Style
‘设置样式
With NewStyle
.SymbolType = miSymbolTypeBitmap
.SymbolBitmapSize = 24
.SymbolBitmapTransparent = False
.SymbolBitmapName = "YIEL2-32.BMP"
End With
‘更新
MainMap.AutoRedraw=False
Lyr.Editable=True
SET Ftr.Style=NewStyle
Ftr.Update True
Lyr.Refresh
Lyr.Editable=False
MainMap.AutoRedraw=True

五、输出


1、属性的输出 输出到EXCEL表:
For I=1 to Flds.Count
Lyr.KeyFields=Flds.Item(i).Name
Excel(1,I).Cell=Ftr.Keyvalue
Next
2、复制、粘贴
Global CopyFtrs AS MapXlib.Features

Set lyr=mainmap.Layers.item(LayerName)
Set Ftrs=Lyr.Selection.Clone ‘复制选中集合
‘复制
For I=1 to Ftrs.Count
CopyFtrs.add Ftrs.Item(I)
Next

‘粘贴(图形)
Set lyr_1=mainmap.Layers.item(LayerName_1)
Mainmap.AutoRedraw=False
Lyr_1.Editabled=True
For J=1 to CopyFtrs.Count
Lyr_1.AddFeature CopyFtrs.Item(J)
Next
Lyr_1.Refresh
Mainmap.AutoRedraw=True
Lyr_1.Editabled=False

3、地图的打印
Dim iScaleMode As Integer

iScaleMode = MainMap.Container.ScaleMode
MainMap.Container.ScaleMode = 6

On Error GoTo PrinterError

Printer.Print " "
Printer.CurrentX = 0
Printer.CurrentY = 0
MainMap.PrintMap Printer.hDC, 0, 0, MainMap.Width * 100, MainMap.Height * 100
Printer.NewPage
Printer.EndDoc
MainMap.Container.ScaleMode = iScaleMode
Exit Sub

PrinterError:
If Err.Number = 482 Then
On Error Resume Next
CommonDialog1.Flags = &H40
CommonDialog1.ShowPrinter
Else
MsgBox " 打印机存在错误,请更正后重试。错误号:" + (Str(Err.Number)), , "失败"
End If


4、另存为图片文件
MainMap.ExportMap(App.Path+”Images”, miFormatJPEG) ‘输出当前地图窗口
参数设置:MainMap.ExportSelection=True ‘将选中部分以不同于其他未选中地图部分形式输出

六、专题图


6种专题图:除独立值专题图绑定的字段类型可以是字符的以外,都必须是数字类型。与其他数据源绑定时,使用ODBC
调用ThemeDlg对话框可以让用户自己定义专题图。示例:
For Each ftr In lyr.Selection

′ The children of the layer are the individual

′ features

Set ftrNode = QueryTree.Nodes.Add(lyrNode, tvwChild,lyr.Name _

& ftr.Name & Str$(ftr.FeatureID), ftr.Name)

For Each fld In ds.Fields

′ Each feature has data attached to it; add

′ this data as a child of the feature

lyr.KeyField = fld.Name

QueryTree.Nodes.Add ftrNode, tvwChild, , lyr.KeyField _

& ": " & ftr.Keyvalue

Next

Next

七、在MapX下紧缩表

在Professional里面,紧缩表用 Pack Table 语句完成。而在MapX中则需要使用临时图层,并用复制技术来完成。示例:
‘紧缩当前Map对象中的所有图层
Dim LayerInfo As New MapXLib.LayerInfo
Dim Lyr As MapXLib.Layer
Dim LyrTemp As MapXLib.Layer
Dim Flds As MapXLib.Fields
Dim Ds As MapXLib.Dataset

Dim I As Integer
Dim LayerName, FilePath As String

On Error Resume Next

For I = MainMap.Layers.Count To 1 Step -1
′复制源表数据到临时表
Set Lyr = MainMap.Layers.Item(I)
Set Ds = Lyr.Datasets.Item(1)
Set Flds = Ds.Fields

LayerName = Lyr.Name

LayerInfo.Type = miLayerInfoTypeTemp
LayerInfo.AddParameter "FileSpec", LayerName
LayerInfo.AddParameter "NAME", LayerName
LayerInfo.AddParameter "Features", Lyr.AllFeatures‘复制所有有效图元
LayerInfo.AddParameter "Fields", Flds ’复制字段列表

LayerInfo.AddParameter "AutoCreateDataset", 1
LayerInfo.AddParameter "datasetname", LayerName
Set LyrTemp = MapTemp.Layers.Add(LayerInfo, 1) ‘复制到另外Map对象

′删除源表
Set Lyr = Nothing
FilePath = MainMap.Layers.Item(I).Filespec
LayerName = Mid(FilePath, InStr(1, FilePath, "Maps" + 6, Len(FilePath) - InStr(1, FilePath, "Maps")
FilePath = Mid(FilePath, 1, InStr(1, FilePath, "Maps" + 5)
LayerName = Mid(LayerName, 1, Len(LayerName) - 4)

MainMap.Layers.Remove (I)
MainMap.Refresh

Kill FilePath + LayerName + ".TAB"

′复制临时表数据到源表
Set LyrTemp = MapTemp.Layers.Item(LayerName)

LayerInfo.Type = miLayerInfoTypeNewTable
LayerInfo.AddParameter "FileSpec", FilePath + LayerName + ".TAB"
LayerInfo.AddParameter "NAME", LayerName
LayerInfo.AddParameter "Features", LyrTemp.AllFeatures
LayerInfo.AddParameter "Fields", Flds

LayerInfo.AddParameter "AutoCreateDataset", 1
LayerInfo.AddParameter "datasetname", LayerName
Set Lyr = MainMap.Layers.Add(LayerInfo, 1)

′删除临时表
MapTemp.Layers.Remove (MapTemp.Layers.Count)
MapTemp.Refresh
Next

Set Lyr = Nothing
Set Ds = Nothing
Set Flds = Nothing
Set LayerInfo = Nothing

八、如何和大型数据库关联


系统是混合结构:对地图的访问使用的是文件访问方式,对属性数据的访问使用的是大型数据库形式使用ID关联:在TAB表和数据库中有ID字段,两个字段作为唯一值关联字段。(一对一的关系)。示例:

Lyr.KeyField=”ID”
Set Ftr=Ftrs.Item(J)

‘SQL语句查找对应的属性信息
SampleAdo.RecordSource =”Select a.id as id,b.name as name from Table1 a, Table2 b WHERE (a.id=b.id) AND ( a.id LIKE ‘%“ +Ftr.Keyvalue+“%’)”

九、空间数据库

2 空间数据库中的索引技术用的是R_Tree技术,而不是原来一般意义上的B_Tree索引技术。
2 空间数据在Spatial中以地理属性信息形式存放。
2 在Oracle的版本中有如下需要注意事项:
a) Oracle 8.1.5这个版本中,首次引入Spatial组件。使用上非常不好:图形的样式非常单一,且为黑白的而非彩色,上载地图数据时,数据丢失非常严重。存取数据时非常慢。在Spatial中自动创建prinx字段作为地图索引主关键字段
b) Oracle 8.1.6版本:图形为彩色的,增加了样式的支持,但不支持同一图层下的多样式(主要指点对象)。创建地图数据时,地图的坐标常发生偏移。属性数据更新 时,需要两次刷新才能完整提交;地图数据数据提交时,其坐标发生偏移:向原点偏移,需要认为地单独将其移动到其初始创建位置。存取速度上还是比较慢,离实 用尚有一定距离。在Spatial中自动创建mi_prinx字段作为地图索引主关键字段
2 Oracle 8.1.7版本:支持多样式,数据上载丢失非常小(只有文本对象存在丢失的记录)。在地图数据存取不是很大的时候,速度上可以被用户接受。
2 如何将MapInfo 的TAB表内容上传到Oracle 中?
a) 免费工具:easyloader6.7(Oracle 8.1.7),下载地址

http://www.mapinfo.com.cn
/;
b) 如何上载?注意:上载之前对Tab表进行紧缩。
c) 在程序中如何使用空间数据库中的地图数据?
d) 添加地图时,必须指定字段mi_prinx的明确值,且该值不能为表中已存在的值。写入地图数据时,应将其全部NOT NULL 字段值赋给,否则保存失败。
e) 示例:Tab表+空间数据表 的数据分布形式。

十、GIS应用的分发


1、 制作你自己的系统的安装盘:可执行文件、必要系统文件、运行库文件、其他数据文件。
2、 单独的MapX安装盘:MapInfo MapX Runtime安装程序,实际上是MapX控件安装程序(存在于MapX sdk包)
3、 注册:安装完成以后,运行GeosetManager40.exe程序获得硬件ID号,然后通过EMAIL的形式将该ID号发送到MapX产品供应商申请 正式的许可文件(mapx40.lic)。获得后覆盖原mapx40.lic文件即可。注意:硬盘格式化后该ID号失效。

十一、构造一个GIS应用系统


需求:鹰眼功能、拓扑关系、不同图形不同颜色表现、数据绑定、系统性能。

结构分析:做基于TAB文件的GIS系统
1、 鹰眼功能
(1) 建立两个Form对象,将两个Map对象分别放在这两个窗口对象中。
(2) 一个小窗口作为鹰眼窗口,大 窗口作为主地图窗口。鹰眼窗口中的Map对象的视野应很大,而主地图窗口的视野根据需要设置。
(3) 两个窗口中加载不同的GST文件。需要的是主地图窗口的显示范围应为鹰眼窗口中某个矩形所包含的地图对象范围。
(4) A、在鹰眼窗口中画一个矩形(Rect为矩形对象),B、主地图窗口执行 Set MainMap.Bounds = Rect
(5) 需要注意的是:鹰眼窗口与主地图窗口两者间的坐标投影系统应完全一致。

2、 拓扑关系
实际上就是图元与图元的空间关系。说历史:原来建立拓扑关系使用的是属性关联。
点查询、圆查询、矩形查询、多边形查询等这些是属于简单空间关系的对比。而对拓扑关系的查询多数情况下使用Parts对象来解决。
Ftr1与另一个Ftr2的空间关联:先找到Ftr1的其止节点,然后以这个节点为中心画一个非常小的圆,在这个圆范围内的某个设备可认为与该Ftr1相连。
判断某个图元在指定图层上的相交对象集合:
Set Ftrs=Lyr.
SearchWithinFeature
(SearchFtr, miSearchTypePartiallyWithin)

3、 不同图形不同颜色表现
(1)更新样式 再结合临时图层就可以很好解决(使用图层刷新)。而且刷新时不会引起整个Map对象的刷新(屏幕抖动)
(2)专题图 存在更新属性值后不能实时刷新专题图的问题。
4、 数据绑定
对未绑定的属性集合使用 MainMap.Datasets.ADD
地图集合和属性集合为一个数据集合的不可分割的两个部分
5、 系统性能
速度是否为用户所接受、系统是否稳定(界面要求)、修改数据数据的时候是否存在数据一致性维护问题、造价是否合理。
(1)速度:使用数据分布可以较好地解决:地图数据:地形图数据以文件形式存放,业务地图数据存放在空间数据库中;属性数据:全部存放在大型数据库中。

(2)系统是否稳定(界面要求):A、字段全部用英文,B、地图拓扑关系在进入系统以前进行必要的验证,C、文件地图数据中字段数减少到最小,可使 访问属性频率大大减少,可有效保证其他用户访问时不会大量出现访问拒绝的现象;D、数据提交时尽可能采用事务机制: 事务开始: Lyr.BeginAccess,事务结束:Lyr.EndAccess;E、数据修改提交时尽可能采用批量提交。至于界面要求,应主要满足从地图对象获 取相关的要求。
(3)数据一致维护:遵循图元优先的原则。图形对象必须首先存在,其他相关信息在此基础上建立。注意:
2 修改时应先修改地图对象,后提交属性信息
2 删除时应先删除其他信息,最后删除图形信息
(4)造价 这里主要指平台费用。A、现有数据格式,B、功能要求:空间分析是否复杂、地图图层是否分散、系统中地图输出的质量要求、系统中统计分析复杂程度是否较繁琐、直接的平台使用用户数(并发数)。

原帖地址:
http://www.cnblogs.com/redfire0922/archive/2007/04/04/699263.html

一直以来Session都是MapXtreme中比较重要的部分。但是这方面的资料却寥寥无几。大概很多人都去用googleMap之类的地图工具了吧。基于此原因结合开发者参考写下这篇文章。

ISession 接口的有用信息

ISession Interface位于MapInfo.Engine命名空间。实现此接口的是一个内部对象SessionInternal,直接并不能使用此对象,必须用MapInfo.Session.Current 访问。从这里看的话这篇文章主要说的还是MapInfo.Session.Current 。因此以下所用的ISession Interface是指SessionInternal的实现接口,Isession实例是指MapInfo.Session.Current 包含的SessionInternal对象。 ISession Interface 是所有MapXtreme程序的起点。它管理Map程序必须初始化的资源。不过这些都不用我们参与,甚至我们想参与都难,所以一方面减轻了开发人员的负担,另一方面减少了灵活度。同时它提供了访问一些重要资源的属性:Catalog、MapFactory、CoordSysFactory、Selections等。

Catalog 是存放整个地图数据表的容器,有点象内存数据库。 MapFactory 是存放地图的容器。跟Catalog主要区别从这里访问到的是地图结构的数据。比如 地图 层 标注 等。Catalog访问到的数据是数据表 数据库连接 SQL等。 CoordSysFactory 是坐标系统。 Selections 是一个多图层多图元的选择集合。它包含了数据表中选中的图元,并以设定的高亮显示地图上。需要注意的是Selections直接包含的是Selection,Selection包含的才是图元。这样区分的好处是可以过滤不需要选择的图层的图元。 管理ISession的实例
一般情况下我们不需要管理ISession的实例。但是我们还是应该清楚:一个线程只能拥有一个ISession实例。这意味着程序中如果有两个完全不同的Session,那么你就需要启动两个线程。当然一般情况下并不需要两个Session,而一个程序两个不同图的要求我还真遇到过,到时你就创建两个Map对象就可以了,在Catalog中当然还是包含了全部需要的表数据。

在桌面程序中,很多情况下都是单线程运转,ISession实例只有一个。它随着程序启动,跟着程序一起销毁,一点都不用操心。在多线程的桌面程序,每个线程都将拥有一个ISession实例。你不能在多线程中共享这些实例。每个实例管理自己的状态,比如:一个线程打开一个表,另外的线程就不能打开。最后还必须调用Session.Dispose来销毁此实例。如果是用Session池更加需要这么做,不然性能没有提升反而有下降的趋势。

在ASP.net程序中我们ISession实例的管理也有需要注意的地方。WebSessionActivator(有关WebSessionActivator信息暂时我还没有,不过它本质上是一个HttpModule)管理了每个客户端连接的ISession实例生命期,同时管理ISession实例的状态和ISession实例池回收。不过它并没有做完它该做的事,如果你想回收内存资源你还必须在Session_End事件中加上Session.Dispose。代码如下:

C# example:

protected void Session_End(Object sender, EventArgs e)
{
MapInfo.Engine.Session.Dispose(this.Session);
}


VB example:

Protected  Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
MapInfo.Engine.Session.Dispose(Me.Session)
End Sub

结语

在实际使用中ISession除了访问资源的便捷性外就是疑窦重重的管理了。充分地了解ISession可以帮助我们更准确地找到一些问题,而不是停留于对问题的猜测。

本文介绍下如何实现Modem的来电显示的功能。Modem的来电显示是在我最早的送水管理软件中实现的,大概是05年完成的,由于Modem的成本比较低(普通的在100元之内),而来电显示功能在送水管理软件中比较需要,因此是一项性价比比较好的功能。
随着时间的推移,Modem的生产越来越少,而支持来电显示模块的Modem就更少一些了,取而代之是功能比较专一的来电显示盒横行天下,一般USB来电显示盒都可以支持2路、4路、8路等等,但是USB来电显示盒较贵,Modem由于性价比比较好,市场上依然还继续出现。本篇主要介绍如何实现Modem的来电显示,下篇将继续介绍基于USB的来电显示盒的接口开发。目前在我的送水软件中,为了兼顾两者的好处,一般是集成了两个硬件的功能,随便选一个硬件都可以使用来电显示功能。
看看Modem来电显示的应用场景,在送水软件中,链接一台电话(Modem只能连接一台电话),当有客户的电话接入的时候,软件会提示用户的信息,并进入下订单的界面,如下所示。


这样非常方便业务员的信息输入,同时还可以调出更多客户的相关信息,如客户的账号信息,购买记录作为默认这次订单的操作等,达到优质服务的目的。如下这个改进版的送水软件的来电显示功能就提供了客户财务信息,默认上次的购买记录等信息。



Modem的来电显示功能需要下面所需的前提条件。
一、 实现来电显示的系统最小需求。
1. 你的固定电话已经向电信局申请开通了来电显示功能,若没有申请,即使MODEM支持也是不行的。
2. 安装了MODEM的专用驱动软件(
注意不要使用Windows如XP自带的驱动程序
)。
3. MODEM支持来电显示。不管是内置MODEM,外置MODEM,只要它支持来电显示即可。

二、怎么判断MODEM是不是支持来电显示?
1. 打开超级终端,随便输入一个连接名称,比如TEST。
2. 按确定后,下个窗口中,看到你的MODEM,不要输入电话号码。再下一步。
3. 在这个窗口中按取消。
4. 这样一个可以输入的空白窗口就有了。
输入:AT回车
如果出现OK,说明MODEM支持AT指令,不然,其他也不用试了。
然后输入下面的命令(每条前面加上AT),只要一条反应有OK,就说明MODEM本身芯片支持来电显示。
#CID=1
%CCID=1
+VCID=1
#CC1
*ID1

三、Modem 驱动安装的问题
如果您的操作系统是Windows 2K/XP,当安装MODEM驱动程序的时候,会自动安装操作系统自带的MODEM驱动,而此驱动程序只能支持数据传送(即只能用来拨号上网,而没有传真和语音功能)。所以您必须升级MODEM的驱动程序,并且在升级的时候手工指定到跟随MODEM的光盘中的驱动程序(而不让系统自己搜索)。并且在升级完之后重新启动系统。


下面介绍如何在C#中实现来电显示模块的功能。

Modem的来电显示需要一个和串口打交道的控件Apax Control,它是一个ActiveX的控件,原则上可以应用在任何语言中,本文只介绍在C#中的应用。
首先需要注册ActiveX控件,然后在开发IDE中引用控件,把控件拖动到界面上,如下所示。


然后生成目录会多出几个文件,如下所示。


在代码中,我们可以再Form_Load方法中初始化控件的一些属性。如下代码所示。



Code


然后我们就只需要关注axApax1_OnRing和axApax1_OnTapiCallerID处理函数了,如下代码所示



Code


最后关闭程序的时候要释放资源,否则会出现COM错误的,代码如下所示。



Code

除了上篇《
硬件接口开发之Modem来电显
》介绍的Modem来电显示,还可以采用USB电话录音盒来进行来电显示和电话录音功能,本文介绍如何在C#中实现该功能。首先我们看看我是如何在我的软件中集成USB电话录音盒的功能,先对USB电话录音盒的功能和应用场景有一个总体的认识先。
我的送水软件可以支持两路及以上多路的
来电显示

电话录音
功能,当用户有新的来电,系统会检测数据库是否存在该电话的用户,如果有那么调出该用户的资料(包括上次订购产品信息),否则提示操作员建立新客户的资料,并记录该次的电话号码。这些来电显示功能非常方便操作人员进行业务操作,点击下鼠标就可以完成客户的订单。


图1 来电自动记录并在状态栏显示相关来电信息


图2 来电显示功能调出已有客户资料,并默认调出上次订购信息

实现来电显示的系统最小需求
1. 你的固定电话已经向电信局申请开通了来电显示功能,若没有申请,即使有软件支持也是不行的。
2. 安装了指定厂商的录音与来电弹屏设备(包括硬件和软件)。
3. 正确安装深田之星送水管理系统网络版软件。

但前提是需要一些前提条件,下面是实现来电显示的最小要求和一些相关问题。


图3 安装所需的来电显示设备驱动


图4 电话录音文件,用户可以选择指定的文件进行回播

使用来电显示和电话录音设备的好处

一、总体优势
1、先进的语音设备
录音设备采用USB或者PCI接口,最多可支持达256路电话同时录音、同时弹出客户资料;
2、强大的电话录音功能
拥有自主知识产权的专用压缩算法,录音数据量小、通话清晰,每线通话数据量只有5.5兆/小时,
即一个120G的硬盘可以单线连续录音21000小时。采用专用的压缩算法,可以有效的防止他人恶意窃听、篡改录音数据,确保资料安全。可随时将重要的录音资料进行备份。
3、录音回听
用户可根据自己的权限回听授权的录音资料,以便对重要通话进行分析、做笔记等。可在本地回听,也可通过局域网或者Internet等广域网进行远程回听,极大地方便了经常出差在外或者公司部门分布较广的公司管理层人员使用。
4、远程同步监听
特定用户可以在本地或者通过局域网或者Internet等广域网进行远程实时电话通话情况查看、实时通话监听等。及时掌握员工对外联系状况,及时跟进重要客户等。
5、来电弹出
客户来电,系统自动根据来电号码调出客户资料,在摘机接听电话前就可以及时掌握来电客户的基本信息,沟通历史等,给员工一种亲切感,同时客户可以得到最及时、最准确、最周到的服务。
6、记录未接来电不放过一个来电信息,保障与客户的即时沟通。
7、电话集中录音,有效防止录音资料丢失;


以上的电话录音盒功能介绍是厂商提供的内容,不过我们一般就是使用来做来电弹出业务窗口、电话录音这两个功能了,其他的都可以不管。那么我们如何在我们开发的程序中集成,也就是使用代码如何完成和硬件的接口开发呢。
由于这个来电显示的录音设备开发包也是一个ActiveX的控件来的,因此和操作其他ActiveX控件一样,我们在工具栏中加入控件,然后拖动到界面上就可以了,注意为了避免给客户产生不好的影响,把控件设置为隐藏即可。

1)首先在Form_OnLoad函数中初始化硬件信息和事件,如下所示



private

void
InitCallControl()



{

this
.axTMNC_OCXX1.OnConnect
+=

new
AxTMNC_OCX.ITMNC_OCXXEvents_OnConnectEventHandler(axTMNC_OCXX1_OnConnect);

this
.axTMNC_OCXX1.OnDisConnect
+=

new
AxTMNC_OCX.ITMNC_OCXXEvents_OnDisConnectEventHandler(axTMNC_OCXX1_OnDisConnect);


this
.axTMNC_OCXX1.OnCallIn
+=

new
AxTMNC_OCX.ITMNC_OCXXEvents_OnCallInEventHandler(axTMNC_OCXX1_OnCallIn);

this
.axTMNC_OCXX1.OnCallOut
+=

new
AxTMNC_OCX.ITMNC_OCXXEvents_OnCallOutEventHandler(axTMNC_OCXX1_OnCallOut);

this
.axTMNC_OCXX1.OnNoAnswer
+=

new
AxTMNC_OCX.ITMNC_OCXXEvents_OnNoAnswerEventHandler(axTMNC_OCXX1_OnNoAnswer);

}




private

void
MainToolWindow_Load(
object
sender, EventArgs e)



{


来电显示设置内容



}


2)然后就是实现上面的几个委托事件了,代码如下所示。


private

void
axTMNC_OCXX1_OnNoAnswer(
object
sender, AxTMNC_OCX.ITMNC_OCXXEvents_OnNoAnswerEvent e)
{

/**//*

说明:当有电话打入,且无人接听的情况,即未接来电信息。
LocalNum:本地号码。CallID:未接来电号码。
注:此来电号码在OnCallIn事件中也会发送过来,但是不同的是,只有当来电无人接听时
才会产生OnNoAnswer事件。

*/


string
content
=

string
.Format(
"
未接来电:{0} 本地号码:{1}
"
, e.callID, e.localNum);
Portal.gc.MainDialog.RefreshComingCallStatus(content);
}


private

void
axTMNC_OCXX1_OnCallOut(
object
sender, AxTMNC_OCX.ITMNC_OCXXEvents_OnCallOutEvent e)
{

string
content
=

string
.Format(
"
拨出号码:{0} 本地号码:{1}
"
, e.callOutNum, e.localNum);
Portal.gc.MainDialog.RefreshComingCallStatus(content);
}


private

void
axTMNC_OCXX1_OnCallIn(
object
sender, AxTMNC_OCX.ITMNC_OCXXEvents_OnCallInEvent e)
{

string
content
=

string
.Format(
"
来电号码:{0} 本地号码:{1}
"
, e.callInNum, e.localNum);
Portal.gc.MainDialog.RefreshComingCallStatus(content);

Portal.gc.DealWithComingCall(e.callInNum);
}


private

void
axTMNC_OCXX1_OnDisConnect(
object
sender, AxTMNC_OCX.ITMNC_OCXXEvents_OnDisConnectEvent e)
{

string
content
=

"
设备未连接
"
;
Portal.gc.MainDialog.RefreshComingCallStatus(content);
}


private

void
axTMNC_OCXX1_OnConnect(
object
sender, AxTMNC_OCX.ITMNC_OCXXEvents_OnConnectEvent e)
{

string
content
=

"
设备已就绪
"
;
Portal.gc.MainDialog.RefreshComingCallStatus(content);
}

近来一直从事Oralce数据的开发工作,处理一些报表,由于数据比较大,因此要求需要进行一定的分页处理,以便提高效率,但由于这些报表是一种轻便的开发模式,不希望引入太多的复杂的东西,而且这些报表有的是用Sql检索数据的,有些是用存储过程的。
由于基本上每个报表都会使用到分页的部分,因此这些内容最好是作为控件的方式,以便减少代码,我原来的文章中有介绍过的分页控件《
查询控件、分页控件、页面展示控件,我的Web开发三大得力助手
》,这个分页控件样式很不错,不过是基于Sql进行分页的,因此我在这个基础上编写了一个用户控件来处理界面和分页内容就可以了。
这个分页控件(使用用户控件模式)减少了很多重复的代码,可以较好适应存储过程或者是Sql查询的情况,当然也具有我一贯的软件风格,好的界面。
下面我看看弄好的用户控件和页面的整合效果图先。

我们在设计时看看分页控件的界面如下所示:


这个用户控件的后台代码如下所示


Code

有了这个分页控件的界面部分,我们就不需要在每个界面中重复这些代码和控制内容了。
我们在Visual Studio中,把用户控件拖动到具体需要分页的页面中的具体位置就完成了界面的设计了,这样可以减少很多重复的代码,下面我们来看看具体的页面调用部分就知道代码是否整洁很多了。

public

partial

class
CounterStatByCar : BasePage
{

protected

void
Page_Load(
object
sender, EventArgs e)
{

this
.PagerControl1.parentPage
=

this
;

this
.PagerControl1.OnDataBind
+=

new
EventHandler(BindDataHandler);
}

private

void
BindDataHandler(
object
sender, EventArgs e)
{
BindData();
}


private
DataTable BindData()
{
DataTable dt

=

null
;

try

{
PagerInfo pageInfo

=

new
PagerInfo();
pageInfo.CurrentPage

=

this
.CurrentPage;
//
读取BasePage中的ViewState信息,当前页面


pageInfo.PageSize
=

this
.PageSize;
//
读取BasePage中的ViewState信息,页面大小



dt

=
dal.GetCounterStatByCar(beginTime, endTime, carPlate,
ref
pageInfo).Tables[
0
];
DataView dv

=
dt.DefaultView;

this
.dg.DataSource
=
dv;

this
.dg.DataBind();


this
.PagerControl1.BindData(pageInfo);
//
更新页面数据


}

catch
(Exception ex)
{
LogHelper.Error(ex);
Helper.Alerts(

this
,
"
获取数据出错
"
);
}

return
dt;
}


protected

void
btnNormalSearch_Click(
object
sender, ImageClickEventArgs e)
{

this
.CurrentPage
=

1
;
BindData();
}
}

上面的
GetCounterStatByCar是一个获取分页数据的函数,由于在方法中传入了分页必须要的信息,当前页,页面大小,数据检索后,会修改总记录数量和页面总数量的,这些信息会显示在分页控件中。我们看看PagerInfo的类代码:
[Serializable]

public

class
PagerInfo
{

private

int
currenetPageIndex
=

1
;
//
当前页码



private

int
pageSize
=

20
;
//
每页显示的记录



private

int
recordCount
=

0
;
//
记录总数




#region
属性变量



///

<summary>


///
获取或设置当前页码

///

</summary>


[XmlElement(ElementName
=

"
CurrentPageIndex
"
)]

public

int
CurrentPage
{

get
{
return
currenetPageIndex; }

set
{ currenetPageIndex
=
value; }
}


///

<summary>


///
获取或设置每页显示的记录

///

</summary>


[XmlElement(ElementName
=

"
PageSize
"
)]

public

int
PageSize
{

get
{
return
pageSize; }

set
{ pageSize
=
value; }
}


///

<summary>


///
获取或设置记录总数

///

</summary>


[XmlElement(ElementName
=

"
RecordCount
"
)]

public

int
RecordCount
{

get
{
return
recordCount; }

set
{ recordCount
=
value; }
}


///

<summary>


///
共有多少页

///

</summary>


[XmlElement(ElementName
=

"
PageCount
"
)]

public

int
PageCount
{

get

{

if
(recordCount
==

0

||
pageSize
==

0
)
{

return

0
;
}

else

{

int
fullPage
=
recordCount
/
pageSize;

int
left
=
recordCount
%
pageSize;

if
(left
>

0
)
{
fullPage

+=

1
;
}

return
fullPage;
}
}
}


#endregion

在BasePage中,我们需要添加几个方法,用来做ViewSate的调用的。

#region
分页的变量



///

<summary>


///
每页的记录数量

///

</summary>



public

int
PageSize
{

get

{

return
GetViewState(
"
PageSize
"
,
20
);
}

set

{
SetViewState(

"
PageSize
"
, value);
}
}


///

<summary>


///
共有几页

///

</summary>



public

int
PageCount
{

get

{

return
GetViewState(
"
PageCount
"
,
0
);
}

set

{
SetViewState(

"
PageCount
"
, value);
}
}


///

<summary>


///
总的记录数量

///

</summary>



public

int
RecordCount
{

get

{

return
GetViewState(
"
RecordCount
"
,
0
);
}

set

{
SetViewState(

"
RecordCount
"
, value);
}
}


///

<summary>


///
当前页码

///

</summary>



public

int
CurrentPage
{

get

{

return
GetViewState(
"
CurrentPage
"
,
1
);
}

set

{

int
pageIndex
=
(value
>=
PageCount)
?
PageCount : value;
pageIndex

=
(pageIndex
<=

1
)
?

1
: pageIndex;
SetViewState(

"
CurrentPage
"
, pageIndex);
}
}

#endregion



public

string
GetViewState(
string
name,
string
defaultValue)
{

if
(ViewState[name]
!=

null
)
{

return
ViewState[name].ToString();
}

else

{

return
defaultValue;
}
}


public

bool
GetViewState(
string
name,
bool
defaultValue)
{

if
(ViewState[name]
!=

null
)
{

return
(
bool
)ViewState[name];
}

else

{

return
defaultValue;
}
}


public

int
GetViewState(
string
name,
int
defaultValue)
{

if
(ViewState[name]
!=

null
)
{

return
(
int
)ViewState[name];
}

else

{

return
defaultValue;
}
}


public

void
SetViewState(
string
name,
object
value)
{
ViewState[name]

=
value;
}


#endregion