This function uses a combination of Microsoft Access, VBA, and Microsoft Excel to transfer the values from an Access form in PivotTable view to the clipboard. It is a good example of automation using late binding.
My goal was to automate the process of copying values from an Access PivotTable to another Office program, like Word or PowerPoint. It is possible to manually copy the values from an Access PivotTable to the clipboard by selecting a data cell, using Ctrl-A to select all of the PivotTable, and then using Ctrl-C to copy. However, when I tried to figure out how to do the same steps using VBA, I could not determine how to select a cell. There may be a solution by embedding the PivotTable form into another form and referencing the PivotTable object directly, but it would require referencing the Office Web Components library, which changed DLLs from Access 2003 (which used the Access 2002 version) and Access 2007. I have clients using both 2003 and 2007, so I opted for a simpler solution which did not require referencing an extra library.
The solution is to use the Export method of the PivotTable, which exports the pivot and the pivot data to Excel. A file name for the export is not specified in the example because the export wants to create an HTML document, something like PivotTable62219.HTM, and an Excel file name confuses it. Once in Excel, the pivot table becomes more familiar and automation is used to copy just the pivot values and formatting to another worksheet. Then the range that has values is copied to the clipboard. At the end of the function, the Excel application is left open so that the values remain on the clipboard. The GetSaveAsFilename method of the Excel application object is used to allow the user to save the results as an Excel workbook.
Below are examples of the Access PivotTable and the Excel results. In my example, I merged the PivotTable column headers into one title for the Excel results.
Late binding is used because I wasn’t sure what version of Excel my users may have installed. It is easier to use early binding (like Dim objExcelApp As Excel.Application), which provides IntelliSense for the Excel objects. I often start with early binding, referencing the Excel library I have installed (by using the Tools, References option on the VBA editor toolbar), and then change to late binding after the code is tested. Late binding also requires a list of Excel constants to be defined, which I found values for by using the object browser in a session of Excel VBA.
- If you are using only Excel 2007, you can change the default file name and filter for the GetSaveAsFilename method to use the new extension, .xlsx.
- The function XAddress() is a custom function that you can find here.
Public Function ExportCopyAccessPTValues(PTForm) As Boolean ' This function exports the values from the Microsoft Access pivottable ' form PTForm to Microsoft Excel. In Excel, it leaves just the values ' and formatting, and then copies the results to the clipboard. ' For example, you may call the function like: ' ExportCopyAccessPTValues(Forms!frmStudentData) ' ExportCopyAccessPTValues() Version 1.0.0 ' Copyright © 2009 Extra Mile Data, www.extramiledata.com. ' For questions or issues, please contact [email protected]. ' Use (at your own risk) and modify freely as long as proper credit is given. On Error GoTo Err_ExportCopyAccessPTValues Const plExportActionOpenInExcel As Long = 1 Dim varFileName Dim lngStart As Long Dim strLC As String ' Excel objects Dim objExcelApp Dim objWB Dim objWS Dim objPT ' Excel constants Const xlByRows = 1 Const xlContinuous = 1 Const xlDataAndLabel = 0 Const xlDown = -4121 Const xlEdgeBottom = 9 Const xlEdgeLeft = 7 Const xlEdgeRight = 10 Const xlEdgeTop = 8 Const xlFormatFromLeftOrAbove = 0 Const xlLastCell = 11 Const xlNone = -4142 Const xlNormal = -4143 Const xlPart = 2 Const xlPasteFormats = -4122 Const xlPasteValuesAndNumberFormats = 12 Const xlThin = 2 Const xlUp = -4162 ' Export the pivot to Excel, without a file name. PTForm.PivotTable.Export , plExportActionOpenInExcel ' Time delay because Excel takes a moment to open and ' it must be fully open with the pivot in view before we ' can continue. lngStart = Timer Do While Timer < lngStart + 3 DoEvents Loop ' Get the Excel application. It will get one that is already ' open, or start a new one. Set objExcelApp = GetObject(, "Excel.Application") With objExcelApp ' Make Excel visible. .Visible = True ' Get the workbook object. Set objWB = .ActiveWorkbook ' Get the worksheet object. Set objWS = objWB.ActiveSheet ' Get the pivottable object, select all the data, and copy it. Set objPT = objWS.PivotTables(1) objPT.PivotSelect "", xlDataAndLabel, True .Selection.Copy ' Add a new worksheet. objWB.Sheets.Add After:=objWB.Sheets(objWB.Sheets.Count) ' Use Paste Special to paste the pivottable to the new worksheet, ' Values and Number Formats, then Formats. .Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _ Operation:=xlNone, SkipBlanks:=False, Transpose:=False .Selection.PasteSpecial Paste:=xlPasteFormats, _ Operation:=xlNone, SkipBlanks:=False, Transpose:=False ' Insert a row. .CutCopyMode = False .Range("A1").EntireRow.Insert Shift:=xlDown, _ CopyOrigin:=xlFormatFromLeftOrAbove ' In A1, concatenate the possible pivot grouping captions. .Range("A1").FormulaR1C1 = _ "=TRIM(RC & "" "" & RC & "" "" & RC & "" "" " _ & "& RC & "" "" & RC)" ' Paste the Formats from B2 to A1. .Range("B2").Copy .Range("A1").PasteSpecial Paste:=xlPasteFormats, _ Operation:=xlNone, SkipBlanks:=False, Transpose:=False ' Now copy over the formula in A1 with the Values and Number Formats from A1. .Range("A1").Copy .Range("A1").PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _ Operation:=xlNone, SkipBlanks:=False, Transpose:=False ' Delete the second row, no longer needed. .Range("A2").EntireRow.Delete Shift:=xlUp ' Put borders around A2. .Range("A2").Select With .Selection.Borders(xlEdgeLeft) .LineStyle = xlContinuous .ColorIndex = 0 .Weight = xlThin End With ' For some reason, this creates an error. ' With .Selection.Borders(xlEdgeTop) ' .LineStyle = xlContinuous ' .ColorIndex = 0 ' .Weight = xlThin ' End With With .Selection.Borders(xlEdgeBottom) .LineStyle = xlContinuous .ColorIndex = 0 .Weight = xlThin End With With .Selection.Borders(xlEdgeRight) .LineStyle = xlContinuous .ColorIndex = 0 .Weight = xlThin End With ' Merge the cells in the title row. This will allow the table ' to work well when it is pasted in another application. ' Start by selecting the whole range of used data. .Range("A1", .ActiveCell.SpecialCells(xlLastCell)).Select ' Find the last column and build an address for the last cell in ' the row that has data. Use that address for the right cell in the ' range to select and A1 for the left cell. strLC = XAddress(.Selection.Address, xatLastColumn) .Range("A1", strLC & "1").Select ' Then merge. .Selection.Merge True ' Put borders around the merged section. With .Selection.Borders(xlEdgeLeft) .LineStyle = xlContinuous .ColorIndex = 0 .Weight = xlThin End With With .Selection.Borders(xlEdgeTop) .LineStyle = xlContinuous .ColorIndex = 0 .Weight = xlThin End With With .Selection.Borders(xlEdgeBottom) .LineStyle = xlContinuous .ColorIndex = 0 .Weight = xlThin End With With .Selection.Borders(xlEdgeRight) .LineStyle = xlContinuous .ColorIndex = 0 .Weight = xlThin End With ' Replace the "Grand Total" caption with "Overall". .Cells.Replace _ What:="Grand Total", Replacement:="Overall", LookAt:=xlPart, _ SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _ ReplaceFormat:=False ' Give specific column widths. .Columns("A:" & strLC).ColumnWidth = 6 ' AutoFit the first column because of the "Overall" caption. .Columns("A:A").EntireColumn.AutoFit ' Turn off user messages. .DisplayAlerts = False objWB.Sheets("Sheet1").Delete ' Delete the first two worksheets that have the original pivottable ' and the pivottable data. objWB.Sheets("Sheet2").Delete ' Select the data and copy it to that it is ready to paste elsewhere. .Range(objExcelApp.Selection, _ objExcelApp.ActiveCell.SpecialCells(xlLastCell)).Select .Selection.Copy ' Get a file name from the user; provide a default. If the user ' clicks Save, then save the workbook. varFileName = .GetSaveAsFilename("Pivot Results.xls", _ "Excel Files (*.xls),*.xls") If varFileName = False Then ' User canceled save. Do nothing. Else ' Save the file with the name selected by the user. objWB.SaveAs varFileName, FileFormat:=xlNormal End If ExportCopyAccessPTValues = True End With 'objExcelApp Exit_ExportCopyAccessPTValues: On Error Resume Next objExcelApp.DisplayAlerts = True ' We do not actually close the Excel application because ' if we do, the clipboard appears to get cleared out. Set objPT = Nothing Set objWS = Nothing Set objWB = Nothing Set objExcelApp = Nothing Exit Function Err_ExportCopyAccessPTValues: MsgBox Err.Number & " " & Err.Description, vbCritical, "ExportCopyAccessPTValues()" ExportCopyAccessPTValues = False Resume Exit_ExportCopyAccessPTValues End Function
Hello, this code seems very useful, but I keep pulling an error when I try to use it:
424 Object required
Thanks for your help
You must pass a form object to the function, like ExportCopyAccessPTValues (Forms!YourPivotTableFormName). Are you doing that?
I am getting the same error – and I used the Forms! format for passing the form into the function.
I just tried it and got the same error. In my case, the pivot was not loading fast enough in Excel. I increased the time delay from 3 seconds to 5 seconds and that solved the problem. Here is where I changed the code:
Do While Timer < lngStart + 5