I have a routine that pastes any recordset into an existing workbook from an MS Access database. The code works fine the first time, but I can never run it twice because it leaves one instance of Excel running in the Task Manager. Of course, this causes an error when I refer to Excel objects in my code the 2nd, 3rd, etc. time, because the objects are ambiguous.
For the sake of missing anything here is the entire code:
'I call the routine like so:
Private Sub cmdGenerateRpt
Dim strPath As String
strPath = "C:\Test\MyReport.xlsx"
Call PushToExistingExcel("MAIN SHEET", strPath)
End sub
Public Sub PushToExistingExcel(strSheetToPlaceData As String, strPathToWorkbook As String)
'Puts a recordset into a specific cell of an Excel workbook
Dim xlApp As Object
Dim wb As Object
Dim xlSheet As Object
Dim rs As DAO.Recordset
Dim rsTotals As DAO.Recordset
Dim x As Integer
Dim fld As Variant
Dim intRecords As Integer
Dim intTotals As Integer
Set xlApp = CreateObject("Excel.Application")
Set wb = xlApp.Workbooks.Open(strPathToWorkbook)
Set xlSheet = wb.Sheets(strSheetToPlaceData) 'or you can manually type the sheet name in place of strSheetToPlaceData
Set rs = CurrentDb.OpenRecordset("Select * from qryRPT")
Set rsTotals = CurrentDb.OpenRecordset("Select * from qryTOTALS")
intRecords = rs.RecordCount
intTotals = intRecords + 3
xlSheet.Select
xlSheet.Range("A3:AH3").Select
xlSheet.Range(Selection, Selection.End(xlDown)).Select
'PLACE
xlSheet.Range("A3").CopyFromRecordset rs
xlSheet.Range("L" & intRecords + 3).CopyFromRecordset rsTotals
Cells.EntireColumn.AutoFit
xlSheet.Range("A1").Select
Range("A" & intTotals & ":AH" & intTotals).Select
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.PatternTintAndShade = 0
End With
With Selection.Font
.Name = "Calibri"
.FontStyle = "Bold"
.Size = 11
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
End With
Selection.NumberFormat = "$#,##0.00"
Range("A" & intTotals).Value = "TOTALS"
wb.Save
MsgBox "Done"
xlApp.Visible = True
'If I use xlApp.quit it quits, but still leaves it running in task manager
Set wb = Nothing
Set xlSheet = Nothing
Set rs = Nothing
Set rsTotals = Nothing
Set xlApp = Nothing
End Sub
At the end of the day, I want for the finished Workbook to open up presenting itself to the user. There is no reason to just say that the report is done - 'go look for it'.
But I can't seem to figure out how to get rid of the instance of Excel left over from VBA.
In order to clean up successfully, you need to
destroy all objects that refer to objects in the Excel App
close all workbooks
Quit the app
Also, to avoid any mistakes and to create cleaner code you should
avoid use of the implicit ActiveSheet. The unqualified references to Cells. ..., Range( ..., Selection. ... may be leaving references to the Excel app hanging. Use variables for all references
avoid Select, Selection etc
See this answer for help on avoiding these
Cleanup code should be
Set xlSheet = Nothing
For Each wb In xlApp.Workbooks
wb.Close False
Next
xlApp.Quit
Set xlApp = Nothing
This one is closer to 'air tight.' In addition to avoiding using '.select' or '.selection any stray reference like cells.EntireColumn.AutoFit was a Gotcha for me.
Note how I tried to stick to 3 variables for Excel - xlApp, wb and xlSheet
Any reference I used needed all three of these tightly integrating the full address. I also used 'Late Binding.'
Then I isolated the presentation of the workbook in another routine.
Use this as an example for pasting a complex query into an existing workbook at a specified location and presenting the report. It works nicely!
Public Sub PushToExistingExcel(strSheetToPlaceData As String, strPathToWorkbook As String)
'Puts a recordset into a specific cell of an Excel workbook
Dim xlApp As Object
Dim wb As Object
Dim xlSheet As Object
Dim rs As DAO.Recordset
Dim rsTotals As DAO.Recordset
Dim x As Integer
Dim fld As Variant
Dim intRecords As Integer
Dim intTotals As Integer
Set xlApp = CreateObject("Excel.Application")
Set wb = xlApp.Workbooks.Open(strPathToWorkbook)
Set xlSheet = wb.Sheets(strSheetToPlaceData) 'or you can manually type the sheet name in place of strSheetToPlaceData
Set rs = CurrentDb.OpenRecordset("Select * from qryRPT")
Set rsTotals = CurrentDb.OpenRecordset("Select * from qryTOTALS")
intRecords = rs.RecordCount
intTotals = intRecords + 3
xlSheet.Rows("3:" & xlSheet.Rows.Count).ClearContents
'PLACE
With xlSheet
.Range("A3").CopyFromRecordset rs
.Range("L" & intRecords + 3).CopyFromRecordset rsTotals
.Cells.EntireColumn.AutoFit
End With
With xlSheet.Range("A" & intTotals & ":AH" & intTotals).Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.PatternTintAndShade = 0
End With
With xlSheet.Range("A" & intTotals & ":AH" & intTotals).Font
.Name = "Calibri"
.FontStyle = "Bold"
.Size = 11
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
End With
xlSheet.Range("A3:AH" & intTotals).NumberFormat = "$#,##0.00"
xlSheet.Range("A" & intTotals).Value = "TOTALS"
wb.Save
'cleanup
Set xlSheet = Nothing
For Each wb In xlApp.Workbooks
wb.Close False
Next
Set rs = Nothing
Set rsTotals = Nothing
xlApp.Quit
Set xlApp = Nothing
MsgBox "Report Complete"
PresentExcel (strPathToWorkbook)
End Sub
Public Sub PresentExcel(strPath As String)
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
xlApp.Workbooks.Open strPath
Debug.Print xlApp.Version
Set xlApp = Nothing
End Sub
Related
Running VBA through Access.
Attempting to transfer select queries from access to excel.
If I run all the code together, then I get 3011 run-time error on the 2nd DoCmd.TransferSpreadsheet.
If I comment out all the code related to PATH1, then the 2nd DoCmd.TransferSpreadhseet runs fine.
The Microsoft Access database engine could not find the object 'TabUSR1'. Make sure the object exists and that you spell its name and the path name correctly...
I have removed a good bit of code that I feel to be irrelevant to my issue. That is why there are so many variables you do not see any code for.
Dim tempR1 As String
Dim tempR2 As String
Dim tempValue1 As String
Dim tempValue2 As String
Dim tempValue3 As String
Dim tempValue4 As String
Dim tempValue5 As String
Dim dt As Date
Dim d As String
Dim row As String
Dim rngC As Range
Dim rngU As Range
Dim fpath As String
Dim strFileExists
Dim xlappC As Excel.Application
Dim xlbookC As Excel.Workbook
Dim xlsheetC As Excel.Worksheet
Dim xlappU As Excel.Application
Dim xlbookU As Excel.Workbook
Dim xlsheetU As Excel.Worksheet
fpath = "PATH1"
strFileExists = Dir(fpath)
If strFileExists <> "" Then
'set variables for Excel
Set xlappC = CreateObject("Excel.Application")
Set xlbookC = xlappC.Workbooks.Open(fpath)
Set xlsheetC = xlbookC.Worksheets("Audit Fees Remittance")
With xlappC
.Visible = False
.DisplayAlerts = False
.Workbooks.Open fpath
'Update Raw Data Cad and CSCT tab
Set xlsheetC = xlbookC.Worksheets("Raw Data CAD and CSCT")
With xlsheetC
Set rst = CurrentDb.OpenRecordset("Weekly CAN 5 Raw Data to include csct")
If rst.RecordCount > 0 Then
tempR2 = rst.RecordCount + 1
tempR2 = .Cells(.Rows.Count, "CV").End(xlUp).Offset(tempR2).Address(False, False)
tempR1 = .Cells(.Rows.Count, "A").End(xlUp).Offset(1).Address(False, False)
Set rngC = .Range(tempR1, tempR2)
rngC.Name = "TabFA8"
DoCmd.TransferSpreadsheet acExport, 10, "PATH1", True, "TabFA8"
.Rows(2).EntireRow.Delete
rst.Close
Set rst = Nothing
Else
rst.Close
Set rst = Nothing
End If
tempValue2 = "$A$2:" & tempR2
.Range(tempValue2).EntireColumn.AutoFit
tempR1 = ""
tempR2 = ""
End With
'Remit for US
fpath = "PATH2"
strFileExists = Dir(fpath)
If strFileExists <> "" Then
'set variables for Excel
Set xlappU = CreateObject("Excel.Application")
Set xlbookU = xlappU.Workbooks.Open(fpath)
Set xlsheetU = xlbookU.Worksheets("Remittance Tab")
With xlappU
.Visible = False
.DisplayAlerts = False
.Workbooks.Open fpath
'Update INTL Remittance tab
Set xlsheetU = xlbookU.Worksheets("INTL Remittance")
With xlsheetU
Set rst = CurrentDb.OpenRecordset("Weekly US 5 Remittance Tab B DHLG and Jas")
If rst.RecordCount > 0 Then
tempR2 = rst.RecordCount + 1
tempR2 = .Cells(.Rows.Count, "V").End(xlUp).Offset(tempR2).Address(False, False)
tempR1 = .Cells(.Rows.Count, "A").End(xlUp).Offset(1).Address(False, False)
If Len(tempR1) = 3 Then
row = Right(tempR1, 2)
Else
row = Right(tempR1, 3)
End If
'set range for renaming
'this will allow TransferSpreadhseet to know where to export to on the sheet
Set rngU = .Range(tempR1, tempR2)
rngU.Name = "TabUSR2"
DoCmd.TransferSpreadsheet acExport, 10, "Weekly US 5 Remittance Tab B DHLG and Jas", "PATH2", True, "TabUSR2"
'delete row with headers
.Rows(row).EntireRow.Delete
rst.Close
Set rst = Nothing
Else
rst.Close
Set rst = Nothing
End If
End With
While I cannot exactly understand or diagnose your issue, for maintenance and readability, consider separating all Excel and Access processes. Avoid walking over same opened files with both object libraries. Therefore, consider Excel's Range.CopyFromRecordset over Access's DoCmd.TransferSpreadsheet using the very recordset you create.
...
Set rst = CurrentDb.OpenRecordset("Weekly CAN 5 Raw Data to include csct")
...
Set rngC = .Range(tempR1, tempR2)
rngC.Name = "TabFA8"
rngC.CopyFromRecordset rst
rst.Close
...
Set rst = CurrentDb.OpenRecordset("Weekly US 5 Remittance Tab B DHLG and Jas")
...
Set rngU = .Range(tempR1, tempR2)
rngU.Name = "TabUSR2"
rngU.CopyFromRecordset rst
rst.Close
Parfait's suggestion of closing the workbook then doing the TransferSpreadsheet solved my issue.
For the purpose of sales department I have a query that tracks previous price points and calculates margins. I would like to export this info to Excel to create a combo chart to make the information more visual. I've found some sample code on another site, but it doesn't quite do everything I need. I've used the macro recorder to come up with my desire code, but it uses different methods than my sample code. Can anyone help me to combine the following codes to come up with Combo Charts via VBA?
'sample code below
Private Sub Command201_Click()
Option Compare Database
Private Const conQuery = "qryTopTenProducts"
Private Const conSheetName = "Top 10 Products"
Private Sub Command201_Click()
Dim rst As ADODB.Recordset
' Excel object variables
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Dim xlChart As Excel.Chart
Dim i As Integer
On Error GoTo HandleErr
' Create Excel Application object.
Set xlApp = New Excel.Application
' Create a new workbook.
Set xlBook = xlApp.Workbooks.Add
' Get rid of all but one worksheet.
xlApp.DisplayAlerts = False
For i = xlBook.Worksheets.Count To 2 Step -1
xlBook.Worksheets(i).Delete
Next i
xlApp.DisplayAlerts = True
' Capture reference to first worksheet.
Set xlSheet = xlBook.ActiveSheet
' Change the worksheet name.
xlSheet.Name = conSheetName
' Create recordset.
Set rst = New ADODB.Recordset
rst.OPEN _
Source:=conQuery, _
ActiveConnection:=CurrentProject.Connection
With xlSheet
' Copy field names to Excel.
' Bold the column headings.
With .Cells(1, 1)
.Value = rst.Fields(0).Name
.Font.Bold = True
End With
With .Cells(1, 2)
.Value = rst.Fields(1).Name
.Font.Bold = True
End With
' Copy all the data from the recordset
' into the spreadsheet.
.Range("A2").CopyFromRecordset rst
' Format the data.
.Columns(1).AutoFit
With .Columns(2)
.NumberFormat = "#,##0"
.AutoFit
End With
End With
' Create the chart.
Set xlChart = xlApp.Charts.Add
With xlChart
.ChartType = xlComboColumnClusteredLine
.SetSourceData xlSheet.Cells(1, 1).CurrentRegion
.PlotBy = xlColumns
.Location _
Where:=xlLocationAsObject, _
Name:=conSheetName
End With
' Setting the location loses the reference, so you
' must retrieve a new reference to the chart.
With xlBook.ActiveChart
.HasTitle = True
.HasLegend = False
With .ChartTitle
.Characters.Text = conSheetName & " Chart"
.Font.Size = 16
.Shadow = True
.Border.LineStyle = xlSolid
End With
With .ChartGroups(1)
.GapWidth = 20
.VaryByCategories = True
End With
.Axes(xlCategory).TickLabels.Font.Size = 8
.Axes(xlCategoryScale).TickLabels.Font.Size = 8
End With
' Display the Excel chart.
xlApp.Visible = True
ExitHere:
On Error Resume Next
' Clean up.
rst.Close
Set rst = Nothing
Set xlSheet = Nothing
Set xlBook = Nothing
Set xlApp = Nothing
Exit Sub
HandleErr:
MsgBox Err & ": " & Err.Description, , "Error in CreateExcelChart"
Resume ExitHere
End Sub
'macro recorded code
ActiveSheet.Shapes.AddChart2(201, xlColumnClustered).Select
ActiveChart.SetSourceData Source:=Range("'PART TARGET'!$A$1:$E$5")
ActiveChart.FullSeriesCollection(1).ChartType = xlColumnClustered
ActiveChart.FullSeriesCollection(1).AxisGroup = 1
ActiveChart.FullSeriesCollection(2).ChartType = xlColumnClustered
ActiveChart.FullSeriesCollection(2).AxisGroup = 1
ActiveChart.FullSeriesCollection(3).ChartType = xlColumnClustered
ActiveChart.FullSeriesCollection(3).AxisGroup = 1
ActiveChart.FullSeriesCollection(4).ChartType = xlLine
ActiveChart.FullSeriesCollection(4).AxisGroup = 1
ActiveChart.FullSeriesCollection(5).ChartType = xlLine
ActiveChart.FullSeriesCollection(5).AxisGroup = 1
ActiveChart.FullSeriesCollection(4).ChartType = xlColumnClustered
ActiveChart.FullSeriesCollection(4).AxisGroup = 2
ActiveChart.FullSeriesCollection(3).ChartType = xlLine
The problem breaks into two parts. Exporting the data to Excel and then having Excel create a Combo Chart. If you are creating the Excel file you can use Access's Export Data Wizard to create a saved export of almost anything in access. Then its a simple call to:
DoCmd.RunSavedImportExport "Export-MyTabletoExcel"
If you already have an Excel File with a macro for creating the chart from where the data goes then you can create the chart by simply calling the macro from Access
runExcelMacro "C:\Users\bubblegum\Desktop\test2.xlsm", "CreateComboChart"
Public Sub runExcelMacro(wkbookPath, macroName)
'adapted from https://access-excel.tips/run-excel-macro-from-access-vba/
Dim XL As Object
Set XL = CreateObject("Excel.Application")
With XL
.Visible = False
.displayalerts = False
.Workbooks.Open wkbookPath
.Run macroName
.ActiveWorkbook.Close (True)
.Quit
End With
Set XL = Nothing
End Sub
But if you have to create the Excel file it will not have a Macro yet so it is best to create that macro in Excel then translate it to Access vba:
Sub CreateComboChart()
' CreateComboChart Macro
Range("B1:D7").Select
ActiveSheet.Shapes.AddChart2(201, xlColumnClustered).Select
ActiveChart.SetSourceData Source:=Range("Table4!$B$1:$D$7")
ActiveChart.FullSeriesCollection(1).ChartType = xlColumnClustered
ActiveChart.FullSeriesCollection(1).AxisGroup = 1
ActiveChart.FullSeriesCollection(2).ChartType = xlColumnClustered
ActiveChart.FullSeriesCollection(2).AxisGroup = 1
ActiveChart.FullSeriesCollection(3).ChartType = xlLine
ActiveChart.FullSeriesCollection(3).AxisGroup = 1
End Sub
became:
Public Sub CreateComboChartinExcel()
'Required: Tools > Refences: Add reference to Microsoft Excel Object Library
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Dim xlChart As Excel.Chart
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("C:\Users\bubblegum\Desktop\test.xlsm")
Set xlSheet = xlBook.ActiveSheet
xlSheet.Range("B1:D7").Select
xlSheet.Shapes.AddChart2(201, xlColumnClustered).Select
Set xlChart = xlBook.ActiveChart
xlChart.SetSourceData Source:=xlSheet.Range("B1:D7")
xlChart.FullSeriesCollection(1).ChartType = xlColumnClustered
xlChart.FullSeriesCollection(1).AxisGroup = 1
xlChart.FullSeriesCollection(2).ChartType = xlColumnClustered
xlChart.FullSeriesCollection(2).AxisGroup = 1
xlChart.FullSeriesCollection(3).ChartType = xlLine
xlChart.FullSeriesCollection(3).AxisGroup = 1
xlBook.Save 'surprisingly important
xlBook.Close
xlApp.Quit
Set xlBook = Nothing
Set xlApp = Nothing
End Sub
Finally, the Access Export Wizard neither lets you append the exported data to the Excel file or lets you see the VBA. So if you want to paste to an Excel file you have to either use Docmd.TransferSpreadsheet or loop through the Access tables and copy and paste to excel. I show Docmd:
Public Sub TransferTable()
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12, "myTable", "C:\Users\bubblegum\Desktop\test.xlsx"
End Sub
Hi I justed posted a few minutes ago and somone asnwerd my question about excel not closing. I am using access to open a sheet and add a table. Excel won't close which causes issues down the road as when I get the excel object again in another function the sheet I am working with won't open and it won't format it. Here is my code. I thought I was explicit here but maybe I am not. Excel just won't closed.
Public Function BrooksFormatTableBrooks()
Dim xlApp As Excel.Application
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
bfile = "S:\_Reports\Brooks\Tyco-Brooks Receiving Tracking MASTER - "
MyFileName = bfile & Format(Date, "mm-dd-yyyy") & ".xls"
On Error Resume Next
Set xlApp = CreateObject("Excel.Application")
On Error GoTo 0
Set wb = xlApp.Workbooks.Open(MyFileName)
Set ws = wb.Sheets(1)
ws.Activate
wb.Sheets(1).Name = "RSSR_List"
Set ws = wb.Sheets(1)
ws.Activate
xlApp.ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$1:$F$312"), , xlYes).Name = _
"RSSR"
ws.Range("A1:F312").Select
DoEvents
ws.Cells.Rows("2:2").Select
xlApp.ActiveWindow.FreezePanes = False
xlApp.ActiveWindow.FreezePanes = True
ws.Columns("A:Z").HorizontalAlignment = xlCenter
ws.Rows("1:1").Font.Bold = True
ws.Rows("1:1").Font.ColorIndex = 1
ws.Rows("1:1").Interior.ColorIndex = 15
ws.Cells.Font.Name = "Calbri"
ws.Cells.Font.Size = 8
ws.Cells.EntireColumn.AutoFit
ws.Cells.EntireRow.AutoFit
xlApp.Cells.Borders.LineStyle = xlContinuous
xlApp.Cells.Borders.Weight = xlThin
xlApp.Cells.Borders.ColorIndex = 0
ws.Cells.Rows("1:1").Select
wb.CheckCompatibility = False
wb.Save
wb.CheckCompatibility = True
wb.Close SaveChanges:=True
xlApp.Quit
Set xlApp = Nothing
Set wb = Nothing
Set ws = Nothing
MsgBox "Table Add"
End Function
Replace Range("$A$1:$F$312") with ws.Range("$A$1:$F$312") or else you will still have a reference to an Excel Application object that won't be destroyed until you exit MSAccess.
I'm playing around with this code snippet, which I found on SO.
Sub Test()
Dim objWord As Object
Dim ws As Worksheet
Set ws1 = ThisWorkbook.Sheets("Contact Information1")
Set ws2 = ThisWorkbook.Sheets("Contact Information2")
'Set ws3 = ThisWorkbook.Sheets("Contact Information3")
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.Documents.Open "C:\Users\rshuell001\Desktop\Final Report.docx" ' change as required
With objWord.ActiveDocument
.Bookmarks("BkMark1").Range.Text = ws1.Range("A1:F24").Value
.Bookmarks("BkMark2").Range.Text = ws2.Range("A1:F8").Value
'.Bookmarks("Report3").Range.Text = ws3.Range("A1:F80").Value
End With
Set objWord = Nothing
End Sub
When I look at it, it makes sense. When I run the script, I get an error on this line:
.Bookmarks("BkMark1").Range.Text = ws1.Range("A1:F24").Value
The error message is:
Run-type error 13
Type mismatch
1) I'm not sure '.Bookmarks("BkMark1").Range.Text' will do what I want. I think it's more of a standard copy/paste.
2) I want to make sure the table fits in the Word document, so I'm going to need something like the line below, to get it to do what I want.
wd.Tables(1).AutoFitBehavior wdAutoFitWindow
Any ideas on how to make this work?
Thanks!
I came up with the script below. It does what I want.
Sub Export_Table_Word()
'Name of the existing Word doc.
'Const stWordReport As String = "Final Report.docx"
'Word objects.
Dim WDApp As Word.Application
Dim WDDoc As Word.Document
Dim wdbmRange1 As Word.Range
'Excel objects.
Dim wbBook As Workbook
Dim wsSheet1 As Worksheet
Dim rnReport1 As Range
'Initialize the Excel objects.
Set wbBook = ThisWorkbook
Set WDApp = New Word.Application
'Set wdDoc = wdApp.Documents.Open(wbBook.Path & "\" & stWordReport)
Set WDDoc = WDApp.Documents.Open("C:\Users\rshuell001\Desktop\Final Report.docx")
'Delete old fields and prepare to replace with new
Dim doc As Document
Dim fld As Field
Set doc = WDDoc
For Each fld In doc.Fields
fld.Select
If fld.Type = 88 Then
fld.Delete
End If
Next
Set wsSheet = wbBook.Worksheets("Contact Information1")
Set rnReport = wsSheet.Range("BkMark1")
Set wdbmRange = WDDoc.Bookmarks("BkMark1").Range
'Turn off screen updating.
Application.ScreenUpdating = False
'Copy the report to the clipboard.
rnReport.Copy
'Select the range defined by the "Report" bookmark and paste in the report from clipboard.
With wdbmRange
.Select
.Paste
End With
WDDoc.Tables(1).AutoFitBehavior wdAutoFitWindow
Set wsSheet = wbBook.Worksheets("Contact Information2")
Set rnReport = wsSheet.Range("BkMark2")
Set wdbmRange = WDDoc.Bookmarks("BkMark2").Range
Application.ScreenUpdating = False
rnReport.Copy
With wdbmRange
.Select
.Paste
End With
WDDoc.Tables(2).AutoFitBehavior wdAutoFitWindow
Set wsSheet = wbBook.Worksheets("Contact Information3")
Set rnReport = wsSheet.Range("BkMark3")
Set wdbmRange = WDDoc.Bookmarks("BkMark3").Range
Application.ScreenUpdating = False
rnReport.Copy
With wdbmRange
.Select
.Paste
End With
WDDoc.Tables(3).AutoFitBehavior wdAutoFitWindow
'Save and close the Word doc.
With WDDoc
.Save
.Close
End With
'Quit Word.
WDApp.Quit
'Null out your variables.
Set fld = Nothing
Set doc = Nothing
Set wdbmRange = Nothing
Set WDDoc = Nothing
Set WDApp = Nothing
'Clear out the clipboard, and turn screen updating back on.
With Application
.CutCopyMode = False
.ScreenUpdating = True
End With
MsgBox "The report has successfully been " & vbNewLine & _
"transferred to " & stWordReport, vbInformation
End Sub
I have been attempting to develop a routine that will highlight every nth row on a range in Excel from an Access database.
This eliminates a lot of the different code offerings on the subject since most leverage the embedded Excel functions.
The code below is a stand alone extraction from my Access VBA that I have been using for testing in hopes that I could find the correct parameter structure to make it work. As such, the code includes some Dim statements, etc that would not be required if I were embedding this macro directly as an Excel macro.
The code I have accomplishes selecting every other row but for some reason, only the first column of the intended range. I have not been able to resolve this problem and include the other columns in the formating process.
Any assistance would be much appreciated.
Sub xxx()
Dim xlbook As Excel.Workbook
Dim xlRng As Range
Dim xlFinalRange As Range
Dim intColumnCount As Integer
Dim introwcount As Integer
Dim strTable As String
Set xlbook = Excel.ThisWorkbook
strTable = "Sheet1"
introwcount = 20
intColumnCount = 14
Set xlFinalRange = Sheets(strTable).Range("A4")
xlFinalRange.Resize(1, intColumnCount).Select
Set xlRng = Sheets(strTable).Range("A4")
xlRng.Resize(1, intColumnCount).Select
intRowsBetween = 2
For i = 0 To introwcount
Set xlRng = xlRng.Offset(intRowsBetween, 0)
xlRng.Resize(1, intColumnCount).Select
Set xlFinalRange = xlbook.Application.Union(xlFinalRange, xlRng)
xlFinalRange.Resize(1, intColumnCount).Select
i = i + (intRowsBetween - 1)
Next i
xlFinalRange.Select
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorAccent1
.TintAndShade = 0.799981688894314
.PatternTintAndShade = 0
End With
End Sub
The best way is to add a proper Step to your loop. Also, qualify everything properly: Range should be Excel.Range, etc. Try the following:
Sub HighlightXL()
Dim WBK As Excel.Workbook
Dim WS As Excel.Worksheet
Dim Iter As Long
Dim CombinedRng As Excel.Range, IterRng As Excel.Range
Excel.Application.Visible = True
Set WBK = Excel.Workbooks.Add 'Modify as necessary.
Set WS = WBK.Sheets("Sheet1") 'Modify as necessary.
With WS
For Iter = 1 To 22 Step 3 '1, 4, 7, 9... etc...
Set IterRng = .Cells(Iter, 1).Resize(1, 5) 'Resize to 14 in your case.
If CombinedRng Is Nothing Then
Set CombinedRng = IterRng
Else
Set CombinedRng = Union(CombinedRng, IterRng)
End If
Next Iter
End With
CombinedRng.Interior.ColorIndex = 3 'Red.
End Sub
Screenshot:
Let us know if this helps. :)
I have taken a slightly different approach in the past. Below is what I would use:
Sub ColourSheet()
Dim ApXL As Object, xlWBk As Object, xlWSh As Object, _
rng As Object, c As Object
Dim strSheet As String, strFile As String
Dim iColourRow As Integer, iRows As Integer, _
iCols As Integer, x As Integer, iStartRow As Integer
strFile = "C:\YourFolder\YourFile.xlsx"
strSheet = "SheetName"
iColourRow = 3
iRows = 30
iCols = 10
iStartRow = 2
If SmartGetObject("Excel.Application") Then
'excel open
Set ApXL = GetObject(, "Excel.Application")
Else
Set ApXL = CreateObject("Excel.Application")
End If
Set xlWBk = ApXL.Workbooks.Add
'Set xlWBk = ApXL.Workbooks.Open(strFile)
Set xlWSh = xlWBk.activesheet
'Set xlWSh = xlWBk.Worksheets(strSheet)
For x = 1 To iRows
If x Mod iColourRow = 0 Then
With xlWSh.range(xlWSh.cells(iStartRow + x - 1, 1), _
xlWSh.cells(iStartRow + x - 1, iCols)).interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
'.ThemeColor = xlThemeColorAccent1
.Color = 255
.TintAndShade = 0.799981688894314
.PatternTintAndShade = 0
End With
End If
Next x
ApXL.Visible = True
End Sub
A few notes:
Especially if you plan to distribute your database I would advise using late binding for references to Excel, if you use VBA references sooner or later someone's database will stop working and you'll reach the conclusion it is due to a missing reference. Search Late Binding and you'll see plenty on the subject. Note that with late binding you don't get the variables such as xlThemeColorAccent1, you can always get these from opening an Excel VBA instance etc.
I have used a Function call GetSmartObject which identifies if you have Excel running already, a problem I ran into quite a bit was opening additional Excel instances, hitting an error and then that instance remaining running in the background, you then need to go into Task Manager to close it.
Lastly I have just commented out the alternate workbook open where you open a designated file and set the sheet, testing it was easier to open a new workbook and use the active sheet.
Hope this helps
Function SmartGetObject(sClass As String) As Integer
Dim oTmpObject As Object
' If Server running, oTmpObject refers to that instance.
' If Server not running Error 429 is generated.
On Error Resume Next
Set oTmpObject = GetObject(, sClass)
' oTmpObject is reference to new object.
If Err = 429 Then
SmartGetObject = False
Exit Function
' Server not running, so create a new instance:
'Simon noted out: Set oTmpObject = GetObject("", sClass)
' NOTE: for Excel, you can add the next line to view the object
' oTmpObject.Visible = True
ElseIf Err > 0 Then
MsgBox Error$
SmartGetObject = False
Exit Function
End If
Set oTmpObject = Nothing
SmartGetObject = True
End Function
Credit for the above function belongs elsewhere but I've had it so long I don't know where it came from, if anyone can tell me I'll credit it correctly in future.
Option Compare Database
Option Explicit
Sub ExporttoExcel()
Dim i As Integer
Dim y As Integer
Dim varArray As Variant 'Used for obtaining the Names of the Sheets from the DB being exported
Dim varField As Variant 'Used for Naming of the Sheets being exported
Dim dbs As DAO.Database
Dim rst1 As DAO.Recordset 'DB Recordset for the Input and Output information
Dim rst2 As DAO.Recordset 'DB Recordset for the Table names to be exported and sheet names in Excel
Dim rst3 As DAO.Recordset 'DB Recordset that is reused for each Table being exported
Dim strFile As String 'Used for the name and location of the Excel file to be saved
Dim strTable As String 'Table name being exported and also used for the Sheet name
Dim strTitle As String 'Title for the Data on each sheet
Dim xlApp As Object
Dim xlBook As Object
Dim xlSheet As Object
Dim xlRunning As Boolean 'Flag to identify that Excel is running or not
Dim intColumnCount As Integer 'The number of columns on a sheet for formatting
Dim intRowCount As Integer 'The number of rows on a sheet for formatting
Dim intStartRow As Integer 'The row from which to start the highlighting process
Dim intRowsBetween As Integer 'The number of rows between highlighting
If SmartGetObject("Excel.Application") Then
Set xlApp = GetObject(, "Excel.Application") 'Excel is already open so the existing instance will be used
xlRunning = True
Else
Set xlApp = CreateObject("Excel.Application") 'Excel is not open so an instance will be created
xlRunning = False
End If
Set xlBook = xlApp.Workbooks.Add
xlApp.Visible = True
xlApp.DisplayAlerts = False
Set dbs = CurrentDb
'Retrieve Study Location and Name for Import to Database
Set rst1 = dbs.OpenRecordset("StudyTarget")
strFile = rst1!OutputFile
' Removed VBA for File Name & Save Path Information
With xlBook
Set rst2 = dbs.OpenRecordset("ExportTableGroup", dbOpenSnapshot)
' Removed VBA for Excel Naming information from DB
For y = 0 To rst2.RecordCount - 1
strTable = varArray(y, 1)
strTitle = varArray(y, 2)
Set rst3 = dbs.OpenRecordset(strTable, dbOpenTable)
.Sheets.Add after:=Sheets(Sheets.Count)
.Sheets(Sheets.Count).Name = strTable
Set xlSheet = .ActiveSheet
'COPY the Access Table Data to the Named Worksheet
xlSheet.Cells(2, 1).CopyFromRecordset rst3
'Select every X number of rows between sheet Data Rows on Worksheet to highlight
intRowsBetween = 2
intStartRow = 4
For i = 0 To intRowCount Step intRowsBetween
If xlSheet.Cells(intStartRow + i, 1) = "" Then
Exit For
End If
With xlSheet.Range(xlSheet.Cells(intStartRow + i, 1), _
xlSheet.Cells(intStartRow + i, intColumnCount)).Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = RGB(186, 186, 186)
.TintAndShade = 0.6
.PatternTintAndShade = 0
End With
Next i 'Next Row
Next 'Next Table
.Sheets("sheet1").Delete
.Sheets(1).Select 'Go to first sheet of workbook
End With
Export_to_Excel_Exit:
rst1.Close
rst2.Close
rst3.Close
xlApp.ActiveWorkbook.Save
xlBook.Close
If xlRunning Then 'Check to see if used an existing instance of Excel via SmartGetObject
Else
xlApp.Quit
Set xlApp = Nothing
End If
Set xlBook = Nothing
Set rst1 = Nothing
Set rst2 = Nothing
Set rst3 = Nothing
Set dbs = Nothing
Exit Sub