Adding labels in vba to polygon layer + point types not working

Hi - I am trying to use MapWinGIS to replace MapObjects. I am slowly moving through it but seem to be going circles on some things. I would appreciate being pointed in the right direction. I add a polygon layer of land parcels and want to add the erf numbers as labels. The shape file is huge and I get it to work using shpLandParcels.GenerateLabels - however it takes a very long time. I then thought I would try and only look up the polygons that are in the current extent. I have managed to use SelectShapes and loop through all the returned shapes and then use shpLandParcels.Labels.AddLabel to add labels to just the currently displayed shapes. Is this the correct way to do it?. Is there another way to do labels - In mapobjects you can make them a layer that gets added? I can only get the correct extent with the SelectBoxFinal. I want to rather get the extent of the current map display. It looks like this should be extents = Map1.extents but it does not seem to be working.
Point Type - Map1.ShapeLayerPointType(hndSchools) = MapWinGIS.tkPointType.ptCircle - This just puts the default square shape no matter what point type I choose
Any help will be greatly appreciated
Colleen

Hello Colleen.

Regarding the labeling, I want to make sure I understand the details. If it is a static layer, you should be able to GenerateLabels once up front. Even if that operation takes a little while (how many shapes are there?), you pay the price once, and then the label rendering itself should be pretty fast after that. This is the preferred way to go, rather than you having to manage the current extent. Even if you do some editing, you can then just refresh that single label without having to regenerate labels for the entire layer.

Regarding the points, here’s a small snippet (in VB)

        Dim utils As New Utils()
        With sf.DefaultDrawingOptions
            .FillColor = utils.ColorByName(tkMapColor.Red)
            .PointType = tkPointSymbolType.ptSymbolStandard
            .PointSize = 10
            .PointShape = tkPointShapeType.ptShapeCircle
            .Visible = True
        End With

That results in the following:

image

You can also use the helper routine that combines a few of the settings for you, as follows:

        Dim utils As New Utils()
        With sf.DefaultDrawingOptions
            .FillColor = utils.ColorByName(tkMapColor.Red)
            .SetDefaultPointSymbol(tkDefaultPointSymbol.dpsStar)
            .PointSize = 10
        End With

which results in the following:

image

Hope that helps. Please let me know if there’s more to the story I don’t understand, regarding the labels.

Regards,
Jerry.

Hi

Thanks for your reply. Points now work perfectly.

I have an Accident Suite application that records every accident in our municipality with loads of info about the accident. This is stored on an SQL database. Every accident is linked to a Location that has x/y coords. The data coders use the map to try and find out info about the accident scene and may search to a particular erf, road, school etc and then zoom in with the aerial photo to determine the layout and find the correct Location to link the accidents to. The land parcels layer is added and removed as required (along with other layers). Normally the user would zoom into a road and then add the land parcels and show the erf numbers so they can identify a property, It has over 500 000 records. I don’t think there is ever a time when they need all the erf numbers and I only allow them to add them when they are sufficiently zoomed in. If I use Map1.Extents - it seems to be using an extent different to what I can see. I would like to know how to do this for further actions that I am going to have to do.
I still have a long way to go. I will need to find out how to do value renderers eg when I show the accident spots on the map, I show red for highest level of acc as Fatal, orange for serious, yellow for slight and blue for no injury. I also need to show charts showing the injuries at the Locations. The shape file just has the Location info in it and then I relate to the sql database that has all the accident information. The user is able to select whatever dates are required and the data is extracted to create the charts. (ie it is not stored on the shape file but rather on our sql database that is changing daily)
I am slowly going through all the options that I need to recreate and hoping that MapWinGIS will be able to do all that we could in MapObjects. I have also looked at SharpMap and we are looking at an ESRI option, but I would prefer to stick with MapWInGis as I can add it to an Access Form.

Regards

Colleen

Hello Colleen.

I understand what you’re going through. I grew up on MapObjects, and my first experience with MapWinGIS was to convert a VB6 map application from MapObjects to MapWinGIS. There were many things I liked about MapObjects, some even better than ESRI’s replacement, ArcGIS Objects.

There are adjustments in a number of the concepts, such as Renderers, as there is no such thing in MapWinGIS. Instead each layer has it’s own rendering attributes (DefaultDrawingOptions). For further detail (such as for so-called ‘unique value rendering’) you can set up Shapefile Categories, each of which is triggered by internal attributes (an Expression, such as [acc] = Fatal) and has it’s own DrawingOptions.

As far as the labeling is concerned, I found a couple layers here with about 200K shapes (not as big as yours) but for which a simple GenerateLabels call and the associated redraw (of the full map) was under 10 seconds. I still think your best bet is to load the layer once, up front, then just manage visibility on an as-need basis, rather than reloading on an as-need basis. This can be done either by toggling visibility manually or by setting a minimum visibility scale (or zoom level) in which the map doesn’t show the layer until the user zooms in to a certain level. Note that you can even load the layer and generate labels invisibly.

That said, I acknowledge that I may not understand all of your conditions, and it may make the most sense to custom render your labels based on the current extent. But even if you do it that way, you should still just load the layer once up front, and control visibility and labeling on-the-fly.

The Map.Extents property should show the current extents. I would consider reviewing the values returned within the Extents (the Top, Bottom, Left, and Right) and see if they’re perhaps in a Map Scale or coordinate system that differs from what you’re expecting (such as UTM vs DMS).

Regards,
Jerry

Thanks, interesting to know that you have a MapObjects background. Could you advise if you think I am on the right track with MapWinGis - should I be able to find a way of replicating most functions of MapObjects.

Regards

Colleen Crawford

Hello Colleen.

I certainly think that MapWinGIS is a viable option (although I admit that there aren’t many OCX map options out there). I’ve used it not only to replace a MapObjects implementation, but ArcObjects products as well. And I’ve gotten involved in the project in the effort to make it better (initially to meet certain capabilities that were required when converting from ESRI, such as individual point rotation based on fields in the database).

I think ESRI has always been strong on labeling, even more so in their newer products, although it does come at a cost in terms of processing time. MapWinGIS may not be as strong on labeling, for example, in terms of relocating a label on-the-fly in order to avoid a conflict, but the engine is fast, and has enough flexibility to produce reasonable results.

The display and rendering are more presentable (more in line with the newer ESRI products) since MapWinGIS uses GDI+, as compared to MapObjects using the older GDI library. This results, among other things, in smoother font rendering, and being able to use PNG images for point features.

The biggest adjustment is simply in the way things get done. The API and object model are just different, and so it’s just a matter of figuring out how to do something in the new world. But you have the support forum here, and there’s the benefit, when it becomes necessary, of having access to the source code.

So I’ve been satisfied with the results, and I think you will find it a capable tool, particularly as you spend more time with it, and learn how best to use it.

I hope this helps.

Kind Regards,
Jerry.

Thanks for the helpful feedback. You are right about the huge learning curve and having to change the way I think.
I am at the moment trying to do what was an AddRelate in Mapobjects ie I am trying to add data to the Locations shape file to use when displaying the different colour dots for highest level of accident.
I assumed here that I would have to create an in memory shape file from the Location shapefile and then add the extra fields and add values to these fields and then use this shape file with categories to add different coloured points to the Map. I started by looping through all shapes in the shapefile and getting the LocationCode field then reading this data off the sql database for the Location and adding the data to the new fields. This was very slow, so I thought it would be better to read through the sql database and from this use the LocationCode to try and find the shape that has this LocationCode and then change the new field values. I cannot find a way to search to a shape using an attribute field. Or maybe I should be doing this totally differently as I can link x/y coords to the accident data from the SQL database. I thought I could read through the sql database, create a new in memory shapefile and create new shapes using the x/y coords.

Regards

Colleen Crawford

Hello Colleen.

I have some thoughts about your issue, but to hopefully get you going, here’s a quick snippet for doing a table query.

Dim whereClause As String = "[FIELD] = value"
' results will come back as an Array of Integers
Dim results As Object = Nothing, err As String
If pShapefile.Table.Query(whereClause, results, err) Then
    ' iterate shape indexes
    For i As Integer = 0 To UBound(results)
        ' you can either do something with the Shape
        Dim pShape As Shape = pShapefile.Shape(results(i)))
        '' or do something with the values in the Shapefile
        pShapefile.EditCellValue(pShapefile.FieldIndexByName("fieldName"), results(i), newValue)
    Next
End If

Regards,
Jerry

Thank you for this. I have created an in memory shape file by using the x/y coords off the SQL database but I will try this approach as well to see which is faster. I am obviously not understanding something about in memory shape files as my code creates the shape but none of the data fields have any data in them. I followed the examples and think it should work. I assume I don’t have to save the in memory shapefile to use it. I don’t need to save it to the disk as it will keep changing depending on the user inpur. I have added the code that I am using

' Create new in memory shapefile with point shape
If shpAccidents.CreateNewWithShapeID("", ShpfileType.SHP_POINT) = False Then
    MsgBox "Cannot create accidents shape file"
    Exit Sub
End If

Dim i As Long
Dim index As Long
Dim NoOfFields As Long
Dim intNoOfAccs As Long
Dim intFatal As Long
Dim intSerious As Long
Dim intSlight As Long
Dim intNoOfPeds As Long
Dim intNoOfVehs As Long
Dim intLevelOfAcc As Long
Dim intLocntype As Long
Dim intLocnCode As Long
Dim pnt As New Point

i = 0
shpAccidents.GeoProjection = shpOpEntity.GeoProjection.Clone
shpAccidents.StartEditingShapes
shpAccidents.StartEditingTable
' Add the extra data field required
intNoOfAccs = shpAccidents.EditAddField("NoOfAccs", INTEGER_FIELD, 0, 5)
intFatal = shpAccidents.EditAddField("Fatal", INTEGER_FIELD, 0, 5)
intSerious = shpAccidents.EditAddField("Serious", INTEGER_FIELD, 0, 5)
intSlight = shpAccidents.EditAddField("Slight", INTEGER_FIELD, 0, 5)
intNoOfPeds = shpAccidents.EditAddField("Peds", INTEGER_FIELD, 0, 5)
intNoOfVehs = shpAccidents.EditAddField("Vehs", INTEGER_FIELD, 0, 5)
intLevelOfAcc = shpAccidents.EditAddField("LevelAcc", INTEGER_FIELD, 0, 5)
intLocnStruct = shpAccidents.EditAddField("LocnStruct", STRING_FIELD, 0, 1)
' Read through the Accident sql table to get data to load into shape file
Do While Not rs.EOF
    ' If no x/y coords filled in ignore
    If GetLen(rs!x_Coord) = 0 And GetLen(rs!y_Coord) = 0 Then
        GoTo ReadNext
    End If
    ' Have to create a new shape for each record
    Set shp = New MapWinGIS.Shape
    ' Set up a new point using the x/y coords
    pnt.x = rs!x_Coord
    pnt.y = rs!y_Coord
    ' Create the point shape and add to the memory shapefile
    index = shp.Create(ShpfileType.SHP_POINT)
    index = shp.AddPoint(pnt.x, pnt.y)
    index = shpAccidents.EditAddShape(shp)
    ' Move data into the data fields
    shpAccidents.EditCellValue intNoOfAccs, i, rs!NoOfAccs
    shpAccidents.EditCellValue intFatal, i, rs!Fatalities
    shpAccidents.EditCellValue intSerious, i, rs!SeriousInjuries
    shpAccidents.EditCellValue intSlight, i, rs!SlightInjuries
    shpAccidents.EditCellValue intNoOfPeds, i, rs!NoOfPeds
    shpAccidents.EditCellValue intNoOfVehs, i, rs!NoOfVehicles
    shpAccidents.EditCellValue intLevelOfAcc, i, rs!HighestLevelOfAcc
    shpAccidents.EditCellValue intLocnStruct, i, rs!LocationStructure
    i = i + 1

ReadNext:
'******
rs.MoveNext
Loop
shpAccidents.StopEditingShapes
shpAccidents.StopEditingTable
rs.Close
db.Close

To try and view the data I used the CellValue as follows
For i = 0 To shpAccidents.NumShapes
val1 = shpAccidents.CellValue(1, i)
Next
Field Index 1 should have the NoOfAccs in it but the field is blank, I tried fieldindex 2 etc all blank. It is strange as the shapes are there as I can load the points but no data and I need the data to do the ShapeCategories correctly.

Thank you for any help you can give me

Regards

Colleen Crawford

Hello Colleen.

It’s late for me here, but at first glance, here is what I would try.

  1. I don’t think I would call StartEditingShapes until after the new fields are added, but of course, before the Do While loop.
  2. You do not need to call both StartEditShapes and StartEditingTable, as the table edit is included by default in the Shapefile edit (note the first parameter, which defaults to True).
  3. I would not rely on your incrementing variable i that you are using to manage the Shape Index. Instead, trust the value of index which is returned from EditAddShape. That will be a reliable value to use in each of your EditCellValue calls.
  4. After the Loop, just call StopEditingShapes (do not call StopEditingTable).
  5. As I think you stated, you do not need to save to disk in order to see the values.
  6. All indexes are zero-based, not 1-based. If you check your value for intNoOfAccs, it is likely zero. This doesn’t explain why the values were all blank. Hopefully it is resolved by some of these other changes.

See if any of this changes the behavior. And please post the updated code, and I will look further tomorrow.

Regards,
Jerry.

Hi Jerry

I have done the changes - please see code below - but still the attribute fields are not being updated. I can see when I debug that there are values in the SQL recordset, but the shapefile is not getting updated. The only thing being updated is the shape. I also saved the shape file to the disk and all the shape values are there but no attributes. I am at a loss. I also tried your method and it produces the same results but seems to run slower. The value for the 0 field index is the shape and comes back as 1, 2, etc but other fields are blank. I did see that there is a join function on the table. I was looking for a way to create an in memory table and then join it by the key field LocationCode to the shape file. I am busy looking at this still as I am not sure if you can create an in memory table and then join this to a shape file.

' Create new in memory shapefile with point shape
If shpAccidents.CreateNewWithShapeID("", ShpfileType.SHP_POINT) = False Then
    MsgBox "Cannot create accidents shape file"
    Exit Sub
End If

Dim i As Long
Dim NoOfFields As Long
Dim intNoOfAccs As Long
Dim intFatal As Long
Dim intSerious As Long
Dim intSlight As Long
Dim intNoOfPeds As Long
Dim intNoOfVehs As Long
Dim intLevelOfAcc As Long
Dim intLocnStruct As String
Dim pnt As New Point

shpAccidents.GeoProjection = shpOpEntity.GeoProjection.Clone
' Add the extra data field required
intNoOfAccs = shpAccidents.EditAddField("NoOfAccs", INTEGER_FIELD, 0, 5)
intFatal = shpAccidents.EditAddField("Fatal", INTEGER_FIELD, 0, 5)
intSerious = shpAccidents.EditAddField("Serious", INTEGER_FIELD, 0, 5)
intSlight = shpAccidents.EditAddField("Slight", INTEGER_FIELD, 0, 5)
intNoOfPeds = shpAccidents.EditAddField("Peds", INTEGER_FIELD, 0, 5)
intNoOfVehs = shpAccidents.EditAddField("Vehs", INTEGER_FIELD, 0, 5)
intLevelOfAcc = shpAccidents.EditAddField("LevelAcc", INTEGER_FIELD, 0, 5)
intLocnStruct = shpAccidents.EditAddField("LocnStruct", STRING_FIELD, 0, 1)
shpAccidents.StartEditingShapes
' Read through the Accident sql table to get data to load into shape file
Do While Not rs.EOF
    ' If no x/y coords filled in ignore
    If GetLen(rs!x_Coord) = 0 And GetLen(rs!y_Coord) = 0 Then
        GoTo ReadNext
    End If
    ' Have to create a new shape for each record
    Set shp = New MapWinGIS.Shape
    ' Set up a new point using the x/y coords
    pnt.x = rs!x_Coord
    pnt.y = rs!y_Coord
    ' Create the point shape and add to the memory shapefile
    shp.Create (ShpfileType.SHP_POINT)
    shp.AddPoint pnt.x, pnt.y
    i = shpAccidents.EditAddShape(shp)
    ' Move data into the data fields
    shpAccidents.EditCellValue intNoOfAccs, i, CInt(rs!NoOfAccs)
    shpAccidents.EditCellValue intFatal, i, CInt(rs!Fatalities)
    shpAccidents.EditCellValue intSerious, i, CInt(rs!SeriousInjuries)
    shpAccidents.EditCellValue intSlight, i, CInt(rs!SlightInjuries)
    shpAccidents.EditCellValue intNoOfPeds, i, CInt(rs!NoOfPeds)
    shpAccidents.EditCellValue intNoOfVehs, i, CInt(rs!NoOfVehicles)
    shpAccidents.EditCellValue intLevelOfAcc, i, CInt(rs!HighestLevelOfAcc)
    shpAccidents.EditCellValue intLocnStruct, i, rs!LocationStructure

ReadNext:
'******
rs.MoveNext
Loop
shpAccidents.StopEditingShapes
rs.Close
db.Close
End If

shpAccidents.Table.SaveAs “D:\Test1.dbf”

Regards

Colleen Crawford

Hello again.

So I copied and slightly modified your code, just for testing. The code is below, along with a screenshot, and it displays the contents of the fields. (the code is in VB NET, but is essentially the same). The only real difference is that I have faked the data, and there’s only 1 row. Some things to consider

  1. Are you sure that you’re not overflowing any of the fields?
  2. Can you set up the global error callback and watch for errors/warnings (see the code at the top of ButtonTest_Click)?
  3. Extract the values into a local variable first (e.g. val1 = CInt(rs!NoOfAccs)) to verify the value, then place into the cell.
  4. Try bailing out after 1 row as a simple test.
  5. These are just random thoughts just to narrow down the problem…

Private Sub ButtonTest_Click(sender As Object, e As EventArgs) Handles ButtonTest.Click
    ' global callback
    Dim gs As New GlobalSettings
    gs.ApplicationCallback = Me

    ' Create new in memory shapefile with point shape
    Dim shpAccidents As New Shapefile
    If shpAccidents.CreateNewWithShapeID("", ShpfileType.SHP_POINT) = False Then
        MsgBox("Cannot create accidents shape file")
        Exit Sub
    End If

    Dim i As Long
    Dim intNoOfAccs As Long
    Dim intFatal As Long
    Dim intSerious As Long
    Dim intSlight As Long
    Dim intNoOfPeds As Long
    Dim intNoOfVehs As Long
    Dim intLevelOfAcc As Long
    Dim intLocnStruct As String
    Dim shp As New Shape
    Dim pnt As New Point

    shpAccidents.GeoProjection.SetWgs84()
    ' Add the extra data field required
    intNoOfAccs = shpAccidents.EditAddField("NoOfAccs", FieldType.INTEGER_FIELD, 0, 5)
    intFatal = shpAccidents.EditAddField("Fatal", FieldType.INTEGER_FIELD, 0, 5)
    intSerious = shpAccidents.EditAddField("Serious", FieldType.INTEGER_FIELD, 0, 5)
    intSlight = shpAccidents.EditAddField("Slight", FieldType.INTEGER_FIELD, 0, 5)
    intNoOfPeds = shpAccidents.EditAddField("Peds", FieldType.INTEGER_FIELD, 0, 5)
    intNoOfVehs = shpAccidents.EditAddField("Vehs", FieldType.INTEGER_FIELD, 0, 5)
    intLevelOfAcc = shpAccidents.EditAddField("LevelAcc", FieldType.INTEGER_FIELD, 0, 5)
    intLocnStruct = shpAccidents.EditAddField("LocnStruct", FieldType.STRING_FIELD, 0, 1)
    shpAccidents.StartEditingShapes
    ' Read through the Accident sql table to get data to load into shape file
    Dim looping As Boolean = True
    Do While looping
        ' Have to create a new shape for each record
        shp = New MapWinGIS.Shape
        ' Set up a new point using the x/y coords
        pnt.x = -117
        pnt.y = 47
        ' Create the point shape and add to the memory shapefile
        shp.Create(ShpfileType.SHP_POINT)
        shp.AddPoint(pnt.x, pnt.y)
        i = shpAccidents.EditAddShape(shp)
        ' Move data into the data fields
        shpAccidents.EditCellValue(intNoOfAccs, i, 100)
        shpAccidents.EditCellValue(intFatal, i, 10)
        shpAccidents.EditCellValue(intSerious, i, 20)
        shpAccidents.EditCellValue(intSlight, i, 30)
        shpAccidents.EditCellValue(intNoOfPeds, i, 10)
        shpAccidents.EditCellValue(intNoOfVehs, i, 40)
        shpAccidents.EditCellValue(intLevelOfAcc, i, 50)
        shpAccidents.EditCellValue(intLocnStruct, i, "L")

        looping = False
    Loop
    shpAccidents.StopEditingShapes()

    AxMap1.AddLayer(shpAccidents, True)

End Sub

Private Sub ButtonTest2_Click(sender As Object, e As EventArgs) Handles ButtonTest2.Click
    Dim s As String = ""
    Dim sf As Shapefile = AxMap1.get_Shapefile(0)
    With sf
        For i As Integer = 0 To .NumShapes - 1
            For j As Integer = 0 To .NumFields - 1
                Dim value As String = .CellValue(j, i).ToString()
                s = s & .Table.Field(j).Name + ": " & value & vbCrLf
            Next
        Next
        MsgBox(s)
    End With
End Sub

Let me know if you discover anything.

Regards,
Jerry.

Hi

Thanks so much for your help. I did as you said.

  1. I checked, the maximum value in any of the integer fields was 378
  2. I tried this but get an error ‘Type Mismatch’ even though vba recognizes Me
  3. I tried a couple of things so will tell you all of them. I did 1 row with figures filled in as you did - this worked. Then I created variables and moved the values in here first and then used the variable in EditCellValue - this worked. Then I tried to move the result into a boolean value eg bool = shpAccidents.EditCellValue(intNoOfAccs, i, CInt(rs!NoOfAccs)) - I used the recordset value here and this worked as well. However, if I take out the CInt it does not work. So it is just when you use the recordset value and don’t put bool = and Cint around the value. I am not quite sure why

It takes a long time to load about 16 000 shapes - do you think it would be helpful to look at the Join to join an in memory table (if that is possible) to an existing shape file with the Location points. I am not sure if I am understanding the Join correctly.

Regards

Colleen Crawford

Hello again.

Using the exclamation point to get the value (rs!NoOfAccs) may have a different behavior than explicitly getting the value (rs.Fields(“NoOfAccs”).Value), having to do with a fields ‘default value’. It would be interesting to try this other syntax, and then you may not have to use the CInt() (although it doesn’t hurt).

I wonder whether you may benefit from modifying your database to include the Geometry data. I did this on a recent project, rather than moving data into a Shapefile, I ran a one-time update to add the Geometry field, create the points using the existing X and Y, and then reading the database as an OGR datasource. It was significantly faster, and I didn’t have to keep data synchronized; it was always up-to-date. This is a little bit more of an undertaking, and I don’t know your timeframe for development, but I think it is worth consideration.

Regards,
Jerry.

Hi

Thanks for your input. I managed to add the geometry field and updated from the x/y coords and it does load much faster.My problem is that I cannot find a way to apply the ShapeCategories to this layer. I first used AddLayerFromDatabase but this loads the points before I can do categories, so I did it in steps

bool = lyr.OpenFromQuery(ConnStr, strSQL)

Set shpAccidents = lyr.GetBuffer()

I thought I could use this shapefile to apply the categories to and then load it as a normal shape file, but that does not seem to work.
When I read the help info it does not seem as if ShapeCategory and ShapeCategories can be applied to an OgrLayer. Am I on the correct track moving it to a shape file first?

Regards

Colleen Crawford







Set lyr = Map1.OgrLayer(hndAccidents)
Set shpAccidents = lyr.GetBuffer()

Hello.

I think you’re generally on the right track in what you’re doing. You want to do the GetBuffer to get the Shapefile wrapper, and add/apply your Categories there.

And It should work either way; whether you OpenFromQuery, then GetBuffer, OR even if you added it to the map (with default rendering), then GetBuffer, THEN add and Apply your categories. BUT I think you should be loading the the OGR layer into the map, not the Shapefile; and just use the Shapefile reference for your Categories.

I just checked my notes from a previous implementation, and there was one thing that might be a problem (and I don’t know if this was specifically a SQL Server issue or something else). After first calling OpenFromQuery, I noticed that the ActiveShapeType was NULL, and so the code didn’t know what to do. It turned out that the AvailableShapeTypes collection held the Shape type, but somehow it never made it into the ActiveShapeType setting. So I added something like the following code sequence:

    If pOgrLayer.OpenFromQuery(ogrConnectionString, sqlQuery) Then
        ' if ActiveShapeType is NULL, try setting it from the AvailableShapeTypes collection
        If pOgrLayer.ActiveShapeType = ShpfileType.SHP_NULLSHAPE AndAlso UBound(pOgrLayer.AvailableShapeTypes) >= 0 Then
            pOgrLayer.ActiveShapeType = pOgrLayer.AvailableShapeTypes(0)
        End If
        . . .
    End If

See if this is the case for you, and if setting the ActiveShapeType then allows you to proceed with successful Categories. If not, then we’ll have to dig deeper. Please repost your updated code if there are still issues. Thanks.

Regards,
Jerry.

Hi

I eventually have it working and it is so much quicker. I had to do quite a bit in SQL as it does not allow any GROUP BY on views with a shape in. I created a temp file of accident details totalled for each Location using a stored procedure so I could have parameters eg Date Range and then created a view that joins this table to the Location table that has the shape. I also got the categories to work on the shape file. Thanks for your help. Here is my code

Dim gs As New GlobalSettings
ConnStr = “MSSQL:server=” & TempVars(“ServerName”).Value & “;DATABASE=” & CurrentDatabaseName & _
“;UID=” & AccSuiteUpdateUserName & “;PWD=” & AccSuitePasswrd
Dim lyr As New OgrLayer
’ Adds an Ogr Layer from database
hndAccidents = Map1.AddLayerFromDatabase(ConnStr, strSQL, True)
If hndAccidents = -1 Then
MsgBox ("Failed to open layer: " + Map1.FileManager.ErrorMsg(Map1.FileManager.LastErrorCode))
’ in case the reason of failure is still unclear, get GDAL details
MsgBox ("Last GDAL error: " + gs.GdalLastErrorMsg)
Exit Sub
End If
’ Move the Layer to a Shape file so you can use Shapefile Categories
Set lyr = Map1.OgrLayer(hndAccidents)
Set shpAccidents = lyr.GetBuffer()

Dim utils As New MapWinGIS.utils

Dim catFatal As ShapefileCategory
Set catFatal = shpAccidents.Categories.Add(“Fatal”)
catFatal.Expression = “[LevelOfAcc] = 1”
Dim sdFatal As ShapeDrawingOptions
Set sdFatal = catFatal.DrawingOptions
With sdFatal
.FillColor = utils.ColorByName(tkMapColor.Red)
.PointShape = tkPointShapeType.ptShapeCircle
.PointSize = 10
If Me!AllAccs = True Or Me!FatalAccs = True Then
.Visible = True
Else
.Visible = False
End If
End With

Dim catSerious As ShapefileCategory
Set catSerious = shpAccidents.Categories.Add(“Serious”)
catSerious.Expression = “[LevelOfAcc] = 2”
Dim sdSerious As ShapeDrawingOptions
Set sdSerious = catSerious.DrawingOptions
With sdSerious
.FillColor = utils.ColorByName(tkMapColor.Orange)
.PointShape = tkPointShapeType.ptShapeCircle
.PointSize = 10
If Me!AllAccs = True Or Me!SeriousAccs = True Then
.Visible = True
Else
.Visible = False
End If
End With

Dim catSlight As ShapefileCategory
Set catSlight = shpAccidents.Categories.Add(“Slight”)
catSlight.Expression = “[LevelOfAcc] = 3”
Dim sdSlight As ShapeDrawingOptions
Set sdSlight = catSlight.DrawingOptions
With sdSlight
.FillColor = utils.ColorByName(tkMapColor.Yellow)
.PointShape = tkPointShapeType.ptShapeCircle
.PointSize = 10
If Me!AllAccs = True Or Me!SlightAccs = True Then
.Visible = True
Else
.Visible = False
End If
End With

Dim catNoInjury As ShapefileCategory
Set catNoInjury = shpAccidents.Categories.Add(“NoInjury”)
catNoInjury.Expression = “[LevelOfAcc] = 4”
Dim sdNoInjury As ShapeDrawingOptions
Set sdNoInjury = catNoInjury.DrawingOptions
With sdNoInjury
.FillColor = utils.ColorByName(tkMapColor.Blue)
.PointShape = tkPointShapeType.ptShapeCircle
.PointSize = 10
If Me!AllAccs = True Or Me!NoInjuryAccs = True Then
.Visible = True
Else
.Visible = False
End If
End With

shpAccidents.Categories.ApplyExpressions

Map1.Redraw

Regards

Colleen Crawford

Very good. I’m impressed with how quickly you’re making headway.

I’m curious about your .Visible settings based on the AllAccs Or NoInjuryAccs, et.al.
These flags are not part of your Category, and so the visibility may not behave as expected. Unless you reset the .Visible property and call ApplyExpressions any time one of these flags changes.

Regards,
Jerry.

Hi

I’m getting there slowly but surely. Still lots of difficult things to do. - charts of injuries, accidents on sections of roads, identify, aerial photo etc
The select categories is actually in a different procedure and I only call that procedure when they click on eg fatal or serious etc. It seems to be working fine as I don’t redo the layer at all.

Regards

Colleen