I need to use VBA to replace part of a textbox in the template of a PowerPoint presentation. The same box contains a field code (is that the right phrase?) for the slide number.
When I execute the following code on every shape oSh in the template:
If oSh.HasTextFrame Then
oSh.TextFrame.TextRange.Text = Replace(oSh.TextFrame.TextRange.Text, searchString, newString)
End If
the information about the field code disappears - slide numbering is broken.
Example, if the shape had "this is slide number " followed by the slide number field code, then if I replace "this is slide number" with "slide", the text will show as "slide <#>".
When I use the PowerPoint "replace" function, the functionality is preserved (slide numbering still works). How is it different? And more importantly - how do I get the substring replaced without destroying the slide numbering?
"When I use the PowerPoint "replace" function, the functionality is preserved (slide numbering still works). How is it different? And more importantly - how do I get the substring replaced without destroying the slide numbering?"
Doesn't the the first sentence answer the question posed in the second? ;-)
For example, this snippet will do the replacement you ask for on each shape on each slide in the presentation:
Dim oSl As Slide
Dim oSh As Shape
For Each oSl In ActivePresentation.Slides
For Each oSh In oSl.Shapes
oSh.TextFrame.TextRange.Replace "This is the slide number", "Slide"
Next
Next
Using PPT's own Replace function solves a number of other problems as well ... it does a pretty good job of retaining mixed formatting, for example.
How's it different from the native VB/VBA Replace function? App-specific functions like this can app-aware, ie, can special-case for features that the specific app supports.
Related
Looking for an example vba code that deletes all slides with a blank layout.
I am trying to create a catalog using a UserForm. The user selects which products they want to look at and the code deletes the slides of the products they don't want to look at.
The problem is that if I delete the array of slides specific to a product, it changes the total number of slides and then the other slide number arrays no longer contain the slides specific to the other products.
I was thinking I would add blank slides in place of the undesired slides and then delete all of the blank slides at the end.
I am open to other ideas and suggestions. Thank you for your time and assistance.
It sounds as though you're working with arrays of SlideNumber or SlideIndex.
Never bother with SlideNumber for various reasons.
And in this case, SlideIndex will change after you delete slides.
Instead, either work with arrays of Slide objects or instead of SlideIndex, use an array of SlideId ... SlideIds are assigned when the slide is created and never change.
Example of how to find a slide from its SlideID, in this case, 258 arbitrarily:
Dim oSl As Slide
Set oSl = ActivePresentation.Slides.FindBySlideID(258)
MsgBox oSl.SlideIndex
I'm trying to have a counter in all slides of a powerpoint presentation.
The counter needs be controlled by a button in all slides that increases it.
I can do it for one specific slide, but when I do it with a slide master it doesn't refresh the screen during Slideshow mode. I have to exit slideshow and enter again to see the changes.
Code that doesn't refresh in Slideshow mode:
ctr = ctr + 1
ActivePresentation.Designs(1).SlideMaster.Shapes("Counter").TextFrame2.TextRange.Text = ctr
Code that works (but only applies to one slide, not all slides in presentation):
ctr = ctr + 1
ActivePresentation.Slides(1).Shapes("Counter").TextFrame2.TextRange.Text = ctr
Thanks!
If your second method works, why not loop it?
Dim sld as Slide
ctr = ctr + 1
For Each sld in ActivePresentation.Slides
sld.Shapes("Counter").TextFrame2.TextRange.Text = ctr
Next
NB: This will error on any slide which doesn't contain a shape named "Counter", and you will need to add logic to handle that condition, if it exists in your Presentation.
Bookmark this link, it's the PPT Object Model Reference which, while laborious to peruse, will explain just about anything you need.
https://msdn.microsoft.com/en-us/library/office/ff743835(v=office.14).aspx
The hardest part (as a beginner) is knowing what questions to ask, and while the Object Model doesn't help you with that immediately, the more you browse it and search it, the more familiar you'll become with the different objects at your disposal, and what you can do with each of them.
If you're new to VBA entirely, also bookmark this list of VBA Statements. This has examples & definitions for all of the control flow & logic statements you might use in putting some code together.
https://msdn.microsoft.com/en-us/library/office/jj692812(v=office.15).aspx
This answer talks about how to run a macro automatically when changing slides, we'll use that approach for your problem. You'll use the OnSlideShowPageChange event because that's an auto macro and doesn't require the more complicated Application Class event handler.
How to run a macro "OnEnterSlide" or "OnLeaveSlide" in Powerpoint VBA?
Implementing this is actually a moderately complicated problem and moreso for someone who is not familiar with VBA or PowerPoint's object model.
Now, you've mentioned a number of things which either are simply not true, or at the very least it is not intuitive or obvious why these must be true, when presented with alternatives:
For that to work I would have to use a macro to add the shape to each slide individually. But then if I wanted to change the size of the shape I have to use code for that too. Not very elegant...would rather force the refresh somehow and use a master slide for the shape
(Note that the scope of your initial problem keeps increasing and becoming more complex).
The reason is to make it easier to change the shape without using code and creating the shape in all the slides.
Sometimes this is the easiest or best way to do things, sometimes it's not. I am in no position to evaluate this with regards to your specific requirements, because you've given only 2 lines of code to examine, but from my vantage point, it seems you are hesitant to write more code because you simply don't know how.
I'm sorry but your deadline is not my problem, and I've spent a generous amount of time on this answer which I hope will at least point you in the right direction.
This is a different approach, you may consider.
Add a button named Sh1, Sh2 in slide 2, Sh3 in slide 3 etc.
and attach all this shapes to the below code
For ctr = 1 To 3
If ActivePresentation.Slides(ctr).Shapes("sh" & ctr).TextFrame2.TextRange.Text = ctr Then
ActivePresentation.SlideShowWindow.View.Next
End If
Exit Sub
Next
End Sub
This would check the current slide with the counter, if matches, moves next else exits.
Wondering if there is a macro that could automatically update slide references for objects on other slides.
For instance, let’s say there is a table on slide X. I want to be able to place a text box on slide 5 and say “refer to page X.”
These presentations are printed so using hyperlinks would not work. We do not want to hard code the reference because if we add/delete slides, we do not want to go back and manually update all the references.
My VBA knowledge is very limited. Not sure how to "tag" an object and then reference it.
To tag a shape, assuming it's currently selected:
With ActiveWindow.Selection.ShapeRange(1)
.Tags.Add "TagName", "TagValue"
End With
So for example, select the table and:
With ActiveWindow.Selection.ShapeRange(1)
.Tags.Add "ShapeTag", "Table1"
' the value above should be unique
End With
Hooking the text that you want to update up to the table will be a bit trickier. I'd approach it by adding two tags to the text shape, the first being the text you want to appear in the text box, but with the slide number included as a replaceable parameter; the next tag would be a reference to the shape in question:
With ActiveWindow.Selection.ShapeRange(1)
.Tags.Add "Text", "Refer to page #page#"
.Tags.Add "Shape", "Table1"
End With
To update, you'd run code that checks each shape on each slide and if the shape has Len(.Tags("Shape")) > 0 you'd call a function that looks at each slide/each shape and returns the slide number where it finds a shape tagged "Table1".
You'd then substitute the slide number in place of #page# in the .Text tag and apply that as the shape's .TextFrame.TextRange.Text
I need to know is selected shape word art or not.
Shape has property "Type" (returns enum MsoShapeType).
When I insert word art and check this property - it returns msoAutoShape instead of msoTextEffect (with AutoShapeType==msoShapeRectangle).
How can I check that spae is word art (not usual rectangle with textbox) ?
Thanks!
If you select either the overall smartart shape or click into text within the smartart shape or select one of the shapes within the smart art, ActiveWindow.Selection.ShapeRange(1) will return the smartart shape.
So
If ActiveWindow.Selection.ShapeRange(1).HasSmartArt Then
Debug.Print "It's smart art"
End if
[edited]
But as you've pointed out, this is for smartart, not word art. My error, sorry.
There isn't a WordArt shape as such; it's more like any shape that has had WordArt formatting applied to the shape as a whole or to text within the shape. That'd include formatting like glow, reflection, shadow and so on, or could be one of the WordArt presets, pre-selected combinations of these different effects. I've added an example that'll help identify shapes or ranges of text within shape that have these presets applied. I don't see any simple way of checking for user-applied WordArt formats other than looking at each run and each text box for each of the various properties (glow, reflection etc) that might be applied. Unfortunately, there's no WordArtFormat = None to tell us we can ignore it. It's either going to be one of the presets or -2, which can mean any of several things.
Sub WordArtist()
Dim oSh As Shape
Dim oRng As TextRange2
' Has word art formatting been applied to
' entire shape?
Set oSh = ActiveWindow.Selection.ShapeRange(1)
Debug.Print oSh.TextFrame2.WordArtFormat
' Has it been applied to individual chunks of
' text within the shape
For Each oRng In oSh.TextFrame2.TextRange.Runs
Debug.Print oRng.Font.WordArtFormat
Next
' Note:
' A result of -2 for the entire shape could mean
' - No text in the shape; not really word art
' - Mixed formatting
' - Text/shape has had glow/shadow/reflection etc applied
' rather than one of the preset WordArt selections
End Sub
I have a report that is generated in PowerPoint, and underneath many of the graphs, there is text that tells the reader to refer to pages in the appendix. I would like to be able to dynamically reference these slides.
For example, under a graph I might have the text "Please see appendix page 54", but I need the 54 to be linked to a slide so that if I insert another slide it will say 55.
Is this possible to do in VBA? I do not expect somebody to write my code for me, I would just like to know if this is a reasonable thing to do before I spend hours attempting to do it.
Side note: I feel horrible asking a question about MS Office on here, but since I believe it would need to be implemented in VBA (I don't think this functionality is built in by default) I think that it is a relevant question.
No need to feel horrible asking this here.
How one might do this:
In PPT, shapes, slides and even the presentation itself can have an associated tag collection; named string values. For example, assuming a reference to the shape in oSh, you can do:
oSh.Tags.Add "AssociatedSlideId", "293"
In this case, you'd apply this tag to your graph; the 293 would be the SlideID of the slide you want to reference. Each slide has a unique SlideID assigned when it's created; the SlideID won't change when you move the slide around/add/delete slides.
To read the tag from the shape:
Debug.Print oSh.Tags("AssociatedSlideId")
In this case, that'd return "293". Feed that to FindBySlideID to get the SlideIndex of the slide (ie, the ordinal position of the slide in the presentation). Or ask it for SlideNumber if you want the number of the slide that'll appear in number placeholders (usually, but not always the same as slide index).
Debug.Print ActivePresentation.Slides.FindBySlideID(clng("293")).SlideIndex
You might also tag the textbox or other shape that you want to use to hold the reference, then write a function along the lines of:
Function ShapeTaggedWith(oSl as Slide, sTagName as String, sTagValue as String) as Shape
This would iterate through the shapes on slide oSl looking for one with a tag named sTagName, value = sTagValue and return it to the caller if found.
Now you can find the shape that's nominated as your caption for the graph, let's call it, and change its text to match the SlideIndex (or SlideNumber) of the slide the chart's supposed to reference.
Hope that's all moderately clear; if not, that's why the StackOverflow gods gave us comments.