Auto Update every picture in a PowerPoint Slideshow - vba

I have a very large and complex PowerPoint with a full size image as the background for every individual slide. I have a directory full of these background pictures, which are all JPEG's. Sometimes I change these photographs, which are made with Photoshop, and when I change them, I save them over the original JPEG in the same directory.
I then have to update them in the PowerPoint. The manual functios to do this is to right-click the photograph, and click replace photo, then pick the new JPEG from the file menu. I want to write a macro in Visual Basic that will go through the entire slideshow, and reload the graphic from the updated JPEGs, without me having to do it manually. I don't know if it is possible, because I don't know if PowerPoint actually remembers the path and filename of each picture that it places.
Is there a picture property which contains the path and filename that was used to paste the picture in the first place? If there is, I could find that property, query it, and use that as the path to reload and thereby update the picture recursively all the way through slide by slide.
Would this be possible?

Is there a picture property which contains the path and filename that was used to paste the picture in the first place?
Not that I'm aware of, but you can create your own, using the Tags property:
http://msdn.microsoft.com/en-us/library/office/ff744290(v=office.15).aspx
You will have to assign a custom tag for each slide, like:
Sub AssignTag()
Dim sld as Slide
Set sld = ActivePresentation.Slides(1)
sld.Tags.Add "img_location", "C:\files\image1.JPG"
End Sub
Once the slide's Tags have been configured, then you can do something like this to update from that location:
Sub UpdateJPGs()
Dim sld As Slide
Dim path As String
For Each sld In ActivePresentation.Slides
path = sld.Tags("img_location")
If Not path = vbNullString Then
On Error Resume Next
sld.Background.Fill.UserPicture path
If Err Then
MsgBox "Unable to update slide #" & sld.SlideNumber
Err.Clear
End If
On Error GoTo 0
End If
Next
End Sub

Related

Problem with Windows Media Player ActiveX control in VBA Powerpoint

it's me and my projects for school again. This time I wanted to insert a video into PowerPoint using file path via WMP ActiveX, so I drew one as follows: (uiMode set to "none")
When the slide show starts, I transfer all data from an Excel file to the presentation, including the paths to the video. Then I hide the WMP with Slide85.WMP.uiMode = "invisible".
When the time comes, I want the WMP to appear at the original size that i drawn and the linked video to play, so I used these codes:
Slide85.WMP_TT.uiMode = "none"
Slide85.WMP_TT.URL = "C:\inetpub\wwwroot\TT2.mp4"
Slide85.WMP_TT.Controls.Play
Already muted the video by changing the settings in the Properties tab.
Then the result came out like this:
The video still plays, but only with sound, which is impossible because I muted the control. No visual images is shown from the video, and the control's dimensions changes too.
As of now I cannot think of any causes to this problem. Please help me, I'd be very grateful.
As mentioned on this Microsoft help page, you have to set height and width parameters in code for the player to reserve the space when triggering uiMode="invisible": Player.uiMode
As an alternative, you can draw the size as you have done, then use VBA to hide or show it on the slide with code like this:
Sub HideWMP()
Dim oSlide As Slide
Dim oShape As Shape
For Each oSlide In ActivePresentation.Slides
For Each oShape In oSlide.Shapes
If oShape.Type = msoOLEControlObject Then
oShape.Visible = msoTrue
End If
Next oShape
Next oSlide
End Sub

Get list of fonts to which PowerPoint has access to and compare to user input

I want to create a macro to set the font for all textboxes throughout PowerPoint.
I have the code to set them but for error handling I need to make sure that the font entered by the user is valid and therefore I need the full collection of fonts that PowerPoint has installed.
Private Sub ChangeTextFont_Click()
Dim oSl As Slide
Dim oSh As Shape
Dim strFontName As String
Dim ValidFont As Font
strFontName = InputBox("Enter the name of the font to use for the text on the screens or press Cancel to keep the existing font.", "Enter Font Name")
If Trim(strFontName) = "" Then Exit Sub
'For Each ValidFont In <collection of all fonts powerpoint has> <-------- this is my issue
If strFontName = ValidFont Then
With ActivePresentation
For Each oSl In .Slides
For Each oSh In oSl.Shapes
With oSh
If .HasTextFrame Then
If .TextFrame.HasText Then
If oSl.Name <> "Config" Then
.TextFrame.TextRange.Font.Name = strFontName
End If
End If
End If
End With
Next
Next
End With
End If
'Next
End Sub
Ideally, I need the solution to only use PowerPoint (not launching Word as this has different font selection) and not be too long as this isn't supposed to be a difficult problem.
So in the end this was easiest to do pulling the list from word. I thought the list was different but that was due to caching fonts in the document I was comparing. Anyway for a good solution please check out the answer on this question: Get a list of all fonts in VBA Excel 2010
You could try looking in the Microsoft Office\root\Office16\1033\PUBFTSCM\FONTSCHM.INI file in your install directory and then parse through that...
Not sure what kind of data in there would be helpful, but it's a start.

Using variables inside .Slides & .Shapes methods in Powerpoint VBA

I am working on an interactive Powerpoint Presentation where the user will click on a thumbnail of photo and be able to view it nearly full screen. I'm having difficulty with .Shapes and .Slides methods.
I want several smaller images to appear on one slide in the presentation. If the user wants to view it very large they just need to click on the image. I would then like the image to appear on it's own newly generated slide as large as it can fit on that slide. When they click the larger image, they will be taken back to the smaller images slide they were viewing. This is easily enough achieved by making a separate full sized image slide for every small image in the show and simply calling the large slide number when the small image is clicked; however it is time consuming and makes the presentation far larger than it needs to be. If a user never clicks to see the enlarged image, then the page with the large image is taking up space. I've opted to execute vba code when an image is clicked on that is supposed to:
copy the image
create a new slide after the last slide in the presentation
paste the image into the new slide
resize the image as large as it can fit on the screen
view the new slide with larger image
send the user back to the slide
they started on.
Code:
Sub ViewFullSize()
Dim pptNewSlide As Slide
' Dim objCurrentSlideIndex As Integer
' objCurrentSlideIndex = ActiveWindow.Selection.SlideRange.SlideIndex
With ActivePresentation
.Slides(2).Shapes("Picture 7").Copy
.Slides(4).Shapes.Paste
End With
Set pptNewSlide = ActivePresentation.Slides.Add(ActivePresentation.Slides.Count + 1, ppLayoutCustom)
ActivePresentation.SlideShowWindow.view.Last
End Sub
This code executes and does what is epected. My issue is, I need the slide numbers and shape numbers to be variables. I don't want to rewrite this snippet of code for 100's of photos that could be clicked on. I've tried to make the current slide a variable like this:
Dim objCurrentSlideIndex As Integer
objCurrentSlideIndex = ActiveWindow.Selection.SlideRange.SlideIndex
With ActivePresentation
.Slides(objCurrentSlideIndex).Shapes("Picture 7").Copy
.Slides(4).Shapes.Paste`
End With
The variable I tried .Slides(objCurrentSlideIndex) causes the whole subroutine not to execute, but doesn't crash the slideshow. I've used Set and a slew of other syntax and can't get it to use a variable instead of a plain number. Is there a way to do this? Can the .Slides() and .Shapes() methods even use variables? I've read several of Microsoft's and PPTools pages, but can find no examples using variables.
Sub ViewFullSize(objCurrentShape As Shape) ' Place shape clicked on into variable.
Dim pptNewSlide As Slide
Dim objCurrentSlideNum As Integer
Dim objLastSlideNum As Integer
' Place current slide number into a variable.
objCurrentSlideNum = ActivePresentation.SlideShowWindow.view.CurrentShowPosition
' Send shape to clipboard for later pasting.
ActivePresentation.Slides(objCurrentSlideNum).Shapes(objCurrentShape.Name).Copy
' Place new blank slide at the end of the presentation.
Set pptNewSlide = ActivePresentation.Slides.Add(ActivePresentation.Slides.Count + 1, ppLayoutCustom)
' Make the new slide the active slide.
ActivePresentation.SlideShowWindow.view.Last
' Place the new slide number into a variable.
objLastSlideNum = ActivePresentation.SlideShowWindow.view.CurrentShowPosition
' Paste the shape image from the clipboard onto the new slide.
ActivePresentation.Slides(objLastSlideNum).Shapes.Paste
End Sub
I stumbled onto a snippet of code that showed when a shape was clicked, it could pass its identifiers directly into the subroutine and be assigned to a variable. In my case (objCurrentShape As Shape). This could then be used with the .Shapes() method that I used to call the shape for copying .Shapes(objCurrentShape.Name).Copy.
The .Slides() method was simpler to assign to a variable (or so I believe) because it was not dependent on which shape was clicked. It's merely the active slide number and was attained with the .View.CurrentShowPosition function.
This code can now be assigned to any number of shapes on a slide and will copy and past that shape to a newly created blank slide at the end of your presentation for further manipulations.
Fully working code!
For anyone interested this is the finished (maybe not gleaned), fully operational code that I have working in Powerpoint 2017.
This was designed to be assigned as a Macro Action to pictures in a slideshow. When there are multiple smaller sized images on a page, they can each be assigned this one macro that will show the image full screen on it's own slide and then send the user right back to the screen they were on that contains the smaller images. It's sort of like a full screen zoom function.
It's documented as well as I can document to allow anyone to follow allong with what's taking place at each step. Edits for proper wording and terminology are welcome if I have stated anything incorrectly.
This is not specific to my machine or paths or anything like that. You can simply copy and paste into a module in powerpoint and start assigning the new macro to any images in your presentation.
Sub ViewFullSize(objCurrentShape As Shape) ' Place shape clicked-on into variable.
' Credit Shyam Pillai # http://www.skphub.com/ppt00040.htm#2 for the method of
' bringing the shape into the macro as a variable allowing easier manipulation.
Dim pptNewSlide As Slide
Dim objCurrentSlideNum As Integer
Dim objLastSlideNum As Integer
Dim objLargeView As Shape
' Place current slide number into a variable.
objCurrentSlideNum = ActivePresentation.SlideShowWindow.view.CurrentShowPosition
' Copy shape to clipboard for later pasting.
ActivePresentation.Slides(objCurrentSlideNum).Shapes(objCurrentShape.Name).Copy
' Place new blank slide at the end of the presentation.
Set pptNewSlide = ActivePresentation.Slides.Add(ActivePresentation.Slides.Count + 1, ppLayoutBlank)
' Make the new slide the active slide.
ActivePresentation.SlideShowWindow.view.Last
' Place the new slide number into a variable.
objLastSlideNum = ActivePresentation.SlideShowWindow.view.CurrentShowPosition
' Paste the shape image from the clipboard onto the new slide.
ActivePresentation.Slides(objLastSlideNum).Shapes.Paste
' Put pasted image into a variable.
Set objLargeView = ActivePresentation.Slides(objLastSlideNum).Shapes(1)
' Full credit for this next section of the code goes to PPTools & David Marcovitz
' # http://www.pptfaq.com/FAQ00352_Batch_Insert_a_folder_full_of_pictures-_one_per_slide.htm
' Thanks for the hard work!
' Manipulate the image using the variable.
With objLargeView
' Set mouse-click action on image to return user back to the slide they came from.
.ActionSettings(ppMouseClick).Action = ppActionLastSlideViewed
' Reposition the image for proper resizing
.Left = 0
.Top = 0
.ScaleHeight 1, msoTrue
.ScaleWidth 1, msoTrue
' Resize the image to full screen while maintaining aspect ratio.
' This is wide screen mode. If you are working with the more
' narrow mode, simply change the 9 to a 3 and the 16 to a 4
' to keep the correct aspect ratio.
If 9 * .Width > 16 * .Height Then
.Width = ActivePresentation.PageSetup.SlideWidth
.Top = 0.5 * (ActivePresentation.PageSetup.SlideHeight - .Height)
Else
.Height = ActivePresentation.PageSetup.SlideHeight
.Left = 0.5 * (ActivePresentation.PageSetup.SlideWidth - .Width)
End If
End With
' From here, the slideshow is now showing the originally clicked-on image
' full screen on its own page waiting for the user to click on it to return
' to the rest of the show. If the slideshow isn't set to kiosk mode, then
' there is the possibility of the user clicking somewhere on the screen out
' of the picture area and it would end the slideshow.
End Sub

What are some other methods I can use INSTEAD of "ActivePresentation" in PowerPoint VBA

I'm currently working on PowerPoint VBA and writing a code to be able to copy the first slide and paste it again in the same presentation. However, I keep getting the error "Clipboard is empty or contains data which may not be posted here" and according to Microsoft page the problem is the use of "ActivePresentation"
I'm looking for another way to refer to the slide that I have open without using ActivePresentation. Any help? Ideas?
The line of code I use ActivePresentation is below:
ActivePresentation.Slides(1).Copy
ActivePresentation.Slides.Paste(ActivePresentation.Slides.Count=1)
Don't copy, duplicate
Dim NewSlide as Slide
Set newSlide = ActivePresentation.Slides(1).Duplicate
NewSlide.MoveTo toPos:=4 'move it to become the fourth slide
Slight variant on Harassed Dad's solution. PPT barks at the Set line because Duplicate returns a SlideRange object rather than a Slide object. .Duplicate(1) returns the first slide in the range as a Slide object. This duplicates slide 2 and moves it to the first position in the presentation.
Sub CopySlide()
Dim oSl As Slide
With ActivePresentation
Set oSl = .Slides(2).Duplicate(1)
oSl.MoveTo (1)
End With
End Sub

View slide title in Powerpoint VBA editor

In the Powerpoint VBA editor, we get a list of slides in the VBA project window, categorised under "Microsoft PowerPoint Objects". This list will include slides that have ActiveX controls on them.
The slides appear with numbers on them ("Slide1", "Slide3", etc), and these numbers look like they are based on the order in which the slides were added to the presentation - not the actual order of the slides in the current presentation. However, the title or name of the slides is not included. This makes it confusing to work with, and difficult to find the slide that has the control one wants to work with.
In Excel VBA, the layout of the editor is the same, with a list of worksheets. However, in Excel the name of the sheet is shown in brackets after the sheet number. So if Sheet1 is called "MyDataSheet", it will show up as "Sheet1 (MyDataSheet)".
How can I achieve something similar in Powerpoint? Is there are way to control the name/title that is used to display each slide in the Powerpoint editor?
This is one of the oddities of the PPT object model. Each slide has an internal name that's assigned by PPT at the time the slide is created. That's what you see in the IDE. Each slide also has a .Name property that's initially the same as the slide name assigned by PPT, but that you can change programmatically.
PPT still shows the assigned name under "Microsoft PowerPoint Objects" but if you look at the Properties window of the IDE (press F4 to display it) you'll see (and can edit) the slide's .Name property. This would let you know which slide you've selected in the IDE.
You could also run a bit of code to change the .Name property in a way that reflect's the slide order:
Sub Thing()
Dim oSl As Slide
For Each oSl In ActivePresentation.Slides
oSl.Name = "SLIDE_" & CStr(oSl.SlideIndex)
Next
End Sub
If you want to get a bit fancier, you can have it pick up the slide's title (if any) as the .Name and use SLIDE_index as the .Name if not:
Sub Thing()
Dim oSl As Slide
Dim sTemp As String
For Each oSl In ActivePresentation.Slides
sTemp = SlideTitle(oSl)
If Len(sTemp) > 0 Then
oSl.Name = oSl.Shapes.Title.TextFrame.TextRange.Text
Else
oSl.Name = "SLIDE_" & CStr(oSl.SlideIndex)
End If
Next
End Sub
Function SlideTitle(oSl As Slide) As String
On Error GoTo ErrHandler
SlideTitle = oSl.Shapes.Title.TextFrame.TextRange.Text
NormalExit:
Exit Function
ErrHandler:
SlideTitle = ""
GoTo NormalExit
End Function
One thing to be careful of here is that PPT may or may not complain if you try to give two slides the same .Name property. In other words, you may want to make sure that your slide titles are unique. There might be other issues (characters that aren't allowed in .Name for example).