How to find the index of a Powerpoint Shape - vba

I'm writing a VBA script to copy+paste charts from an Excel worksheet to an existing Powerpoint presentation as Picture.
So far I was successful to do the copy-paste as Picture, but failed to change the size of the pasted picture. I believe the pasted picture is a shape, so I'm trying to do something like:
For Each iChart In arrChart
xlWorkBook.Worksheets("PPT").ChartObjects(iChart).CopyPicture
ActivePresentation.Slides(iCurrSlide).Shapes.Paste
'Reshape
ActivePresentation.Slides(iCurrSlide).Select
With ActivePresentation.Slides(iCurrSlide).Shapes.Item(5)
.Select
.Height = ActiveWindow.Presentation.PageSetup.SlideHeight
.Width = ActiveWindow.Presentation.PageSetup.SlideWidth
.Left = 0
.Top = 0
End With
iCurrSlide = iCurrSlide + 1
Next iChart
However I seem to get the wrong index, so I'm wondering if there is a way to capture the index of the picture (as a shape)? I have my hands tied as I cannot name the picture (if I'm to name each picture pasted, I'd rather throw the script into garbage can and simply paste manually), and I cannot change anything about the pptx and xlsx.

Avoid selecting anything unless it's absolutely necessary, which it seldom is.
Assuming this is happening in VBA within PPT:
Dim oSh as Shape
For Each iChart In arrChart
xlWorkBook.Worksheets("PPT").ChartObjects(iChart).CopyPicture
' Set a reference to the just-pasted shape
Set oSh = ActivePresentation.Slides(iCurrSlide).Shapes.Paste(1)
'Reshape
' You don't need this:
' ActivePresentation.Slides(iCurrSlide).Select
' With ActivePresentation.Slides(iCurrSlide).Shapes.Item(5)
With oSh
' No need to select it as long as you've got a reference to it:
'.Select
' I'd use ActivePresentation.PageSetup here but it may not matter
.Height = ActiveWindow.Presentation.PageSetup.SlideHeight
.Width = ActiveWindow.Presentation.PageSetup.SlideWidth
.Left = 0
.Top = 0
End With ' oSh
iCurrSlide = iCurrSlide + 1
Next iChart

Related

VBA PPT copy/paste chart inconsistent

I'm slowly getting crazy because of this problem. I'm creating a powerpoint presentation from an excel workbook, where data needs to be filled in. I'm creating multiple slides already with no issues and tackled most problems already.
One of the final things for me to do is copy a chart from excel and pasting it in my ppt. This has worked before, but suddenly it just breaks, it doesnt want to paste the chart anymore.
In my main module I call sub ROI with some required data to continue
Call ROI(PPPRes, Slidestart, language, i)
This is in a seperate Module to keep things clean in the main module
Sub ROI(PPPRes, Slidenumber, language, proposal)
Set pp = CreateObject("PowerPoint.Application")
Dim oPPTShape As PowerPoint.Shape
Dim PPSlide As PowerPoint.Slide
Dim ColumnWidthArray As Variant
Dim i As Integer
'Create a slide on Slidenumber location
Set PPSlide = PPPRes.Slides.Add(Slidenumber, ppLayoutTitleOnly)
PPSlide.Select
PPSlide.Shapes("Title 1").TextFrame.TextRange.Text = Range("Titlename in chosen language")
PPSlide.Shapes.AddTable(3, 3).Select
Set oPPTShape = PPSlide.Shapes("Table 4")
'Filling in data in the table from an excel table. Basic stuff working with a few loops to make this happen
'Changing the width of the created table, column by column
ColumnWidthArray = Array(37, 210, 180)
Set oPPTShape = PPSlide.Shapes("Table 4")
On Error Resume Next
With oPPTShape
For i = 1 To 3
.table.columns(i).width = ColumnWidthArray(i - 1)
Next i
.Top = 180
.Left = 520
.height = 200
End With
'Add a rectangle on the slide
PPSlide.Shapes.AddShape Type:=msoShapeRectangle, Left:=404, Top:=400, width:=153, height:=43
'Copy a picture from excel and paste it in the active slide
Sheets("Shapes").Shapes("ROI_img").Copy
PPSlide.Shapes.Paste.Select
pp.ActiveWindow.Selection.ShapeRange.Left = 800
pp.ActiveWindow.Selection.ShapeRange.Top = 20
'Copy chart from excel (with index number that is linked to "proposal") and then paste onto slide
Sheets("Proposals").Shapes("ChartInvProp" & proposal).Copy
PPSlide.Shapes.Paste.Select
Set oPPTShape = PPSlide.Shapes("ChartInvProp" & proposal)
With PPSlide.Shapes("ChartInvProp" & proposal)
.Left = 20
.Top = 120
.width = 480
.height = 320
End With
end sub
So everything in the code is executed, but most of the time the chart from excel is NOT being pasted onto the slide.
However, if I checked what is in the clipboard by breaking the code just after copying the chart from excel. And I then manually paste whatever is in the clipboard into a Word document I will see the chart. --> The action of copying the chart is being executed, but not the pasting part
If I now continue after the break, the chart will be pasted on the powerpoint somehow. But if I do NOT break the code, and let it run its course, the chart will not be pasted.
Somehow it seems to need more time after copy before it can actually paste the chart. I dont really understand what is happening here.
Sometimes it only pastes Chart 1 in the slide, and when it loops for the second/third/etc... chart it doesnt want to paste it anymore.
It really is very random, and I only see a little bit of structure in it not executing...
This was the solution, using a 'DoEvents' between copy and pasting.
This issue only occurred with Charts made in Excel, if I made the charts into pictures it worked without a problem. But copy/pasting a chart from Excel apparently takes more processing time and was slower than the program run speed. So it would skip from time to time.
Sheets("Proposals").Shapes("ChartInvProp" & proposal).Copy
DoEvents
PPSlide.Shapes.Paste.Select
Got the answer from:
Error in script which copies charts from Excel to PowerPoint

.Left positioning shapes in wrong place in PowerPoint 2016 VBA

I'm trying to copy ranges from an Excel sheet and paste them into slides as tables, then position and resize them. However, when I try to position the shapes in ppt, the .Left method doesn't behave as expected; in the slide thumbnails on the left of the screen the shapes are in the expected positions (centred as in the below code), but when I select the slide the shapes are shifted far to the right of where they ought to be.
I thought it may be using 'centre' as its reference point instead of the left bound of the slide but this doesn't match up with the amount it's offset.
Would really appreciate some help with this - would be good to know if it's a bug in ppt or an error in my code as if it's a bug it has a large impact on the feasibility of this project. For this particular example I could probably use the .Align method as a workaround but for later slides I need to be able to position multiple shapes on the same slide accurately.
I'm using Office 365.
Code below:
Sub PP_export()
Dim PPApp As PowerPoint.Application
Dim PPPres As PowerPoint.Presentation
Dim PPSlide As PowerPoint.Slide
Dim XLws As Worksheet
Set PPApp = New PowerPoint.Application
Set XLws = ActiveSheet
Set PPPres = PPApp.Presentations.Open("Y:\Research\PROJECTS\2018\Magic Macro\ppt_template_.potx")
PPApp.Visible = True
''Lifestyle Statements
'By Col%
Set PPSlide = PPPres.Slides(3)
Dim LSCol As PowerPoint.Shape
XLws.Range("M106:o126").Copy
PPSlide.Shapes.PasteSpecial ppPasteDefault
Set LSCol = PPSlide.Shapes("Table 2")
With LSCol
.Left = (28.35 * 10.56)
.Top = (28.35 * 3.83)
.Height = (28.35 * 13.21)
.Width = (28.35 * 12.75)
End With
'By Index
Set PPSlide = PPPres.Slides(4)
Dim LSIndex As PowerPoint.Shape
XLws.Range("Q106:s126").Copy
PPSlide.Shapes.PasteSpecial ppPasteDefault
Set LSIndex = PPSlide.Shapes("Table 2")
With LSIndex
.Left = (28.35 * 10.56)
.Top = (28.35 * 3.83)
.Height = (28.35 * 13.21)
.Width = (28.35 * 12.75)
End With
I got the same problem and I run a debug message showing the position after inserting and it seems to be correct. But only the thumbnail looks fine, the actual slide is wrong.
I found out that the position of the table will be correct when activating or displaying the slide before pasting the table. Also if several tables need to be inserted I needed to make a short break of 2 seconds between the paste operations.
My workaround is pretty ugly and I am still searching for the reason. It is likely a bug but maybe it also has to do with some kind of offset of the slide in the background.
You need to loop over the table and the data if you are using a template.
If you already have a table (table 2) on slide 3, then you could use this. just send in the excel file object and the template (path+name)
it may need some tinkering.
Sub Slide_3(ByRef xlWorkBook, Template)
For Each oSh In Presentations(Template).Slides(3).Shapes
Select Case oSh.Name
Case "Table 2"
For i = 1 To 20
For j = 1 To 3
oSh.Table.Cell(i, j).Shape.TextFrame.TextRange.Text = xlWorkBook.Worksheets(24).Cells(105 + i, j + 12).Value
Next j
Next i
'M106:o126
End Select
Next oSh
End Sub

Macro Excel won't past exact image to Powerpoint Presentation

The strangest thing is happening with my macro in Excel. It works like a charm, but when it has to copy 2 charts and paste into my powerpoint presentation, suddenly, the Chart isn't exactly the same.
My code:
Set Wb = Workbooks.Open("Path\WbName.xlsx", ReadOnly:=True, UpdateLinks:=0)
It opens 5 more workbooks... And then it goes through a loop, to copy all the Charts
Dim Charts_Arr As Variant
Charts_Arr = Worksheets("Parameters").ListObjects("Parameters").DataBodyRange.Value
For i = LBound(Charts_Arr) To UBound(Charts_Arr)
SourcePath = Charts_Arr(i, 8)
SheetName = Charts_Arr(i, 4)
ShapeNr = Charts_Arr(i, 2)
SlideNr = Charts_Arr(i, 3)
Schaling = Charts_Arr(i, 6)
Set Source = Workbooks(SourcePath)
Set PPpres = oPPTApp.ActivePresentation
Set Sh = Source.Sheets(SheetName).Shapes(ShapeNr)
Sh.Copy
Set NewSh = PPpres.Slides(SlideNr).Shapes.PasteSpecial(ppPasteJPG)
With NewSh
.Top = Charts_Arr(i, 5)
.Left = Charts_Arr(i, 7)
.ScaleHeight Schaling, msoTrue
End With
Next i
This goes perfectly. But when I take a look at the ppt-file, 2 charts are not exactly the same.
(TIP: Excel is Chartarea, not a shape - didn't know this at first)
When copy the picture manually, I get the correct picture:
And what's more bizarre, I have 2 other Charts on another Sheet in the same workbook who doesn't cause any problems.
Could this be a problem with links, or the way I copy?
UPDATE
If I adjust the code as suggested below:
Source.Sheets(SheetName).ChartObjects(ShapeNr).Chart.CopyPicture
Set NewSh = PPpres.Slides(SlideNr).Shapes.Paste
With NewSh
.Top = Charts_Arr(i, 5)
.Left = Charts_Arr(i, 7)
.ScaleHeight Schaling, msoTrue
End With
I get this:
I'm doing something wrong with the Paste part of the code, I guess.
Tried other possibilities, always end up getting no images, or the one above.
FIXERSUPDATE
So I made/used a loophole. Couldn't find a way to paste the images directly into Powerpoint, So I pasted it into an excelsheet 'Temp' instead. And adjusted the Array, and that seemed to work. But I still would like to know how to do this directly in Powerpoint.
Thanks in advance for your insights!
I couldn't find a PasteSpecial Option that could fix the issue.
CopyasPicture works, but I can't seem to figure out how to paste it directly into ppt. So I used a workaround. I created a 'Temp' Sheet, where I could paste the Chart as Picture in the right format, afterwards I could program it to paste the shape into Ppt. Not the cleanest way to solve the issue, but it works.

Replace existing image in MS PowerPoint with a new image using VBA

I'm updating my MS PowerPoint by pasting images on different slides using VBA.
Rest of the code is working fine. What I'm unable to do is delete the existing image on all the slides and paste the new image. Currently it paste the new image on top of old image, but old image remains. I'm using below code:
Dim pptApp As PowerPoint.Application
Set pptApp = CreateObject("PowerPoint.Application")
pptApp.Visible = msoTrue
xlApp.Worksheets(2).Range("M2:S12").Copy
Set shp1 = ActivePresentation.Slides(17).Shapes.PasteSpecial(ppPasteEnhancedMetafile)(1)
With shp1
.Left = 370
.Top = 100
.Height = 360
.Width = 340
End With
Being a newbie to VBA, I dont know where and how to add delete command in above code. Any kind of help would be appreciated.
This (thanks, L42) will work for single msoPicture shapes on a slide, but if there's more than one shape, it may miss some:
Dim s As Shape
For Each s In ActivePresentation.Slides(17).Shapes
If s.Type = 13 Then s.Delete '13 is msoPicture
Next
Why? Suppose you have three shapes on the slide. We iterate through the shapes collection, find that the first shape is a picture and delete it. Now there are two shapes in the shapes collection, but VBA's counter doesn't take account of changes in the collection count. It looks at the second shape in the collection, but that's now what WAS the third shape on the slide, so the code will miss shape #2 altogether.
It's more reliable to use something like this:
Dim x as Long
For x = ActivePresentation.Slides(17).Shapes.Count to 1 Step -1
If ActivePresentation.Slides(17).Shapes(x).Type = msoPicture Then
ActivePresentation.Slides(17).Shapes(x).Delete
End If
Next
Edit1: As what Steve pointed out, the first posted solution is unreliable; also as confirmed in this POST by Doug.
To delete all pictures using loop, take Steve's approach as explained in his post.
Now, if you just want to delete all the pictures, you can try this:
ActivePresentation.Slides(17).Shapes.Range.Delete
But this deletes all shapes, not only pictures but textboxes, lines, shapes etc.
To delete only pictures, below is another approach using loop.
Dim s As Shape, pictodel As Variant
For Each s In ActivePresentation.Slides(17).Shapes
If s.Type = 13 Then
If IsArray(pictodel) Then
ReDim Preserve pictodel(UBound(pictodel) + 1)
pictodel(UBound(pictodel)) = s.Name
Else
pictodel = Array(s.Name)
End If
End If
Next
ActivePresentation.Slides(17).Shapes.Range(pictodel).Delete
Hope this helps but a simpler solution would be Steve's. :)

Powerpoint VBA Make duplicated shape view active to select for grouping

I have a library of eight images on my PowerPoint slide. Based on a userform input, some of the components get duplicated and renamed by adding a "1" or "2" after the original image's name so that they are differentiable. I then want to group the new images (I am building up an item from the component images). I am able to duplicate the images and line them up correctly, but I am having trouble grouping them. Note that I am not always grouping the same number of items, it is dependent on user inputs.
I receive the error "Shape (unknown member): Invalid request. To select a shape, its view must be active."
I searched and attempted to implement several strategies from the help forums but am coming up empty.
PLEASE HELP!!!
-Kevin
Part of code below because it is very long, but this is where my first problem arises:
Dim Cargo As Shape, Cargo_Dup as Shape, Chemical as Shape, Chemical_Dup as Shape
Set Cargo = ActivePresentation.Slides(2).Shapes("Cargo")
Set Chemical = ActivePresentation.Slides(2).Shapes("Chemical")
Cargo.Name = "Cargo"
Chemical.Name = "Chemical"
With ActivePresentation
Set Cargo_Dup = ActivePresentation.Slides(2).Shapes("Cargo")
With Cargo_Dup.Duplicate
.Name = "Cargo_1st"
.Left = 0
.Top = 540
End With
'CHEMICAL
If Input1 = "Chemical" Then
Set Chemical_Dup = ActivePresentation.Slides(2).Shapes("Chemical")
With Chemical_Dup.Duplicate
.Name = "Chemical" & 1
.Left = 36.74352
.Top = 540 + 0.36
End With
'''''WHERE PROBLEM ARISES'''''
ActivePresentation.Slides(2).Shapes("Cargo_1st").Select
ActivePresentation.Slides(2).Shapes("Chemical1").Select msoFalse
Set Vehicle = ActiveWindow.Selection.ShapeRange.Group
Vehicle.Name = "Vehicle"
'Elseif with a bunch for options where addition grouping occurs
I need some kind of keyboard macro to type this for me:
Never select anything unless you absolutely have to.
You nearly never absolutely have to.
You're asking how to make a view active so that you can select something.
I figure that's the wrong question.
It's more useful to know how to work with shapes WITHOUT having to select them.
Grouping shapes w/o selecting them is a bit tricky, but it can be done.
Here's an example of how you might go about this:
Sub GroupWithoutSelecting()
Dim oSl As Slide
Dim oSh As Shape
Dim aShapes() As String
Set oSl = ActivePresentation.Slides(2) ' or whichever slide you like
ReDim aShapes(1 To 1)
With oSl
For Each oSh In .Shapes
If oSh.Type <> msoPlaceholder Then ' can't group placeholders
' Substitute the real condition you want to use
' for selecting shapes to be grouped here
If oSh.Type = msoAutoShape Then
' add it to the array
aShapes(UBound(aShapes)) = oSh.Name
ReDim Preserve aShapes(1 To UBound(aShapes) + 1)
End If
End If
Next
' eliminate the last (empty) element in the array
ReDim Preserve aShapes(1 To UBound(aShapes) - 1)
' Create a shaperange from the array members and group the shaperange
.Shapes.Range(aShapes).Group
End With ' oSl
End Sub