I have a database in Excel, each entry runs horizontally for 8 cells (A2:H10 for example).
I am trying to create Word documents enmasse from each 8 cell entry that inject vertically into a Word document table that is 8 cells total.
Here is an example of the code I have tried.
Sub CreateEntry()
Dim wdApp As Object
Dim wd As Object
Dim myarray As Variant
On Error Resume Next
Set wdApp = GetObject(, "Word.Application")
If Err.Number <> 0 Then
Set wdApp = CreateObject("Word.Application")
End If
On Error GoTo 0
Set wd = wdApp.Documents.Add
wdApp.Visible = True
Sheets("Accommodation").Activate
Set Rng = ThisWorkbook.ActiveSheet.Range("A1:E76")
myarray = Range("A2:H2")
Range("A2:H2").Value = myarray
Range("A40:A48").Value = Application.WorksheetFunction.Transpose(myarray)
Set Rng = ThisWorkbook.ActiveSheet.Range("A40:A48")
Rng.Copy
With wd.Range
.Collapse Direction:=0
.InsertParagraphAfter
.Collapse Direction:=0
.PasteSpecial False, False, True
End With
End Sub
You can create tables directly in Word using the Word object model. That gives you more control over how it turns out.
Sub CreateEntry()
Dim doc As Object, rw As Range, tbl As Object
Dim n As Long
For Each rw In ThisWorkbook.Sheets("Accommodation").Range("A2:H3").Rows
Set doc = GetWordDoc()
Set tbl = doc.tables.Add(doc.Range, rw.Cells.Count, 1)
For n = 1 To rw.Cells.Count
tbl.Cell(n, 1).Range.Text = rw.Cells(n).Text
Next n
Next rw
End Sub
Function GetWordDoc() As Object
Dim wdApp As Object
On Error Resume Next
Set wdApp = GetObject(, "Word.Application")
If Err.Number <> 0 Then
Set wdApp = CreateObject("Word.Application")
wdApp.Visible = True
End If
On Error GoTo 0
Set GetWordDoc = wdApp.Documents.Add
End Function
Related
Currently I am using this code which does not take in count the sparklines :
Sub generatemail()
Dim r As Range
Set r = Range("A1:F71")
r.Copy
Dim outlookApp As Outlook.Application
Set outlookApp = CreateObject("Outlook.Application")
Dim outMail As Outlook.MailItem
Set outMail = outlookApp.CreateItem(olMailItem)
outMail.Display
Dim wordDoc As Word.Document
Set wordDoc = outMail.GetInspector.WordEditor
wordDoc.Range.Paste
End Sub
The workaround I found to take in count spark line is to paste the image of the range with
wordDoc.Range.PasteAndFormat wdChartPicture
But they are blurred :
Does a way exist to copy sparkline ? (with Range.Copy) If it is not possible how would I get a better screen shot without blur ?
Note : When I do this by and the SparkLine are not blur :
I usually create a picture file then insert it on the mail. This works fine for me, try it.
Option Explicit
Private PicFilename As String
Sub generatemail()
Dim r As Range: Set r = Range("A1:F71")
' Create picture
Call createPicture("xChart", r)
Dim outlookApp As Outlook.Application: Set outlookApp = CreateObject("Outlook.Application")
Dim OutMail As Outlook.MailItem: Set OutMail = outlookApp.CreateItem(olMailItem)
' Display mail
OutMail.Display
' Insert picture
Dim shp As Word.InlineShape
Dim wordDoc As Word.Document: Set wordDoc = OutMail.GetInspector.WordEditor
Set shp = wordDoc.Range.InlineShapes.AddPicture(PicFilename)
End Sub
Public Function createPicture(picName As String, picRng As Range) As Boolean
Dim PicTop, PicLeft, PicWidth, PicHeight As Long
Dim oChart As ChartObject
createPicture = False
PicFilename = ThisWorkbook.Path & "\" & picName & ".jpg"
On Error Resume Next
Kill PicFilename
ActiveSheet.ChartObjects(1).Delete
On Error GoTo 0
On Error GoTo ErrHandler
' Delete any existing picture
On Error Resume Next
If Dir(PicFilename) > 0 Then Kill (PicFilename)
On Error GoTo 0
' Create a bitmap image
On Error Resume Next
picRng.CopyPicture xlScreen, xlBitmap
On Error GoTo 0
' Create a new Temporary Chart
PicTop = picRng.Top
PicLeft = picRng.Left
PicWidth = picRng.Width
PicHeight = picRng.Height
Set oChart = ActiveSheet.ChartObjects.Add(Left:=PicLeft, Top:=PicTop, Width:=PicWidth, Height:=PicHeight)
With oChart
.Name = picName
.Activate
' Select chart area
.Chart.Parent.Select
' Paste the Picture in the chart area
.Chart.Paste
' Save chart as picture
.Chart.Export PicFilename
' Delete Picture
.Delete
createPicture = True
End With
exitRoutine:
Exit Function
ErrHandler:
Debug.Print Now() & ": " & Err.Description
Resume exitRoutine
End Function
I can insert a table but the tables borders are not visible. You can see the created document. In order to allow others to run this script I have to use late binding which I suspect may be the cause.
My Code is here:
Sub Button1_Click()
Dim objWord As Object
Dim objDoc
Dim objSelection
Dim i As Long
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add
objWord.Visible = True
Set objSelection = objWord.Selection
objSelection.TypeText ("Insert table after this text")
Set myRange = objDoc.Content
myRange.Collapse Direction:=wdCollapseEnd
objDoc.Tables.Add Range:=myRange, NumRows:=3, NumColumns:=4
Set myTable = objDoc.Tables(1)
With myTable.Borders
.Enable = True
.InsideLineStyle = wdLineStyleSingle
.OutsideLineStyle = wdLineStyleDouble
.InsideColor = wdColorBlack
.OutsideColor = wdColorBlack
End With
End Sub
Here’s your code revised and in my testing it works when I run it from Excel.
Sub Button1_Click()
Dim objWord As Object
Dim objDoc As Object
Dim objSelection As Object
Dim i As Long
Dim myRange As Object
Dim myTable As Object
On Error Resume Next
Set objWord = GetObject(, "Word.Application")
If Err.Number <> 0 Then
Err.Clear
Set objWord = CreateObject("Word.Application")
End If
objWord.Visible = True
On Error GoTo 0
Set objDoc = objWord.Documents.Add
Set objSelection = objWord.Selection
objSelection.TypeText ("Insert table after this text")
Set myRange = objDoc.Content
myRange.Collapse Direction:=wdCollapseEnd
Set myTable = objDoc.Tables.Add(Range:=myRange, NumRows:=3, NumColumns:=4)
With myTable.Borders
.Enable = True
.InsideLineStyle = 1
.OutsideLineStyle = 7
.InsideColor = 0
.OutsideColor = 0
End With
End Sub
The issue with with the table borders not displaying is when using late binding you have to use the numeric values for the setting.
I also made a few other adjustments, they have no impact on the problem you were having, but they are better practices. All objects are declared and I added a test to see if the Word application was already running. In some releases of the Office applications, multiple instances of the application could get loaded into memory when you execute a CreateObject and the application was already there.
I am trying to copy a table from excel to word and then back again to excel using VBA. I have a script to do both of those things but how can I make the copy from word back to excel from the active word file that got created with "Copy2word" so that I dont have to specify the location of the word document in "Copy2excel"?
Sub Copy2word()
Dim wdApp As Object
Dim wdDoc As Object
Dim wkSht As Worksheet
'\\ Stay on any sheet from which you want to copy data
Set wkSht = ActiveSheet
wkSht.UsedRange.Copy
'\\ Start word and create new document to paste data
On Error Resume Next
Set wdApp = GetObject(, "Word.Application")
If wdApp Is Nothing Then
Set wdApp = CreateObject("Word.Application")
wdApp.Visible = True
End If
Set wdDoc = wdApp.Documents.Add
'\\ Paste Data from Excel
wdDoc.Range.PasteExcelTable False, False, True
'\\ Stop Excel's cut copy mode
Application.CutCopyMode = False
MsgBox "Copy to Word Finished!", vbInformation, "Copy to Word"
End Sub
Sub Copy2excel()
Const DOC_PATH As String = "C:\Users\MASS\Desktop\Test\TK1.docx"
Dim sht As Worksheet
Dim WordDoc As Word.Document
Dim WordApp As Word.Application
Dim i As Long, r As Long, c As Long
Dim rng As Range, t As Word.Table
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
Set WordDoc = WordApp.Documents.Open(DOC_PATH, ReadOnly:=True)
Set sht = Sheets("Sheet4")
Set rng = sht.Range("A20")
sht.Activate
For Each t In WordDoc.Tables
t.Range.Copy
rng.Select
rng.Parent.PasteSpecial Format:="Text", Link:=False, _
DisplayAsIcon:=False
With rng.Resize(t.Rows.Count, t.Columns.Count)
.Cells.UnMerge
.Cells.ColumnWidth = 14
.Cells.RowHeight = 14
.Cells.Font.Size = 10
End With
Set rng = rng.Offset(t.Rows.Count + 2, 0)
Next t
WordDoc.Close
WordApp.Quit
End Sub
I'm trying to extract first table of each mail of a specific folder to Excel. If there is more than one table in the mail we can exclude it and move to next mail item. Below is the code I have at the moment. Could you please help?
Public Sub Import_Tables_From_Outlook_Emails()
Dim oApp As Outlook.Application, oMapi As Outlook.MAPIFolder
Dim oMail As Outlook.MailItem, HTMLdoc As MSHTML.HTMLDocument
Dim tables As MSHTML.IHTMLElementCollection, table As MSHTML.HTMLTable
Dim objExcelApp As Excel.Application, x As Long, y As Long, destCell As Range
Dim objExcelWorkbook As Excel.Workbook, objExcelWorksheet As Excel.Worksheet
Set objExcelApp = CreateObject("Excel.Application") 'Create a new excel workbook
Set objExcelWorkbook = objExcelApp.Workbooks.Add
objExcelApp.Visible = True
Set destCell = ActiveSheet.Cells(Rows.Count, "A").End(xlUp)
On Error Resume Next
Set oApp = GetObject(, "OUTLOOK.APPLICATION")
If oApp Is Nothing Then Set oApp = CreateObject("OUTLOOK.APPLICATION")
On Error GoTo 0
Set oMapi = oApp.GetNamespace("MAPI").PickFolder
If Not oMapi Is Nothing Then
For Each oMail In oMapi.items
'Get HTML tables from email object
Set HTMLdoc = New MSHTML.HTMLDocument
With HTMLdoc
.Body.innerHTML = oMail.HTMLBody
Set tables = .getElementsByTagName("table")
End With
For Each table In tables
For x = 0 To table.Rows.Length - 1
For y = 0 To table.Rows(x).Cells.Length - 1
destCell.Offset(x, y).Value = _
table.Rows(x).Cells(y).innerText
Next y
Next x
Sheets.Add After:=ActiveSheet
Range("A1").Activate
Set destCell = ActiveSheet.Range("A1")
Next
Next
End If
Set oApp = Nothing
Set oMapi = Nothing
Set oMail = Nothing
Set HTMLdoc = Nothing
Set tables = Nothing
MsgBox "Finished"
End Sub
The following macro prompts the user to select a folder from Outlook, loops though each item in the folder, and copies the first table from each item to a separate worksheet in a newly created workbook.
Edit
The code has been edited to 1) restrict the mail items based on ReceivedTime, 2) sort the restricted items by ReceivedTime, and in descending order, 3) loop through the items from earliest to latest date.
Option Explicit
Public Sub Import_Tables_From_Outlook_Emails()
Dim oMapiFolder As Folder
Dim oMail As Object
Dim oMailItems As Object
Dim oRestrictItems As Object
Dim oHTMLDoc As Object
Dim oHTMLTable As Object
Dim xlApp As Object
Dim xlWkb As Object
Dim r As Long
Dim c As Long
Dim i As Long
Set oMapiFolder = Application.GetNamespace("MAPI").PickFolder
If oMapiFolder Is Nothing Then
Exit Sub
End If
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
If xlApp Is Nothing Then
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
End If
On Error GoTo 0
Set xlWkb = xlApp.workbooks.Add(-4167) 'xlWBATWorksheet
Set oHTMLDoc = CreateObject("htmlfile")
Set oMailItems = oMapiFolder.Items
Set oRestrictItems = oMailItems.Restrict("[ReceivedTime] >= '" & Format("1/1/17 12:00am", "ddddd h:nn AMPM") & "'")
oRestrictItems.Sort "[ReceivedTime]", olDescending
For i = 1 To oRestrictItems.Count
Set oMail = oRestrictItems(i)
With oHTMLDoc
.Body.innerHTML = oMail.HTMLBody
Set oHTMLTable = .getElementsByTagName("table")(0)
End With
If Not oHTMLTable Is Nothing Then
xlWkb.Worksheets.Add after:=xlWkb.activesheet
For r = 0 To oHTMLTable.Rows.Length - 1
For c = 0 To oHTMLTable.Rows(r).Cells.Length - 1
xlWkb.activesheet.Range("A1").Offset(r, c).Value = _
oHTMLTable.Rows(r).Cells(c).innerText
Next c
Next r
Set oHTMLTable = Nothing
End If
Next i
xlApp.DisplayAlerts = False
xlWkb.Worksheets(1).Delete
xlApp.DisplayAlerts = True
Application.ActiveExplorer.Activate
Set oMapiFolder = Nothing
Set oMail = Nothing
Set oHTMLDoc = Nothing
Set oHTMLTable = Nothing
Set xlApp = Nothing
Set xlWkb = Nothing
MsgBox "Finished"
End Sub
I have a word document which is updated periodically. I can go into that Word document, select the contents of an entire table and copy, then go into an Excel spreadsheet and paste it. It's screwed up; however, I fix it as follows:
sht.Cells.UnMerge
sht.Cells.ColumnWidth = 14
sht.Cells.RowHeight = 14
sht.Cells.Font.Size = 10
This manual copy-paste works regardless of whether the table is has merged fields.
Then I can start to manipulate it manually: parsing, checking, computations, etc.
I can do this one table at a time, but it's tedious and of course error prone.
I want to automate this. I found some code:
Sub read_word_document()
Dim sht As Worksheet
Dim WordDoc As Word.Document
Dim WordApp As Word.Application
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
On Error GoTo ErrHandler
Set WordDoc = WordApp.Documents.Open("Z:\mydir\myfile1.DOC", ReadOnly:=True)
j = 0
For i = 1 To WordDoc.Tables.Count
DoEvents
Dim s As String
s = WordDoc.Tables(i).Cell(1, 1).Range.Text
Debug.Print i, s
WordDoc.Tables(i).
Set sht = Sheets("temp")
'sht.Cells.Clear
sht.Cells(1, 1).Select
sht.PasteSpecial (xlPasteAll)
End If
Next i
WordDoc.Close
WordApp.Quit
GoTo done
ErrClose:
On Error Resume Next
ErrHandler:
Debug.Print Err.Description
On Error GoTo 0
done:
End Sub
Of course this would just overwrite the same sheet again and again - and that's okay. This is just a test. The problem is this will work for those tables that do not have merged cells. However, it fails if the table has merged cells. I have no control over the file I get. It contains almost a hundred tables. Is there a way to do the copy paste the EXACT WAY that I do when I perform the operation manually?
Something like this:
Sub read_word_document()
Const DOC_PATH As String = "Z:\mydir\myfile1.DOC"
Dim sht As Worksheet
Dim WordDoc As Word.Document
Dim WordApp As Word.Application
Dim i As Long, r As Long, c As Long
Dim rng As Range, t As Word.Table
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
Set WordDoc = WordApp.Documents.Open(DOC_PATH, ReadOnly:=True)
Set sht = Sheets("Temp")
Set rng = sht.Range("A1")
sht.Activate
For Each t In WordDoc.Tables
t.Range.Copy
rng.Select
rng.Parent.PasteSpecial Format:="Text", Link:=False, _
DisplayAsIcon:=False
With rng.Resize(t.Rows.Count, t.Columns.Count)
.Cells.UnMerge
.Cells.ColumnWidth = 14
.Cells.RowHeight = 14
.Cells.Font.Size = 10
End With
Set rng = rng.Offset(t.Rows.Count + 2, 0)
Next t
WordDoc.Close
WordApp.Quit
End Sub