I'm having trouble with a Powerpoint 2010 presentation containing an OLEFormat.Object of an Excel chart.
I update the chart using data from Excel and save it at various stages - the idea is that I end up with three presentations:
The original that has been renamed with the word "(Previous)" appended to the file name.
A new version of the original file containing the new data - this is the template for the following month.
A new file containing the new data - this is the report version that is emailed out.
The problem I'm having is that the charts don't seem to retain the updated data. The charts will show the new data, but as soon as I go to edit the chart it flips back and only shows the original data - there's no updated data in the worksheet.
The image below shows what I mean - they're both the same chart, but once I edit the chart the last series changes from December back to June.
To recreate the problem:
Create a new folder and place a new blank presentation in there.
Delete the Click to add title and click to add subtitle objects from the first slide.
On the Insert ribbon select Object and Insert Excel Chart from the Insert Object dialog box.
The chart is called Object 3 (as you deleted the first two objects) and contains six months of random data.
Ensure the presentation is saved as Presentation 1.pptx.
In the same folder create a new Excel 2010 workbook.
Add the following VBA code to a module within the workbook and execute the Produce_Report procedure:
Option Explicit
Public Sub Produce_Report()
Dim sTemplate As String 'Path to PPTX Template.
Dim oPPT As Object 'Reference to PPT application.
Dim oPresentation As Object 'Reference to opened presentation.
sTemplate = ThisWorkbook.Path & "\Presentation1.pptx"
'Open the Powerpoint template and save a copy so we can roll back.
Set oPPT = CreatePPT
Set oPresentation = oPPT.Presentations.Open(sTemplate)
'Save a copy of the template - allows a rollback.
oPresentation.SaveCopyAs _
Left(oPresentation.FullName, InStrRev(oPresentation.FullName, ".") - 1) & " (Previous)"
'Update the chart.
Audit_Volumes oPresentation.slides(1)
'Save the presentation using the current name.
oPresentation.Save
'Save the presentation giving it a new report name.
oPresentation.SaveAs ThisWorkbook.Path & "\New Presentation"
End Sub
Private Sub Audit_Volumes(oSlide As Object)
Dim wrkSht As Worksheet
Dim wrkCht As Chart
With oSlide
With .Shapes("Object 3")
Set wrkSht = .OLEFormat.Object.Worksheets(1)
Set wrkCht = .OLEFormat.Object.Charts(1)
End With
With wrkSht
.Range("A3:D7").Copy Destination:=.Range("A2")
.Range("A7:D7") = Array("December", 3, 4, 5)
End With
RefreshThumbnail .Parent
End With
Set wrkSht = Nothing
Set wrkCht = Nothing
End Sub
Public Sub RefreshThumbnail(PPT As Object)
With PPT
.designs(1).slidemaster.Shapes(1).Left = .designs(1).slidemaster.Shapes(1).Left + 1
.designs(1).slidemaster.Shapes(1).Left = .designs(1).slidemaster.Shapes(1).Left - 1
End With
End Sub
Public Function CreatePPT(Optional bVisible As Boolean = True) As Object
Dim oTmpPPT As Object
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Defer error trapping in case Powerpoint is not running. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
On Error Resume Next
Set oTmpPPT = GetObject(, "Powerpoint.Application")
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'If an error occurs then create an instance of Powerpoint. '
'Reinstate error handling. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If Err.Number <> 0 Then
Err.Clear
Set oTmpPPT = CreateObject("Powerpoint.Application")
End If
oTmpPPT.Visible = bVisible
Set CreatePPT = oTmpPPT
On Error GoTo 0
End Function
Surely the two versions of the presentation saved after the chart has been updated should show the data for the updated chart?
When updating charts in Powerpoint I've previously seen examples of changing the Powerpoint view to slidesorter, performing an action on the shape (DoVerb) and then switching the view back again.
I've often had problems with the code throwing errors, probably because I generally update Powerpoint from either Excel or Access.
I've had a play around and got it to work.
An embedded chart object has two verbs available as far as I can tell - Edit and Open.
So in my code where I have RefreshThumbnail .Parent, I have updated the code to RefreshChart .Parent, .slidenumber, .Shapes("Object 3").
The new procedure is:
Public Sub RefreshChart(oPPT As Object, SlideNum As Long, sh As Object)
oPPT.Windows(1).viewtype = 7 'ppViewSlideSorter
oPPT.Windows(1).View.gotoslide SlideNum
oPPT.Windows(1).viewtype = 9 'ppViewNormal
sh.OLEFormat.DoVerb (1)
End Sub
(previously I was using oPPT.ActiveWindow which I think was causing the problem).
Now I'm just having problems with one chart resizing itself and the calculations behind another not recalculating - different problems for different questions I think.
You might try replacing the RefreshChart sub routine (from Darren Bartrup-Cook) with just this
oPPT.OLEFormat.Activate
Call Pause or Sleep (3000) ' anything that pauses the macro and allows Powerpoint to do it's work
ActiveWindow.Selection.Unselect 'This is like clicking off the opened embedded object
You may need this too. Where slideindex is the current slide's index.
ActiveWindow.View.GotoSlide oSl.Slideindex
Related
I have included the current code which works to update the source value, My presentation is for a monthly report and each Month I change the data source which is an excel file.
But then I have to click on each chart in the presentation and click "refresh Data" in order for the chart to update.
Is there any code that I could add to this VBA that will update all of the charts automatically?
Sub UpdateLinks()
Dim ExcelFile
Dim exl As Object
Set exl = CreateObject("Excel.Application")
'Open a dialog box to promt for the new source file.
ExcelFile = exl.Application.GetOpenFilename(, , "Select Excel File")
Dim i As Integer
Dim k As Integer
'Go through every slide
For i = 1 To ActivePresentation.Slides.Count
With ActivePresentation.Slides(i)
'Go through every shape on every slide
For k = 1 To .Shapes.Count
On Error Resume Next
'Set the source to be the same as teh file chosen in the opening dialog box
.Shapes(k).LinkFormat.SourceFullName = ExcelFile
If .Shapes(k).LinkFormat.SourceFullName = ExcelFile Then
'If the change was successful then also set it to update automatically
.Shapes(k).LinkFormat.AutoUpdate = ppUpdateOptionAutomatic 'other option is ppUpdateOptionManual
End If
On Error GoTo 0
Next k
End With
Next i
End Sub
I have tried various code that I have found on the internet and have tried using ChatGPT to write the code but nothing seems to work.
I am using VBA to open the open PowerPoint chart data in Excel and perform a series of actions, such as hiding/deleting rows & columns. I am using the chart.ChartData.Activate command to open the Excel. I had issues in the past with trying to close the workbook immediately after processing, using Workbook.Close(), so I left the Excels open. This has now become an issue with larger presentations and it's causing PowerPoint to crash and open back up in Recovery Mode. Even when I reinstate the Workbook.Close() command, sometimes these instances of Excel still remain open or I lose scope to them inside the routine.
I am processing the presentation on a slide by slide basis so I'm looking for a way to close these open instances all at once, after I'm done processing each slide.
Does anyone know how to access these hanging Excel processes? I've included a picture to better help explain where they reside.
I created an example routine below. I am using the ChartData.ActivateChartDataWindow command instead ChartData.Activate b/c when originally designing this, the Activate command caused the full Excel application to open instead of the ChartDataWindow and tremendously slowed down processing and would sometimes crash when repeated over and over again.
I also added an image of PowerPoint with the ChartDataWindows that are left open by my code.
Private Sub ClearColumnsInExcel()
'Set the slide
Dim slide As slide
Set slide = pptPres.Slides(1)
'Index through each shape on the slide
Dim shapeX As Integer
For shapeX = 1 To slide.Shapes.Count
'If this shape has a chart
If slide.Shapes(shapeX).Type = msoChart Then
'Set the chart
Dim chart As chart
Set chart = slide.Shapes(shapeX).chart
'Set the worksheet
Dim wks As Worksheet
Set wks = chart.ChartData.Workbook.Worksheets(1)
'Activate the workbook
chart.ChartData.ActivateChartDataWindow
'Clear target columns
'Remove objects from memomry
Set wks = Nothing
Set chart = Nothing
End If
Next shapeX
End Sub
I am not sure how you build you code, but you are just closing the workbook. To get the desired outcome, you need to quit the excel application.
I think something like this you do the trick:
Private Sub testSave()
Dim xlsApp As Excel.Application
Dim xlsWbk As Excel.Workbooks
Set xlsApp = New Excel.Application
xlsApp.Visible = True
Set xlswkb = xlsApp.Workbooks.Add 'creating a new wokbook just to test
'do your thing here
xlswkb.Close SaveChanges:=False ' close workbook without saving in this
example
xlsApp.Quit ' quitting the excel app
End Sub
I have a Word 2010 document embedded inside an Excel sheet. I want to create content control boxes inside the word doc which can be populated programatically. For this I need to set tags for the content control.
I read on the MSDN website and some other sources that it is simple enough - you just have to enable Design Mode and then right click the content control box and click Properties. However, the properties option is grayed out and disabled even though I'm in Design Mode.
When I do this on a standalone Word document (not an embedded one), it works just fine. So that's a workaround I'm using right now. However it's really inconvenient to have to create the boxes in the standalone Word doc and copy them over into the one embedded in Excel.
Is it possible to edit properties of content control box in a Word doc embedded inside an Excel sheet?
It can be done programmatically, something like the code snippet that follows.
An embedded Word document is an Excel OLEObject; such an object can be named, for example: ws.Objects(1).Name = "WordDoc" - this is saved in the workbook and will remain the same, even if other objects are added later. This does not name the document, only the object on the surface of the Worksheet.
If the embedded document has never been accessed during a session, it first needs to be activated. As doing so causes the screen to jump and the selection to change, IF conditions are included to test that and first activate the OLEObject, as well as re-selecting the cell that was active previously.
Working with the .Tag property is shown in the For Each...Next loop. You can see the result if you go into Design Mode.
Note that the macro will not work if you're in Design Mode or if the selection is in the embedded Word document.
Sub Test()
Dim ws As Excel.Worksheet
Dim currCel As Excel.Range
Dim oDoc As OLEObject
Set currCel = Application.Selection
Set ws = ActiveWorkbook.Worksheets("Sheet1")
'Debug.Print ws.OLEObjects.Count
Set oDoc = ws.OLEObjects("WordDoc")
' Debug.Print oDoc.OLEType 'Type 1 = Embedded
WorkWithWordDoc oDoc, currCel
End Sub
Sub WorkWithWordDoc(oDoc As OLEObject, selRange As Excel.Range)
Dim doc As Word.Document
Dim wasActivated As Boolean
Dim cc As Word.ContentControl
'On first opening the Workbook
'the OLE interface of the OLEObject
'isn't accessible, so activate it
wasActivated = True
On Error Resume Next
Set doc = oDoc.Object
If Err.Number = 1004 Then
Excel.Application.ScreenUpdating = False
oDoc.Activate
wasActivated = False
Set doc = oDoc.Object
Excel.Application.ScreenUpdating = True
End If
On Error GoTo 0
For Each cc In doc.ContentControls
cc.Tag = "CC in embedded Doc"
Next
'Clean up
If Not wasActivated Then
'Deactivate the document
selRange.Select
End If
Set doc = Nothing
End Sub
Updated & cross-posted from: http://www.ozgrid.com/forum/showthread.php?t=203827
My objective is to run an Excel macro from within PowerPoint. [All the macro does is change the row filtering for a data range in Excel, thus changing lines depicted on a chart].
So my PPT macro should (1) run the Excel macro which changes the chart, and then (2) update that chart in PPT which is linked to the Excel chart.
Here’s what I’ve tried:
Sub Test()
Excel.Application.Run "'" & "C:\myPath\" & "PPT Macro Test.xlsm'!Steps"
ActivePresentation.UpdateLinks
End Sub
It runs the “Steps” macro, updating the chart in Excel, but does not update the PPT chart.
So I adapted a technique from this post: How to update excel embedded charts in powerpoint? (hat tip brettdj).
Sub Test()
Excel.Application.Run "'" & "C:\myPath\" & "PPT Macro Test.xlsm'!Steps"
ChangeChartData
End Sub
Sub ChangeChartData()
Dim pptChart As Chart
Dim pptChartData As ChartData
Dim pptWorkbook As Object
Dim sld As Slide
Dim shp As Shape
For Each sld In ActivePresentation.Slides
For Each shp In sld.Shapes
If shp.HasChart Then
Set pptChart = shp.Chart
Set pptChartData = pptChart.ChartData
pptChartData.Activate
Set pptWorkbook = pptChartData.Workbook
On Error Resume Next
'update first link
pptWorkbook.UpdateLink pptWorkbook.LinkSources(1)
On Error GoTo 0
pptWorkbook.Close True
End If
Next
Next
Set pptWorkbook = Nothing
Set pptChartData = Nothing
Set pptChart = Nothing
End Sub
Now it works as hoped, but it pauses while it opens, saves & closes the workbook. It’s a fairly large file, so this is an unacceptable delay during a presentation. Is there a way to run a macro in an Excel workbook which is already open “behind the scenes”, without reopening and closing it?
Thanks in advance.
In my brief testing, assuming the workbook is already open, then the data should update in real-time based on the Excel procedure. You should not need to call the ChangeChartData procedure from PowerPoint at all.
Sub Test()
Excel.Application.Run "'" & "C:\myPath\" & "PPT Macro Test.xlsm'!Steps"
End Sub
This avoids the (presumably) resource-intensive task of the Save method against a very large Excel file, which when called from your PPT is being done against every chart, regardless of need, and which seems a very likely culprit for unnecessarily long runtime.
There may be some exceptions based on how the Test procedure is invoked from PowerPoint, and if you observe otherwise you should please add more detail (minimally: how the procedure is being run whilst the PPT is in Presentation Mode)
This answer is promising though, it has some apparent caveats (both files must be open, the Excel file should be the only Excel file open, etc.). I haven't tested other scenarios to see if it still works. It does appear to be working for me:
Set pres = Presentations("Chart.pptm") 'ActivePresentation, modify as needed.
' Make sure you reference correct shape name on the next line:
pres.Slides(1).Shapes("Chart1").LinkFormat.Update
In your implementation, perhaps:
For Each sld In ActivePresentation.Slides
For Each shp In sld.Shapes
If shp.HasChart Then
Set pptChart = shp.Chart
pptChart.LinkFormat.Update
End If
Next
Next
Regarding the Activate method of the ChartData object, MSDN Notes that:
You must call the Activate method before referencing this property; otherwise, an error occurs.
This is by design and "wont' be changed", but I've never spoke to anyone who understands why this is considered a good or desireable UI experience...
This self-answered question from a few years ago suggests you can avoid the Activate requirement, but I do not think this is accurate -- I can't replicate it and I can't find any other sources which indicate this can be done.
#David, thanks for the help. This (mostly) works:
Sub Test()
Excel.Application.Run "'" & "C:\myPath\" & "PPT Macro Test.xlsm'!Steps"
Slide1.Shapes(1).LinkFormat.Update
End Sub
Mostly. Your comments "it was working, then it wasn't, now it is" forced me into some troubleshooting. Here's the workaround:
Open the PPT file, click update links
Immediately, right click on the embedded/linked chart, select "Edit Data"
This opens the Excel file (NOT read-only)
Close Excel, without saving the file
Amazingly, it then runs by clicking the button in slideshow view, or stepping thru in the VB Explorer. Even more amazing, when it runs it doesn't open Excel--it just works in the background.
If I do NOT right click >> "Edit Data" first, it will ALWAYS open Excel & prompt for Read-Only/Notify/Cancel. Then I can't run the macro from PPT, and running it within Excel updates the chart only in Excel, not in PPT as well.
Alternately I tried "Slide1.Shapes(1).LinkFormat.AutoUpdate = ppUpdateOptionAutomatic" to see if that would set updating to automatic...it didn't.
If anyone can chime in with a fix to the workaround, I'd appreciate it. In the meantime, thanks David for your selfless perseverance, and I'll try to figure out how to give you credit for the answer.
I'm new to VBA/macro's and I want to copy a specific data range in excel to powerpoint. I have searched this website for codes and I found something that goes in the good direction (see link below), but I can't adjust it well enough to make it work since I don't know enough of the language.
What I need is a code that selects 1 column range (>150 cells) in Excel and pastes every individual cell to an existing powerpoint file from slide 3 and onward (cell A3 to slide 3, A4 to slide 4, etc) in the right corner.
copy text from Excel cell to PPT textbox
My version crashes when I try for example:
ThisWorkbook.Sheets("RMs").Range("A3:A8").Value
The problem might be that I don't specify the shape well enough and/or give a proper range of slides.
If anyone can help me I would be most grateful, thanks in advance.
I written down some slight modification of the existing code from the link you gave above that complies with your needs.
Be aware that you will need to have the presentation with the slides already saved and ready to be filled with data from Excel.
After pasting the cell in each slide based on your logic of cell A3 in slide 3 you can move the newly created shapes with the coordinates of left and top.
Code:
Option Explicit
Sub Sammple()
Dim oPPApp As Object, oPPPrsn As Object, oPPSlide As Object
Dim oPPShape As Object
Dim FlName As String
Dim i as integer
'~~> Change this to the relevant file
FlName = "C:\MyFile.PPTX"
'~~> Establish an PowerPoint application object
On Error Resume Next
Set oPPApp = GetObject(, "PowerPoint.Application")
If Err.Number <> 0 Then
Set oPPApp = CreateObject("PowerPoint.Application")
End If
Err.Clear
On Error GoTo 0
oPPApp.Visible = True
'~~> Open the relevant powerpoint file
Set oPPPrsn = oPPApp.Presentations.Open(FlName)
for i=3 to ThisWorkbook.Sheets("RMs").Range("A65000").end(xlup).row
'~~> Change this to the relevant slide which has the shape
Set oPPSlide = oPPPrsn.Slides(i)
'~~> Write to the shape
ThisWorkbook.Sheets("RMs").Range("A" & i).CopyPicture Appearance:=xlScreen, _
Format:=xlPicture
oPPSlide.Shapes.Paste.Select
'
'~~> Rest of the code
'
End Sub
As Catalin's already mentioned, you must first create the presentation and add enough slides to hold the data you want to paste.
Sub AddSlideExamples()
Dim osl As Slide
With ActivePresentation
' You can duplicate an existing slide that's already set up
' the way you want it:
Set osl = .Slides(1).Duplicate(1)
' Or you can add a new slide based on one of the presentation
' master layouts:
Set osl = .Slides.AddSlide(.Slides.Count + 1, .Designs(1).SlideMaster.CustomLayouts(1))
End With
End Sub