Solution - Novice Challenge 6: How Animated Am I?
For the first five challenges we sort of eased you into all the Visual Basic for Applications (VBA) stuff. This is, after all, the Novice division, so these challenges aren’t supposed to be too hard. But after easing beyond the halfway point, it was time to make things a little more, well, challenging, here in Challenge number 6.
In this challenge you needed to work with several different aspects of Microsoft Office PowerPoint. You had to work with shapes, animations, new slides, all sorts of different things. And we’d have to say that we’re pretty impressed with how well people did on this. (No, it doesn’t take a lot to impress us, but you should feel proud of yourselves anyway.)
Here’s the solution we came up with:
Sub getAnimations()
Dim s As Slide
Dim sh As Shape
Dim sObjs As Shapes
Dim str As String
Dim intSlides As Integer
Dim i As Integer
Dim j As Integer
' Set counters
i = 1
j = 0
'Find out how many slides there are
intSlides = ActivePresentation.Slides.Count
'Add a new slide to the end of the deck with a new shape
Set sObjs = _
ActivePresentation.Slides.Add((intSlides + 1), ppLayoutText).Shapes
'Add a title to the new slide
sObjs.Title.TextFrame.TextRange.Text = "Animated Shapes Per Slide"
'Cycle through the slides one at a time
For Each s In ActivePresentation.Slides
'Make sure we're not at the last slide
If i <= intSlides Then
'Cycle through all the shapes on the slide
For Each sh In s.Shapes
'If there's an animation effect, increment the counter
If sh.AnimationSettings.TextLevelEffect <> ppAnimateLevelNone Then
j = j + 1
End If
Next
'Build a string the has the slide number plus
' the number of animations on each slide
str = str & "Slide " & i & " has " & j & " animated shapes." & vbNewLine
i = i + 1
End If
j = 0
Next
'Add the string to the Text shape on the last slide
sObjs.Placeholders(2).TextFrame.TextRange.Text = str
End Sub
We start off by declaring a bunch of variables we’ll be using throughout the subroutine and then initializing some counter variables. Next, because we need to go through and look at each slide, we retrieve the Count property of the Slides object to find out how many slides there are:
intSlides = ActivePresentation.Slides.Count
Part of the challenge is to list the results on a new slide. Now that we have the number of slides in the original slide show, we can add one new slide. We do that by calling the Add method:
Set sObjs = _
ActivePresentation.Slides.Add((intSlides + 1), ppLayoutText).Shapes
Notice that we pass the number of slides (intSlides) plus 1 to the Add method. This number represents the position in the presentation where we want to add the new slide. We’re adding to the end of the presentation, so the position would be the number of slides in the original plus 1. We also passed a second parameter to the Add method, ppLayoutText. This parameter specifies the layout of the slide. We want a standard text layout, which will include a title and a text box.
And speaking of the title and text box, notice how, following the call to the Add method we tack on the .Shapes property:
Set sObjs = _
ActivePresentation.Slides.Add((intSlides + 1), ppLayoutText) .Shapes
This returns a collection of all the shapes on the slide we just created (the title shape and text box shape). We assign this collection to the sObjs variable. And the reason we do this becomes evident in the next line of code:
sObjs.Title.TextFrame.TextRange.Text = "Animated Shapes Per Slide"
Here we’re using the object reference sObjs to make it easy to add a title to our new slide.
We now know how many slides we started with (which just happens to be the number of slides we need to look through to find our animations), plus we have a new slide where we can display the results. Now it’s time to start looking for our animations. We do that with a For Each loop:
For Each s In ActivePresentation.Slides
We’re going to go through our presentation one slide at a time, each time assigning the current slide to the variable s. Of course, we don’t need to look at the last slide we just created; we only need to look at the original slides. So the first thing we do is check to make sure we’re not past the original set of slides:
If i <= intSlides Then
If we’re still within the original set of slides, we need to check the slide for animations. Animations exist on shapes, so have to go through each slide and find all the shapes. We do that with another For Each loop:
For Each sh In s.Shapes
For each shape on a slide we check the shape to see whether or not it’s animated. How do we do that? Like this:
If sh.AnimationSettings.TextLevelEffect <> ppAnimateLevelNone Then
We check the TextLevelEffect of the AnimationSettings of each slide to see whether it has an animation. If the shape doesn’t have any animations attached to it then the TextLevelEffect will be equal to ppAnimateLevelNone. If the shape does have an animation attached, we increment our counter by 1, like so:
j = j + 1
In order to display the number of animations per slide on the new slide we created, we’ll need to populate the text box on that slide with a string containing that information. That’s why, after we’ve found all the animations on a slide, we run this line of code:
str = str & "Slide " & i & " has " & j & " animated shapes." & vbNewLine
We’re going to keep building this string as we go, adding information to it for each slide. Because of that we start by assigning the value current contents of the string back to the string:
str = str
Next we add some text, the word Slide:
str = str & "Slide "
We then tack on the slide number, which we’re keeping track of in the variable i:
str = str & "Slide " & i
We add some more text (the word has, with spaces on either side), then we include the number of animations that we kept track of with our counter variable j:
str = str & "Slide " & i & " has " & j
We then end our string with some more text:
str = str & "Slide " & i & " has " & j & " animated shapes."
The end result will be something like this:
Slide 1 has 0 animated shapes.
When we do this for the next slide, we want the information for slide 2 to be on the next line, so the last thing we do in building our string is to add a new line character:
str = str & "Slide " & i & " has " & j & " animated shapes." & vbNewLine
After that we increment our slide counter, reset our animated shapes counter, and start over again with the next slide. After we’ve done that for all the slides, the only thing left to do is to put our string on the last slide:
sObjs.Placeholders(2).TextFrame.TextRange.Text = str
Here’s what your final slide should have looked like:
And that’s it. Yes, compared to the other challenges so far that seems like a lot, but once we broke it all down it wasn’t that bad, was it? We didn’t think so, either.