Need little help from this forum.
I want to replace shape(autoshape) with other autoshape in my project & found a solution here http://www.vbaexpress.com/forum/showthread.php?68760-Change-Fill-color-using-VBA-in-PowerPoint.
But in my project there are some shapes which contains text(I did not use textbox).
The code are select shape(which will be replaced) by some critaria
ie
by height 2. by weidth 3. fill colour 4. by top position.
As textbox is not a autoshape thats why I used shape which contains text & to give text backgroung transparent I used 'shape fill' to 'no fill'.
In my project there are shapes(not contains text) which are same size & same top position(ie the shape just behind the text shape).
Code is working fine for those shape which did not contains text.When I select the text shape & run the code it replaced all the shape behind the text shape ie
not replace the text shape(which I want to replace).
I tried a lot but not getting the solution.I also tried with changeing the weidth of the shape behind the textshape but not get desire result.
Sir any solution will be highly appreaciate.
Option Explicit
Dim oShapeAfterChange As Shape, oShapeToChange As Shape
Dim tShapeAfterChange As MsoAutoShapeType, tShapeToChange As MsoAutoShapeType
Dim iShapeAfterChangeRGB As Long, iShapeAfterChangeHeight As Double, iShapeAfterChangeWidth As Double, iShapeAfterChangeTop As Double
Sub Step1()
If MsgBox("This is Step 1 of a two step process" & vbCrLf & vbCrLf & _
"1. You must already have inserted and selected a new Shape to change to" & vbCrLf & _
"2. After running, Step1 will remember the new type of shape" & vbCrLf & _
"3. Select one of the shapes to be changed" & vbCrLf & _
"4. Run the Step2 Macro", vbOKCancel + vbInformation, "Change Shapes") = vbCancel Then
Exit Sub
End If
Set oShapeAfterChange = Nothing
On Error Resume Next
Set oShapeAfterChange = ActiveWindow.Selection.ShapeRange(1)
oShapeAfterChange.PickUp
tShapeAfterChange = oShapeAfterChange.AutoShapeType
On Error GoTo 0
If oShapeAfterChange Is Nothing Then
Call MsgBox("You must select an AutoShape", vbCritical + vbOKOnly, "Change Shapes")
Exit Sub
End If
Call MsgBox("Destination Shape type memorized", vbOK + vbInformation, "Change Shapes")
End Sub
Sub Step2()
Dim oPres As Presentation
Dim oSlide As Slide
Dim oShape As Shape, oShapeInGroup As Shape
If MsgBox("This is Step 2 of a two step process" & vbCrLf & vbCrLf & _
"1. You must already have selected an instance of a Shape to change" & vbCrLf & _
"2. All instances on all slides of that type of Shape will be changed", vbOKCancel + vbInformation, "Change Shapes") = vbCancel Then
Exit Sub
End If
If oShapeAfterChange Is Nothing Then
Call MsgBox("1. You must select an example of a new Shape to change the shapes to" & vbCrLf & _
"2. Re-run Step1", vbCritical + vbOKOnly, "Change Shapes")
Exit Sub
End If
Set oShapeToChange = Nothing
Set oShapeToChange = ActiveWindow.Selection.ShapeRange(1)
If oShapeToChange.Type = msoGroup Then
If ActiveWindow.Selection.HasChildShapeRange Then
If ActiveWindow.Selection.ChildShapeRange.Count <> 1 Then
Call MsgBox("You must select exactly one Shape within the Group of the type to be changed", vbCritical + vbOKOnly, "Change Shapes")
Exit Sub
Else
Set oShapeToChange = ActiveWindow.Selection.ChildShapeRange(1)
End If
End If
End If
If oShapeToChange Is Nothing Then
Call MsgBox("You must select a Shape of the type to be changed", vbCritical + vbOKOnly, "Change Shapes")
Exit Sub
End If
With oShapeToChange
tShapeToChange = .AutoShapeType
iShapeAfterChangeRGB = .Fill.ForeColor.RGB
iShapeAfterChangeHeight = Round(.Height, 0)
iShapeAfterChangeWidth = Round(.Width, 0)
iShapeAfterChangeTop = Round(.Top, 0)
End With
Set oPres = ActivePresentation
For Each oSlide In oPres.Slides
For Each oShape In oSlide.Shapes
If oShape.Type = msoGroup Then
For Each oShapeInGroup In oShape.GroupItems
Call pvtChangeAutoShapeType(oShapeInGroup)
Next
Else
Call pvtChangeAutoShapeType(oShape)
End If
Next
Next
oShapeAfterChange.Delete
MsgBox "Shapes updated successfully"
End Sub
Private Sub pvtChangeAutoShapeType(o As Shape)
Dim CenterTop As Double, CenterLeft As Double
With o
If .Type <> msoAutoShape Then Exit Sub
If .AutoShapeType <> tShapeToChange Then Exit Sub
If .Fill.ForeColor.RGB <> iShapeAfterChangeRGB Then Exit Sub
If Round(.Height, 0) <> iShapeAfterChangeHeight Then Exit Sub
If Round(.Width, 0) <> iShapeAfterChangeWidth Then Exit Sub
If Round(.Top, 0) <> iShapeAfterChangeTop Then Exit Sub
.AutoShapeType = tShapeAfterChange
CenterTop = .Top + .Height / 2#
CenterLeft = .Left + .Width / 2#
.Height = oShapeAfterChange.Height
.Width = oShapeAfterChange.Width
.Left = CenterLeft - oShapeAfterChange.Width / 2#
.Top = CenterTop - oShapeAfterChange.Height / 2#
.Apply
End With
End Sub
Related
I need help with inserting a sizeable code into "ThisWorkbook" module in Excel using VBA.
Using the code below I'm able to insert the code into "ThisWorkbook" module, but this method (as I've learned recently) has limitations of 24 lines due to line beak (& _).
Sub AddCode()
Dim VBP As Object
Dim newmod As Object
Set VBP = ActiveWorkbook.VBProject
Set newmod = VBP.VBComponents.Add(1)
Dim StartLine As Long
Dim cLines As Long
With ActiveWorkbook.VBProject.VBComponents("ThisWorkbook").CodeModule
cLines = .CountOfLines + 1
.InsertLines cLines, _
"Private Sub Workbook_Open()" & Chr(13) & _
" Application.Calculation = xlManual" & Chr(13) & _
" Application.CalculateBeforeSave = False" & Chr(13) & _
" Application.DisplayFormulaBar = False" & Chr(13) & _
"Call Module1.ProtectAll" & Chr(13) & _
"End Sub"
End With
End Sub
The code I want to inject in addition to the code above is below (code found on another site). This allows me to track changes on the workbook that I share with others. I do not want to use Excel's built-in "Track Changes" feature.
Dim vOldVal
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim bBold As Boolean
If Target.Cells.Count > 1 Then Exit Sub
On Error Resume Next
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
If IsEmpty(vOldVal) Then vOldVal = "Empty Cell"
bBold = Target.HasFormula
With Sheet1
.Unprotect Password:="Passcode"
If .Range("A1") = vbNullString Then
.Range("A1:E1") = Array("CELL CHANGED", "OLD VALUE", _
"NEW VALUE", "TIME OF CHANGE", "DATE OF CHANGE")
End If
With .Cells(.Rows.Count, 1).End(xlUp)(2, 1)
.Value = Target.Address
.Offset(0, 1) = vOldVal
With .Offset(0, 2)
If bBold = True Then
.ClearComments
.AddComment.Text Text:= _
"Note:" & Chr(10) & "" & Chr(10) & _
"Bold values are the results of formulas"
End If
.Value = Target
.Font.Bold = bBold
End With
.Offset(0, 3) = Time
.Offset(0, 4) = Date
End With
.Cells.Columns.AutoFit
.Protect Password:="Passcode"
End With
vOldVal = vbNullString
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
vOldVal = Target
End Sub
How can I achieve this? What is the best and the most efficient way to do this?
I've tried splitting the code in chunks of 20 lines and create 3 "AddCode" sub-routines, but I get an error at "bBold = Target.HasFormula". I have searched the web for alternatives, but nothing seems to be working.
Thanks in advance.
This is an abbreviated version of what I'm doing to create on load code. I create the onload event, then add a new module.
Sub AddOnload()
''Create on load sub
With ActiveWorkbook.VBProject.VBComponents("ThisWorkbook").CodeModule
.InsertLines 1, "Private Sub Workbook_Open()"
.InsertLines 2, " call CallMe"
.InsertLines 3, "End Sub"
End With
Call CreateCode
End Sub
''Add new module with code
Sub CreateCode()
Dim vbp As VBProject
Dim vbc As VBComponent
Dim strCode
Set vbp = Application.VBE.ActiveVBProject
Set vbc = vbp.VBComponents.Add(vbext_ct_StdModule)
vbc.Name = "tracker"
strCode = "Sub CallMe()" & vbCrLf & "End Sub"
vbc.CodeModule.AddFromString strCode
End Sub
I am trying to write a macro to find and copy all the graphs/images inline in a word document and paste them into individual slides in a new powerpoint. However when I run into multiple runtime errors. Here's the entire code.
Sub wordtoppt()
'This macro copies all pictures out of a word document of your choice and into a new powerpoint presentation.
'Two reference libraries need to be open - Word and Powerpoint. Go Tools > References, and tick the relevant box.
Dim wdApp As Word.Application 'Set up word and powerpoint objects
Dim wdDoc As Word.Document
Dim pptApp As PowerPoint.Application
Dim pptShw As PowerPoint.Presentation
Dim pptChart As PowerPoint.Shape
Dim pptSld As PowerPoint.Slide
On Error GoTo 0
Dim wcount As Integer 'Number of open word documents
Dim doclist() As String 'Collects the names of open word documents
Dim desc As String 'inputbox text
Dim chosendoc As Integer 'stores the index number of your selected word document
Dim ccount As Integer 'number of shapes in the word document
Dim wellpasted As Integer 'Counts the number of shapes that have successfully been pasted into powerpoint.
Application.ScreenUpdating = False
'Establishes link with word.
On Error Resume Next
Set wdApp = GetObject(, "Word.Application")
On Error GoTo 0
If wdApp Is Nothing Then 'Error message if Word is not open
MsgBox "Error: Word is not open." & Chr(10) & Chr(10) & "Is word actually open? This is a bug."
Exit Sub
End If
'Counts the number of word documents open
wcount = CInt(wdApp.Documents.Count)
ReDim doclist(wcount) 'resizes string array of word documents
If wcount = 0 Then 'Error message if Word is open, but there are no documents open
MsgBox "There are no word documents open!" & Chr(10) & "Open a word document and try again"
Exit Sub
End If
'text for input box
desc = "Which document would you like to extract the graphs from?" & Chr(10) & Chr(10) & "Type the number in the box (one number only)." & Chr(10) & Chr(10)
'input boxes for selection of word document
If wcount = 1 Then 'if only one document open
myinput = MsgBox("Do you want to paste graphs from " & wdApp.Documents(1).Name & "?", vbYesNo, "From Release Note to Powerpoint")
If myinput = vbYes Then
chosendoc = 1
Else
Exit Sub
End If
Else
For i = 1 To wcount 'multiple documents open
doclist(i) = wdApp.Documents(i).Name
desc = desc & i & ": " & doclist(i) & Chr(10)
Next
myinput = InputBox(desc, "From Release Note to Powerpoint")
If IsNumeric(myinput) And myinput <= wcount Then 'Error handling - if cancel is clicked, or anything other than a number is typed into the input box.
chosendoc = CInt(myinput)
Else
If myinput = "" Then 'clicking cancel, or leaving input box blank
MsgBox "You didn't enter anything!"
Exit Sub
Else 'if you type a short novel
MsgBox "You didn't enter a valid number!" & Chr(10) & "(Your response was " & myinput & ")"
Exit Sub
End If
End If
End If
'Error handling, for chart-free word documents.
If wdApp.Documents(chosendoc).InlineShapes.Count = 0 Then
MsgBox "There are no charts in this Word Document!"
Exit Sub
End If
'Opens a new powerpoint presentation
Set pptApp = CreateObject("PowerPoint.Application")
Set pptShw = pptApp.Presentations.Add
'PowerPoint.Application
'Sets up slide dimensions
Dim sldwidth As Integer
Dim sldheight As Integer
sldwidth = pptShw.PageSetup.SlideWidth
sldheight = pptShw.PageSetup.SlideHeight
wellpasted = 0
Dim shapecount As Integer 'Number of shapes in the word document
shapecount = wdApp.Documents(chosendoc).InlineShapes.Count
For j = 1 To shapecount 'Adds in the correct number of slides into the powerpoint presentation
Set pptSld = pptShw.Slides.Add(pptShw.Slides.Count + 1, ppLayoutBlank)
Next
For j = 1 To shapecount 'loops through all shapes in the document
On Error GoTo Skiptheloop 'sometimes some objects don't paste. This is a way to skip over them.
'Application.Wait Now + (1 / 86400)
wdApp.Documents(chosendoc).InlineShapes(j).Range.Copy 'copies chart
Set pptSld = pptShw.Slides(j)
pptSld.Shapes.Paste 'pastes chart
'Application.CutCopyMode = False
With pptSld.Shapes(1) 'resizes and aligns shapes
.LockAspectRatio = msoTrue 'Currently sets charts to the height of the slide. Alternatively can scale to 100%
.Height = sldheight
.Left = (sldwidth / 2) - (.Width / 2)
.Top = (sldheight / 2) - (.Height / 2)
End With
wellpasted = wellpasted + 1 'if the chart was pasted successfully, increment by 1.
Skiptheloop:
Next
On Error GoTo 0
If (shapecount - wellpasted) <> 0 Then 'produces a message box if some shapes did not paste successfully.
MsgBox CStr(shapecount - wellpasted) & " (of " & CStr(shapecount) & ") shapes were not pasted. Best that you check all the graphs are in."
End If
Application.ScreenUpdating = True
pptApp.Activate 'brings powerpoint to the front of the screen
Exit Sub
End Sub
On the line pptSld.shapes.paste I get the error clipboard empty or cannot paste.
Any ideas?
I am using Simple solution for my job devided in two pars
1) Extract all images from word file
This can be done in two ways.
a. save as html which will create the folder filenam_files which will hold all the images in .png formate. There may be duplicate images in diff formate but .png will be unique.
b. change filename of word from file.docx to file.docx.zip
You can get the images at file.docx\word\media
There will be no duplicate images in this method.
2) Import all images in powerpoint.
1)
As you have already opened the document manually you can do one more step manually or record macro which will look like this.
Sub exportimages()
ChangeFileOpenDirectory "D:\temp\"
ActiveDocument.SaveAs2 FileName:="data.html", FileFormat:=wdFormatHTML, _
LockComments:=False, passWord:="", AddToRecentFiles:=True, WritePassword _
:="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:= _
False, CompatibilityMode:=0
End Sub
2)
Close the word document.
Open Power point and paste this
Sub ImportABunch()
Dim strTemp As String
Dim strPath As String
Dim strFileSpec As String
Dim oSld As Slide
Dim oPic As Shape
strPath = "D:\temp\data_files\"
strFileSpec = "*.png" 'if you are using mehtod **a.** to extract the images.
'strFileSpec = "*.*" 'if you are using mehtod **b.** to extract the images.
strTemp = Dir(strPath & strFileSpec)
Do While strTemp <> ""
Set oSld = ActivePresentation.Slides.Add(ActivePresentation.Slides.Count + 1, ppLayoutBlank)
Set oPic = oSld.Shapes.AddPicture(FileName:=strPath & strTemp, _
LinkToFile:=msoFalse, _
SaveWithDocument:=msoTrue, _
Left:=0, _
Top:=0, _
Width:=-1, _
Height:=-1)
strTemp = Dir
Loop
End Sub
You can write vbscript to combine this two steps together. I have no idea how to do that. You can google it.
I have a script in VBA that prints out certain user selected variables to a PPT template. In this sub:
Private Sub WarningInfo()
Call Dictionary.WarningInfo
'Sets the font for the warning information text.
With ActiveWindow.Selection.SlideRange.Shapes("WarningText1").TextFrame2.TextRange.Font
.Size = 24
.Name = "Calibri"
.Shadow.Visible = True
End With
ComboBoxList = Array(CStr(ComboBox3))
For Each Ky In ComboBoxList
'On Error Resume Next
'If nothing is selected in ComboBox3, do nothing and exit this sub.
If ComboBox3 = "" Then
Exit Sub
'Otherwise, if it has a selection, insert selected text.
Else
ActiveWindow.Selection.SlideRange.Shapes("WarningText1").TextFrame2.TextRange = vbCrLf & dict2.Item(Ky)(0)
End If
Next
Set dict2 = Nothing
End Sub
It will print out dict2.Item(Ky)(0) within the shape WarningText1. This variable is selected by the user in a GUI and it is pulled from a dictionary. An example of what would be selected and output is "No hail expected".
My next sub is this:
Private Sub WarningInfo2()
Call Dictionary.WindInfo
'Sets the font for the warning information text.
With ActiveWindow.Selection.SlideRange.Shapes("WarningText1").TextFrame2.TextRange.Font
.Size = 24
.Name = "Calibri"
.Shadow.Visible = True
End With
ComboBoxList = Array(CStr(ComboBox4))
For Each Ky In ComboBoxList
'On Error Resume Next
'If nothing is selected in ComboBox4, do nothing and exit this sub.
If ComboBox4 = "" Then
Exit Sub
'Otherwise, if it has a selection, insert selected text.
Else
ActiveWindow.Selection.SlideRange.Shapes("WarningText1").TextFrame2.TextRange = vbCrLf & dict3.Item(Ky)(0)
End If
Next
Set dict3 = Nothing
End Sub
It will print out dict3.Item(Ky)(0). However, with the way this second sub is set up, it will just overwrite the data from the first sub (since both subs are within the same UserForm). I need to find a way to change this line of code ActiveWindow.Selection.SlideRange.Shapes("WarningText1").TextFrame2.TextRange = vbCrLf & dict3.Item(Ky)(0) so that it ADDS this text to the existing text within the shape "WarningText1".
Any ideas?
Thanks!!
ActiveWindow.Selection.SlideRange.Shapes("WarningText1").TextFrame2.TextRange = ActiveWindow.Selection.SlideRange.Shapes("WarningText1").TextFrame2.TextRange & vBCrLf & dict3.Item(Ky) (0)
I need an 'autorun' piece of VBA for Word 2013 to either add or remove a Watermark dependent on the filename of the document. I want to add this to a template we use for our Technical Reports which, in turn, are generated by an external Application/System and automatically named in the process. So the same document template may be named differently dependent on workflow
For documents entitled "DRAFT.XXX.NNNNNNNN.." I want a 'Draft' watermark
For any other documents there should be no watermark (or the watermark could be coloured white, ie invisible)
I've successfully created VBA/Macros to insert or remove Watermarks:
Sub InsertWaterMark()
Dim strWMName As String
On Error GoTo ErrHandler
'selects all the sheets
ActiveDocument.Sections(1).Range.Select
strWMName = ActiveDocument.Sections(1).Index
ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
'Change the text for your watermark here
Selection.HeaderFooter.Shapes.AddTextEffect(msoTextEffect1, _
"DRAFT", "Arial", 1, False, False, 0, 0).Select
With Selection.ShapeRange
.Name = strWMName
.TextEffect.NormalizedHeight = False
.Line.Visible = False
With .Fill
.Visible = True
.Solid
.ForeColor.RGB = Gray
.Transparency = 0.5
End With
.Rotation = 315
.LockAspectRatio = True
.Height = InchesToPoints(2.42)
.Width = InchesToPoints(6.04)
With .WrapFormat
.AllowOverlap = True
.Side = wdWrapNone
.Type = 3
End With
.RelativeHorizontalPosition = wdRelativeVerticalPositionMargin
.RelativeVerticalPosition = wdRelativeVerticalPositionMargin
'If using Word 2000 you may need to comment the 2
'lines above and uncomment the 2 below.
' .RelativeHorizontalPosition = wdRelativeVerticalPositionPage
' .RelativeVerticalPosition = wdRelativeVerticalPositionPage
.Left = wdShapeCenter
.Top = wdShapeCenter
End With
ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
Selection.Collapse Direction:=wdCollapseEnd
Exit Sub
ErrHandler:
MsgBox "An error occured trying to insert the watermark." & Chr(13) & _
"Error Number: " & Err.Number & Chr(13) & _
"Decription: " & Err.Description, vbOKOnly + vbCritical, "Error"
End Sub
Sub RemoveWaterMark()
Dim strWMName As String
On Error GoTo ErrHandler
ActiveDocument.Sections(1).Range.Select
strWMName = ActiveDocument.Sections(1).Index
ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
Selection.HeaderFooter.Shapes(strWMName).Select
Selection.Delete
ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
Selection.Collapse Direction:=wdCollapseEnd
Exit Sub
ErrHandler:
'MsgBox "An error occured trying to remove the watermark." & Chr(13) & _
'"Error Number: " & Err.Number & Chr(13) & _
'"Decription: " & Err.Description, vbOKOnly + vbCritical, "Error"
ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
Selection.Collapse Direction:=wdCollapseEnd
End Sub
I've created an AutoOpen macro which checks the first five characters of the document for "DRAFT", "Draft" or "draft" and then it should call the appropriate Subroutine:
Sub AutoOpen()
Dim oldfilename As String
Dim draft As String
oldfilename = ActiveDocument.Name
draft = Left(oldfilename, 5)
Select Case draft
Case "DRAFT", "Draft", "draft"
Call InsertWaterMark
Case Else
Call RemoveWaterMark
End Select
Exit Sub
BUT I'm getting an error when the code branches to the InsertWatermark Subroutine and the line
.Name = strWMName
I then get an error:
An error occurred trying to insert the watermark. Error Number: 70 Description: Permission denied
How can I fix the error?
You need to convert Integer which comes from .Sections(1).Index property into string. Two suggestions:
.Name = Cstr(strWMName)
or
.Name = "WaterMarkName" & strWMName
Please remember to change accordingly in RemoveWaterMark subroutine.
I'm trying to replace all shape objects on the slide (pictures) with shape objects of another type (rectangular shape). I can delete old object and create new, but i will loose all animation information and sequence order. Is it possible to store animation information and order in timeline, and copy it to the new shape object?
Well, i have found a solution myself, hope someone could find it useful. So, it is not necessary to copy animation information from old shape to a new one, just cycle through sequence's items and replace the shape object refrence to the new shape. Like this:
On Error Resume Next
Dim shp1 As Shape 'old shape
Set shp1 = ActivePresentation.Slides(1).Shapes(3)
Dim shp2 As Shape 'new shape
Set shp2 = ActivePresentation.Slides(1).Shapes.AddPicture("c:\imgres2.jpg", msoFalse, msoTrue, 0, 0) 'it is important to create new shape before cycling through existing ones.
For i = ActivePresentation.Slides(1).TimeLine.MainSequence.count To 1 Step -1
'using "is" opeartor to compare refrences
If shp1 Is ActivePresentation.Slides(1).TimeLine.MainSequence.Item(i).Shape Then
ActivePresentation.Slides(1).TimeLine.MainSequence.Item(i).Shape = shp2
End If
Next i
shp1.Delete 'delete the old shape
Try something like this code to copy the animation into new added shape:
Sub PasteAnimationBehaviours()
Dim SHP As Shape 'for existing shape
Set SHP = ActivePresentation.Slides(1).Shapes(1)
SHP.PickupAnimation
Dim newSHP As Shape 'pasting to new shape
Set newSHP = ActivePresentation.Slides(1).Shapes.AddShape(msoShapeRectangle, 100, 100, 100, 100)
newSHP.ApplyAnimation
End Sub
Added after comment: If you only need to replace type of shape try to use something like this:
Sub ShapeSubstition()
Dim SHP As Shape 'for existing shape
'test for 1st shape in 1st slide
Set SHP = ActivePresentation.Slides(1).Shapes(1)
SHP.AutoShapeType = msoShapeRectangle 'to rectangle
SHP.AutoShapeType = msoShapeOval 'to oval
End Sub
I think it is probably easier to just use the "Animation Painter" command button to copy the animations and apply them to another object. The Animation Painter functions in the same way as the Format Painter. After you have copied the desired animations, you can reorder the individual animations using the Animation Pane.
This code shows how to copy effects from one shape to another. Select a shape before running routine "SetSourceShape" and select one or more shapes before running "PaintEffects".
Option Explicit
' resources:
' http://msdn.microsoft.com/en-us/library/aa168134(v=office.11).aspx
' http://msdn.microsoft.com/en-us/library/aa168135(office.11).aspx
' http://skp.mvps.org/ppttimeline1.htm
' uses functions from:
' https://answers.microsoft.com/en-us/msoffice/forum/all/how-to-copy-paste-animation-effect-in-powerpoint/c0f255c0-167a-4a12-ae37-1e713ee1d8df
Public MySourceShapeId As Long
Public MySourceSlideIndex As Long ' need this with shape id for unique selection
Sub SetSourceShape() ' sets source shape id value if successfull
Dim oShp As PowerPoint.Shape
Dim myShp As PowerPoint.Shape
Dim oSld As Slide
Dim oEffect As Effect
Dim HowMany As Long
Dim FoundEffect As Boolean
HowMany = 0 ' default value for nothing selected
MySourceShapeId = 0 ' default value for nothing available to copy
MySourceSlideIndex = 0
FoundEffect = False ' default value unless selected shape has any effect(s)
On Error Resume Next ' handles error when nothing is selected
HowMany = ActiveWindow.Selection.ShapeRange.Count
On Error GoTo 0 ' restore normal error handling
If HowMany = 0 Then
MsgBox "Nothing is selected"
Else
If HowMany = 1 Then
Set oShp = ActiveWindow.Selection.ShapeRange(1) ' selection on a single slide
For Each oEffect In ActiveWindow.Selection.SlideRange(1).TimeLine.MainSequence
If oEffect.Shape.Id = oShp.Id Then
MySourceShapeId = oShp.Id
MySourceSlideIndex = ActiveWindow.Selection.SlideRange(1).SlideIndex
FoundEffect = True
End If
Next
If FoundEffect Then
MsgBox "Source is selected, Slide: " & MySourceSlideIndex & ", ShapeID: " & MySourceShapeId
Else
MsgBox "Selected item has no effect(s)"
End If
Else
MsgBox "Select only one item"
End If
End If
End Sub
Sub PaintEffects()
Dim oShp As PowerPoint.Shape
Dim oEffect As Effect
Dim HowMany As Long
Dim msg As String
HowMany = 0 ' default value for nothing selected
If MySourceShapeId = 0 Then
MsgBox "No source is selected"
Exit Sub
End If
On Error Resume Next ' handles error when nothing is selected
HowMany = ActiveWindow.Selection.ShapeRange.Count
On Error GoTo 0 ' restore normal error handling
If HowMany = 0 Then
MsgBox "Nothing is selected to paint"
Else
' make sure source is not in this selection
If ActiveWindow.Selection.SlideRange(1).SlideIndex = MySourceSlideIndex Then ' check shapes
For Each oShp In ActiveWindow.Selection.ShapeRange
If oShp.Id = MySourceShapeId Then ' complain
MsgBox "Target selection must not include source item"
Exit Sub
End If
Next
End If
' OK, proceed
For Each oShp In ActiveWindow.Selection.ShapeRange
For Each oEffect In ActivePresentation.Slides(MySourceSlideIndex).TimeLine.MainSequence
If oEffect.Shape.Id = MySourceShapeId Then
Call TransferEffects(oEffect, ActiveWindow.Selection.SlideRange(1), oShp)
End If
Next
Next
End If
End Sub
Sub TransferEffects(oEffectA As PowerPoint.Effect, oSlide As Slide, oShape As PowerPoint.Shape)
Dim oEffectB As Effect
Dim IsMotion As Boolean
Set oEffectB = oSlide.TimeLine.MainSequence.AddEffect(oShape, oEffectA.EffectType)
DoEvents
On Error Resume Next
oEffectB.EffectParameters.Amount = oEffectA.EffectParameters.Amount
If Err.Number = 0 Then
Select Case oEffectA.EffectParameters.Color2.Type
Case Is = msoColorTypeScheme
oEffectB.EffectParameters.Color2.SchemeColor = oEffectA.EffectParameters.Color2.SchemeColor
Case Is = msoColorTypeRGB
oEffectB.EffectParameters.Color2.RGB = oEffectA.EffectParameters.Color2.RGB
End Select
End If
oEffectB.EffectParameters.Direction = oEffectA.EffectParameters.Direction
oEffectB.EffectParameters.FontName = oEffectA.EffectParameters.FontName
If oEffectA.EffectType <> msoAnimEffectGrowShrink Then
oEffectB.EffectParameters.Size = oEffectA.EffectParameters.Size
Else
oEffectB.Behaviors(1).ScaleEffect.ByX = oEffectA.Behaviors(1).ScaleEffect.ByX
oEffectB.Behaviors(1).ScaleEffect.ByY = oEffectA.Behaviors(1).ScaleEffect.ByY
End If
oEffectB.Timing.Duration = oEffectA.Timing.Duration
oEffectB.Timing.Accelerate = oEffectA.Timing.Accelerate
oEffectB.Timing.AutoReverse = oEffectA.Timing.AutoReverse
oEffectB.Timing.Decelerate = oEffectA.Timing.Decelerate
oEffectB.Timing.Restart = oEffectA.Timing.Restart
oEffectB.Timing.RewindAtEnd = oEffectA.Timing.RewindAtEnd
oEffectB.Timing.SmoothStart = oEffectA.Timing.SmoothStart
oEffectB.Timing.SmoothEnd = oEffectA.Timing.SmoothEnd
oEffectB.Exit = oEffectA.Exit
oEffectB.Timing.TriggerType = oEffectA.Timing.TriggerType
oEffectB.Timing.TriggerDelayTime = oEffectA.Timing.TriggerDelayTime
oEffectB.Timing.RepeatCount = oEffectA.Timing.RepeatCount
oEffectB.Timing.RepeatDuration = oEffectA.Timing.RepeatDuration
oEffectB.Timing.Speed = oEffectA.Timing.Speed
With oSlide.TimeLine.MainSequence
If oEffectA.Shape.HasTextFrame Then
Call .ConvertToAnimateBackground(oEffectB, oEffectA.EffectInformation.AnimateBackground)
Else
Call .ConvertToAnimateBackground(oEffectB, True)
End If
Select Case oEffectA.EffectInformation.AfterEffect
Case 2 ' Hide
Call .ConvertToAfterEffect(oEffectB, oEffectA.EffectInformation.AfterEffect)
Case 1 ' Dim
Call .ConvertToAfterEffect(oEffectB, oEffectA.EffectInformation.AfterEffect, oEffectA.EffectInformation.Dim)
Case 3 ' Hide on click
Call .ConvertToAfterEffect(oEffectB, oEffectA.EffectInformation.AfterEffect)
End Select
Call .ConvertToAnimateInReverse(oEffectB, oEffectA.EffectInformation.AnimateTextInReverse)
Call .ConvertToTextUnitEffect(oEffectB, oEffectA.EffectInformation.TextUnitEffect)
End With
Err.Clear
oEffectB.EffectParameters.Relative = oEffectA.EffectParameters.Relative
If Err.Number <> 0 Then
IsMotion = False
Else
IsMotion = True
End If
If IsMotion Then
oEffectB.Behaviors(1).MotionEffect.Path = oEffectA.Behaviors(1).MotionEffect.Path
On Error GoTo 0
If Sgn(Val(oEffectA.Behaviors(1).Timing.Speed)) = -1 Then
oEffectB.Behaviors(1).MotionEffect.Path = Left(oEffectA.Behaviors(1).MotionEffect.Path, 1) & " " & ReversePathInfo(Trim(Mid(oEffectA.Behaviors(1).MotionEffect.Path, 2)))
End If
End If
Exit Sub
errHandler:
If MsgBox(Err.Number & " " & Err.Description & vbCrLf & "Do you wish to continue?", vbQuestion + vbYesNo, "APP_NAME") = vbYes Then
Resume Next
End If
End Sub
Function ReversePathInfo(sPath As String) As String
Dim sItems() As String
Dim i As Integer
Dim sPositions() As String
Dim sReversedPath As String
Dim sClosedPath As String
If Not IsNumeric(Right(sPath, 1)) Then
sClosedPath = Right(sPath, 1)
sPath = Left(sPath, Len(sPath) - 1)
End If
sPath = Replace(sPath, " ", "~")
sItems = Split(sPath, "~")
ReDim sPositions(0 To UBound(sItems))
For i = LBound(sItems) To UBound(sItems)
If Left(sItems(i), 1) = "L" Then sPositions(i) = "L"
If Left(sItems(i), 1) = "C" Then sPositions(i) = "C"
If Left(sItems(i), 1) = "c" Then sPositions(i) = "c"
If Left(sItems(i), 1) = "l" Then sPositions(i) = "l"
Next i
For i = LBound(sPositions) To UBound(sPositions)
If LCase(sPositions(i)) = "c" Then
sPositions(i + 2) = sPositions(i)
sPositions(i) = ""
i = i + 2
End If
Next i
For i = UBound(sItems) To LBound(sItems) Step -1
Select Case Left(sItems(i), 1)
Case "L", "C", "c", "l"
sItems(i) = Trim(Mid(sItems(i), 2))
End Select
sReversedPath = sReversedPath & sItems(i) & " " & sPositions(i) & IIf(sPositions(i) <> "", " ", "")
Next i
ReversePathInfo = Trim(sReversedPath) & IIf(sClosedPath = "", "", " " & sClosedPath)
End Function