VBA Excel copy multiple shapes to clipboard - vba

I have an Excel sheet with four shapes and a couple of buttons to run macros. The shapes are named topCircle, leftCircle, rightCircle & midCircle.
Wanting one of the buttons to run a macro that copies the four shapes to clipboard, for pasting into other Office docs.
Have been though various MSDN articles (like https://msdn.microsoft.com/en-us/library/office/ff940375.aspx) but having trouble. Trying to imitate the example on the linked article, I wrote this:
Set myDocument = Worksheets("Overall")
myDocument.Shapes.Range(Array("leftCircle", "rightCircle", "topCircle", "midCircle")).Copy
But getting an error "Object doesn't support this property or method". Have also tried a few other things without luck. Any ideas as to how to get this to work? Cheers!

It seems that to copy multiple shapes from an Excel worksheet you have 3 options:
Option 1: Use Select first to select all Shapes, and then copy the Selection :
myDocument.Shapes.Range(Array("leftCircle", "rightCircle", "topCircle", "midCircle")).Select
Selection.Copy
Option 2: Use the Group to group all selected shapes, then copy them together, and afterwards use the Ungroup to split them back:
With myDocument.Shapes.Range(Array("leftCircle", "rightCircle", "topCircle", "midCircle"))
.Group.Copy
' paste to wherever you want
.Ungroup
End With
Option 3: use For Each MyShape In myDocument.Shapes to loop through all Shapes in myDocument worksheet, and if it mathces one of the Shape.Name you wanted it, copy it:
Dim MyShape As Shape
For Each MyShape In myDocument.Shapes
Select Case MyShape.Name
Case "leftCircle", "rightCircle", "topCircle", "midCircle"
MyShape.Copy
' paste to wherever you want
End Select
Next MyShape

Related

Error in script which copies charts from Excel to PowerPoint

I am attempting to call the below Sub in order to copy given chart to a specified PowerPoint presentation. However, when I run the macro which calls this Sub, the line indicated below returns the following error: "Object doesn't support this property or method." What's odd is that both Shapes and Slide do contain the methods which are called. As well, the bitmap is correctly copied to my clipboard and pastes into the slide before the error is called. You will find the Sub() below.
Sub copyChart(chrt As Chart, pres As PowerPoint.Presentation)
Dim curSlide As Slide, dummySlide As Slide
Set dummySlide= pres.Slides(2) 'Second slide is dummy slide.
Set curSlide = dummySlide.Duplicate(1) 'Duplicate dummy, set as current slide.
chrt.CopyPicture Appearance:=xlScreen, Format:=xlBitmap 'Copy the chart as a picture.
curSlide.Shapes.Paste '<-----------Error here.
End Sub
As well, I was hoping to provide a .txt file of my entire script, but was unsure how (it is a little lengthy to paste here). Thanks for your help.
(Note that this implementation is very similar to that at Paste Excel Chart into Powerpoint using VBA, further confusing me.)
I have had a lot of trouble in recent versions of Office. 2003 and earlier didn't have this problem, 2007 and 2010 had it a bit, and 2013 and 2016 have it in spades.
When you step through the code it works fine, but when you run it at full speed, it errors on the paste.
It's as if the copy doesn't have time to finish finish, so when you paste the clipboard doesn't have anything in it yet to paste.
Sometimes this helps:
chrt.CopyPicture Appearance:=xlScreen, Format:=xlBitmap
DoEvents
curSlide.Shapes.Paste
DoEvents tells VBA to wait while background operations have a chance to finish up.
It looks like the error can be attributed to how VBA handles variables across different references. (In particular, how PPT VBA handles them.) I was able to get the macro to work by actively selecting/copying the charts. I will need to do a little more research to get why variables cause problems, but at least I know how tackle the problem.
Sub copyChart(curSlide As Slide)
Dim chr as ChartObject
Set chr = Sheets("CHARTSHEET").ChartObjects(1)
Sheets("CHARTSHEET").Select
ActiveChart.CopyPicture
curSlide.Shapes.PasteSpecial
End Sub
I like to use another method, I like to define an Object, then set it to the pasted Chart. Afterwards, it's much easier modifying the pasted Chart object's parameters inside PowerPoint (from Excel).
See code below:
Sub copyChart(curSlide As Slide)
Dim chr As ChartObject
Dim myChart As Object
Set chr = Sheets("CHARTSHEET").ChartObjects(1)
chr.Copy
' setting myChart object to the pasted chart (let's me later an easy way to modify it's parameters)
Set myChart = curSlide.Shapes.PasteSpecial(ppPasteBitmap, msoFalse) ' can change first parameter to other avaialabe formats : ppPasteGIF, ppPasteEnhancedMetafile, ppPasteOLEObject, etc.
' set different parameters for the pasted chart in PowerPoint slide
With myChart
.Left = 200
.Top = 200
End With
End Sub
In the code line:
Set myChart = curSlide.Shapes.PasteSpecial(ppPasteBitmap, msoFalse)
You can change the first parameter in brackets: ppPasteBitmap to many other avaialble formats (test them and see which one gives you the best result), such as: ppPasteGIF, ppPasteEnhancedMetafile, ppPasteOLEObject, etc.

Error in Code to Paste / Copy Shapes from Excel to PowerPoint VBA

I created a code in VBA to copy shapes from a sheet in Excel to an existing PowerPoint file, these shapes are added to existing slides. In Excel I have a table that indicates which slide and in which position to paste each shape (I named all shapes so that I can reference them by name). My code loops through this table to get the shape and paste it to the designated slide. This is my code:
Dim nombrePic As String, auxi As String, i As Integer
Dim PPT As Object
Dim PPSlide As PowerPoint.Slide
Dim numSlide As Integer, posVertical As Double, posHorizontal As Double
'Abrir PPT
Set PPT = CreateObject("PowerPoint.Application")
PPT.Visible = True
PPT.Presentations.Open "c:\prueba.pptx"
auxi = Sheets("FigurasResumen_RangPD").Cells(2, 5)
i = 2
Do
Sheets("FigurasResumen_RangPD").Shapes(auxi).Copy
'Get paste information about shape
numSlide = Sheets("FigurasResumen_RangPD").Cells(i, 8)
posHorizontal = Sheets("FigurasResumen_RangPD").Cells(i, 9)
posVertical = Sheets("FigurasResumen_RangPD").Cells(i, 10)
PPT.ActiveWindow.View.GotoSlide (numSlide)
PPT.ActiveWindow.View.PasteSpecial DataType:=ppPasteDefault
PPT.ActiveWindow.Selection.ShapeRange.Left = Format(Application.CentimetersToPoints(posHorizontal), "0.00")
PPT.ActiveWindow.Selection.ShapeRange.Top = Format(Application.CentimetersToPoints(posVertical), "0.00")
PPT.ActiveWindow.Selection.ShapeRange.ZOrder msoSendToBack
i = i + 1
auxi = Sheets("FigurasResumen_RangPD").Cells(i, 5)
Loop Until auxi = ""
End Sub
When I first tried it, it work fine. I created a sample PPT and everything went great.
Once I changed the path to use the official PPT (which weights around 120MB) it shows the following error:
View.PasteSpecial : Invalid Request.
Clipboard is empty or contains data which may not be pasted here.
[Answer replaced: I wrote an answer yesterday but I think this one is better.]
VBA sees "copy" and "paste" operations as unrelated to each other. It also executes asynchronously - it starts executing an instruction, and then it may move on to executing the next one while the previous instruction is still being executed. It shouldn't do so if the second instruction depends on the first, but "paste" just takes ANYTHING from the clipboard, it is not aware of how things got on the clipboard. In particular, it doesn't relate specifically to the "copy" command right before it. Then, copying to the clipboard is a slow process; program execution gets to "paste" before anything is on the clipboard (or only partial, incomplete data is on it).
There are two ways to address the problem. One is to add a Sleep xxx instruction before the paste command. xxx is a number of milliseconds - and for Sleep to work, you need to declare it properly at the top of your module (it is a Windows function, not a VBA function). Google "VBA Sleep function" or something similar. With this solution, you have to experiment with xxx, sometimes 2 ms will suffice and sometimes 50 ms will not be enough. Not a good solution.
The better solution in your case would be to declare a Shape variable, assign to it the shape you were copying, and then add it to your target slide. This should work, because the shape (saved as the Shape variable) cannot be added to the new slide until the variable assignment completes. ASSUMING, of course, that VBA has a method for adding a shape to a slide...

Excel VBA add hyperlink to shape to link to another sheet

I have a macro that creates a summary sheet at the front of a Workbook. Shapes are created and labeled after the sheets in the workbook and then hyperlinks are added to the shapes to redirect to those sheets, however, when I recorded the macro to do this, the code generated was:
ActiveSheet.Shapes.Range(Array("Rounded Rectangle 1")).Select
ActiveSheet.Hyperlinks.Add Anchor:=Selection.ShapeRange.Item(1), Address:=""
The hyperlinks that were manually created in excel while recording the macro work just fine and when hovering over them, display the file path and " - Sheet!A1" but they don't seem to actually be adding the link location into the address portion of the macro. Does anyone know the code that should go in that address section to link to the sheet?
The macro recorder doesn't record what is actually happening in this case. The property you are looking for is SubAddress. Address is correctly set in your code.
Create a hyperlink from a shape without selecting it
You want to avoid selecting things in your code if possible, and in this case it definitely is. Create a shape variable and set it to the shape you want to modify, then add the hyperlink to the sheet the shape is on. Note that you can also set the text for the screen tip.
In the example below, the shape I want to modify is on Sheet 6, and hyperlinks to a range on Sheet 4.
Sub SetHyperlinkOnShape()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet6")
Dim hyperLinkedShape As Shape
Set hyperLinkedShape = ws.Shapes("Rectangle 1")
ws.Hyperlinks.Add Anchor:=hyperLinkedShape, Address:="", _
SubAddress:="Sheet4!C4:C8", ScreenTip:="yadda yadda"
End Sub

Go through all the objects to which a macro can be assigned

As far as I know, in Excel we can assign macros to several kinds of objects: shape, Form Control, ActiveX Control...
I would like to write a VBA code to do the following, given an Excel file:
Go through all the existing objects which are eligible to be assigned to a macro
For each object found, print its name and the name of its macro (or ideally the body as well) if a macro is assigned.
I would like this to be exhaustive, could anyone help?
Extending #mehow answer for shapes located in ActiveSheet the following code will result with names of shape and it's macro name if one associated.
Sub getShapeMacro()
'to secure for unexpected...
On Error Resume Next
Dim SHP As Shape
For Each SHP In ActiveSheet.Shapes
Debug.Print SHP.Name, SHP.OnAction
Next
End Sub

How to edit / ungroup EMF pastes in PPT using VBA?

it's Martin from Berlin (Germany - so please excuse my wrong English)...
I'm trying to edit EMF pastes in PPT using VBA. The EMF pastes are Excel charts and I used
ActiveWindow.Selection.SlideRange.Shapes.PasteSpecial DataType:=3 (enhanced metafile)
Without VBA it is easy: Just rightclick the image and "ungroup" (2x).
In VBA I tried the following:
1. Selecting the right shape (works), then
ActiveWindow.Selection.ShapeRange.Ungroup.Select
This runs on an error: "...cannot ungroup".
In another thread a "solution" was given: Recording a macro -> not possible in PPT 2007!
When I record a macro in PPT 2003, it says exactly the same:
ActiveWindow.Selection.ShapeRange.Ungroup.Select
but it doesn't work.
It seems that there should be one step before that converts the emf image into "office format" (if you do it without VBA after clicking "ungroup" a message box occurs that askes, if you want to convert the graphics into "office format").
Any idea what to do that ungroup is working with VBA?
This works here:
Sub UngroupPastedChart()
Dim oShRange As ShapeRange
Dim oSh As Shape
Set oShRange = ActiveWindow.Selection.SlideRange.Shapes.PasteSpecial(ppPasteEnhancedMetafile)
Set oShRange = oShRange.Ungroup
Set oShRange = oShRange.Ungroup
End Sub
and add oShRange.Select if you want the ungrouped shapes to be selected at the end.