I am editing a coverage of stream segments (lines) and would like to log any updates to a non-spatial, standalone table in the geodatabase so I can keep track of the evolution of the dataset over time. The application will first need to know which datasets to edit, so I start by adding two combo boxes to the form that will be automatically populated with the two necessary types of data, named cboFlowingWatersLayer, and cboFlowingWatersUpdateTable, respectively.
The first combo box will allow me to select any of the the spatial datasets (geodatabase coverages/feature classes/shapefiles/projected datasets/etc.) that are available in the Table of Contents pane:
Map layers in an active ArcMap project |
The second combo box will select the non-spatial, standalone table (highlighted below) that is otherwise available under the Source tab in the Table of Contents pane. There are two additional dummy tables that I added to this project that are not visible in the screenshot below, but you'll see them later.
Non-spatial tables in an ArcMap project |
Coding:
I add some code to populate the combo boxes with any available layers or standalone tables when the form activates. There's a brief Setup section, then an If/Then statement will check to see if there is a layer already set in there. If not, it'll clear it and populate the control with any spatial layers that are available. If there is anything in there, it will run a separate function to check if it's the right layer. I won't address that procedure here, so it's commented out below (though I recommend adding such a function). Let's get started with filling in the names of just the spatial datasets first:
Private Sub UserForm_Activeate()
'Setup
Dim pMxDoc As IMxDocument
Dim
pMap
As
IMap
Set pMxDoc = ThisDocument
Set
pMap = pMxDoc.FocusMap
'Populate the first combo box with any available spatial
' layers that will show up in the Display tab in the
' ArcMap Table of Contents pane
Dim
i
As
Integer
If cboFlowingWatersLayer.ListCount = 0 Then
cboFlowingWatersLayer.Clear
For i = 0 To pMap.LayerCount - 1
Me.cboFlowingWatersLayer.Additem (pMap.Layer(i).Name)
Next i
Else
'Call Me.FlowingWatersLayerCheck
End If
End Sub
What should appear when the first combo box is selected are any layers that are available the Display tab of an ArcMap project.
(Note that apps can only work with shapefiles, geodatabase coverages, etc. and not groups of data. Data groups appear in this example as individual layers, but since they are not really spatial datasets, selecting them will cause an error at run time if they are selected and processed.)
Next we'll add some more code to add any standalone tables that are in the project using the IStandaloneTableCollection interface:
Private Sub UserForm_Activeate()
'Setup
Dim pMxDoc As IMxDocument
Dim
pMap
As
IMap
Dim
pSATCollection
As
IStandaloneTableCollection
Set pMxDoc = ThisDocument
Set
pMap = pMxDoc.FocusMap
Set
pSATCollection = pMxDoc.FocusMap
'Populate the first combo box with any available spatial
' layers that will show up in the Display tab in the
' ArcMap Table of Contents pane
Dim
i
As
Integer
If cboFlowingWatersLayer.ListCount = 0 Then
cboFlowingWatersLayer.Clear
For i = 0 To pMap.LayerCount - 1
Me.cboFlowingWatersLayer.Additem (pMap.Layer(i).Name)
Next i
Else
'Call Me.FlowingWatersLayerCheck
End If
'Populate the second combo box with any available non-spatial
' tables that will show up in the Source tab in the
' ArcMap Table of Contents pane
Dim
j
As
Integer
If cboFlowingWatersUpdateTable.ListCount = 0 Then
cboFlowingWatersUpdateTable
.Clear
For j = 0 To pSATCollection.StandaloneTableCount - 1
Me.
cboFlowingWatersUpdateTable
.Additem _
(pSATCollection.StandaloneTable(j).Name)
Next j
Else
'Call Me.FlowingWatersTableCheck
End If
End Sub
Finally, this is what the second combo box will look like (with the additional two dummy datasets that were hidden from view in the screenshot above - they're named "Delete - Test 1" and "Delete - Test 2"):
Referencing the selected layer/table:
There are a virtually unlimited number of uses for mapping layers like this. The idea is that the method above provides a heads-up interface to access the position of a given layer or table in the Table of Contents. Think of the position as the dataset's number in line, starting at 0 instead of 1. Take the five spatial "layers" that are available for example:
Place in line | VB Position # | Layer Name |
1st / Top 2nd 3rd 4th 5th / Bottom | 0 1 2 3 4 | "FlowingWaters layer" "New Group Layer" "Florida NHD" "SWFWMD_draft_primary_canals" "Reporting Units" |
Whenever you need to use a specific layer, the interface we built above will allow a quick way for Visual Basic to reference the position number of a selected layer. Of course you will need some error checking and handling code to ensure that the layer position isn't changed (adding, removing, or moving the order of layers in the Table of Contents will affect each layer's position number).
The following are a few examples on how to reference a layer's position number using the interface that we built above.
Example 1 - Connect to a dataset:
A working example follows, so don't worry about the function of the code yet. This simply illustrates the structure of references needed to connect to a dataset.
The previous sections explain that an ArcMap project is made of up layers and sometimes non-spatial tables. Further, those layers and tables have position numbers associated with them that are usually just unimportant background information. Well, now we will use those position numbers to tell a program where to target its procedures.
After we choose a layer from the program interface, that combo box/pull down menu will store our selection as a number, which it refers to as its ListIndex. Now if we want to know which layer or table we chose, we'll call it by referencing cboFlowingWatersLayer.ListIndex.
In the example below, we are instantiating a new variable based off of the IFeatureLayer interface (again, don't worry about what's happening yet). We will set that new variable, named pFeatureLayer, equal to a specific layer number (position number) in an ArcMap project so we can do some more work on it later. Just pay attention to the way that the combo box position is referenced:
Dim pMxDoc As IMxDocument 'Whatever
Dim pFeatureLayer
As
IFeatureClass
'Slightly Important
'.
..more code
Set pMxDoc = ThisDocument
'Still not the point
'Oh, here we go!
Set
pFeatureLayer = _
pMxDoc.FocusMap.Layer(cboFlowingWatersLayer.ListIndex)
'.
..more code
Ok! This essentially told the function/sub routine that:
- We're working with this project (aka ThisDocument)
- We're looking for a specific feature layer (spatial dataset/shapefile/geodatabase coverage/etc.)
- That dataset of interest will be in a certain position when you focus the map; and that position number can be found by A) looking at the combo box (pull down menu named cboFlowingWatersLayer) and B) pulling its current ListIndex value.
Example 2 - Count the selected spatial features:
Add two command buttons to the form, named cboLayerCount & cboTableCount, and change their captions to match the screenshot below
Added two command buttons |
When a user clicks on one of these buttons, a message box will report how many records are selected in a layer or a table. I'll add a quick error check at the beginning to make sure that a layer has been selected. If a layer has not been selected yet, the ListIndex value will be -1. Here's the code:
Private Sub cmdLayerCount_Click()
'Error Checking
If cboFlowingWatersLayer.ListIndex = -1 Then
MsgBox "Please choose a layer to count."
Exit Sub
End If
'Setup
Dim pMxDoc As IMxDocument
Dim
pMap
As
IMap
Dim
pFS
As
IFeatureSelection
Dim
pSelectedFeatures
As
ISelectionSet
Set pMxDoc = ThisDocument
Set
pMap = pMxDoc.FocusMap
Set
pFS = pMap.Layer(cboFlowingWatersLayer.ListIndex)
Set
pSelectedFeatures = pFS.SelectionSet
'Display a message box to report info
If pSelectedFeatures.Count = 1 Then
MsgBox "There is 1 feature selected."
Else
MsgBox "There are " & pSelectedFeatures.Count & _
" features selected."
End If
End Sub
Save this, run the code, select a few features and you should get something like this:
Example 3 - Count the selected standalone table features
Using the same GUI (graphic user interface) that was built in the previous example, apply the following code to the "Table Count" command button to count the number of selected records in a standalone table. A very similar method will be used for this procedure, however we will need to use the ITableSelection inteface in place of the IFeatureSelection interface since we're working with a standalone table instead of a spatial dataset. Further, I won't need to sort through any of the selected features in the standalone table in my larger project, so I'll leave out the Selection Set and count directly from my Table Selection:
Private Sub cmdTableCount_Click()
'Error Checking
If cboFlowingWatersUpdateTable.ListIndex = -1 Then
MsgBox "Please choose a layer to count."
Exit Sub
End If
'Setup
Dim pMxDoc As IMxDocument
Dim
pSATCollection
As
IStandAloneTableCollection
Dim
pTS
As
ITableSelection
Set pMxDoc = ThisDocument
Set
pSATCollection = pMxDoc.FocusMap
'Th
is next bit must be on the a single line;
' the format of this blog makes coding difficult.
Set
pTS = pSATCollection.StandaloneTable(
cboFlowingWatersUpdateTable.ListIndex)
'Display a message box to report info
If pTS.SelectionSet.Count = 1 Then
MsgBox "There is 1 feature selected."
Else
MsgBox "There are " & pTS.SelectionSet.Count & _
" features selected."
End If
End Sub
Now, after you map a standalone table in the Flowing Waters Update Table combo box and click the Table Count command button, you will be able to count any selected records in the table, just like you would count the records in a spatial layer.