VBA Excel to Outlook - Separating pasted tables - excel

I'm running a basic macro to copy/paste/format emails to simplify reports that I'm handing off to my team.
(This will be the 3rd question I've posted here this weekend and I'm immensely grateful for all of the support and patience you've all shown)
As with most of my other questions, I've got a macro that functionally works, but it's missing the part that makes it look like I know what I'm doing..
The macro runs through several separate ranges in a worksheet. For each range it copies the selected area, pastes it into the email and centers the pasted table.
This is an expansion on my previously asked question:
How Do I Center a Pasted Table with VBA
The issue I'm having is that even with .Range.InsertParagraphBefore to create a new line, My tables seem to be nesting inside of each other as they load in.
Dims for Context:
Sub Macro7()
' Works in Excel 2000, Excel 2002, Excel 2003, Excel 2007, Excel 2010, Outlook 2000, Outlook 2002, Outlook 2003, Outlook 2007, and Outlook 2010.
Dim rng As Range
Dim OutApp As Object
Dim outMail As Object
Dim Location As String
Dim Signature As String
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
'Open new mail item
Dim outlookApp As Object
Set outlookApp = CreateObject("Outlook.Application")
Set outMail = outlookApp.CreateItem(0)
'Get Word editor
outMail.Display
Dim wordDoc As Object
Set wordDoc = outMail.GetInspector.WordEditor
Problem Code:
'Copy contents
Sheets("Tables").Select
Range("AB7:AI75").Select
Range("AB7").Activate
Selection.Copy
'Paste as image (Centered)
wordDoc.Range.InsertParagraphBefore 'Create new empty paragraph before signature
wordDoc.Paragraphs.first.Range.PasteAndFormat Type:=wdChartPicture
wordDoc.Range.InsertParagraphBefore
With wordDoc.Tables(1).Rows
.WrapAroundText = 0 'If this is true does not work
.Alignment = 1
End With
'======== SECOND TABLE ========
'Copy contents (2)
Sheets("Tables").Select
Range("P7:Z29").Select
Range("P7").Activate
Selection.Copy
'Paste as image (Centered)(2)
wordDoc.Range.InsertParagraphBefore
wordDoc.Range.InsertParagraphBefore 'Create new empty paragraph before signature
wordDoc.Paragraphs.first.Range.PasteAndFormat Type:=wdChartPicture
With wordDoc.Tables(1).Rows
.WrapAroundText = 0 'If this is true does not work
.Alignment = 1
End With
'======== THIRD TABLE ==========
'Copy contents (3)
Sheets("Tables").Select
Range("F7:M30").Select
Range("F7").Activate
Selection.Copy
'Paste as image (Centered)(3)
wordDoc.Range.InsertParagraphBefore 'Create new empty paragraph before signature
wordDoc.Paragraphs.first.Range.PasteAndFormat Type:=wdChartPicture
With wordDoc.Tables(1).Rows
.WrapAroundText = 0 'If this is true does not work
.Alignment = 1
End With
Obviously I'm just copy/pasting my way through this and it felt great when the first two went in and looked right (similar widths), but the rest.. well, not so much..
Essentially, each pasted table is dropped inside of the top line of the table before, nesting one inside the other, and I'm looking for a way to break them apart.

This pastes the tables sequentially one after the other (not before the other), the idea os you look for the last paragraph and use the .previous property to insert the table in the paragraph before the last paragraph that it has been created on the lines before.
Sub Macro7()
' Works in Excel 2000, Excel 2002, Excel 2003, Excel 2007, Excel 2010, Outlook 2000, Outlook 2002, Outlook 2003, Outlook 2007, and Outlook 2010.
Dim Rng As Range
Dim OutApp As Object
Dim outMail As Object
Dim Location As String
Dim Signature As String
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
'Open new mail item
Dim outlookApp As Object
Set outlookApp = CreateObject("Outlook.Application")
Set outMail = outlookApp.CreateItem(0)
'Get Word editor
outMail.Display
Dim wordDoc As Object
Set wordDoc = outMail.GetInspector.WordEditor
'Copy contents
Sheets("Tables").Select
Range("AB7:AI75").Select
Range("AB7").Activate
Selection.Copy
'Paste as image (Centered)
Dim insertPoint As Object
wordDoc.Paragraphs.first.Range.InsertParagraphBefore 'Create new empty paragraph before signature
Set insertPoint = wordDoc.Paragraphs.first
insertPoint.Range.InsertParagraphBefore 'Create another
insertPoint.Previous.Range.PasteAndFormat Type:=wdChartPicture
With wordDoc.Tables(1).Rows
.WrapAroundText = 0 'If this is true does not work
.Alignment = 1
End With
'======== SECOND TABLE ========
'Copy contents (2)
Sheets("Tables").Select
Range("P7:Z29").Select
Range("P7").Activate
Selection.Copy
'Paste as image (Centered)(2)
insertPoint.Range.InsertParagraphBefore 'Create new empty paragraph before signature
insertPoint.Range.InsertParagraphBefore 'Create another
insertPoint.Previous.Range.PasteAndFormat Type:=wdChartPicture
With wordDoc.Tables(2).Rows
.WrapAroundText = 0 'If this is true does not work
.Alignment = 1
End With
'======== THIRD TABLE ==========
'Copy contents (3)
Sheets("Tables").Select
Range("F7:M30").Select
Range("F7").Activate
Selection.Copy
'Paste as image (Centered)(3)
insertPoint.Range.InsertParagraphBefore 'Create new empty paragraph before signature
insertPoint.Range.InsertParagraphBefore 'Create another
insertPoint.Previous.Range.PasteAndFormat Type:=wdChartPicture
With wordDoc.Tables(3).Rows
.WrapAroundText = 0 'If this is true does not work
.Alignment = 1
End With
End Sub
``

Related

Is there a way to reserve the order in which these charts are being display in the PowerPoint?

The problem I am trying to solve is to automate the copy and paste from Excel to powerPoint which at the moment is time consuming because we deal with lots of charts in different sheets. So I did some research online to see if anyone else tried or succeeded at the task and here is the fruits of the research. However, it doesn't fully satisfy my purposes because even though it successfully copies and pastes in to powerpoint, the ordering is messed up since it paste from oldest to newest.
I tried to used create a loop that starts in the last sheet to the first but having multiple charts per sheet still messed up the ordering in which I would like to see the charts displayed.
Sub chart_deliveryReverse()
'declaring all of the objects that will be used
Dim objPP, objPPFile, mySlide, myShape As Object
Dim DestinationPPT, button As String
Dim sht As Worksheet
Dim charts As Long
Dim counter, counter1 As Integer
Dim Xchart As Excel.ChartObject
'Message Box with a message giving the user Feedback
button1 = MsgBox("Creating PowerPoint")
'assign the objPP to powerPoint App
Set objPP = CreateObject("PowerPoint.Application")
'make it visible in the screen
objPP.Visible = True
'open specific powerPoint presentation
DestinationPPT = "location of powerPoint"
Set objPPFile = objPP.Presentations.Open(DestinationPPT)
'Loop that start from beginning to ended
For counter = 1 To Worksheets.Count Step 1
'Commnented loop that starts at the last sheet to the beginning
'For counter = Worksheets.Count To 1 Step -1
Set sht = Worksheets(counter)
'Locate Excel charts to paste into the new PowerPoint presentation
For Each Xchart In sht.ChartObjects
'Copy each Excel chart and paste it into PowerPoint
sht.Activate
Xchart.Select
ActiveChart.ChartArea.Copy
'Customizes the powerPoint first number being where to start inserting slides and second number the layout
Set mySlide = objPPFile.Slides.Add(2, 11) '11 = ppLayoutTitle
Set myShape = mySlide.Shapes(mySlide.Shapes.Count)
mySlide.Shapes.PasteSpecial DataType:=6
objPP.ActiveWindow.Selection.ShapeRange.Align msoAlignCenters, True
objPP.ActiveWindow.Selection.ShapeRange.Align msoAlignMiddles, True
mySlide.Shapes(1).TextFrame.TextRange.Text = Xchart.Chart.ChartTitle.Text
'Align the lastest stored shape
myShape.Left = 100
myShape.Top = 50
Next
Next
'Next
' Clean up
Set objPP = Nothing
Set objPPFile = Nothing
Set mySlide = Nothing
End Sub
It opens up the specified powerpoint and populates it with the charts from the excel sheets

Copy only certain pages from word doc into excel using VBA

1) I open a pdf using Microsoft word, through excel VBA.
2) From the word doc, I wish to copy only page 3 and page 4 (these two are tables without captions) into excel
3) at the moment, I could only copy the entire word doc into the excel, which can be troublesome.
below is my code:
Sub convertpdftowordthenexcel()
Dim wordapp As Word.Application
Dim input1 As String
input1 = "C:\Users\Me\Desktop\Fruitjuice.pdf"
'open pdf in word
Set wordapp = New Word.Application
wordapp.documents.Open Filename:=input1, Format:="PDF Files", ConfirmConversions:=False
wordapp.Visible = True
'copy the content of the word file
wordapp.ActiveDocument.Content.Copy '<------this is where I want to change
'go to excel and paste it there
Workbooks("openpdfusingdoc.xlsm").Worksheets("Sheet1").Activate
Worksheets("Sheet1").Activate
Cells(1, 1).Select
ActiveSheet.PasteSpecial Format:="Text"
wordapp.Quit savechanges:=wdDoNotSaveChanges
End Sub
Any suggestion on how to do this?
Thanks so much guys!
You can access tables through the tables collection - you may need to workout what index number the two you want are, I've assumed they're the first two in the document
Sub convertpdftowordthenexcel()
Dim wordapp As Word.Application
Dim input1 As String
input1 = "C:\Users\Me\Desktop\Fruitjuice.pdf"
'open pdf in word
Set wordapp = New Word.Application
wordapp.documents.Open Filename:=input1, Format:="PDF Files", ConfirmConversions:=False
wordapp.Visible = True
'copy the first two tables of the word file
wordapp.ActiveDocument.tables(1).range.Copy
'go to excel and paste it there
with Workbooks("openpdfusingdoc.xlsm").Worksheets("Sheet1")
.Cells(1, 1).PasteSpecial Format:="Text"
wordapp.ActiveDocument.tables(2).range.Copy
.cells(.rows.count,1).end(xlup).offset(2,0).pastespecial format:="Text"
end with
wordapp.Quit savechanges:=wdDoNotSaveChanges
End Sub
(PS Never use Select)

Pasting multiple linked Excel Charts to Word returning Run-Time Error 5345 Word Cannot Obtain the Data

I am trying to copy multiple Excel charts and paste them to a Word document, on separate pages, as the data type linked OLEObject but I am getting a run-time error.
Run-time error '5343':
Word cannot obtain the data for the
{00020832-0000-0000-C000-000000000046 link.
This is code that I've used in the past but literally, the only thing I changed in this code is to add an outer loop that processes the worksheets in the active workbook. Since adding that outer loop it no longer works, which is a little strange to me because I don't really see what is different.
It works for the first sheet (the currently active one), but fails when the loop moves to the next sheet. It does not matter whether the chart is pasted with or without a link.
Here is the full code for your reference:
Sub ExportingToWord_MultipleCharts()
'Declare Word Variables
Dim WrdApp As Word.Application
Dim WrdDoc As Word.Document
Dim SecCnt As Integer
'Declare Excel Variables
Dim ChrtObj As ChartObject
Dim Rng As Range
'Create a new instance of Word
Set WrdApp = New Word.Application
WrdApp.Visible = True
WrdApp.Activate
'Create a new word document
Set WrdDoc = WrdApp.Documents.Add
'Loop through each worksheet in the active workbook.
For Each WrkSht In ActiveWorkbook.Worksheets
'Loop through the charts on the active sheet
For Each ChrtObj In WrkSht.ChartObjects
'Copy the chart
ChrtObj.Chart.ChartArea.Copy
'Paste the Chart in the Word Document
With WrdApp.Selection
.PasteSpecial Link:=True, DataType:=wdPasteOLEObject, Placement:=wdInLine
End With
'Add a new page to the document.
WrdApp.ActiveDocument.Sections.Add
'Go to the newly created page.
WrdApp.Selection.GoTo What:=wdGoToPage, Which:=wdGoToNext
Next ChrtObj
Next WrkSht
End Sub
It returns the error on the following line:
'Paste the Chart in the Word Document
With WrdApp.Selection
.PasteSpecial Link:=True, DataType:=wdPasteOLEObject, Placement:=wdInLine
End With
I found a workaround, but it still doesn't explain why the error is happening. What I had to do is activate the actual worksheet in the loop.
'***ACTIVATE THE WORKSHEET IN ORDER TO REMOVE THE ERROR***
WrkSht.Activate
For whatever reason, this seemed to remove the error from popping up. However, I find this strange because when I've exported charts from PowerPoint I am not required to activate the worksheet in order to copy it. Here is the code with the adjustments, I've called out the section I added.
Sub ExportingToWord_MultipleCharts()
'Declare Word Variables
Dim WrdApp As Word.Application
Dim WrdDoc As Word.Document
Dim SecCnt As Integer
'Declare Excel Variables
Dim ChrtObj As ChartObject
Dim Rng As Range
'Create a new instance of Word
Set WrdApp = New Word.Application
WrdApp.Visible = True
WrdApp.Activate
'Create a new word document
Set WrdDoc = WrdApp.Documents.Add
'Loop through each worksheet in the active workbook.
For Each WrkSht In ActiveWorkbook.Worksheets
'***ACTIVATE THE WORKSHEET IN ORDER TO REMOVE THE ERROR***
WrkSht.Activate
'Loop through the charts on the active sheet
For Each ChrtObj In WrkSht.ChartObjects
'Copy the chart
ChrtObj.Chart.ChartArea.Copy
'Paste the Chart in the Word Document
With WrdApp.Selection
.PasteSpecial Link:=False, DataType:=wdPasteOLEObject, Placement:=wdInLine
End With
'Add a new page to the document.
WrdApp.ActiveDocument.Sections.Add
'Go to the newly created page.
WrdApp.Selection.GoTo What:=wdGoToPage, Which:=wdGoToNext
Next ChrtObj
Next WrkSht
End Sub

Pasting a selected range from Excel to a Word document

I am converting code I had written in Excel VBA to vb.NET on VS 2017. When I run the code, I get the error
This method or property is not available because the Clipboard is
empty or not valid.
This message appears while the application is running, when it tries to paste the selected range from Excel to the Word document. I have kept the worksheet being copied visible while the code runs, and can see that it selects the correct range but doesn't actually copy it.
What is the correct way to copy a range of cells in vb.NET?
Here is the part of my code where the error occurs:
excelApp = New Excel.Application
excelWB = excelApp.Workbooks.Open(SurveyFormLoc)
excelApp.Visible = True
With excelApp
.Sheets("Site Details").Select
.Range("B2:I11").Copy()
End With
excelWB.Save()
wdApp = CreateObject("Word.Application")
wdApp.Visible = False
wdDoc = wdApp.Documents.Open(DesignReportLoc)
With wdDoc
.Application.Selection.Find.Text = "INSERT FROM SURVEY FORM"
.Application.Selection.Find.Execute()
.Application.Selection.ParagraphFormat.Alignment = 0
End With
With wdApp
.Selection.PasteSpecial(Link:=True, DataType:=0, Placement:=0, DisplayAsIcon:=False) 'Asked question to get this
.Selection.TypeParagraph()
End With
Could the problem be that excelWB.Save() resets copy selection? The same thing happens in user interface too.

Copy Excel chart to PowerPoint with embedded data using VBA

After pasting a chart in from Excel, there's a "Smart Tag" that pops up in the bottom right of the chart, from which one can select "Excel chart (entire workbook)" (as opposed to the default "Chart (linked to Excel data)"). This has the effect of embedding the data in the chart so that the data can still be modified, but the chart is not linked to the Excel file. Has anyone been able to replicate this using VBA (using either in Excel-VBA or PowerPoint-VBA)?
I haven't found any way to programmatically access the "Smart Tag" from VBA. Moreover, the Paste Special options do not seem to have an option for this.
I'm using Office 2007.
Try this Tahlor:
Option Explicit
' ===========================================================================================
' Copy Specified chart to PowerPoint whilst maintaining a data link.
' Written by : Jamie Garroch of YOUpresent Ltd. (UK)
' Date : 08 JULY 2015
' For more amazing PowerPoint stuff visit us at from http://youpresent.co.uk/
' ===========================================================================================
' Copyright (c) 2015 YOUpresent Ltd.
' Source code is provide under Creative Commons Attribution License
' This means you must give credit for our original creation in the following form:
' "Includes code created by YOUpresent Ltd. (YOUpresent.co.uk)"
' Commons Deed # http://creativecommons.org/licenses/by/3.0/
' License Legal # http://creativecommons.org/licenses/by/3.0/legalcode
' ===========================================================================================
' Macro Execution Environment : Designed to run in Excel VBA.
' ===========================================================================================
' You can use Early Binding (with the advantage that IntelliSense adds) by adding a reference
' to the PowerPoint Object Library and setting the compiler constant EARLYBINDING to True
' but delete it afterwards otherwise you will face a nightmare of compatibility!!!
' ===========================================================================================
#Const EARLYBINDING = False
Sub CopyPasteLinkedChartToPowerPoint()
#If EARLYBINDING Then
' Define Early Binding PowerPoint objects so you can use IntelliSense while debuggging
' Requires a reference (Tools/References) to the Microsoft PowerPoint XX.Y Object Library
Dim oPPT As PowerPoint.Application
Dim oPres As PowerPoint.Presentation
Dim oSld As PowerPoint.Slide
#Else
' Define Late Binding PowerPoint objects
' Remove the reference to the Microsoft PowerPoint Object Library
Dim oPPT As Object
Dim oPres As Object
Dim oSld As Object
Const ppLayoutTitle = 1
#End If
' Define Excel objects
Dim oWB As Workbook
Dim oWS As Worksheet
Dim oCHT As ChartObject
Set oPPT = CreateObject("PowerPoint.Application")
Set oPres = oPPT.Presentations.Add(msoTrue)
Set oSld = oPres.Slides.Add(1, ppLayoutTitle)
' Modify these lines according to how you want to selet the chart
Set oWB = ActiveWorkbook
Set oWS = oWB.Worksheets(1)
Set oCHT = oWS.ChartObjects(1)
oCHT.Select
ActiveChart.ChartArea.Copy
' Paste the chart to the PowerPoint slide with a data link
oSld.Shapes.PasteSpecial link:=msoTrue
' Clear objects
Set oPPT = Nothing: Set oPres = Nothing: Set oSld = Nothing
Set oWB = Nothing: Set oWS = Nothing: Set oCHT = Nothing
End Sub
This is probably really bad form (posting as an answer to my question the answer to Joel's question in his answer), but the code below should help you with your question Joel. This is designed to be run from PowerPoint, and will delete all of the sheets that the selected chart doesn't use. Porting this to Excel should be pretty straightforward, just make sure chart1 is the PowerPoint chart you just pasted in and not the Excel chart you copied over. In any event, be extra careful to make sure that the graphs are being pasted in with the data (as opposed to being linked to the original workbook), as this code will delete every extra sheet in whatever workbook the chart references.
This has not been tested thoroughly. Obviously, back everything up.
'Delete extra sheets of selected chart in PowerPoint
Sub delete_excess_sheets()
Application.DisplayAlerts = False
Dim chart1 As Chart, used_sheets As Collection
Set chart1 = ActiveWindow.Selection.ShapeRange(1).Chart
chart1.ChartData.Activate
chart1.ChartData.Workbook.Application.DisplayAlerts = False
'Get sheets being used by chart
Set used_sheets = find_source(chart1)
For Each sht In chart1.ChartData.Workbook.worksheets 'this only loops through worksheets, not worksheet-charts
'note that you might first copy/paste values of the sheet supporting the data, if that sheet itself refers to other sheets
If Not InCollection(used_sheets, sht.Name) Then
sht.Delete
End If
Next
Application.DisplayAlerts = True
chart1.ChartData.Workbook.Application.DisplayAlerts = True
End Sub
'Determine which sheets are being used by the chart
Function find_source(search_cht As Object) As Collection
Dim strTemp As String, sheet_collection As New Collection
For Each mysrs In search_cht.SeriesCollection
first_part = Split(Split(mysrs.Formula, "!")(0), "=SERIES(")(1)
If (InStr(first_part, "'") = 1 And Right(first_part, 1) = "'") Then first_part = Mid(first_part, 2, Len(first_part) - 2)
sheet_collection.Add first_part, first_part
Next
Set find_source = sheet_collection
End Function
'Determine if object is in a collection
Public Function InCollection(col As Collection, key As String) As Boolean
Dim var As Variant
Dim errNumber As Long
InCollection = False
Set var = Nothing
err.Clear
On Error Resume Next
var = col.Item(key)
errNumber = CLng(err.Number)
On Error GoTo 0
'5 is not in, 0 and 438 represent incollection
If errNumber = 5 Then ' it is 5 if not in collection
InCollection = False
Else
InCollection = True
End If
End Function

Resources