Create shapes and layers programmatically -- My Code so far

the following is what I have tried so far:

Public Sub Form_Load()
Dim db As DAO.Database
Dim rst_MapConfigData As DAO.Recordset2
Set db = CurrentDb()
sql_MapConfigData = “SELECT * FROM [TBL Map Config Data];”
Set rst_MapConfigData = db.OpenRecordset(sql_MapConfigData)
rst_MapConfigData.MoveLast
rst_MapConfigData.MoveFirst

Dim sf As New MapWinGIS.Shapefile

For i = 1 To rst_MapConfigData.RecordCount

            fileNames = rst_MapConfigData.Fields("Directory_Path") & rst_MapConfigData.Fields("File_Name")
            Shape_Name = rst_MapConfigData.Fields("Shape_Name")
            Layer_Name = rst_MapConfigData.Fields("Layer_Name")
            Shape_Type = rst_MapConfigData.Fields("MapwinGIS_Shape_Type")
            
           
            csf = sf.CreateNew(Shape_Name, Shape_Type)
                  
            osf = sf.Open(fileNames, Null)
            
            Map0.AddLayer (sf)
            
            mal = Map0.AddLayer(Layer_Name, True)

Next i

    Map0.ShapeLayerLineColor(Boundary_Layer) = RGB(127, 127, 127)
    Map0.ShapeLayerLineWidth(Boundary_Layer) = 6
    Map0.ShapeLayerFillTransparency(Boundary_Layer) = 0

Map0.ZoomToLayer (Boundary_Layer)

End Sub

Hello again. First observations:

  1. I looks like the database table is perhaps a list of Shapefiles on disk?
  2. You shouldn’t have to CreateNew, then Open. If it is already a valid Shapefile, you can just open it, and it will be created on-the-fly while opening.
  3. I don’t see where Boundary_Layer is set.

If you are still having issues, and you are willing, could you upload the MDB and a couple of the Shapefiles? Perhaps I could then see more.

Regards,
Jerry.

Jerry

Thank you for responding to my post.

I was looking for a more difficult solution, then I found one of your old posts, and now see that loading a shapefile only takes one line of code.

  1. I have had some success, I have a VBA program that reads the data from the table, and makes the map almost correctly. However, it does not recognize symbol type values. A copy of the source code is at the end of this email.

This map loads the shapefiles as layers using: lhandle = Map0.AddLayerFromFilename(filenames(i), fosVectorDatasource, True)

  1. I want to change the program to load the shapefiles as shapefiles.

Why?

  • I will be adding code that searches through the shapefiles to find a record, then zoom to that feature on the map.
  • I have had better success setting feature colors and symbols with shapefiles using functions such as:

sf.DefaultDrawingOptions.FillBgColor = RGB(RGB_Red, RGB_Green, RGB_Blue)

  1. I have had problems loading the map with shapefiles. The following line of code throws a “Object Required” Error. I don’t understand what object is missing.

open_sf = sf.Open(filenames, Null)

  1. When I was able to load shapefiles, MapWinGIS would load one layer, then clear the layer and load the next.
  • It would not load one layer on top of the other.
  • It would not apply the feature color and symbol settings.

I assume there are commands that add the layers to AxMap1, post feature symbology and draws the map to the output screen. I have not found these commands yet.

  1. The database table is as follows. I am able to read the data with my VBA program in MS Access.

Shape_Name | Layer_Name | MapWinGIS_Shape_Type | Directory_Path | File_Name | RED | GREEN | BLUE | Size | Transparency | Symbol |

  • | - | - | - | - | - | - | - | - | - | - |
    sf_Boundary | Boundary_Layer | SHP_POLYGON | C:\Users\SP_ETL\Desktop\OldPost\gis\shp\ | OldPost_Boundary.shp | 0 | 255 | 0 | 6 | 0 | 0 |
    sf_Bridges | Bridges_Layer | SHP_POINT | C:\Users\SP_ETL\Desktop\OldPost\gis\shp\ | OldPost_Bridge.shp | 255 | 0 | 0 | 25 | 255 | 1 |
    sf_Culverts | Culverts_Layer | SHP_POINT | C:\Users\SP_ETL\Desktop\OldPost\gis\shp\ | OldPost_Culvert.shp | 0 | 0 | 255 | 25 | 255 | 5 |
    sf_Highways | Highways_Layer | SHP_POLYLINE | C:\Users\SP_ETL\Desktop\OldPost\gis\shp\ | OldPost_Highway.shp | 255 | 181 | 145 | 4 | 255 | 0 |
    sf_Roads_LMG | Roads_LMG_Layer | SHP_POLYLINE | C:\Users\SP_ETL\Desktop\OldPost\gis\shp\ | OldPost_Road_LMG.shp | 202 | 0 | 202 | 4 | 255 | 0 |
    sf_Prim_Grid_Roads | Prim_Grid_Roads_Layer | SHP_POLYLINE | C:\Users\SP_ETL\Desktop\OldPost\gis\shp\ | OldPost_Road_PrimGrid.shp | 0 | 255 | 0 | 4 | 255 | 0 |
    sf_Roads_MFA | Roads_MFA_Layer | SHP_POLYLINE | C:\Users\SP_ETL\Desktop\OldPost\gis\shp\ | OldPost_Road_MFA.shp | 0 | 128 | 255 | 4 | 255 | 0 |
    sf_Roads_GRID | Roads_GRID_Layer | SHP_POLYLINE | C:\Users\SP_ETL\Desktop\OldPost\gis\shp\ | OldPost_Road_Grid.shp | 255 | 0 | 0 | 4 | 255 | 0 |
    sf_Roads_Undev | Roads_Undev_Layer | SHP_POLYLINE | C:\Users\SP_ETL\Desktop\OldPost\gis\shp\ | OldPost_Road_Undev.shp | 0 | 0 | 0 | 1 | 255 | 0 |
  1. Working VBA Code that loads shapefiles as layers and draws an almost correct map.

Public Sub Form_Load()

Dim lay(15), filenames(15), open_sf(15)

Dim db As DAO.Database

Dim rst_MapConfigData As DAO.Recordset2

Dim sf As New MapWinGIS.Shapefile
Dim xMap0 As New MapWinGIS.Map

Set db = CurrentDb()

sql_MapConfigData = “SELECT * FROM [TBL Map Config Data];”

Set rst_MapConfigData = db.OpenRecordset(sql_MapConfigData)

rst_MapConfigData.MoveLast
rst_MapConfigData.MoveFirst

For i = 1 To rst_MapConfigData.RecordCount

filenames(i) = rst_MapConfigData.Fields(“Directory_Path”) & rst_MapConfigData.Fields(“File_Name”)
Shape_Name = rst_MapConfigData.Fields(“Shape_Name”)
Layer_Name = rst_MapConfigData.Fields(“Layer_Name”)
Shape_Type = rst_MapConfigData.Fields(“MapwinGIS_Shape_Type”)
RGB_Red = CInt(rst_MapConfigData.Fields(“RED”))
RGB_Green = CInt(rst_MapConfigData.Fields(“GREEN”))
RGB_Blue = CInt(rst_MapConfigData.Fields(“BLUE”))
Size = CInt(rst_MapConfigData.Fields(“Size”))
Transparency = CInt(rst_MapConfigData.Fields(“Transparency”))
Symbol = CInt(rst_MapConfigData.Fields(“Symbol”))

lhandle = Map0.AddLayerFromFilename(filenames(i), fosVectorDatasource, True)

Select Case Shape_Type

Case “SHP_POINT” ’ POINT Shape

Map0.ShapeLayerPointColor(lhandle) = RGB(RGB_Red, RGB_Green, RGB_Blue)
Map0.ShapeLayerPointSize(lhandle) = Size
Map0.ShapeLayerPointType(lhandle) = 5
Map0.ShapeLayerFillTransparency(lhandle) = Transparency

Case “SHP_POLYLINE” ’ LINE Shape

Map0.ShapeLayerLineColor(lhandle) = RGB(RGB_Red, RGB_Green, RGB_Blue)
Map0.ShapeLayerLineWidth(lhandle) = Size

Case “SHP_POLYGON” ’ POLYGON Shape

Map0.ShapeLayerLineColor(lhandle) = RGB(RGB_Red, RGB_Green, RGB_Blue)
Map0.ShapeLayerLineWidth(lhandle) = Size
Map0.ShapeLayerFillTransparency(lhandle) = Transparency

Case Else ’ UNKOWN or MISSING Shape try to draw as a RED line

Map0.ShapeLayerLineColor(lhandle) = RGB(255, 0, 0)
Map0.ShapeLayerLineWidth(lhandle) = 4

End Select

rst_MapConfigData.MoveNext

Next i

endproc:

Map0.ZoomToLayer (lhandle)

End Sub

  1. The output from the working version of my VBA Code

Hello Stu. Following are comments regarding some of your statements.

The methods you are using (ShapeLayerPointColor, ShapeLayerPointType, etc) are not all implemented (specifically I saw that the PointType method was not implemented). These apparently were some sort of shortcut functions someone was implementing, and most of them are marked as “hidden” in the IDL (as if they will eventually be deprecated).

Instead, get a reference to the ShapeDrawingOptions and make your settings there, such as:

With sf.DefaultDrawingOptions
    .FillColor = RGB(RGB_Red, RGB_Green, RGB_Blue)
    .PointSize = Size
    .PointType = tkPointSymbolType.ptSymbolStandard
    .PointShape = tkPointShapeType.ptShapeCircle
    .FillTransparency = Transparency
End With

You will find all of the same properties, and more, including LineColor, LineWidth, etc.

I’m a little confused by this statement. If you AddLayerFromFilename, and the file is a Shapefile, then you are loading shapefiles as shapefiles. So you can already do the things you say you want to do. What am I missing?

I would have to see the specific code for this to know what might have gone wrong. Perhaps it is because open_sf is an array and you need to say open_sf(i) = sf.Open(filenames(i), True)

Again, I would have to see specific code, but it appears that you are no longer having this problem. Is this correct?

Again, I apologize, but I’m not sure what you’re saying here. Because you are already adding layers to the map, setting feature symbology, and drawing the resulting map.

Regarding your posted code. Most of it looks fine. My suggestions would be:

  1. Replace the ShapeLayerPointxxx, ShapeLayerLinexxx, etc, with specific settings in the DefaultDrawingOptions, as I mentioned above. After loading each layer, do something like:

    sf = AxMap1.get_Shapefile(lHandle)
    open_sf(i) = sf

and then you can use the shapefile reference (sf) within the loop to set your drawing options.

  1. You don’t have an easy way to go back and make any changes to layers once their loaded (and perhaps they are static, and you don’t need to add/remove shapes and make any changes). Otherwise, I would set up a way to easily fetch the reference to a specific layer. Perhaps some sort of mapping between a Layer Name and the Shapefile reference, or saving individual Layer Handles for important layers.

Please feel free to clarify anything I may be overlooking, and let me know if you have other questions.

Regards,
Jerry.

I see Jerry has answered your questions. I am also using vba and sometimes the commands need a bit of changing. Here I am allowing the User to select up to 5 shapefiles to load. It may be of some help to you

’ Open shape file - lots of other code not shown here but Filename has the path to the shp file in it, the fs is Filesystemobject to check it exists
If fs.FileExists(FileName) = True Then
shp(LyrNo).Open (FileName)
Else ’ can’t find the shape file
MsgBox (FileName & " is not a valid layer")
Me(“Layer” & LyrNo) = False
Exit Sub
End If

Then set up the defaultdrawingoptions

’ Select the Shape type and assign the size
Select Case shp(LyrNo).ShapefileType
Case ShpfileType.SHP_POINT
With shp(LyrNo).DefaultDrawingOptions
.FillColor = ColorChosen
.PointType = tkPointSymbolType.ptSymbolStandard
.PointSize = 10
.PointShape = tkPointShapeType.ptShapeStar
.Visible = True
End With
hnd(LyrNo) = Forms!DisplayGisMap.Map1.AddLayer(shp(LyrNo), True)
Case ShpfileType.SHP_POLYLINE
With shp(LyrNo).DefaultDrawingOptions
.LineColor = ColorChosen
.LineWidth = 5
.Visible = True
End With
hnd(LyrNo) = Forms!DisplayGisMap.Map1.AddLayer(shp(LyrNo), True)
Case ShpfileType.SHP_POLYGON
hnd(LyrNo) = Forms!DisplayGisMap.Map1.AddLayer(shp(LyrNo), True)
’ Line color of polygon
Forms!DisplayGisMap.Map1.ShapeLayerLineColor(hnd(LyrNo)) = ColorChosen
’ Size of polygon outline
Forms!DisplayGisMap.Map1.ShapeLayerLineWidth(hnd(LyrNo)) = 2
Forms!DisplayGisMap.Map1.ShapeLayerDrawFill(hnd(LyrNo)) = False
End Select
Forms!DisplayGisMap.Map1.Redraw

Hope this helps

Hi Jerry

Thanks again for your help.

1 I think something is corrupt in my installation of MapWinGIS. I tried using sf = AxMap1.get_Shapefile(lHandle), but my version of the object browser does not show get_Shapefile.
This may be why a valid statement like open_sf = sf.Open(filenames, Null) is looking for an object.

  • Microsoft ran an upgrade to MS Access 365 this week. open_sf = sf.Open(filenames, Null) stopped working about that time. I have reinstalled MS Office 365, but no fix.
  • I am using the latest version v5.2.4-x64-VS2017.exe
  • I removed it and reinstalled it a couple times, and used Regsvr32 to make sure the components were removed between installs.
  • MapwinGIS Components do not show up in a list of MS Access VBA References, so I have to manually point to the MapWinGIS.OCX file to load the reference.
  1. I will use the ShapeDrawingOptions as you recommended.

  2. Thanks for providing the clarification between shapefiles and layers.

stu

Hello stu.

I don’t have much time to comment right now, but I do want to say (as I remember) that VB/VBA doesn’t always see the same method names as c# or c++. So you may well simply see AxMap1.Shapefile(lHandle) rather than get_Shapefile(lHandle).

Hello Jerry

I got it working!

sfOpen = sf(i).Open(filenames)

Whats different?

  • sf is now array sf(i)
  • I don’t add the argument for the callback as in sf(i).Open(filenames,Null)

Again, Thanks for the help

stu