Just to let you all know, I'm a beginner to VBA and I'm using Excel and PowerPoint 2013.
The aim: I'm writing code in Excel VBA to paste a chart from Excel into PowerPoint. Then when it's pasted, move it to a set place within the slide.
The code I used: The framework of the code I started with is in http://peltiertech.com/Excel/XL_PPT.html#chartppt, the part called 'Paste the Active Excel Chart into the Active PowerPoint Slide (Early Binding)'.
The main difference is around the 'Paste' part, this is instead a 'PasteSpecial' and my code is as follows:
.
Charty.CopyPicture
ppApp.ActivePresentation.Slides(SlideNumber).Shapes.PasteSpecial (ppPasteEnhancedMetafile)
' Setting the correct position on the slide
ppApp.ActiveWindow.Selection.ShapeRange.Top = ChartTop
ppApp.ActiveWindow.Selection.ShapeRange.Left = ChartLeft
(Note. ChartTop and ChartLeft have been defined earlier)
The issues: I'm aware that after the PasteSpecial it doesn't have a select statement. However, (1) When I run the above code I get a runtime error '-2147188160' saying the Selection.ShapeRange is an invalid request (in the 'ChartTop' line), ie. it isn't selected so it can't be moved. (2) When I add a select statement to the 'Paste.Special' line I get an 'Object required' error on the new 'PasteSpecial' line, ie. it doesn't recognise it as a paste select statement.
The odd part: When I run the same macro on other people's computers using the exact same Excel and PowerPoint files it works (without the select statement in the 'PasteSpecial' line). I've looked at 'Tools' => 'References', and both of our computer have the same settings.
The questions: Is there a setting that I have overlooked on my computer which prevents the code from working? Is there a way after I've pasted it to reselect it before it is moved (I should tell you that the macro is to paste in many graphs into ppt simultaneously)? How come for other people at my work it works on their computers without the 'select' part of the PasteSpecial statement? How come when I use the Shapes.PasteSpecial (ppPasteEnhancedMetafile).Select statement, it doesn't recognise it as an object?
I hope that's clear.
Thanks in advance.
Dim oSh as Shape
Set oSh = ppApp.ActivePresentation.Slides(SlideNumber).Shapes.PasteSpecial (ppPasteEnhancedMetafile)(1)
Now you don't need to select anything (which is best avoided whenever possible). Just manipulate the pasted shape, oSh, directly.
The curious syntax (the (1) at the end) is because Shapes.Paste or .PasteSpecial returns a shaperange, not a shape; the (1) causes it to assign the first shape in the range to the oSh variable. Since there's only one shape in the range, that suits us just fine.
Related
I have a macro that is intended to copy a chart from excel into a word document in the same way as manually copy and pasting using "Keep Source Formatting and Embed Workbook." Below is the code that, to my understanding, should accomplish this.
Set reductionChart = graphWorksheet.ChartObjects("reduction")
reductionChart.Copy
masterReport.Paragraphs.Last.Range.PasteAndFormat wdChart
graphWorksheet is the worksheet that contains the graphs, masterReport is the word document.
The issue I am having is error 4605 command not available on the PasteAndFormat line. I happened to discover that manually copying the graph then running the line worked without issue. Thinking that maybe right clicking copied in a different way than .copy so I record a macro of the action and ended up with:
ActiveSheet.ChartObjects("Reduction").Activate
ActiveChart.ChartArea.Copy
Even substituting this in the error still occurs. What is happening here?
After some additional testing I am thinking that possibly when using .copy the chart is sort of only stored within excel and not the clipboard so when paste and format looks for something it see an empty clipboard and has an error, but right clicking copy stores it to the clipboard hence why is available still even after I run ActiveChart.ChartArea.Copy again.
I've attempted to create new workbook with a single sheet and chart. Also tried using late binding instead on the off chance that did something. This is the full code still giving the same issue
Sub test()
Dim masterWord As Object
Dim masterReport As Object
Set masterWord = CreateObject("Word.Application")
Set masterReport = masterWord.Documents.Add
masterWord.Visible = True
ThisWorkbook.Worksheets(1).ChartObjects("Chart 1").Copy
masterReport.Paragraphs.last.Range.PasteAndFormat wdChart
End Sub
After much testing this is the best workaround I'm managed to figure out.
reductionChart.Chart.ChartArea.Copy
masterReport.Paragraphs.Last.Range.PasteAndFormat wdFormatOriginalFormatting
masterReport.InlineShapes(masterReport.InlineShapes.Count).LinkFormat.BreakLink
wdFormatOriginalFormatting and wdPasteDefault both work and don't seem to make a difference to the outcome as far as I have seen.
This has one issue that I've found which is that on ActiveDocument.Fields.Update an information box will popup warning that the linked file is unavailable. This will occur for each unlinked item. I attempted to use Application.DisplayAlerts = False but this did not prevent the popup. This may come back to bite me, but I simply removed this line as it was unnecessary for my purposes.
I'm sorry to be posting another PasteSpecial-question, but I haven't found something that relates precisely to what I'm trying to do.
I have some VBA code:
For Each Workbook In Workbooks
For Each Sheet In Workbook.Sheets
running_pp_app.ActivePresentation.Slides.Add running_pp_app.ActivePresentation.Slides.Count + 1, ppLayoutTitleOnly
Sheet.Range("a1:b2").Copy
running_pp_app.ActivePresentation.Slides(running_pp_app.ActivePresentation.Slides.Count).Shapes.PasteSpecial DataType:=ppPasteDefault, link:=msoCTrue
Next Sheet
Next Workbook
When I paste the Excel-range into a slide, I ultimately want to have the pasted range/shape occupying a placeholder in the slide-layout. I don't want it to be just some additional shape on the slide.
Ultimately, my goal is to be able to easily control all of the pasted ranges/shapes via master-layouts (via the UI, after my VBA runs). I don't know how to paste the linked OLE object into the slide so that it occupies a placeholder-position--so that it is the "content" in the "Title and Content" master-layout, for example.
How can I do this?
All help is appreciated. Thanks.
My first thought was that this doesn't appear to be possible. This works to paste into a placeholder:
Sub PasteIntoPlaceholder()
ActivePresentation.Slides(1).Shapes(2).Select
ActiveWindow.View.PasteSpecial DataType:=ppPasteDefault
End Sub
But as soon as you add the link parameter, it pastes as a separate shape, not in the placeholder.
This mostly corresponds to analogous actions in the user interface. A straight Paste onto a slide with a selected placeholder will insert the chart as expected, but a Paste Special will not.
Revision:
Following your suggestion, this mostly does the job. The placeholder shrinks to fit the pasted Excel object instead of the Excel object expanding to fit the placeholder, but hey, it works:
Sub PasteIntoPlaceholder()
With ActiveWindow
.View.PasteSpecial DataType:=ppPasteDefault, Link:=msoCTrue
.Selection.Cut
ActivePresentation.Slides(1).Shapes(2).Select
.View.Paste
End With
End Sub
I am trying to copy some charts (embedded) in different worksheets of an excel workbook using vbscript into different slides of a powerpoint. I would like to keep the link between the excel sheet and the powerpoint while doing so and therefore I used the below piece of code that allows me to keep formatting and link (instead of a simple paste or PasteSpeical. Is there any other way?) :
For i = 1 to TotalNumWorkSheets 'I iterated with indices.
Set pptSlide = pptPres.Slides.Add(i, 11) 'There is one opening slide before this.
set ws = wb.Worksheets(i)
ws.ChartObjects(1).Chart.ChartArea.Copy
pptApp.CommandBars.ExecuteMso("PasteExcelChartSourceFormatting")
pptApp.CommandBars.ReleaseFocus
With pptSlide
.Shapes.Title.TextFrame.TextRange.Text = objCurSheet.Name
'Adding some more textboxes here. Working fine. Position checks out in PPT.
.Shapes(.Shapes.Count).Left = 20 'Doesn't work for all slides.
End With
Next
The code works and copies all the charts, creates titles, adds new text as expected, but I am not able to position the charts on individual slides because after the ExecuteMso command, I don't know how to access the reference to the chart. I read in one of the SO posts that pasting using this method looses the chart selection but you can access the last .Shapes object since pasting always adds the object to the end of the list. Is that always the case? I tried accessing and positioning my chart by accessing the last object but it only works for the first slide of the loop (i.e. the first chart pasted is shifted to Left=20). The rest all charts in other slides are centered. Can someone explain where and how to add the formatting chart options? I ran into an even weirder problem. If I increase the number of worksheets, even the first plot looses it's Left formatting. The above code is the only place where I add formatting so I don't know what is happening. I am sure I am not formatting it correctly.
Many thanks for your suggestions.
Edit: One additional thing which I tested. I am using
WScript.Sleep 500
code before the For loop ends since it gives enough time for earlier operations to finish (at least that's what I understood from many other google searches).
So after some more searching and testing, I found a solution (for my case at least).
Moved the WScript.Sleep 1000 (500 didn't work for me) statement just below CommandBars.ReleaseFocus.
It makes some sense now since it is the Chart copying, pasting and linking from excel that needs time. Especially with source formatting. After that there is only text generation which I believe is not so heavy.
Cleared all the set Object variables when not used. Especially the ones associated with the "With" keyword.
set obj = CreateObject()
With obj
'Do something here.
End With
set obj = Nothing
Not clearing them, apparently, can also prevent you from closing the applications even after you use the .Close and .Quit method. At least that's what I observed. I found PowerPoint.exe running in the task manager when nothing was opened.
After doing the above, I am able to copy with format the charts and also able to set the position of the charts. The weird problem of larger number of worksheets also disappeared. Hopefully, it might help others. If someone thinks the observations are incorrect or troublesome, please correct.
I am looking at inserting/pasting a range of text data (40 columns) from Excel into bookmarks in Word. Most of the answers are done using Excel VBA, which is so not practical for my use case as I will have the Word document open, add a button that would run this 'import data' macro. I actually already have a button in the doc that inserts images into bookmarks, so that's one more reason I don't want to do it via Excel VBA.
I know this is not great code, but for the lack of definite leads, I'm throwing it here and hope that this gives you an idea of what I'm trying to achieve:
Sub ImportData()
Workbooks.Open ("\Book2.xlsm")
ActiveWindow.WindowState = xlMinimized
ThisWorkbook.Activate
Windows("Book2.xlsm").Activate
Range("A1:AF1").Select
Selection.Copy
Documents("test.docm").Activate
Selection.GoTo What:=wdGoToBookmark, Name:="Overlay_1"
Selection.Paste
End Sub
PS: It would be great if I could sort of 'transpose' the 40 columns into rows as it is pasted in Word.
Here's an update to my code based off #Variatus 's advice:
Sub ImportData()
Dim wb As Workbooks
Dim ws As Worksheets
Dim objSheet As Object
Dim objWord As Object
Set objWord = CreateObject("Word.Application")
wb.Open ("C:\Users\pc\Documents\Book2.xlsm")
Set objSheet = CreateObject("Excel.Application")
ActiveWindow.WindowState = xlMinimized
Set ws = Workbooks("Book2.xlsm").Sheets("Sheet1")
ws.Range("A1").Value.Copy
With objWord.ActiveDocument
.Bookmarks("Bookmark_1").Range.Text = ws.Range("A1").Value
End With
End Sub
I'm getting this error:
Runtime Error '91':
Object variable or With block variable not set.
Notice how I stuck with a single cell reference for now (A1). I'll just update my code as I learn along the way :)
When you click the button in your Word document you want the following sequence to be initiated.
Create an Excel application object. Make sure that a reference to Excel has been set (VBE > Tools > References) so that Excel's VBA objects are available.
Using the Excel application object, open the workbook. Create an object. Place the object in an invisible window.
Definitely forget about activating or selecting anything in either the workbook or your Word document. The latter is active and remains active from beginning to end. The bookmarks are points in your document you can reference and manipulate by name without selecting them. The Excel workbook is invisible. You can access any part of it using the Range object.
The data you want from your workbook are contained in Worksheets. Be sure to create an object for the worksheet you are about to draw data from.
Excel tables don't translate very well into Word tables. If you do want to go that way I suggest that you use VBA to create the table you want in Excel (transpose the data before you import them into Word). However, you may find it easier to first create the tables you want in Word and then just copy values from your Excel source into the word tables. That would involve taking one cell value at a time and placing it into one Word table cell. Transposing would be done by the algorithm you employ.
Close the workbook. Quit the Excel application. Set the Excel application = Nothing. At the end of your macro everything is as it was before except that your document has data in it which it didn't have before.
Each of the above six points will lead you to at least one question which you can ask here after you have googled the subject and written some code. In fact, I strongly urge you to create one Main procedure (the one which responds to your button click) and let that procedure call various subs which carry out the individual tasks and functions to support the subs. The smaller the parts you create the easier it is to write the code, to find questions to ask and get answers to them. If you plan your project well expect to have about 12 procedures in it by the time you are done. Good luck!
[There is another recent question with a similar title that has not yet been answered satisfactorily, and gave me no insight :-( ]
This is my first attempt to integrate a little Word automation with Excel VBA, so I started with a macro recording in Word VBA to have a clue. Unfortunately, when I try to translate this into Excel, even making allowances for having to use the Excel local wrdDoc to qualify references, the code that works in Word VBA does not work from Excel VBA. Deeply frustrating.
Here is the recorded code snippet from Word that I started with:
[Shape name manually edited after recording to match assigned name for the Watermark image]
ActiveDocument.Sections(1).Range.Select
ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
Selection.HeaderFooter.Shapes("US-CA watermark").Select
Selection.Delete
Here is the code snippet from Excel I derived from that:
[sWatermark string predefined to match the picture name]
With wrdDoc
.Sections(1).Range.Select
.ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
.Selection.HeaderFooter.Shapes(sWatermark).Select
.Selection.Delete
End With
Result: VBA chokes every time when I try to select the watermark (line 3 within the With block).
I have tried the problem line with and without the . prefix [i.e. as wrdDoc.Selection and just Selection (as in the original Word macro) ].
I have tried accessing the watermark as .HeaderFooter.shapes(1) after verifying that there is only 1 item in the range. Again, this seems to work quite satisfactorily in Word VBA, but never in Excel VBA.
WHY?!?!?!
Avoid using the Selection when possible, as it can be changed during macro execution. For example:
wrdDoc.StoryRanges(wdPrimaryHeaderStory).ShapeRange(1).Delete