Lesson Four
GIS Programming Makes You Lazy

 

Table Of Contents

Next

Let's expand our repertoire a bit. If you are starting from this lesson. Open ArcMap, and open the VBEditor. Add a new module to the project. Go to the previous lesson, and copy the final code into the module.

If you are continuing from the previous lesson, you should already have that module open with the sub routine. Let's modify our sub routine first. Change the starting line to:

Private Sub FirstTry (ByVal value as Long)

Now the subroutine accepts a single argument of type long. If you try and run the program, VBA won't let you, because there is no way of knowing what that argument is.  Your sub routine is no longer stand alone.

Next change this line of code:

Set pLayer = pMap.Layer(value)

This passes a variable as the argument, instead of directly typing in the value.

Add a new sub routine:

Private Sub StartHere()

and then we'll call the FirstTry sub routine, passing it a value.

FirstTry 0

This calls FirstTry passing it a zero as the argument. With your cursor inside the StartHere sub, press the play button. You should get a messagebox with the layer name. To demonstrate how volatile this code is, and really how pointless it is. Change the zero to 500, and run the StartHere Sub again. You should get an error. Click Debug. This should take you to the Set pLayer line of code. Click the stop button at the top to exit Debug mode. Here is the final set up:

Private Sub StartHere()

FirstTry 0

End Sub

Private Sub FirstTry (ByVal value as Long)

Dim pMxDoc as IMxDocument

Set pMxDoc = ThisDocument

Dim pMap as IMap

Set pMap = pMxDoc.FocusMap

Dim pLayer as ILayer

Set pLayer = pMap.Layer(value)

MsgBox pLayer.Name

End Sub

That was merely an intermediary step. We'll build upon the concepts to produce something more useful. Change the FirstTry Sub argument type to a string:

Private Sub FirstTry (ByVal value as String)

And let's comment out a couple of lines of code that we won't be using in the next round. To comment a line of code place an apostrophe (') in front of the line. Comments are ignored by VBA when the program runs. They are generally used to add information about your program. I have the unfortunate habit of not commenting my code. Even though I'm usually the only person that reads it, sometimes I forget what I did...so you should get in the habit of doing it. Do what I say, not what I do.

'These lines of code are not used anymore

'Set pLayer = pMap.Layer(value)

'MsgBox pLayer.Name

The color of your commented code will turn green. Declare a new variable called i of type Long, and give it a value of zero

Dim i as Long

i = 0

And now we're going to use a for...next loop. We want to be able to loop through all the layers in a Data Frame. We don't want an endless loop, so we need to find out how many layers there are in the Data Frame. Remember our Data Frame is a FocusMap which is a type of IMap. Let's look at the IMap Members page. There is a property that returns the LayerCount, which returns a type of Long. We have two options, either set a variable to the LayerCount, or use the LayerCount directly. Since, we only will use LayerCount once in our code, let's use it directly.

For i = 0 to pMap.LayerCount

Next

For i equals zero to the value returned by pMap.LayerCount, default is one step at a time. What's wrong with this picture? Well, LayerCount counts the layers. If the Data Frame only had one layer, then the count would be 1. But to retrieve the first layer you need the number zero. This means that i will always be one less than the number of layers. So we need to modify our code a little bit.

For i = 0 to pMap.LayerCount - 1

Next

Now we will stop our loop at the right point.  For i equals zero to the value returned by LayerCount minus 1. For each step in the loop we want to retrieve the corresponding layer. We'll need to set the layer object to the current layer we are on.

Set pLayer = pMap.Layer(i)

With this code you are cycling through the layers in the Data Frame setting the pLayer variable to the current step. If i is zero then you set the layer to the first layer. If i is one then you set the layer to the second layer, and so on.

That's all well and good, but it doesn't really do much. We want to compare the name of the layer to the input string. To do this we write a conditional.

If pLayer.Name = value Then

End If

If the current layer name is equal to the input string (the argument of FirstTry) then do something. Let's modify this a bit to compensate for case sensitivity. What do I mean by case sensitivity? When you compare to strings, VBA looks to see if they are exactly the same. That means "test" is not equal to "TeSt". There is a handy little built-in function in VBA called UCase(). This function (remember a function returns a value) returns the input string in all upper case letters.

If Ucase(pLayer.Name) = Ucase(value) Then

End If

By doing it this way, you are creating a temporary string for the name and the input, and not actually changing these values. Which is what we want, we don't want to change the values. Now to do something with this.

If Ucase(pLayer.Name) = Ucase(value) Then

Msgbox "Layer Index:   " & i

Exit For

End If

If the Layer Name is the same as the input string, then display a messagebox with the string "Layer Index:   " and the current value of the variable i. Exit For is a command that tells VBA to stop the for..next loop. We've found what we are looking for, there is no need to continue looping. The ampersand (&, shift 7) is used to concatenate strings. What!?! Concatenate is a big word that means join. In this case, you are joining two strings together. It would be confusing to someone who didn't write this code and a messagebox showing a number popped up, so thats why we added the description string at the start.

Again, that really isn't useful. Who cares what the layer index is? Let's add another line to actually perform an action.

If Ucase(pLayer.Name) = Ucase(value) Then

Msgbox "Layer Index: " & i

pLayer.Visible = False

Exit For

End If

We've found the layer, and using the Visible property of the layer, we've turned it off. Visible is a boolean type. Boolean types, if you remember, accept the value of True or False. In this case True means on, and False means off. If you want to know more, check out the ILayer Members page.  

There are two lines of code that need to execute after you exit the for..next loop, and before you end the sub routine.

pMxDoc.UpdateContents

pMxDoc.ActiveView.Refresh 


UpdateContents is a member of IMxDocument and is a Method that refreshes the table of contents so that the changes you make are visible.  The second line calls up the ActiveView which is the current view (either a Data View or Page Layout View) and the refresh method refreshes that view.  These two commands refresh you table of contents and activeview so that you can see the changes.

You're not done yet! You need to change the StartHere sub routine so that it passes the name of the layer, instead of the index. Pick a layer name from the files you've loaded and change the zero to that name. Don't forget to use quotes!

"States" or "Layer Name" etc...

Here is the final code:

Private Sub StartHere()

FirstTry "Your Layer's Name"

End Sub

Private Sub FirstTry (ByVal value as String)

Dim pMxDoc as IMxDocument

Set pMxDoc = ThisDocument

Dim pMap as IMap

Set pMap = pMxDoc.FocusMap

Dim pLayer as ILayer

'These lines of code are not used anymore

'Set pLayer = pMap.Layer(value)

'MsgBox pLayer.Name

For i = 0 to pMap.LayerCount - 1

Set pLayer = pMap.Layer(i)

If Ucase(pLayer.Name) = Ucase(value) Then

Msgbox "Layer Index: " & i

pLayer.Visible = False

Exit For

End If

Next

pMxDoc.UpdateContents

pMxDoc.ActiveView.Refresh 

End Sub

 Yours should look something like this (in this case I put the UpdateContents, and Refresh within the for loop before it exits.  Either location works fine):

 

Now run it. Hopefully it works :).

Before you go onto the next lesson, first try this - Remove the minus one (- 1) from the for...next loop, and comment out the Exit For statement.

For i = 0 to pMap.LayerCount

Set pLayer = pMap.Layer(i) 

If Ucase(pLayer.Name) = Ucase(value) Then

Msgbox "Layer Index: " & i

pLayer.Visible = False

'Exit For

End If

Next

Now run the program again. You should get an error. Press the Debug button. It should take you to the line that's the problem. This is helpful, because you might forget to add this bit of code.

 

Hopefully the added complexity wasn't too big of a jump. In this lesson I added an extra sub routine, and looping. You should be proud of yourself, because now you can loop through all the layers in the table of contents.  This is a surprisingly powerful few lines of code.  Please leave comments on the blog if there are problems.