首页 百科知识 系统设计与开发

系统设计与开发

时间:2022-06-19 百科知识 版权反馈
【摘要】:二、系统设计与开发1.地图数据集的建立MapX可以直接读取的是包含若干个表文件的地理数据集Gst文件,这里的目的就是有用户指定所需要的地图数据,然后自动生成合适的结果。MapX的安装程序附带了一个应用程序Geoset Manager,它可以将表文件集成为地理数据集Gst,但是考虑到所开发系统的独立性,系统将这一功能予以实现。

二、系统设计与开发

1.地图数据集的建立

MapX可以直接读取的是包含若干个表文件的地理数据集Gst文件,这里的目的就是有用户指定所需要的地图数据,然后自动生成合适的结果。MapX的安装程序附带了一个应用程序Geoset Manager,它可以将表文件集成为地理数据集Gst,但是考虑到所开发系统的独立性,系统将这一功能予以实现。

这一功能的入口是菜单“地图信息”的子项“新建”,直接对应的代码如下,程序中首先判断当前是否有打开的文档被修改过,如果是,则首先保存之,然后指定欲新建的数据集名称、存放位置,再调用数据层修改功能打开相应的若干表文件,最后将其保存并且初始化相关信息。

Private Sub mnuMapNew_Click()

    Dim strFile As String

    If(gbDocDirty=True)Then

    'gbDocDirty为全局变量,在本章末尾给出定义。

    If MsgBox("Save Project?",vbYesNo+vbInformation)=vbYes Then

    mnuMapSave_Click

 End If

 End If

 strFile=GetFileName(0,True)

'获得一个数据集文件名,GetFileName的实现在本章末尾给出。

If(strFile<>"")Then

  mpMain.Geoset=""

  PrepareGUI

  '初始化相关的交互信息,具体实现见后述。

  mnuMapAlter_Click'表文件的管理

  If(mpMain.Layers.Count>0)Then

    '若调入的表文件数目大于0则继续

    mnuMapAlter.Enabled=True

    Me.tlbMain.Buttons("layer").Enabled=True

    mpMain.SaveMapAsGeoset strFile,strFile

    OpenAMap strFile

    '打开数据集文件,具体实现见后述。

End If

End If

End Sub

过程中使用到MapX的属性Geoset,它指定待打开的数据集名称,如果赋给空字符串则清空当前数据集,还用到了MapX的方法SaveMapAsGeoset,其要求两个字符串类型的参数,第一个指定数据集的用户名称,第二个是待保存的文件名,这里都是用文件名代替,可以添加一段交互程序,为用户指定一个有一定意义、易于记忆的名称。

2.地图数据集的打开

打开是根据指定的地图数据集的文件名,将附属的表文件调入,这一功能的入口是菜单“地图信息”的子项“打开”,直接对应的代码如下。

Private Sub mnuMapOpen_Click()

 Dim strNewGst As String

 strNewGst=GetFileName(0)'获得一个数据集文件名

 If IsFileExist(strNewGst)

 Then OpenAMap strNewGst

 '判断文件是否存在,如果存在则打开。

End Sub

3.数据集的修改与保存

数据集的修改是指对当前数据集中包含的表文件进行添加、删除和修改可视等属性,这一功能只在电子地图设计时使用,因此没有对它进行灵活性和应用性的考虑,而直接调用MapX内置的图层管理对话框,该对话框的使用与MapInfo中图层管理是一致的。

Private Sub mnuMapAlter_Click()

 gbDocDirty=True'当前的层被修改了?

 mpMain.Layers.LayersDlg'调用MapX内置的图层管理对话框

 PrepareGUI'更新交互信息

End Sub

对当前操作的地图数据集的保存是通过调用前文述及的MapX的内置方法SaveMapAsGeoset完成的,保存之前要判断当前地图集中表文件数目(图层数)是否为空,因为方法SaveMapAsGeoset不能保存数目为0的数据集。

Private Sub mnuMapSave_Click()

Dim strFile As String

If(mpMain.Layers.Count>0 And gbDocDirty=True)Then

'当前地图集中图层数不为0,并且被修改过

  If(mpMain.Geoset="")Then strFile=GetFileName(0,True)

  If(strFile<>"")Then

   mpMain.SaveMapAsGeoset strFile,strFile

   gbDocDirty=False

  End If

 End If

End Sub

4.视图管理

在计算机环境下传统地图的一览性受到了限制,必须通过一定的手段进行弥补。充分利用计算机可视化的灵活性、动态性,一方面,可以实现记录用户浏览电子地图过程中的视图轨迹,并且在需要时回退到某个状态。另一方面,通过提供一个缩小了的缩略图(索引图),可以使得用户在使用电子地图过程中时刻清楚当前察看的视图在全图中的位置。

可以利用MapX设计这种功能,其中主要部分是在控件的MapViewChanged事件中进行处理,同时使用了一个自定义的类来管理用户浏览电子地图过程中的视图轨迹。

在HypMap中,缩略图是在MapX控件mpOverview上显示的,缩略图显示的数据集必须与主图显示的数据集相同。该功能的目标是,用户在主图区通过放大、缩小、漫游等功能改变视图时,用一个矩形框同时在缩略图mpOverview中标示出对应的区域;或者用户可以使用鼠标在缩略图mpOverview上画出一个矩形框,然后主图mpMain会调整当前视图,显示该框内的地图信息。有些时候用户可能希望直接在缩略图上拖动小矩形框来改变视图,而不是画出一个矩形,以实现此功能。

首先,在主图打开后,对缩略图进行初始化如下代码实现以及相关注释。

Private Sub InitialOverviewMap()

 Dim tmpRect As MapXLib.Rectangle

 Dim aRetFtre As MapXLib.Feature

 Dim aLyer As MapXLib.Layer

 mpOverview.Geoset=mpMain.Geoset'打开同一个数据集

 If(mpOverview.Layers.Count>0)Then

  Set mpMain.NumericCoordSys=mpMain.Layers.Item(1).CoordSys

  Set mpOverview.NumericCoordSys=mpMain.NumericCoordSys

  Set mpOverview.DisplayCoordSys=mpMain.DisplayCoordSys

  '必须将主图的投影设置为图层中使用的投影,这里以第一个图层

  '为准。同时缩略图的投影必须以主图为准。

  For Each aLyer In mpOverview.Layers

   aLyer.Selectable=False

   aLyer.Editable=False

   aLyer.AutoLabel=False

   aLyer.ShowLineDirection=False

  Next aLyer

  '将缩略图的所有图层设置为只读,且不显示注记。

  Set mpOverview.Bounds=mpOverview.Layers.Bounds

  '缩略图全图显示所有要素。

  Set tmpRect=mpOverview.Bounds

  '获取缩略图显示范围。

  Set aLyer=mpOverview.Layers.CreateLayer("Locate Rectangle",,1)

  '在缩略图中创建一个临时图层,并置于顶层。

  aLyer.Editable=True'将临时图层设置为可编辑。

  Set aRetFtre=GetRectFeature(tmpRect.xMin,tmpRect.yMin,_

  tmpRect.xMax,tmpRect.yMax,mpOverview)

  '将显示范围转换为一个矩形要素。

  Set aRetFtre=mpOverview.Layers.Item("Locate Rectangle")._

  AddFeature(aRetFtre)

  '将要素添加到缩略图的临时图层上。

  mpOverview.Tag=aRetFtre.FeatureKey

  '为了方便管理,记录该矩形要素的标识码(关键字)。

 End If

End Sub

初始化缩略图的程序中,为了记录并显示标明范围的矩形框,使用到了函数GetRectFeature,其功能是在给定MapX控件上以给定的坐标范围创建一个矩形的面状要素,并作为返回值传递回来。具体实现代码如下。

Private Function GetRectFeature(xMin As Double,yMin As Double,_

xMax As Double,yMax As Double,_

fMapCtl As MapXLib.Map)As MapXLib.Feature

 Dim pts As New MapXLib.Points,Pt As New MapXLib.Point

 Dim rcEagleLocate As New MapXLib.Feature

 Pt.Set xMin,yMin:pts.Add Pt

 Pt.Set xMax,yMin:pts.Add Pt

 Pt.Set xMax,yMax:pts.Add Pt

 Pt.Set xMin,yMax:pts.Add Pt

 '使用给定的坐标范围生成含有四个角顶点的点集。

 rcEagleLocate.Attach fMapCtl'使用fMapCtl来校正要素的坐标空间。

 rcEagleLocate.Type=miFeatureTypeRegion

 rcEagleLocate.Parts.Add pts

 '将点集添加到新生成的要素上,其为面状要素类型。

 With rcEagleLocate.Style

  .RegionBorderWidth=2

  .RegionBorderColor=vbBlue

  .RegionColor=vbRed

  .RegionTransparent=True

  .RegionPattern=miPatternNoFill'miPatternCross

 End With'修改要素的符号样式。

 Set GetRectFeature=rcEagleLocate

 Set pts=Nothing

 Set Pt=Nothing

 Set rcEagleLocate=Nothing'显式释放内存空间。

End Function

当用户在缩略图中使用鼠标画出一个矩形框后,根据矩形框的位置调整主图的显示范围。其处理是在mpOverview的MapX的标准事件ToolUsed中进行的,首先根据事件传递过来的两个坐标点创建一个矩形框,然后将主图mpMain的显示范围设置为该矩形范围。其中使用的工具DRAGRECTANGLE为自定义工具。具体实现如下。

Private Sub mpOverview_ToolUsed(ByVal ToolNum As Integer,_

ByVal X1 As Double,ByVal Y1 As Double,_

ByVal X2 As Double,ByVal Y2 As Double,_

ByVal Distance As Double,_

ByVal Shift As Boolean,ByVal Ctrl As Boolean,_

EnableDefault As Boolean)

 If(ToolNum=DRAGRECTANGLE)Then

  Dim rcDrag As New MapXLib.Rectangle

  rcDrag.Set X1,Y1,X2,Y2

  Set mpMain.Bounds=rcDrag

  Set rcDrag=Nothing

 End If

End Sub

自定义工具DRAGRECTANGLE是miToolTypeMarquee类型的工具,它可以在MapX控件上画出一个虚线的矩形,该工具是在系统初始化中创建的,部分的相关代码如下。

Private Sub Form_Load()'

 mpOverview.CreateCustomTool DRAGRECTANGLE,_

 miToolTypeMarquee,miCrossCursor

 mpOverview.CurrentTool=DRAGRECTANGLE

End Sub

前面的设计实现了由缩略图到主图的交互。另一方面,当主图的视图发生变化时,缩略图也要进行相应的调整,也即更新指示主图显示范围的矩形框。当主图显示范围大于或者等于实际地理范围时,缩略图中指示矩形框达到最大值,也即与当前数据集的图幅等大。

Private Sub mpMain_MapViewChanged()

 If(mpMain.Geoset<>"")Then

 Dim aRetFtre As MapXLib.Feature

 Call EvwhtMap.Add(mpMain.Zoom,mpMain.CenterX,mpMain.CenterY)

 If Not(mpMain.Bounds.Width>mpMain.Layers.Bounds.Width Or_

 mpMain.Bounds.Height>mpMain.Layers.Bounds.Height)Then

 '如果主图的显示范围小于实际的地理范围,进行如下处理。

 mpOverview.Layers.Item("Locate Rectangle").DeleteFeature_

 mpOverview.Tag

 '删除当前缩略图上的矩形框,mpOverview.Tag为其关键字。

 With mpMain.Bounds

  Set aRetFtre=GetRectFeature(.xMin,.yMin,.xMax,_

  .yMax,mpOverview)

  '根据主图当前的显示范围生成矩形面状要素。

  Set aRetFtre=mpOverview.Layers.Item_

  ("Locate Rectangle").AddFeature(aRetFtre)

  '将要素添加到临时图层中。

End With

mpOverview.Tag=aRetFtre.FeatureKey

Else

'如果主图的显示范围大于或者等于实际的地理范围,进行如下处理。

Set aRetFtre=mpOverview.Layers.Item("Locate Rectangle")_

            .GetFeatureByKey(mpOverview.Tag)

If(aRetFtre.Bounds.Width<mpOverview.Layers.Bounds.Width Or_

 aRetFtre.Bounds.Height<mpOverview.Layers.Bounds.Height)Then

 mpOverview.Layers.Item("Locate Rectangle").DeleteFeature_

mpOverview.Tag

With mpOverview.Layers.Bounds

 Set aRetFtre=GetRectFeature(.xMin,.yMin,_

        .xMax,.yMax,mpOverview)

 Set aRetFtre=mpOverview.Layers.Item_

        ("Locate Rectangle").AddFeature(aRetFtre)

   With

   mpOverview.Tag=aRetFtre.FeatureKey

   End If

  End If

 End If

End Sub

用户已经查看过的历史视图是通过自定义的类BViewHist来管理的。类的实现代码以及对应的说明如下:

Option Explicit

'自定义事件,当用户调用方法LastView、NextView,请求改变视图的参数时激发该事件,

'参数含义依次为所请求上一视图或者下一视图的显示比例尺、中心点的横坐标、中心点的纵坐标。

Public Event PopupViewFrame(fScale As Double,fX As Double,fY As Double)

'自定义结构,每一帧视图对应一个ViewParam,其成员分别记录该视图的

'显示比例尺、中心点的横坐标、中心点的纵坐标。

Private Type ViewParam

    dScale As Double

    dX As Double

    dY As Double

End Type'

类属性

Dim sMapNm As String

Dim ViewPath()As ViewParam

Dim nViewFrm As Long,nCurrView As Long'

类初始化,初始化变量

Private Sub Class_Initialize()

   nViewFrm=-1

   nCurrView=-1

   sMapNm=""

   Erase ViewPath

End Sub

'类的结束处理

Private Sub Class_Terminate()

  Erase ViewPath

  '释放动态数组内存

End Sub

'获取对应的数据集名称

Public Property Get MapName()As String

  MapName=sMapNm

End Property

'记录对应的数据集名称,如果与当前的数据集不同,则重新开始记录。

'留待后续系统扩展用,可以将数据集名称作为视图帧的属性,同时修改系统其他部分,

'以能返回到已经关闭的数据集。

Public Property Let MapName(fMapNm As String)

 If(sMapNm<>fMapNm)Then

  nCurrView=-1

  nViewFrm=-1

  Erase ViewPath

 End If

 sMapNm=fMapNm

End Property

'获取当前记录的视图帧的数目。

Public Property Get ViewFrame()As Long

 ViewFrame=nViewFrm

End Property

'使用该方法请求上一帧视图的参数,激发自定义事件传递给外部处理。

Public Function LastView()As Boolean

 If(sMapNm="")Then Exit Function

 If(nCurrView>=0)Then

  LastView=nCurrView<>0

  '如果已经是第一帧,则返回False,并且不激发事件。

  If(LastView)Then

    nCurrView=nCurrView-1

    RaiseEvent PopupViewFrame(ViewPath(nCurrView).dScale,_

    ViewPath(nCurrView).dX,ViewPath(nCurrView).dY)

 End If

 End If

End Function

'使用该方法请求下一帧视图的参数,激发自定义事件传递给外部处理。

Public Function NextView()As Boolean

 If(sMapNm="")Then Exit Function

 If(nCurrView<nViewFrm)Then

 NextView=nCurrView<>nViewFrm

 '如果已经是最后一帧,则返回False,并且不激发事件。

  If(NextView)Then

   nCurrView=nCurrView+1

   RaiseEvent PopupViewFrame(ViewPath(nCurrView).dScale,_

   ViewPath(nCurrView).dX,ViewPath(nCurrView).dY)

  End If

 End If

End Function

'追加一帧视图,记录三个参数。

Public Sub Add(fScale As Double,fX As Double,fY As Double)

 If(nCurrView>=0)Then

'对于连续两帧视图,判断其比例尺、中心点是否相同。

'若是,则不添加新帧

If(CSng(ViewPath(nCurrView).dScale)=CSng(fScale)And_

 CSng(ViewPath(nCurrView).dX)=CSng(fX)And_

 CSng(ViewPath(nCurrView).dY)=CSng(fY))Then

   Exit Sub

  End If

 End If

 nCurrView=nCurrView+1

 ReDim Preserve ViewPath(nCurrView)

 ViewPath(nCurrView).dScale=fScale

 ViewPath(nCurrView).dX=fX

 ViewPath(nCurrView).dY=fY

 nViewFrm=nCurrView

End Sub

有了这个类的定义后,创建一个实例,在合适的地方使用方法Add记录视图的变化,然后在需要时就可以通过调用两个方法LastView、NextView激发事件PopupViewFrame,即可向外部传递对应的视图帧的参数信息。

在系统主模块frmMain中声明事件变量:

Dim WithEvents EvwhtMap As BViewHist

然后在模块初始化中创建:

Private Sub Form_Load()

 Set EvwhtMap=New BViewHist

 End Sub

在打开地图数据集时,记录对应的数据集名称以及第一次调入时视图的状态参数:

Private Sub OpenAMap(fstrMapNm As String)

 EvwhtMap.MapName=mpMain.Geoset

 gstrUnitName=GetUnitName(mpMain.MapUnit)

 Call EvwhtMap.Add(mpMain.Zoom,mpMain.CenterX,mpMain.CenterY)

End Sub

在主图的视图变化事件中记录变化后视图状态参数:

Private Sub mpMain_MapViewChanged()

Call EvwhtMap.Add(mpMain.Zoom,mpMain.CenterX,mpMain.CenterY)

End Sub

在与用户交互的地方调用上下视图方法:

Private Sub mnuViewHist_Click(Index As Integer)

 If(Index=1)Then'last frame view

  EvwhtMap.LastView

  ElseIf(Index=2)Then

  EvwhtMap.NextView

 End If

End Sub

如果上下视图存在,则上面的函数会激发类BViewHist的事件:

Private Sub EvwhtMap_PopupViewFrame(fScale As Double,fX As Double,_ fY As Double)

 mpMain.ZoomTo fScale,fX,fY

 '调整主图的视图参数,等同于以下注释代码:

 'mpMain.AutoRedraw=False

 'mpMain.Zoom=fScale

 'mpMain.CenterX=fX

 'mpMain.CenterY=fY

 'mpMain.AutoRedraw=True

End Sub

HypMap还提供了显示全图和显示选择两种功能。前者使用菜单mnuViewAll与用户交互。

Private Sub mnuViewAll_Click()

  Set mpMain.Bounds=mpMain.Layers.Bounds

End Sub

后者使用mnuViewSelect与用户交互。

Private Sub mnuViewSelect_Click()

  Dim rcSelectAs MapXLib.Rectangle

  Dim aLayerAs MapXLib.Layer

  Dim ftresSelAs MapXLib.Features

  For Each aLayer In mpMain.Layers

    Set ftresSel=aLayer.Selection.Clone

    If ftresSel.Count>0 Then

     If(rcSelect Is Nothing)Then

       Set rcSelect=ftresSel.Bounds

     Else

        If(rcSelect.xMin>ftresSel.Bounds.xMin)Then

        rcSelect.xMin=ftresSel.Bounds.xMin

     End If

     If(rcSelect.yMin>ftresSel.Bounds.yMin)Then

       rcSelect.yMin=ftresSel.Bounds.yMin

     End If

     If(rcSelect.xMax<ftresSel.Bounds.xMax)Then

       rcSelect.xMax=ftresSel.Bounds.xMax

     End If

     If(rcSelect.yMax<ftresSel.Bounds.yMax)Then

       rcSelect.yMax=ftresSel.Bounds.yMax

     End If

    End If

   End If

  Next

 If Not rcSelect Is Nothing Then Set mpMain.Bounds=rcSelect

 Set rcSelect=Nothing

 Set ftresSel=Nothing

End Sub

5.量算功能

利用MapX控件进行地图的量测和量算是非常方便的。MapX已经提供了直线段的长度量测功能,也即其标准事件ToolUsed中的参数Distance。

Private Sub mpMain_ToolUsed(ByVal ToolNum As Integer,_

 ByVal X1 As Double,ByVal Y1 As Double,ByVal X2 As Double,_

 ByVal Y2 As Double,ByVal Distance As Double,_

 ByVal Shift As Boolean,ByVal Ctrl As Boolean,EnableDefault As Boolean)

 Debug.Print"The distance is:"&CStr(Distance)

End Sub

由于实际应用中,直线段的量测用途有限,而且直线段是折线的特例,因此HypMap中提供了折线的长度量测和多边形的面积量算功能。首先将当前鼠标工具设置为量测状态,通过菜单实现,代码如下。

Private Sub mnuMeasDime_Click(Index As Integer)

 If Not(m_CurrMouseMenu Is Nothing)Then

  m_CurrMouseMenu.Checked=False

 End If

 If Not(m_CurrBtn Is Nothing)Then m_CurrBtn.Value=tbrUnpressed

 If(Index=1)Then

  mpMain.CurrentTool=POLYLINERULERID

 ElseIf(Index=2)Then

 mpMain.CurrentTool=REGIONAREAID

 End If

 Set m_CurrMouseMenu=mnuMeasDime(Index)

 m_CurrMouseMenu.Checked=True

End Sub

自定义工具POLYLINERULERID是miToolTypePoly类型的,工具REGIONAREAID是mi-ToolTypePolygon类型的,其定义见后文。使用鼠标在mpMain控件上画出折线或者多边形过程中,会激发MapX的标准事件PolyToolUsed,该事件第一个参数指示使用的工具代码;第二个参数表示当前操作状态,为miPolyToolBegin表示鼠标在控件上点了第一个点,miPolyToolEnd表示鼠标双击MapX控件结束了操作,miPolyToolEndEscaped表示用户使用了键盘上的Esc键取消了操作或者使用BACKSPACE键删除的上一点是最后一点,miPolyToolInProgress表示其他状态;第三个参数是当前鼠标已经点击的点坐标数组,第四个和第五个参数指示键盘上Shift和Ctrl键的状态;最后一个是在使用MapX内置工具时确定是否执行其缺省的操作。我们在这个事件中根据前三个参数标示的状态来显示结果,其代码以及说明如下。

Private Sub mpMain_PolyToolUsed(ByVal ToolNum As Integer,_

 ByVal Flags As Long,ByVal Points As Object,ByVal bShift As Boolean,_

 ByVal bCtrl As Boolean,EnableDefault As Boolean)

 Dim aPolygon As New MapXLib.Feature

 Dim aTmpLyer As MapXLib.Layer

 Dim iPt As Integer,sngSumDis As Double

 Dim sx As Single,sy As Single

 ptMeasureX=Points.Item(Points.Count).x

 ptMeasureY=Points.Item(Points.Count).y

 'ptMeasureX、ptMeasureY为模块变量,取最新一点坐标。

 mpMain.ConvertCoord sx,sy,ptMeasureX,ptMeasureY,miMapToScreen

 '将坐标转换为屏幕坐标。

 If(Flags=miPolyToolBegin)Then

  stBar.Panels("measure").Text=""

  '使用第一点定位显示结果的位置。

  ctlMeasure.Move sx*Screen.TwipsPerPixelX,_

  sy*Screen.TwipsPerPixelY

  ctlMeasure.Tag=0

ElseIf(Flags<>miPolyToolBegin And_

        Flags<>miPolyToolInProgress)Then

'如果结束则刷新屏幕显示。

 mpMain.Refresh

ctlMeasure.Visible=False

End If

If(ToolNum=REGIONAREAID)Then

 '量算多边形面积的工具,只在点数大于2的时候才计算。

 If(Points.Count>2 And Flags=miPolyToolInProgress)Then

  ctlMeasure.Visible=True

  Set aPolygon=New Feature

  aPolygon.Attach mpMain

  aPolygon.Type=miFeatureTypeRegion

  aPolygon.Parts.Add Points

  sx=aPolygon.Area

  ctlMeasure.Tag=sx

  ctlMeasure.Width=8*ctlMeasure.Font.Size*_

  LenB(ctlMeasure.Tag&gstrUnitName)

  ctlMeasure.Text=sx&gstrUnitName&"^2"

  stBar.Panels("measure").Text=sx&""&gstrUnitName&"^2" Else

  ctlMeasure.Text=0

End If

ElseIf(ToolNum=POLYLINERULERID)Then

 sngSumDis=0

 If Points.Count>1 And Flags=miPolyToolInProgress Then

  '累计各段直线的长度即为折线长。

  For iPt=2 To Points.Count

   sngSumDis=sngSumDis+mpMain.Distance(_

   Points.Item(iPt-1).x,Points.Item(iPt-1).y,_

   Points.Item(iPt).x,Points.Item(iPt).y)

  Next

  ctlMeasure.Tag=sngSumDis

  ctlMeasure.Width=8*ctlMeasure.FontSize*_

  LenB(ctlMeasure.Tag&gstrUnitName)

  ctlMeasure.Text=sngSumDis&gstrUnitName

  ctlMeasure.Visible=True

  stBar.Panels("measure").Text=sngSumDis&""&_

  gstrUnitName

 End If

End If

End Sub

6.空间查询与分析

以下代码给出了“图元属性数据提取工具”InfoTool的实现。当用户使用该工具选择一个图元时,系统就显示该图元所有的属性数据。

首先定义属性数据提取工具标号。

Public Const InfoTool=120

在Form_Load事件中生成InfoTool。

Private Sub Form_Load()

 MpMain.CreateCustomTool InfoTool,miToolTypePoint,miCrossCursor

End Sub

然后,在ToolUsed事件中获取选中的图元,查询属性数据并显示。图元属性数据的读取可通过图层的KeyField属性和图元的KeyValue属性来获得。

Private Sub mpMain_ToolUsed(ByVal ToolNum As Integer,_

 ByVal Flags As Long,ByVal Points As Object,ByVal bShift As Boolean,_

 ByVal bCtrl As Boolean,EnableDefault As Boolean)

 …

 Dim pnt As New Point

 Dim pnts As New MapXLib.Points

 Dim ftrs As Features

 Dim ftr As Feature

 Dim lyr As Layer

 Dim strInfo As String

 Dim flds As MapXLib.Fields

 Dim fld As MapXLib.Field

 Dim ds As MapXLib.Dataset

 Select Case ToolNum

 …

 Case InfoTool

  pnt.Set X1,Y1

  For Each lyr In mpMain.Layers

   Set ftrs=lyr.SearchAtPoint(pnt)

   If ftrs.Count>0 Then

    strInfo="Layer name:"&lyr.Name&vbCrLf

    strInfo=strInfo&"Feature Name:"&ftrs.Item(1).Name&vb_

     CrLf

    Set ds=mpMain.Datasets.Add(miDataSetLayer,lyr)

    For Each fld In ds.Fields

      strInfo=strInfo&fld.Name&":"

      Set lyr.KeyField=fld

      strInfo=strInfo&ftrs.Item(1).KeyValue&vbCrLf

     Next

     MsgBox strInfo

     Exit For

  End If

Next

If ftrs.Count=0 Then

   MsgBox'没有图元被选中

  End If

 End Select

End Sub

根据属性查询图元。MapX提供的Layer.Search方法允许用户进行单项和符合条件查询。利用它可以实现属性数据到空间数据的查询。

以下代码在图层“行政区域”中查询出区名为“RegionName”的图元,并将查询的结果在地

图上高亮显示。

Dim lyr As MapXLib.Layer

Dim ftrs As MapXLib.Features

Set lyr=mpMain.Layers("行政区域")

mpMain.Datasets.Add miDataSetLayer lyr

Set ftrs=lyr.Search("Region="RegionName"")

lyr.Selection.Replace ftrs

查询的结果作为图元可以用上面介绍的高亮方式表示出来,也可以利用定时器让这些图元进行闪烁,以便查看。所谓闪烁可以将查询的结果图元利用图层的Selection属性,分别反复地放入选择集合和清除出选择集合来实现。

下面代码是定位查询对象的函数,在这里设置定时器的开关为开始:

Private Function LocateQueryResult()

 intBlinkCount=0

 tmrFeatureBlink.Enabled=True'打开定时开关,开始闪烁

 Exit Function

End Function

下面是定时器的事件,在这里设置闪烁方式,并根据闪烁的次数来停止闪烁:

'设置被查询定位的第五次闪烁

Private Sub tmrFeatureBlink_Timer()

Dim ftr As New Feature

Dim ftrs As Features

'设置闪烁的次数为5次

If intBlindCoun<5 Then

  '第一次闪烁,将目标放入Selection集合,还要完成查询结果目标的地图定位

  If intBlinkCount=0 Then

  mpMain.Layers.Item(strLocateLayerName).KeyField=g_cntIDFieldName

  Set ftrs=mpMain.Layers.Item(strLocateLayerName).AllFeatures

  For Each ftr In ftrs

    If ftr.KeyValue=lngRecordSetID Then

    mpMain.Layers.Item(strLocateLayerName).Selection.ClearSelection

    mpMain.Layers.Item(strLocateLayerName).Selection.Add ftr

    If bInLocate=True Then

      mpMain.ZoomTo mpMain.Zoom,ftr.CenterX,ftr.CenterY

    End If

    Exit For

  End If

 Next ftr

Else

 '在第2、第4次定时事件触发时,将目标放入Selection中

 If intBlinkCount=2 Or intBlinkCount=4 Then

 Map.Layers.Item(strLocateLayerName).KeyField=g_cntIDFieldName

 Set ftrs=Map.Layers.Item(strLocateLayerName).AllFeatures

 '针对选中的每一个图元进行闪烁

 For Each ftr In ftrs

   If ftr.KeyValue=lngRecordSetID Then

   mpMain.Layers.Item(strLocateLayerName).Selection.ClearSelection

   mpMain.Layers.Item(strLocateLayerName).Selection.Add ftr

 Exit For

 End If

 Next ftr

 Else

 '在第1、3、5次定时事件触发时,将目标清楚Selection

 Map.Layers.Item(strLocateLayerName).Selection.ClearSelection

 End If

 End If

 '计算闪烁的次数

 intBlinkCount=intBlinkCount+1

 Else

 '闪烁的次数够了,停止计时和闪烁

 intBlinkCount=0

 tmrFeatureBlink.Enabled=False

End If

Exit Sub

End Sub

7.地图输出(打印)

MapX中提供了PrintMap方法实现地图的打印。但打印地图的范围是整个MapX控件窗口显示部分的内容,要将打印输出的地图按照比例尺打印,也就是在打印的地图上可以进行测量(例如图中1厘米对应实际的1公里),这就是要进行地图打印比例尺的设置。

首先声明打印区域选择工具标号。

Public Const PrintMapTool=119

窗体加载过程中生成打印区域选择工具:

Private Sub Form_Load()

 …

 '生成打印区域选择工具

 mpMain.CreateCustomTool PrintMapTool,miToolTypeMarquee,miCrossCursor

End Sub

在ToolUsed事件中调用地图打印过程:

Private Sub mpMain_ToolUsed(ByVal ToolNum As Integer,_

 ByVal Flags As Long,ByVal Points As Object,ByVal bShift As Boolean,_

 ByVal bCtrl As Boolean,EnableDefault As Boolean)

 Select Case ToolNum

 …

 Case PrintMapTool

   PrintScaledMap X1,Y1,X2,Y2

 End Select

End Sub

按比例打印指定的地图区域

Private Sub PrintScaledMap(ByVal X1 As Double,ByVal Y1 As Double,ByVal X2 As_

Double,ByVal Y2 As Double)

Dim sngXMin As Single

Dim sngYMin As Single

Dim sngXMax As Single

Dim sngYMax As Single

Dim sngWidth As Single

Dim sngHeight As Single

Dim newRect As New Rectangle

Dim oldRect As Rectangle

Dim dblZoom As Double

Dim dblScale As Double

Dim dblNewScale As Double

Dim sstrNewScale As String

Dim dblDistance As Double

'设置地图单位

mpMain.PaperUnit=miPaperUnitMillimeter

ScaleMode=vbMillimeters

'保存地图原有的边界

Set oldRect=mpMain.Bounds

'将地理坐标转化为屏幕坐标

mpMain.ConvertCoord sngXMin,sngYMin,X1,Y1,miMapToScreen

mpMain.ConvertCoord sngXMax,sngXMax,sngYMas,X2,Y2,miMapToScreen

sngWidth=Abs(sngXMax–sngXMin)

sngHeight=Abs(sngYMax–sngYMin)

'计算当前屏幕显示比例尺

mpMain.MapUnit=miUnitMillimeter

dblDistance=mpMain.Distance(X1,Y1,X2,Y2)

dblScale=dblDistance/sngWidth

'获取打印比例尺

strNewScale=InputBox("请设置打印比例尺1∶X","打印比例尺",CStr(dblScale))

dblZoom=dblScale/CDbl(strNewScale)

'改变地图显示范围为指定打印区域

mpMain.Width=Me.ScaleX(sngWidth,vbPixels,vbMillimeters)

mpMain.Height=Me.ScaleY(sngHeight,vbPixels,vbMillimeters)

newRect.Set X1,Y1,X2,Y2

Set mpMain.Bounds=newRect

'显示打印机设置对话框

With CmnDlg

  .CanceError=True

  .Flags=cdlPDPrintSetup

  .PrinterDefault=True

  .ShowPrinter

End With

'打印地图

Printer.CurrentX=0

Printer.CurrentY=0

Printer.Print""

 MpMain.PrintMap Printer.hdc,0,0,mpMain.Width*100*dblZoom,_

MpMain.Height*100*dblZoom

Printer.NewPage

Printer.EndDoc

'恢复地图显示

mpMain.Width=Me.ScaleWidth

mpMain.Height=Me.ScaleHeight

Set mpMain.Bounds=oldRect

Exit Sub

End Sub

通过以上步骤可以实现地图的按比例打印。其中,可以由用户指定地图打印的比例尺,例如1∶1 000 000等。

8.其他辅助功能函数

前面已经叙述了HypMap的重要功能模块,在此之外,还用到了大量的支持代码,例如一些常量的定义,常用函数的定义与实现以及界面元素的协调等。

HypMap的系统启动是定义在模块文件中主函数Main(),下面是该模块的内容和说明。

Option Explicit

'modFunc.bas

Public Declare Function mciSendString Lib"winmm.dll"Alias_

  "mciSendStringA"(ByVal lpstrCommand As String,_

  ByVal lpstrReturnString As String,_

  ByVal uReturnLength As Long,ByVal hwndCallback As Long)As Long

Public Const MAX_PATH As Integer=260

Public Const DATABASE_DRIVER As String=_

       "PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source="

Public Const DELIMITER As String="|"'

系统主函数。

Public Sub Main()

Load frmMain'加载主模块。

   frmMain.Show

End Sub

'系统通用的错误输出处理函数,如果fbClearErr为真,则清除错误状况,

'如果参数fstrMsg非空,则以它为提示信息。

'不处理标准文件对话框“取消”按钮产生的错误(代码为32755)。

Public Function DefErrorOut(fbClearErr As Boolean,_

 Optional fstrMsg As String)As Boolean

 If(Err.Number=0 Or Err.Number=32755)Then

 DefErrorOut=True

 Else

 DefErrorOut=False

 If(fstrMsg<>"")Then'(Not IsMissing(fstrMsg))Then

  MsgBox fstrMsg&vbCrLf,vbInformation

 Else

  Dim strM As String

  strM="不适当的操作,描述为:"

  strM=strM&Err.Number&vbCrLf&Err.Description

  strM=strM&vbCrLf

  MsgBox strM,vbInformation

 End If

  If(fbClearErr)Then Err.Clear

  Err.Clear

  End If

End Function

'判断参数fstrFileName指示的文件是否存在,是则返回真值,否则为假。

Public Function IsFileExist(fstrFileName As String)As Boolean

On Error GoTo errGetOut

  Dim hFile As Integer

  If(fstrFileName="")Then

   IsFileExist=False

   Exit Function

  Else

   hFile=FreeFile()

   Open fstrFileName For Input Access Read As#hFile

   Close#hFile

  End If

errGetOut:

  IsFileExist=DefErrorOut(True)',"IsFileExist"&fstrFileName)

End Function

'获取一个文件名,参数Index为对话框出现时后缀,若fbSave为真则

'显示"保存"对话框,否则显示"打开"对话框

Public Function GetFileName(Index As Integer,_

Optional fbSave As Boolean=False)As String

On Error GoTo errCancel

  Dim strTitle As String,strfilter As String

  strTitle="指定目标文件"

  If(Index=0)Then

  strfilter="地图文件|*.gst|*.*|*.*"

  ElseIf(Index<5)Then

strfilter="文字文件|*.txt;*.rtf|图片文件|*.bmp;*.jpg;*.gif|" strfilter=strfilter&"视频文件|*.avi|声音文件|*.wav;*.mid"

End If

With frmMain.cmnDialog

 .Filter=strfilter

 .FilterIndex=Index

 .DialogTitle=strTitle

 .FileName=""

If(fbSave)Then

  .Flags=.Flags Or cdlOFNOverwritePrompt

  .ShowSave

Else

  .Flags=.Flags Or cdlOFNFileMustExist

  .ShowOpen

End If

  GetFileName=.FileName

End With

errCancel:

   DefErrorOut False

End Function

'分解文件名为路径、标题、后缀。参数fFName为待分解的文件名。

Public Function GetFilePathAttr(fFName As String,Optional fstrPath As String,_

   Optional fstrFName As String,Optional fstrExt As String)As Boolean

On Error GoTo lblGetFilePathAttr

fstrExt=RightLimitter$(fFName,".")

fstrFName=RightLimitter$(fFName,"\")

fstrPath=Left$(fFName,Len(fFName)-Len(fstrFName))

fstrFName=Left$(fstrFName,Len(fstrFName)-Len(fstrExt)-1)

'GetFilePathAttr=fstrExt&vbCrLf&fstrFName&vbCrLf&fstrPath

lblGetFilePathAttr:

GetFilePathAttr=DefErrorOut(True)

End Function

'取字符串fstrSrc中fchrLim右边的部分。

Public Function RightLimitter(fstrSrc As String,fchrLim As String)As String

  Dim iLoop As Integer,nstrLen As Integer

  nstrLen=Len(fstrSrc)

  For iLoop=nstrLen To 1 Step-1

    If(Mid(fstrSrc,iLoop,1)=fchrLim)Then Exit For

  Next iLoop

  If(iLoop>0)Then RightLimitter=Right$(fstrSrc,nstrLen-iLoop)

End Function

'取字符串fstrSrc中fchrLim左边的部分。

Public Function LeftLimitter(fstrSrc As String,fchrLim As String)As String

Dim iLoop As Integer,nstrLen As Integer

nstrLen=Len(fstrSrc)

For iLoop=1 To nstrLen

 If(Mid(fstrSrc,iLoop,1)=fchrLim)Then Exit For

Next iLoop

If(iLoop>0)Then LeftLimitter=Left$(fstrSrc,iLoop-1)

End Function

'根据MapX的地图量度单位代码确定其对应含义的字符串名。

Public Function GetUnitName(fInnerUnit As MapUnitConstants)As String

    GetUnitName=Choose(fInnerUnit+1,"英里","公里","英寸",_

    "英尺","码","厘米","分米","米","测量英尺","海里",_

    "缇","点","字","度","令","链","杆")

End Function

'MapX控件的地图文件中图层lyr是否为非临时图层。

Public Function IsLayerPermanent(lyr As Layer)As Boolean

If(LCase$(Right$(lyr.Filespec,3))="tab")Then

IsLayerPermanent=True

ElseIf(LCase$(Right$(lyr.Filespec,3))="tmp")Then

IsLayerPermanent=False

End If

End Function

另外,在主窗体模块frmMain中有部分界面元素协调等功能的代码,具体实现以及相关说明如下:

'frmMain.frm

'Option Explicit

Private Const MAINMAP_WIDTH As Integer=5300

Private Const CLOSE_WIDTH As Integer=70

Private Const DRAGRECTANGLE As Integer=101

Private Const POLYLINERULERID As Integer=103

Private Const REGIONAREAID As Integer=104

Dim WithEvents EvwhtMap As BViewHist

Dim WithEvents EinfoGet As frmInf

Dim gbDocDirty As Boolean

Dim gstrUnitName As String

Dim m_CurrMouseMenu As Menu,m_CurrBtn As Button

Dim ptMeasureX As Double,ptMeasureY As Double

Dim ProjInf As BDBInf

'启动主窗体。

Private Sub Form_Load()

 Call mnuInfoManipu_Click(1)

 Set EvwhtMap=New BViewHist

 Set EinfoGet=New=frmInf

   gbDocDirty=False

mpMain.CreateCustomTool POLYLINERULERID,miToolTypePoly,_

               miCrossCursor

mpMain.CreateCustomTool REGIONAREAID,miToolTypePolygon,_

miCrossCursor

mpOverview.CreateCustomTool DRAGRECTANGLE,_

             miToolTypeMarquee,miCrossCursor

mpOverview.CurrentTool=DRAGRECTANGLE

End Sub

'窗体调整大小时的处理。

Private Sub Form_Resize()

   If(Me.WindowState<>FormWindowStateConstants.vbMinimized)Then

     Dim nHeight As Integer

     With picSeparator

       .Top=Me.ScaleTop+Me.tlbMain.Height

       nHeight=Me.ScaleHeight-stBar.Height-tlbMain.Height

       .Height=IIf(nHeight<0,0,nHeight)

       If(.Tag="")Then

         .Left=Me.ScaleWidth*5/6

         .Tag="00"

       End If

    If(.Left>Me.ScaleWidth)Then

Me.mnuViewTree.Checked=False

End If

.Width=50

.BorderStyle=0'none fixed border

End With

Call InitInterface

End If

End Sub

'窗体卸载时,清理内存变量。

Private Sub Form_Unload(Cancel As Integer)

 mnuExit_Click

 Set frmMain=Nothing

 Set EvwhtMap=Nothing

 Set EinfoGet=Nothing

 End

End Sub

 Private Sub mnuExit_Click()

 Dim aFrm As Form

  mnuMapSave_Click

  For Each aFrm In Forms

    Unload aFrm

 Next

End Sub

Private Sub mnuHelpAbout_Click()

 MsgBox App.LegalCopyright,vbInformation

End Sub

'缩放漫游地图显示的鼠标状态。

Private Sub mnuViewChange_Click(Index As Integer)

  If Not(m_CurrMouseMenu Is Nothing)Then

    m_CurrMouseMenu.Checked=False

  End If

  If Not(m_CurrBtn Is Nothing)Then m_CurrBtn.Value=tbrUnpressed

  Select Case Index

   Case 1

    mpMain.CurrentTool=miZoomInTool

    Set m_CurrBtn=tlbMain.Buttons("zoomin")

   Case 2

    mpMain.CurrentTool=miZoomOutTool

    Set m_CurrBtn=tlbMain.Buttons("zoomout")

   Case 3

    mpMain.CurrentTool=miPanTool

    Set m_CurrBtn=tlbMain.Buttons("pan")

 End Select

 Set m_CurrMouseMenu=mnuViewChange(Index)

 m_CurrMouseMenu.Checked=True

End Sub

Private Sub mpOverview_KeyDown(KeyCode As Integer,Shift As Integer)

If(KeyCode=vbKeyDelete)Then

mpOverview.Layers.ClearSelection

End If

End Sub

'用于表示当前图层列表的树视图控件的节点选项控制。

Private Sub trvLayer_NodeCheck(ByVal Node As MSComctlLib.Node)

Dim aNde As Node

If(Node.Key<>mpMain.Geoset)Then

 mpMain.Layers.Item(Node.Text).Visible=Node.Checked

Else'checking the root will affect all its children

 For Each aNde In trvLayer.Nodes

   If(aNde.Key<>mpMain.Geoset)Then

     aNde.Checked=trvLayer.Nodes(mpMain.Geoset).Checked

     trvLayer_NodeCheck aNde

   End If

  Next

 End If

End Sub

'关闭树视图显示。

Private Sub mnuViewTree_Click()

  mnuViewTree.Checked=Not mnuViewTree.Checked

  If(mnuViewTree.Checked)Then picSeparator.Left=Me.ScaleWidth*5/6

  Call Me.InitInterface

End Sub

'容器大小变化时,调整地图控件。

Private Sub picFrame_Resize()

 With Me.mpMain

 .Left=Me.picFrame.ScaleLeft

 .Top=Me.picFrame.ScaleTop

 .Width=Me.picFrame.ScaleWidth

 .Height=Me.picFrame.ScaleHeight

End With

End Sub

'调整树视图大小时的相关处理。

Private Sub picSeparator_MouseDown(Button As Integer,Shift As Integer,_

x As Single,y As Single)

Dim sTag As String

If(Button=vbLeftButton)Then

  picSeparator.ZOrder 0

  sTag=picSeparator.Tag

  Mid(sTag,1,1)="1"

  picSeparator.Tag=sTag

 End If

End Sub

Private Sub picSeparator_MouseMove(Button As Integer,Shift As Integer,_

            x As Single,y As Single)

Dim sTag As String

sTag=picSeparator.Tag

If(Button=MouseButtonConstants.vbLeftButton)And_

(Mid$(sTag,1,1)="1")Then

If(Mid$(sTag,2,1)="0")Then

Mid$(sTag,2,1)="0"

picSeparator.Tag=sTag

End If

piSeparator.Lefi=picSeparator.Left+x-1

End if

End Sub

Private Sub picSeparator_MouseUp(Button As Integer,Shift As Integer,_

x As Single,y As Single)

If(Button=vbLeftButton)Then

picSeparator.Tag="00"'picSeparator.BackColor=&H8000000F'SystemColorConstants.vbMenuBar

Dim nMinWid As Integer

nMinWid=Me.ScaleWidth/2

Me.mnuViewTree.Checked=True

If(picSeparator.Left>Me.ScaleWidth-CLOSE_WIDTH*4)Then

Me.mnuViewTree.Checked=False

ElseIf(picSeparator.Left<nMinWid)Then picSeparator.Left=nMinWid

End If

Call InitInterface

End If

End Sub

'用户在工具栏上选择功能项时设置相应的状态。

Private Sub tlbMain_ButtonClick(ByVal Button As MSComctlLib.Button)

Select Case Button.Key

Case"new"

mnuMapNew_Click

Case"open"

mnuMapOpen_Click

Case"zoomin"

Call mnuViewChange_Click(1)

Case"zoomout"

Call mnuViewChange_Click(2)

Case"pan"

Call mnuViewChange_Click(3)

Case"ptselect"

If(tlbMain.Buttons("modify").Value=tbrPressed)Then

Call mnuInfoManipu_Click(2)

Else

Call mnuInfoManipu_Click(1)

End If

Case"modify"

If(Button.Value=tbrPressed)Then

Call mnuInfoManipu_Click(2)

ElseIf(Button.Value=tbrUnpressed And_

tlbMain.Buttons("ptselect").Value=tbrPressed)Then

Call mnuInfoManipu_Click(1)

End If

Case"zoomback"

mnuViewHist_Click 1

Case"zoomforward"

mnuViewHist_Click 2

Case"layer"

mnuMapAlter_Click

Case Else

DefErrorOut True,"Undefined Buttons!"

End Select

End Sub

'界面元素变化时,调整相关控件大小以及位置。

Public Sub InitInterface()

On Error Resume Next

If(Me.mnuViewTree.Checked=False)Then

picSeparator.Left=Me.ScaleWidth-picSeparator.Width

Me.tbsLayer.Left=Me.ScaleWidth

Me.framLayer.Left=Me.ScaleWidth

Me.framOver.Left=Me.ScaleWidth

Else

With Me.tbsLayer

.Visible=True

.Left=Me.picSeparator.Left

.Width=Me.ScaleWidth-picSeparator.Left

.Top=picSeparator.Top

.Height=picSeparator.Height

Me.framLayer.Top=.Top

Me.framLayer.Height=.ClientHeight/2

Me.framLayer.Left=.Left+picSeparator.Width

Me.framLayer.Width=.ClientWidth-picSeparator.Width

Me.trvLayer.Left=CLOSE_WIDTH

Me.trvLayer.Top=CLOSE_WIDTH*2

Me.trvLayer.Width=Me.framLayer.Width-CLOSE_WIDTH*2

Me.trvLayer.Height=Me.framLayer.Height-CLOSE_WIDTH*3

trvInf.Left=trvLayer.Left

trvInf.Top=trvLayer.Top

trvInf.Height=trvLayer.Height

trvInf.Width=trvLayer.Width

Me.framOver.Top=framLayer.Height+framLayer.Top

Me.framOver.Height=.ClientHeight/2

Me.framOver.Left=framLayer.Left

Me.framOver.Width=framLayer.Width

Me.mpOverview.Left=CLOSE_WIDTH

Me.mpOverview.Top=CLOSE_WIDTH*2

Me.mpOverview.Width=Me.framOver.Width-CLOSE_WIDTH*2

Me.mpOverview.Height=Me.framOver.Height-_

CLOSE_WIDTH*3

End With

End If

With Me.picFrame

.Left=Me.ScaleLeft

.Top=picSeparator.Top

.Width=Me.picSeparator.Left'Me.ScaleWidth-Me.tbsLayer.Width

.Height=picSeparator.Height

End With

Err.Clear

End Sub

'初始化界面显示

Public Sub PrepareGUI()

Dim aLyer As MapXLib.Layer

Dim aNde As Node,ndRoot As Node

Dim bOneVisible As Boolean

Me.trvLayer.Nodes.Clear

Me.trvInf.Nodes.Clear

If(mpMain.Layers.Count>0)Then

Set ndRoot=trvLayer.Nodes.Add(,,mpMain.Geoset,mpMain.Title)

For Each aLyer In mpMain.Layers

Set aNde=trvLayer.Nodes.Add(ndRoot,tvwChild,_

aLyer.Filespec,aLyer.Name)

aNde.Checked=aLyer.Visible

If(aNde.Checked)Then bOneVisible=True

Next

If(bOneVisible)Then ndRoot.Checked=True

ndRoot.Expanded=True

End If

InitialOverviewMap

End Sub

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈