I have modified the code from Macro to export MS Word tables to Excel sheets to copy a sequential interval of tables (e.g. 1 to 4) instead of copying all tables, as in the original code.
But I cannot figure out how to copy a selection of tables in the Word document (e.g. tables 1, 3, 7, 8).
Help to tweak the relevant section of code much appreciated!
'For tableStart = 1 To tableTo '<- copies all tables
For tableStart = 1 To 4 '<- copies sequential interval of tables
With .tables(tableStart)
.Range.Copy
Target.Activate
Target.Parent.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False
'ActiveSheet.Paste <- pastes with formatting
Set Target = Target.Offset(.Rows.Count + 2, 0)
End With
Next tableStart
The entire macro is:
Sub ImportWordTables()
Dim WordApp As Object
Dim WordDoc As Object
Dim arrFileList As Variant, FileName As Variant
Dim tableNo As Integer 'table number in Word
Dim tableStart As Integer
Dim tableTot As Integer
Dim Target As Range
On Error Resume Next
arrFileList = Application.GetOpenFilename("Word files (*.doc; *.docx),*.doc;*.docx", 2, _
"Browse for file containing table to be imported", , True)
If Not IsArray(arrFileList) Then Exit Sub '<-user cancelled import file browser
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
Range("A:AZ").ClearContents
Set Target = Worksheets("MySheet").Range("A1")
For Each FileName In arrFileList
Set WordDoc = WordApp.Documents.Open(FileName, ReadOnly:=True)
With WordDoc
tableNo = WordDoc.tables.Count
tableTot = WordDoc.tables.Count
If tableNo = 0 Then
MsgBox WordDoc.Name & "Contains no tables", vbExclamation, "Import Word Table"
End If
'For tableStart = 1 To tableTo '<- copies all tables
For tableStart = 1 To 4 '<- copies interval of tables
With .tables(tableStart)
.Range.Copy
Target.Activate
Target.Parent.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False
'ActiveSheet.Paste <- pastes with formatting
Set Target = Target.Offset(.Rows.Count + 2, 0)
End With
Next tableStart
.Close False
End With
Next FileName
WordApp.Quit
Set WordDoc = Nothing
Set WordApp = Nothing
End Sub
You could supply the list of tables as an array. I added this to the restructured code below. You provide a variant containing an array of the table numbers you want to copy to the ImportWordTables sub. I'll leave it to you to modify the code by making the parameter optional so that you either copy all tables or the tables in the list.
Option Explicit
Public Enum TableImportError
NoTables
UnexpectedIndex
End Enum
Public Sub ImportWordTables(ByVal ipTableList As Variant)
Dim arrFileList As Variant
If Not TryGetFileNameList(arrFileList) Then Exit Sub
Dim WordApp As Object
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
' the range should be qualified by the relevant wb/ws
Range("A:AZ").ClearContents
Dim FileName As Variant
For Each FileName In arrFileList
Dim WordDoc As Object
Set WordDoc = WordApp.Documents.Open(FileName, ReadOnly:=True)
Dim myReason As TableImportError
If Not TryImportTables(WordDoc, ipTableList, myReason) Then
Select Case myReason
Case TableImportError.NoTables
MsgBox WordDoc.Name & "Contains no tables", vbExclamation, "Import Word Table"
Case TableImportError.UnexpectedIndex
MsgBox WordDoc.Name & "Unexpected index", vbExclamation, "The table indexes exceed the total table count. No tables copies"
End Select
End If
Next FileName
WordApp.Quit
Set WordDoc = Nothing
Set WordApp = Nothing
End Sub
Private Function TryGetFileNameList(ByRef opFileList As Variant) As Boolean
On Error Resume Next
opFileList = Application.GetOpenFilename("Word files (*.doc; *.docx),*.doc;*.docx", 2, _
"Browse for file containing table to be imported", , True)
On Error GoTo 0
TryGetFileNameList = IsArray(opFileList)
End Function
Private Function TryImportTables(ByRef ipDoc As Word.Document, ByVal ipTableList As Variant, ByRef opReason As TableImportError) As Boolean
TryImportTables = False
If ipDoc.Tables.Count = 0 Then
opReason = TableImportError.NoTables
Exit Function
End If
Dim myTable As Variant
For Each myTable In ipTableList
If myTable > ipDoc.Tables.Count Then
opReason = TableImportError.UnexpectedIndex
Exit Function
End If
Next
For Each myTable In ipTableList
With ipDoc.Tables.Item(myTable)
.Range.Copy
' replaced Target by worksheet refernce
' ideally this item should be passed as a parameter
' or second best defined as a module level variable.
'
' worksheets should be qualified by the relevant wb
With Worksheets("MySheet")
.Activate
.Parent.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False
Set .Range("A1") = .Range("A1").Offset(.Rows.Count + 2, 0)
'.Paste
End With
End With
Next
TryImportTables = True
End Function
The code above compiles and doesn't give any unexpected Code Inspection warning by the free and fantastic Rubberduck addin for VBA. However as its a radical restructuring I can't guarantee it will work exactly as you previous code so please do check if you decide to use it.
Set this code of yours as a Function that you call from the Main Sub with the a TableIndex
With .tables(tableIndex)
.Range.Copy
Target.Activate
Target.Parent.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False
'ActiveSheet.Paste <- pastes with formatting
Set Target = Target.Offset(.Rows.Count + 2, 0)
End With
Set the tableIndex variable as a Random number assigned from the collection of tables in the Word document. You'll have to decide how many times you will iterate thru the code so you get the random sample size you want but the basic code might look like this:
Sub ReturnRandomNumber()
Dim TableIndex As Integer
Dim WordDoc As Word.Document
Randomize
TableIndex = Int((WordDoc.Tables.Count * Rnd) + 1)
CopyRandomTable WordDoc, TableIndex
End Sub
Function CopyRandomTable(ByRef WordDoc As Word.Document, ByRef TableIndex As Integer)
With WordDoc.Tables(TableIndex)
.Range.Copy
Target.Activate
Target.Parent.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False
'ActiveSheet.Paste <- pastes with formatting
Set Target = Target.Offset(.rows.Count + 2, 0)
End With
End Function
The RND function might also return the same table index so you should think about how you might want to deal with that ... like possibly setting up an array of table indexes already used and then act accordingly.
For more information about Randomize and the RND function here is a Microsoft Article on the RND Function.
Solved, but input box and memory capacity issue still to be fixed.
Replace With .tables(tableIndex) section in my first example above with the following:
'For array
Dim tables() As Variant
Dim tableCounter As Long
tables = Array(1, 3, 7) '<- define array manually here
For tableCounter = LBound(tables) To UBound(tables)
With .tables(tables(tableCounter))
.Range.Copy
Target.Activate
'Target.Parent.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False '<- gives RAM capacity problems!
ActiveSheet.Paste '<- pastes with formatting
Set Target = Target.Offset(.Rows.Count + 2, 0)
End With
Next tableCounter
Related
Problem:
I would like to create letters using 2 different letter templates based on a cell value in a column in Excel.
My Question is an extension to the following question:
VBA Automated Mailmerge using 2 templates based on cell value
Example:
In the example below, the value in column C should dictate which letter template will be used for each row. (If cell value is YES use letter template "Yes.docx" otherwise use letter template "No.docx")
Solution proposed by #user3598756 (modified to the above example):
Option Explicit
Sub CommandButton2_Click()
Dim wordApp As Object
Set wordApp = GetWordObject '<--| get a Word object
If wordApp Is Nothing Then Exit Sub '<--| if no Word Object has been gotten then exit sub
With ThisWorkbook.Sheets("Sheet1") '<--| reference your letter worksheet
With Application.Intersect(.UsedRange, Range("A1:C1").EntireColumn) '<--| reference your data range as that in referenced worksheet columns D:H used range
CreateWordDocuments .Cells, "YES", wordApp, "C:\Users\camil\Desktop\YES.docx" '<--| process "YES" documents
CreateWordDocuments .Cells, "NO", wordApp, "C:\Users\camil\Desktop\NO.docx" '<--| process "NO" documents
End With
.AutoFilterMode = False '<--| show all rows back and remove autofilter
End With
'"dispose" Word
wordApp.Quit True '<--| quit Word and save changes to open documents
Set wordApp = Nothing
End Sub
Sub CreateWordDocuments(dataRng As Range, criteria As String, wordApp As Object, templateDocPath As String)
Dim cell As Range
With dataRng '<--| reference data range
.AutoFilter Field:=3, Criteria1:=criteria '<--| filter it on its column 3 with given criteria
If Application.WorksheetFunction.Subtotal(103, .Resize(, 1)) > 1 Then '<--| if any cell has been filtered
For Each cell In .Offset(1).Resize(.Rows.Count - 1, 1).SpecialCells(xlCellTypeVisible) '<--| loop through filtered cells
wordApp.Documents.Add templateDocPath '<-- open the passed Word template
wordApp.Run "Module1.SaveIndividualWordFiles" '<--| run your macro
Next cell
End If
End With
End Sub
Function GetWordObject() As Object
Dim wordApp As Object
On Error Resume Next
Set wordApp = GetObject(, "Word.Application") '<--| try getting a running Word application
On Error GoTo 0
If wordApp Is Nothing Then Set wordApp = CreateObject("Word.Application") '<--| if no running instance of Word has been found then open a new one
Set GetWordObject = wordApp '<--| return the set Word application
wordApp.Visible = False
End Function
Request:
Unfortunately, the original poster of the question didn't share his "SaveIndividualWordFiles" macro.
I tried to fill in the gap with parts of the VBA I usually use to mailmerge from Word, when I only have one letter template. (Seen below)
However I can't fit the pieces together.
Sub Merge_To_Individual_Files()
Application.ScreenUpdating = False
Dim StrFolder As String, StrName As String, MainDoc As Document, i As Long, j As Long
Const StrNoChr As String = """*./\:?|"
Set MainDoc = ActiveDocument
With MainDoc
StrFolder = .Path & Application.PathSeparator
For i = 1 To .MailMerge.DataSource.RecordCount
With .MailMerge
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
With .DataSource
.FirstRecord = i
.LastRecord = i
.ActiveRecord = i
If Trim(.DataFields("Col A")) = "" Then Exit For
StrName = .DataFields("Col A") & " " & .DataFields("Col C")
End With
.Execute Pause:=False
If Err.Number = 5631 Then
Err.Clear
GoTo NextRecord
End If
End With
For j = 1 To Len(StrNoChr)
StrName = Replace(StrName, Mid(StrNoChr, j, 1), "_")
Next
StrName = Trim(StrName)
With ActiveDocument
.SaveAs FileName:=StrFolder & StrName & ".docx", FileFormat:=wdFormatXMLDocument, AddToRecentFiles:=False
.SaveAs FileName:=StrFolder & StrName & ".pdf", FileFormat:=wdFormatPDF, AddToRecentFiles:=False
.Close SaveChanges:=False
End With
NextRecord:
Next i
End With
Application.ScreenUpdating = False
End Sub
Any help is appreciated.
I posted a question here, regarding using a macro and having a screentip and I received a very good idea from #Tim Williams but in order for this to work I need to convert subs into functions. I have never done that before and I don't know if it is possible but I hope one of you experts can guide me. Here are my subroutines that need to be converted for this to work.
Normal / Editable View - This program is run from full screen mode. So this subroutine allows the user to press a button and go to normal excel view.
```
Sub ScreenDisplayNorm()
Call UnProtectAllSheets
With Application
.DisplayFullScreen = False
With ActiveWindow
.WindowState = xlNormal
.DisplayHeadings = True
.DisplayWorkbookTabs = True
.DisplayGridlines = False
.DisplayHorizontalScrollBar = True
.DisplayVerticalScrollBar = True
.Zoom = 80
End With
.DisplayStatusBar = True
.DisplayFormulaBar = True
End With
End Sub
```
Fullscreen View - Press button to convert view back to fullscreen!
```
Sub GotoResources()
Set wbPB = PokerBros
Dim maxWidth As Long
Dim myWidth As Long
Dim Myzoom As Single
Dim wsR As Worksheet: Set wsR = wbPB.Worksheets("Resource Data")
Dim Rng As Range: Set Rng = wsR.Range("A1:U35")
Call UnProtectAllSheets
wsR.Activate
Call EnhancePerformance 'call sub to Improve speed (screen updates and calculations)
Call ScreenDisplayMax 'call sub to maximize
maxWidth = GetSystemMetrics(0) * 0.96 'maximum width measurement
myWidth = ActiveSheet.Range("U1").Left 'Actual width of program starting from the left edge of the cell furthest_
'to the right that fits the best view
Myzoom = maxWidth / myWidth
ActiveWindow.Zoom = Myzoom * 90
Rng.Select
ActiveWindow.Zoom = True 'set range zoom
ActiveSheet.Range("A1").Select
Call NormalPerformance 'call sub to perform normal (screen updates and calculations)
Call ProtectAllSheets
End Sub
```
Save - Button will save current file
```
Sub SaveWorkbook()
ActiveWorkbook.Save
End Sub
```
SaveAs - User can save file to a different location.
```
Sub SaveAsDialogBox()
Dim CarryOn As Boolean
Call UnProtectAllSheets
CarryOn = MsgBox("Do you want to save a copy of this original file?", vbYesNo, "Save Copy Recommended")
If CarryOn = True Then
CopyToNewBook
End If
End Sub
```
Player Profile - Opens player profile userform to gather data.
```
Sub OpenProfileUF()
ufDirectory.Show vbModeless
End Sub
```
Import Data - Allows user to calculate results
```
Sub UpdateArray()
Dim wsDest As Worksheet
Dim arSource() As Variant, arDest() As Variant, varID As Variant, ImportDate As Variant
Dim outputColumns As Variant, inputColumns As Variant
Dim filename As String: filename = "C:\Users\AdamRhodes\OneDrive\Desktop\PokerBros\PokerBrosSuppliment.xlsm"
Dim strDest As String, lastsrcrow As Long, AddRow As Integer, strfilename As String
Dim lrow As Long, CarryOn As Boolean, MsgAnswer As Integer
Set wbPB = PokerBros
Set wsPT = wbPB.Worksheets("Player Tracking")
Call UnProtectAllSheets
Call EnhancePerformance
CarryOn = MsgBox("Running this macro will import" & "," & "extract" & "," & _
"and compute data from other files and will add calculations to some reporting" & "." & "It is recommended to save a copy to restore with confidence" & "." & "If you already saved a copy and wish to proceed select ""Yes"" and select ""No"" to exit and save a copy" & "!", vbYesNo, "Please Approve Data Load")
If CarryOn = vbNo Then
Exit Sub
End If
MsgAnswer = MsgBox("Would you like to select your filepath? If you select ""NO"" The application will attempt to open the file" & ".", vbYesNoCancel + vbQuestion, "Locate File to Export Data!")
If MsgAnswer = vbYes Then
strfilename = Application.GetOpenFilename(Title:="Browse and Select you Newest PokerBrosSuppliment.xls file", FileFilter:="Excel Files (*.xls*),*xls*")
Set wbSource = Application.Workbooks.Open(filename:=strfilename, ReadOnly:=True)
ElseIf MsgAnswer = vbNo Then
On Error Resume Next 'Call function to check if the file is open
If IsFileOpen(filename) = False Then 'Insert actions to be performed on the closed file
Set wbSource = Application.Workbooks.Open(filename:=filename, ReadOnly:=True)
Else: MsgBox filename & " is already open." 'The file is open or another error occurred
Set wbSource = Workbooks("PokerBrosSuppliment.xlsm") 'open the file manually
If IsError(Error) Then 'if there is an error opening the file it may already be open.
strfilename = Application.GetOpenFilename(Title:="Browse and Select you Newest PokerBrosSuppliment.xls file", FileFilter:="Excel Files (*.xls*),*xls*")
Set wbSource = Application.Workbooks.Open(filename:=strfilename, ReadOnly:=True)
Else: Set wbSource = Application.Workbooks.Open(filename:=strfilename, ReadOnly:=True)
End If
End If
ElseIf MsgAnswer = vbCancel Then
MsgBox "No file has been selected" & "." & "File has not been imported" & "!", vbOKOnly + vbExclamation, "Procedure was Cancelled"
Exit Sub
End If
On Error GoTo 0
Set wsSource = wbSource.Worksheets("Export")
'use last row from suppliment to determine how many formatted rows needed for player tracking
lastsrcrow = wsSource.Cells(wsSource.Rows.Count, "B").End(xlUp).Row
AddRow = lastsrcrow - rCntr 'rcntr is a constant 150. so the last row minus 150 determines how many formatted rows to be added.
wsPT.Activate ' activate Player Tracking
Call AddNew_Worksheet 'call sub to add new worksheet
strDest = wbPB.Worksheets(ActiveSheet.Name).Name 'rename the new spreadsheet
Set wsDest = wbPB.Worksheets(strDest) 'set the worksheet object
If AddRow > 0 Then 'Add rows if needed
wsDest.Rows(rCntr + 1 & ":" & AddRow + rCntr + 1).Select 'determine how many rows to add
Selection.EntireRow.Insert Shift:=xlShiftDown, CopyOrigin:=xlFormatFromLeftOrAbove 'select the range and insert rows
With wsDest
.Range("B150:N150").AutoFill Destination:=Range("B150:N" & AddRow + 151), Type:=xlFillDefault 'autofill from cells above to format
End With
End If
inputColumns = Array(6, 4, 5, 7, 8, 23, 35, 36) 'source array data
outputColumns = Array(2, 3, 4, 5, 6, 7, 12, 13) 'Destination array data
Call writeArray(inputColumns, outputColumns) 'write the array
Call Get_RakeBack_Rates 'call sub to insert Rake Back Rates
Application.DisplayAlerts = False 'hide alert about closing the source file with data on the clipboard
wbSource.Close savechanges:=False 'close workbook
Application.DisplayAlerts = True 'activate alerts again
Call NormalPerformance
Call ProtectAllSheets
End Sub
```
Directory Adds - Adds new accounts to the directory.
```
Sub DirectoryAdds()
Set wbPB = PokerBros
Dim srcColumns As Variant: srcColumns = Array(2, 3, 4, 5, 6, 7, 8, 10, 11, 13, 14)
Dim tgtColumns As Variant: tgtColumns = Array(2, 3, 4, 5, 6, 8, 7, 9, 10, 11, 12)
Dim wsIT As Worksheet: Set wsIT = wbPB.Worksheets(Worksheets.Count)
Dim wsPD As Worksheet: Set wsPD = wbPB.Worksheets("Player Directory")
Dim Rng As Range, rngSource As Range, c As Range
Dim Curr, ub As Long, i As Long, k As Long
Dim wsPDlastrow As Long: wsPDlastrow = wsPD.Cells(Rows.Count, "B").End(xlUp).Row
Dim lastrow As Long, inc As Integer, FillRow As Integer, NextRow As Integer, lastRR As Long
Call UnProtectAllSheets
Call EnhancePerformance
ub = UBound(srcColumns) 'Player Tracking UBound column count
If wsIT Is wsPD Then 'If Player Directory sheet is Activesheet exit sub. Player Tracking needs to be active at start of macro
MsgBox "Wrong sheet selected."
Exit Sub
End If
'set source range from Player Tracking
Set rngSource = wsIT.Range(wsIT.Cells(srcFirstRow, srcColumns(0)), wsIT.Cells(Rows.Count, srcColumns(0)).End(xlUp))
For Each c In rngSource.Cells
If Len(c.Value) > 0 Then
'Simpler to search full column, but assumes there will be no match in the header or the cells above it.
Curr = Application.Match(c.Value, wsPD.Columns(tgtColumns(0)), 0) 'no Worksheetfunction=no runtime error if no match
If Not IsError(Curr) Then 'increment last column
For inc = 5 To 10
If inc > 10 Then Exit For
If inc = 6 Or inc = 7 Then
GoTo SKIP_ITERATION:
End If
With wsPD.Cells(Curr, tgtColumns(inc))
.Value = .Value + wsIT.Cells(c.Row, srcColumns(inc)).Value
End With
SKIP_ITERATION: Next inc
Else
Set Rng = wsPD.Cells(Rows.Count, tgtColumns(0)).End(xlUp).Offset(1, 0) 'no
match: copy over
For k = 0 To ub
wsPD.Cells(Rng.Row, tgtColumns(k)).Value = wsIT.Cells(c.Row, srcColumns(k)).Value
Next k
End If
End If
lastrow = wsPD.Range("B" & Rows.Count).End(xlUp).Row
With wsPD.Cells(lastrow + 1, 2)
.EntireRow.Copy
.EntireRow.Insert Shift:=xlShiftDown, CopyOrigin:=xlFormatFromLeftOrAbove
End With
Application.CutCopyMode = False
Next c
For Each c In wsPD.Range("B4:M" & lastrow) 'locate all blank rows in player details cells
If IsEmpty(c) Then
c.Value = "None" 'Put "TBD" in all blank cells
End If
Next c
MsgBox "Operation finished successfully."
Call NormalPerformance
Call ProtectAllSheets
End Sub
```
To convert a Sub to a Function, you simply need to change the definition from Sub xxx to Function xxx, the closing End Sub to End Function and any Exit Sub to Exit Function. That`s all - however it will be rather useless to do so.
None of these functions will return anything, and the basic idea of a function is to return something (in opposite to a sub that cannot return anything - in other programming languages this is called a void function). The question is why you want to convert it to a function and what you want to return?
To let a function return anything, you simply assign a value to the function name. So if you have a function foo, you write:
Function foo
(...)
foo = "Hello world"
end Function
Now, the function will return the string "Hello world". You should declare the type that is returned by the function (else it will return a variant):
Function doubleMe(x as Long) As Long
(...)
doubleMe = x * 2
End Function
and use the result on your code
myVal = doubleMe(12345)
y1 = 555
Debug.Print doubleMe(y1) & " is twice as much as " & y1
If you are not interested in the result you can call the function like any subroutine, either with Call (and use parenthesis for the parameter) or without (then you have to omit the parenthesis)
doubleMe 0
Call doubleMe(-1)
Often you see that a function returns a Boolean indicating the success
Function ToSomethingComplicated(p1, p2, p3) as boolean
ToSomethingComplicated = False
(do your complicated stuff here)
if (something failed) Then Exit Function
(do some more complicated stuff)
(...)
' If everything was successfull, return True
ToSomethingComplicated = True
End Function
I made a nice Excel file with several (almost the same) macros. Goal is to fill open a Word template, fill in the bookmarks and save every individual document with predefined fields in the filename. Works like a charm... but it doesn't go further then the 10th row of my Excel file. All 12 macros have the same issue, basically the macro is the same only the fields are different.
The VBA I have now is this:
Option Explicit
Sub Akkoordverklaring()
Dim lonLaatsteRij As Long
Dim rngData As Range
Dim strVoornaam As String, strAchternaam As String, strSlber As String
Dim c As Range
With Sheets("Cijferlijst")
lonLaatsteRij = .Cells(Rows.Count, "A").End(xlUp).Row
Set rngData = .Range(.Cells(2, 1), .Cells(lonLaatsteRij, 1))
End With
For Each c In rngData
strVoornaam = c.Value
strAchternaam = c.Offset(0, 1).Value
strSlber = c.Offset(0, 12).Value
Call maakWordDocument(strVoornaam, strAchternaam, strSlber)
Next c
End Sub
Private Sub maakWordDocument(strVoornaam As String, strAchternaam As String, _
strSlber As String)
Dim wordApp As Object, WordDoc As Object
On Error Resume Next
Set wordApp = GetObject("", "Word.Application")
If wordApp Is Nothing Then
Set wordApp = CreateObject("Word.Application")
End If
wordApp.Visible = False
Set WordDoc = wordApp.Documents.Open(ThisWorkbook.Path & _
"Formulieren\Akkoordverklaring.docx")
Call InvullenBladwijzer(wordApp, "voornaam", strVoornaam)
Call InvullenBladwijzer(wordApp, "achternaam", strAchternaam)
Call InvullenBladwijzer(wordApp, "slber", strSlber)
wordApp.DisplayAlerts = False
WordDoc.SaveAs Filename:=ThisWorkbook.Path & _
"Akkoordverklaring\Akkoordverklaring " & strVoornaam & Space(1) & _
strAchternaam, FileFormat:=wdFormatDocumentDefault
WordDoc.Close
wordApp.Quit
Set WordDoc = Nothing
Set wordApp = Nothing
End Sub
Sub InvullenBladwijzer(wordApp As Object, strBladwijzer As String, _
strTekst As String)
wordApp.Selection.Goto What:=wdGoToBookmark, Name:=strBladwijzer
wordApp.Selection.TypeText strTekst
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
As I'm not a programmer I just know how to read some VBA. Some users in here also helped me out with the VBA above:
Excel: change VBA action frome same sheet to another sheet
I'm using Access 2013 and exporting data to an exisitng Excel 2010 workbook. I'm using the following code (passing the query, worksheet and excel filename). It all works great:
Public Function SendTQ2XLWbSheetSizeRange(strTQName As String, strSheetName As String, strFilePath As String)
' strTQName is the name of the table or query you want to send to Excel
' strSheetName is the name of the sheet you want to send it to
' strFilePath is the name and path of the file you want to send this data into.
Dim rst As DAO.Recordset
Dim ApXL As Object
Dim xlWBk As Object
Dim xlWSh As Object
Dim fld As DAO.Field
Dim strPath As String
Const xlCenter As Long = -4108
Const xlBottom As Long = -4107
On Error GoTo err_handler
strPath = strFilePath
Set rst = CurrentDb.OpenRecordset(strTQName)
Set ApXL = CreateObject("Excel.Application")
Set xlWBk = ApXL.Workbooks.Open(strPath)
ApXL.Visible = True
Set xlWSh = xlWBk.Worksheets(strSheetName)
xlWSh.Activate
xlWSh.Range("A5").Select
For Each fld In rst.Fields
ApXL.ActiveCell = fld.Name
ApXL.ActiveCell.Offset(0, 1).Select
Next
rst.MoveFirst
xlWSh.Range("A6").CopyFromRecordset rst
xlWSh.Range("1:1").Select
' This is included to show some of what you can do about formatting. You can comment out or delete
' any of this that you don't want to use in your own export.
With ApXL.Selection.Font
.Name = "Arial"
.Size = 12
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
End With
ApXL.Selection.Font.Bold = True
With ApXL.Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlBottom
.WrapText = False
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.MergeCells = False
End With
' selects all of the cells
ApXL.ActiveSheet.Cells.Select
' does the "autofit" for all columns
ApXL.ActiveSheet.Cells.EntireColumn.AutoFit
' selects the first cell to unselect all cells
xlWSh.Range("A1").Select
rst.Close
Set rst = Nothing
Exit_SendTQ2XLWbSheet:
Exit Function
err_handler:
DoCmd.SetWarnings True
MsgBox Err.Description, vbExclamation, Err.Number
Resume Exit_SendTQ2XLWbSheet
End Function
Now I have a requirement to export another query to a different workbook within the same Excel file. The problem is the code above opens the Excel file, so if I then call the procedure again, it then opens an additional read-only copy of the Excel. How do I get around this? It total I will need to perform 3 exports to 3 different worksheets within 1 Excel file. Can anyone help?
I'd use three procedures. The first just identifies which file to open and which query goes on which sheet.
This will place Query1 on Sheet1, Query2 on Sheet2. It uses a ParamArray so you can add as many sheet/query pairs as you like:
Public Sub ProcessExcel()
SendToExcel "<full path to Excel file>", "Sheet1", "Query1", "Sheet2", "Query2"
End Sub
The second procedure sets a reference to Excel, opens the workbook and then starts processing the ParamArray. The sheet name is used to create a reference to the actual sheet which is then passed to the next procedure.
Public Sub SendToExcel(sFilePath As String, ParamArray ShtQry() As Variant)
Dim oXL As Object 'Ref to Excel.
Dim oWB As Object 'Ref to workbook.
Dim x As Long 'General counter
'Get or create reference to Excel.
On Error Resume Next
Set oXL = GetObject(, "Excel.Application")
If Err.Number <> 0 Then
Err.Clear
On Error GoTo Err_Handle
Set oXL = CreateObject("Excel.Application")
End If
On Error GoTo Err_Handle
Set oWB = oXL.Workbooks.Open(sFilePath)
For x = LBound(ShtQry) To UBound(ShtQry) Step 2
SendTQ2XLWbSheetSizeRange oWB.worksheets(CStr(ShtQry(x))), CStr(ShtQry(x + 1))
Next x
Exit Sub
Err_Handle:
End Sub
The final procedure opens the recordset and pastes everything onto the correct sheet:
Public Sub SendTQ2XLWbSheetSizeRange(oWrkSht As Object, sTQName As String)
Dim rst As DAO.Recordset
Dim db As DAO.Database
Dim x As Long
Set db = CurrentDb
Set rst = db.OpenRecordset(sTQName)
With oWrkSht
'Place field headings.
For x = 0 To rst.Fields.Count - 1
.cells(5, x + 1) = rst.Fields(x).Name
Next x
'Place values.
.Range("A6").CopyFromRecordset rst
End With
rst.Close
Set rst = Nothing
Set db = Nothing
End Sub
I've missed out plenty of error checks in the code - ensure the sheet exists, that the array holds sheet/query pairs and lots I haven't even considered.
Note: Not a single Select or Activate in sight - just reference the sheet.
This doesn't sound right: 'export another query to a different workbook within the same Excel file'. How about exporting the contents of different tables to one single Excel file, but placing the results of each table to a separate sheet in the same Excel file. You can easily modify the code to export queries to separate Excel sheets, instead of exporting tables.
Option Compare Database
Option Explicit
Private Sub Command0_Click()
Dim strFile As String
Dim varItem As Variant
strFile = InputBox("Designate the path and file name to export to...", "Export")
If (strFile = vbNullString) Then Exit Sub
For Each varItem In Me.List0.ItemsSelected
DoCmd.TransferSpreadsheet transferType:=acExport, _
spreadsheetType:=acSpreadsheetTypeExcel9, _
tableName:=Me.List0.ItemData(varItem), _
FileName:=strFile
Next
MsgBox "Process complete.", vbOKOnly, "Export"
End Sub
Private Sub Form_Open(Cancel As Integer)
Dim strTables As String
Dim tdf As TableDef
' Reference: MS DAO 3.6
' Properties > All > Row Source Type = Value List
For Each tdf In CurrentDb.TableDefs
If (Left(tdf.Name, 4) <> "MSys") Then
strTables = strTables & tdf.Name & ","
End If
Next
strTables = Left(strTables, Len(strTables) - 1)
Me.List0.RowSource = strTables
End Sub
Add a ListBox to a form, and a button on the same form, and run it that way.
Thanks to everyone for their kind words and suggestions. I've gone with #Cody G. 2nd suggestions and just closed the excel file each time, so just adding
xlWBk.Close True
Set xlWBk = Nothing
ApXL.Quit
Set ApXL = Nothing
Each time.
My issue is after I have imported a table from Microsoft Word into Excel by creating an OLEObject, it won't let me copy and paste the table into excel. It continually keeps pasting whatever was last copied on my clipboard into the first cell. Currently my code asks the user for the file name, opens that file as an OLEObject in the active excel sheet, and then pastes the incorrect information into cell A1. It's not copying and pasting what's inside the Word OLEObject.
Sub Macro1()
Dim FName As String, FD As FileDialog
Dim ExR As Range
Set FD = Application.FileDialog(msoFileDialogOpen)
FD.Show
If FD.SelectedItems.Count <> 0 Then
FName = FD.SelectedItems(1)
Else
Exit Sub
End If
ActiveSheet.OLEObjects.Add(fileName:=FName, Link:=False, DisplayAsIcon:=False).Select
Selection.Verb Verb:=xlPrimary
Range("A1").Select
ActiveSheet.Paste
End Sub
Thank you!
From Word to Excel, should be something like this.
Sub ImportFromWord()
'Activate Word Object Library
'Dim WordApp As Word.Application
Dim WordDoc As Word.Document
Set WordApp = CreateObject("word.application") ' Open Word session
WordApp.Visible = False 'keep word invisible
Set WordDoc = WordApp.Documents.Open("C:\Users\your_path_here_\WordFile.docx") ' open Word file
'copy third row of first Word table
WordDoc.Tables(1).Rows(3).Range.Copy
'paste in Excel
Range("A1").PasteSpecial xlPasteValues
WordDoc.Close 'close Word doc
WordApp.Quit ' close Word
End Sub
Or this.
Sub GetTables()
FName = Application _
.GetOpenFilename("Word Files (*.doc), *.doc")
Set WordObject = GetObject(FName)
First = True
RowCount = 2
For Each Tble In WordObject.tables
For i = 1 To 22
If First = True Then
Data = Tble.Rows(i).Cells(1).Range
'Remove cell markers
Cells(1, i) = Left(Data, Len(Data) - 2)
End If
Data = Tble.Rows(i).Cells(2).Range.Text
'Remove cell markers
Cells(RowCount, i) = Left(Data, Len(Data) - 2)
Next i
RowCount = RowCount + 1
First = False
Next Tble
WordObject.Close savechanges = False
End Sub
Using the code from the link How to preserve source formatting while copying data from word table to excel sheet using VB macro? , I've only been able to get the code to work when the macro pastes my Word table in a whole new separate workbook. When clicking a command button that's within the excel workbook that I want to import the Word table to, the table never pastes into the sheet called "Scraping Sheets" I've messed around with the code, but the closest thing I could get was placing the entire table into one cell with all formatting lost.
Private Sub CommandButton22_Click()
Dim oWordApp As Object, oWordDoc As Object
Dim FlName As String
Dim tbl As Object
FlName = Application.GetOpenFilename("Word files (*.Doc*),*.Doc*", , _
On Error Resume Next
Set oWordApp = GetObject(, "Word.Applicaton")
If Err.Number <> 0 Then
Set oWordApp = CreateObject("Word.Application")
End If
Err.Clear
On Error GoTo 0
oWordApp.Visible = True
Set oWordDoc = oWordApp.Documents.Open(FlName)
Set tbl = oWordDoc.Tables(1)
Dim wb As Workbook, ws As Worksheet
Set wb = Workbooks.Open(""C:\Users\xxxx\Desktop\292 Int'l_Weekly_Win_Loss_YYYY MM DD TEMPLATE.xlsm"")
Set ws = wb.Sheets("Scraping Sheet")
tbl.Range.Copy
ws.Range("A1").Activate
ws.Paste
MsgBox "Successfully Added File!"
End Sub