Currently I have code which combines pdfs together.
It takes all pages from each file I specify in Column A3:A5 and appends to A2.
Lets say all my pdfs have 5 pages each. However what If I want to only take the first 3 A3, and full 5 pages of A4, and 1 page A5?
Also I don't need to specify in between pages, ie 2 , 4 and 5 of A3.
It will always be in order, ie 1-3 or 1-5 or 1-2.
I have a counter that gets the number of pages already
Dim i As Long, pgnumber As Range
For Each pgnumber In Range("A2:A100")
If Not IsEmpty(pgnumber) Then
i = i + 1
AcroDoc.Open pgnumber
PageNum = AcroDoc.GetNumPages
Cells(pgnumber.Row, 4) = PageNum
End If
AcroDoc.Close
Next pgnumber
full code:
Sub main3()
Set app = CreateObject("Acroexch.app")
Dim FilePaths As Collection
Set FilePaths = New Collection
Dim AcroDoc As Object
Set AcroDoc = New AcroPDDoc
'Counts # of pages in each pdf, loads to column D.
Dim i As Long, pgnumber As Range
For Each pgnumber In Range("A2:A100")
If Not IsEmpty(pgnumber) Then
i = i + 1
AcroDoc.Open pgnumber
PageNum = AcroDoc.GetNumPages
Cells(pgnumber.Row, 4) = PageNum
End If
AcroDoc.Close
Next pgnumber
'Append to this file, ideally will be a front page to append to, commented out for now.
'FilePaths.Add "\path\name\here"
'Active or not feature in Column B, Specify Yes to include in combination, no to exclude
Dim cell As Range
For Each cell In Range("A2:A100")
If cell.Offset(0, 1).Value2 <> "No" Then FilePaths.Add cell.Value2
Next cell
'Combine files which are listed in Column A.
Set primaryDoc = CreateObject("AcroExch.PDDoc")
OK = primaryDoc.Open(FilePaths(1))
Debug.Print "PRIMARY DOC OPENED & PDDOC SET: " & OK
For colIndex = 2 To FilePaths.Count
numPages = primaryDoc.GetNumPages() - 1
Set sourceDoc = CreateObject("AcroExch.PDDoc")
OK = sourceDoc.Open(FilePaths(colIndex))
Debug.Print "(" & colIndex & ") SOURCE DOC OPENED & PDDOC SET: " & OK
numberOfPagesToInsert = sourceDoc.GetNumPages
OK = primaryDoc.InsertPages(numPages, sourceDoc, 0, numberOfPagesToInsert, False)
Debug.Print "(" & colIndex & ") PAGES INSERTED SUCCESSFULLY: " & OK
Set sourceDoc = Nothing
Next colIndex
OK = primaryDoc.Save(PDSaveFull, FilePaths(1))
Debug.Print "PRIMARYDOC SAVED PROPERLY: " & OK
Set primaryDoc = Nothing
app.Exit
Set app = Nothing
MsgBox "DONE"
End Sub
Any help on how to achieve this would be appreciated.
Tried the below code, but it doesn't have any effect:
'attempt to do start and end page in col E and F.
startPage = Range("E" & colIndex)
endPage = Range("F" & colIndex)
OK = sourceDoc.DeletePages(1, startPage - 1)
OK = sourceDoc.DeletePages(endPage - startPage + 2, sourceDoc.GetNumPages)
There is a More Nearly Complete Answer Below
See my comment on your question. If that is accurate, this may fix the problem:
Add:
Dim FileRows As Collection
Set FileRows = New Collection
Change
If cell.Offset(0, 1).Value2 <> "No" Then FilePaths.Add cell.Value2
To:
If cell.Offset(0, 1).Value2 <> "No" Then
FilePaths.Add cell.Value2
FileRows.Add cell.Row
Endif
Change:
startPage = Range("E" & colIndex)
endPage = Range("F" & colIndex)
To:
startPage = Range("E" & FileRows(colIndex))
endPage = Range("F" & FileRows(colIndex))
More Nearly Complete Answer
Okay, I know I shouldn't do this, but here we go. I have revised your code to work the way I think it should work. It is not a complete revision, because the whole thing could be doing in one pass and the Collection objects could be eliminated. There may be bugs in the following code, because I don't have the Adobe Acrobat SDK. But, I think it gets you closer than you were and it puts everything in place. You should be able to do any debugging from here:
Sub CompileDocuments()
Dim acroExchangeApp as Object ' Needed because?
Dim filePaths As Collection ' Paths for PDFs to append
Dim fileRows As Collection ' Row numbers PDFs to append
Dim fileIndex as Long ' For walking through the collections
Dim acroDoc As AcroPDDoc ' Manages imported PDFs
Dim sourceDoc as Object ' Manages imported PDFs (Same as above?)
Dim primaryDoc As Object ' Everything gets appended to this
Dim importPath As Range ' Cell containing a PDF to append
Dim pageCount As Long ' Total pages in an appendable PDF
Dim insertPoint as Long ' PDFs will be appended after this page in the primary Doc
Dim startPage as Long ' First desired page of appended PDF
Dim endPage as Long ' Last desired page of appended PDF
' Initialize
Set filePaths = New Collection
Set fileRows = New Collection
Set acroDoc = New AcroPDDoc
Set acroExchangeApp = CreateObject("Acroexch.app")
Set primaryDoc = CreateObject("AcroExch.PDDoc")
' Pass through rows setting page numbers and capturing paths
For Each importPath In Range("A2:A100")
' Put the page count of each PDF document in column D
If Not IsEmpty(importPath) Then
acroDoc.Open importPath
pageCount = acroDoc.GetNumPages
importPath.OffSet(0,3) = pageCount
acroDoc.Close
End If
Set acroDoc = Nothing
' Remember which documents to append and the row on which they appear
' Skipping any rows with "No" in column B
If importPath.Offset(0, 1).Value2 <> "No" Then
filePaths.Add importPath.Value2
fileRows.Add importPath.Row
End If
Next importPath
' Combine all file listed in Column A.
' Start by opening the file in A2.
OK = primaryDoc.Open(filePaths(1))
Debug.Print "PRIMARY DOC OPENED & PDDOC SET: " & OK
' Loop through the remaining files, appending pages to A2
' Note that columns E and F define the desired pages to extract from
' the appended document.
For fileIndex = 2 To filePaths.Count
' Pages will be added after this insert point
insertPoint = primaryDoc.GetNumPages() - 1
' Open the source document
Set sourceDoc = CreateObject("AcroExch.PDDoc")
OK = sourceDoc.Open(filePaths(fileIndex))
Debug.Print "(" & fileIndex & ") SOURCE DOC OPENED & PDDOC SET: " & OK
' Get start and end pages
startPage = Range("E" & CStr(fileRows(fileIndex))).Value
endPage = Range("F" & CStr(fileRows(fileIndex))).Value
OK = primaryDoc.InsertPages(insertPoint, sourceDoc, startPage, endPage-startPage+1, False)
Debug.Print "(" & fileIndex & ") " & endPage-startPage+1 & " PAGES INSERTED SUCCESSFULLY: " & OK
Set sourceDoc = Nothing
Next fileIndex
OK = primaryDoc.Save(PDSaveFull, filePaths(1))
Debug.Print "primaryDoc SAVED PROPERLY: " & OK
Set primaryDoc = Nothing
acroExchangeApp.Exit
Set acroExchangeApp = Nothing
MsgBox "DONE"
End Sub
You can try deleting the unwanted parts of each pdf prior to appending them all together with sourceDoc.DeletePages(startPage, endPage) for example:
OK = sourceDoc.Open(FilePaths(colIndex))
startPage = Range("C" & colIndex)
endPage = Range("D" & colIndex)
OK = sourceDoc.DeletePages(1, startPage - 1)
OK = sourceDoc.DeletePages(endPage - startPage + 2, sourceDoc.GetNumPages) ' just some arithmetic
Debug.Print "(" & colIndex & ") SOURCE DOC OPENED & PDDOC SET: " & OK
You would just need to specify startPage and endPage for each in columns C & D... or you can change this snippet and specificy them however you prefer
EXPLANATION:
For First Code I removed everything but the barebones: filepath to the doc being appended to and filepaths to the file that we are getting the pages that are to be appended into primary doc.
I set up a constant for us and set it to 2. We can set it to 3 or 5 etc. This constant will be passed in the PAGE TO END part of the insertpage function. I have a feeling that you are going to say that there is some relationship between total num of pages in a pdf and the num to append, but this is not clear from OP
BREAKING DOWN INSERTPAGES():
INSERTPAGES(the page number where insertion starts (inside primaryDoc), a path to the PDF that is the source of the insertion pages (sourcedoc pathway), page to start from (sourceDoc), page to end (sourceDoc), true or false whether books are inserted too
CODE BAREBONES:
Option Explicit
Sub AppendPDF()
Dim app As Object
Dim acroDoc As Object
Dim filePaths As Collection
Dim pathwayIterator As Range
Dim primaryDoc As Object
Dim OK As String
Dim numPages As Long
Dim colIndex As Long
Dim sourceDoc As Object
Const finalPage = 2
Set app = CreateObject("Acroexch.app")
Set acroDoc = New AcroPDDoc
Set filePaths = New Collection
For Each pathwayIterator In Range("A2:A100")
If pathwayIterator.Value <> "" Then
filePaths.Add pathwayIterator.Value2
End If
Next pathwayIterator
Set primaryDoc = CreateObject("AcroExch.PDDoc")
OK = primaryDoc.Open(filePaths(1))
Debug.Print "PRIMARY DOC OPENED & PDDOC SET: " & OK
For colIndex = 2 To filePaths.Count
numPages = primaryDoc.GetNumPages() - 1
Set sourceDoc = CreateObject("AcroExch.PDDoc")
OK = sourceDoc.Open(filePaths(colIndex))
Debug.Print "(" & colIndex & ") SOURCE DOC OPENED & PDDOC SET: " & OK
OK = primaryDoc.InsertPages(numPages, sourceDoc, 0, finalPage, False)
Debug.Print "(" & colIndex & ") PAGES INSERTED SUCCESSFULLY: " & OK
sourceDoc.Close
Set sourceDoc = Nothing
Next colIndex
OK = primaryDoc.Save(PDSaveFull, filePaths(1))
Debug.Print "PRIMARYDOC SAVED PROPERLY: " & OK
Set primaryDoc = Nothing
app.Exit
Set app = Nothing
MsgBox "DONE"
End Sub
CODE EXTRA:
Here we added a bit more. I am not sure what you are doing with the file lengths, I have a feeling that you are going to link them with the number of pages to append. Here we make two collections, one with pathways to the files we are working with a second holds the number of pages of each of these files
Option Explicit
Sub AppendPDF()
Dim app As Object
Dim acroDoc As Object
Dim filePaths As Collection
Dim pgnumber As Range
Dim pageNum As Long
Dim FileNumPages As Collection
Dim pathwayIterator As Range
Dim primaryDoc As Object
Dim OK As String
Dim numPages As Long
Dim colIndex As Long
Dim sourceDoc As Object
Const finalPage = 2
Set app = CreateObject("Acroexch.app")
Set acroDoc = New AcroPDDoc
Set filePaths = New Collection
'Counts # of pages in each pdf, loads to column D.
For Each pgnumber In Range("A2:A100")
If Not IsEmpty(pgnumber) Then
acroDoc.Open pgnumber
pageNum = acroDoc.GetNumPages
Cells(pgnumber.Row, 4) = pageNum
End If
acroDoc.Close
Next pgnumber
'Append to this file, ideally will be a front page to append to, commented out for now.
'FilePaths.Add "\path\name\here"
'Active or not feature in Column B, Specify Yes to include in combination, no to exclude
Set filePaths = New Collection
Set FileNumPages = New Collection
For Each pathwayIterator In Range("A2:A100")
If pathwayIterator.Value <> "" Then
filePaths.Add pathwayIterator.Value2
FileNumPages.Add Cells(pathwayIterator.Row, 4)
End If
Next pathwayIterator
'Combine files which are listed in Column A.
Set primaryDoc = CreateObject("AcroExch.PDDoc")
OK = primaryDoc.Open(filePaths(1))
Debug.Print "PRIMARY DOC OPENED & PDDOC SET: " & OK
For colIndex = 2 To filePaths.Count
numPages = primaryDoc.GetNumPages() - 1
Set sourceDoc = CreateObject("AcroExch.PDDoc")
OK = sourceDoc.Open(filePaths(colIndex))
Debug.Print "(" & colIndex & ") SOURCE DOC OPENED & PDDOC SET: " & OK
OK = primaryDoc.InsertPages(numPages, sourceDoc, 0, finalPage, False)
Debug.Print "(" & colIndex & ") PAGES INSERTED SUCCESSFULLY: " & OK
sourceDoc.Close
Set sourceDoc = Nothing
Next colIndex
OK = primaryDoc.Save(PDSaveFull, filePaths(1))
Debug.Print "PRIMARYDOC SAVED PROPERLY: " & OK
Set primaryDoc = Nothing
app.Exit
Set app = Nothing
MsgBox "DONE"
End Sub
Related
I've managed to piece together this VBA which takes data from excel and turns it into .txt flat file. It works exactly as I need, but I would like to alter it so that the end result is saved as Unicode as opposed to ANSI.
I've done some reading and the answer I keep coming back to is to use FileSystemObject. I found a VBA on here that does the job perfectly, but I can't for the life of me work out how to incorporate it into my existing code. Any chance someone could throw me some pointers?
This is my current code:
' Defines everything first. So, from B2, across and down.
LastRow = Sheets("Pricing").Range("B" & Rows.Count).End(xlUp).Row
LastColumn = Sheets("Pricing").Cells(2, Columns.Count).End(xlToLeft).Column
' File name, path to save to and delimiter.
file = Sheets("Pricing").TextBox1 & ".txt"
If TextBox1.Value = "" Then MsgBox "What we calling it genius?", vbQuestion
If TextBox1.Value = "" Then Exit Sub
Path = "C:\Users\me.me\Desktop\Files\"
Delimeter = "|"
' The magic bit.
myFileName = Path & file
FN = FreeFile
Open myFileName For Output As #FN
For Row = 2 To LastRow
For Column = 2 To LastColumn
If Column = 2 Then Record = Trim(Cells(Row, Column)) Else Record = Record & Delimeter & Trim(Cells(Row, Column))
Next Column
Print #FN, Record
Next Row
Close #FN
MsgBox "BOOM! LOOKIT ---> " & myFileName
' Opens the finished file.
Dim fso As Object
Dim sfile As String
Set fso = CreateObject("shell.application")
sfile = "C:\Users\me.me\Desktop\Files\" & Sheets("Pricing").TextBox1 & ".txt"
fso.Open (sfile)
And this is what I've been trying to incorporate (HUGE thanks to MarkJ for posting this on another question):
Dim fso As Object, MyFile As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.CreateTextFile("c:\testfile.txt", False,True) 'Unicode=True'
MyFile.WriteLine("This is a test.")
MyFile.Close
I just can't get it to work.
Please, test the next code. You did not answer my clarification question, but it works using the above comment assumptions. It take the file name, from an activeX text box situated on the sheet to be processed. The code should be faster than yours for big ranges, avoiding to iterate between all cells:
Sub SaveAsUnicode()
Dim shP As Worksheet, iRow As Long, Record As String, Delimeter As String
Dim file As String, myFileName As String, path As String, txtB As MSForms.TextBox
Dim rng As Range, lastCell As Range, arr, arrRow
Dim fso As Object, MyFile As Object, shApp As Object
Set shP = Worksheets("Pricinig")
Set txtB = shP.OLEObjects("TextBox1").Object 'it sets an activeX sheet text box
file = txtB.Text & ".txt"
If txtB.value = "" Then MsgBox "What we calling it genius?", vbQuestion: Exit Sub
Set lastCell = shP.cells.SpecialCells(xlCellTypeLastCell) 'last cell of the sheet
Set rng = shP.Range("A2", lastCell) 'create the range to be processed
arr = rng.value 'put the range in an array
path = "C:\Users\me.me\Desktop\Files\" 'take care to adjust the path!
myFileName = path & file
Delimeter = "|"
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.CreateTextFile(myFileName, False, True) 'open the file to write Unicode:
For iRow = 1 To UBound(arr) 'itereate between the array rows
arrRow = Application.Index(arr, iRow, 0) 'make a slice of the currrent arrray row
Record = Join(arrRow, Delimeter) 'join the iD obtained array, using the set Delimiter
MyFile.WriteLine (Record) 'write the row in the Unicode file
Next iRow
MyFile.Close 'close the file
'open the obtained Unicode file:
Set shApp = CreateObject("shell.application")
shApp.Open (myFileName)
End Sub
I tested the above code on a sheet using characters not supported in ANSI and it works as expected.
Please, send some feedback after testing it, or if my assumptions after reading your question are not correct...
#FaneDuru, this is what I ended up putting together, it's working great for me. Thanks again for all of your help.
Private Sub FlatButton_Click()
'Does all the setup stuff.
Dim fso As Object, MyFile As Object
Dim MyFileName As String
Dim txtB As MSForms.TextBox
Set shP = Worksheets("Pricing")
Set txtB = shP.OLEObjects("TextBox1").Object
file = txtB.Text & ".txt"
If txtB.Value = "" Then MsgBox "What we calling it?", vbQuestion: Exit Sub
' Defines the range. So, from B2, across and down.
LastRow = Sheets("Pricing").Range("B" & Rows.Count).End(xlUp).Row
LastColumn = Sheets("Pricing").Cells(2, Columns.Count).End(xlToLeft).Column
'File details.
path = "C:\Users\me.me\Blah\Blah\"
MyFileName = path & file
Delimeter = "|"
' The magic bit.
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.CreateTextFile(MyFileName, False, True) '<==== This defines the Unicode bit.
For Row = 2 To LastRow
For Column = 2 To LastColumn
If Column = 2 Then Record = Trim(Cells(Row, Column)) Else Record = Record & Delimeter & Trim(Cells(Row, Column))
Next Column
MyFile.WriteLine (Record)
Next Row
MyFile.Close
MsgBox "BOOM! ---> " & MyFileName
'Option to open the finished product.
If ActiveSheet.CheckBox2.Value = True Then
Set shApp = CreateObject("shell.application")
shApp.Open (MyFileName)
End If
End Sub
I have some outlook VBA code which works fine to save attachments, however every time I get an email or a meeting notification in Outlook it causes an instant Out of Bounds error If I don't get any emails or notifications the code will run fine through to completion.
Is there a way to ensure that these notifications will not stop the code from running?
Option Explicit
Sub SaveAttachmentsFromSelectedItemsPDF2_ForNext()
Dim currentItem As Object
Dim currentAttachment As Attachment
Dim saveToFolder As String
Dim savedFileCountPDF As Long
Dim i As Long
Dim j As Long
saveToFolder = "c:\dev\outlookexport" 'change the path accordingly
savedFileCountPDF = 0
For i = 1 To ActiveExplorer.Selection.Count
Set currentItem = ActiveExplorer.Selection(i)
For j = 1 To currentItem.Attachments.Count
Set currentAttachment = currentItem.Attachments(j)
If UCase(Right(currentAttachment.DisplayName, 5)) = UCase(".xlsx") Then
currentAttachment.SaveAsFile saveToFolder & "\" & _
Left(currentAttachment.DisplayName, Len(currentAttachment.DisplayName) - 5) & ".xlsx"
savedFileCountPDF = savedFileCountPDF + 1
End If
' If For Next does not release memory automatically then
' uncomment to see if this has an impact
'Set currentAttachment = Nothing
Next
' If For Next does not release memory automatically then
' uncomment to see if this has an impact
'Set currentItem = Nothing
Next
MsgBox "Number of PDF files saved: " & savedFileCountPDF, vbInformation
End Sub
This is what I tried to create from the answer below:
Option Explicit
Sub SaveAttachmentsFromSelectedItemsPDF2_ForNext()
Dim currentItem As Object
Dim currentAttachment As Attachment
Dim saveToFolder As String
Dim savedFileCountPDF As Long
Dim i As Long
Dim j As Long
Dim x As Long
Dim myOlExp As Object
Dim myOlSel As Object
' New
Set myOlExp = Application.ActiveExplorer
Set myOlSel = myOlExp.Selection
saveToFolder = "c:\dev\outlookexport" 'change the path accordingly
savedFileCountPDF = 0
For x = 1 To myOlSel.Count
If myOlSel.Item(x).Class = OlObjectClass.olMail Then
Set currentItem = ActiveExplorer.Selection(i)
For j = 1 To currentItem.Attachments.Count
Set currentAttachment = currentItem.Attachments(j)
If UCase(Right(currentAttachment.DisplayName, 5)) = UCase(".xlsx") Then
currentAttachment.SaveAsFile saveToFolder & "\" & _
Left(currentAttachment.DisplayName, Len(currentAttachment.DisplayName) - 5) & ".xlsx"
savedFileCountPDF = savedFileCountPDF + 1
End If
Next
End If
Next
MsgBox "Number of PDF files saved: " & savedFileCountPDF, vbInformation
End Sub
The Selection property of the Explorer class returns a Selection object that contains the item or items that are selected in the explorer window. In your code I've noticed the following lines of code:
For i = 1 To ActiveExplorer.Selection.Count
Set currentItem = ActiveExplorer.Selection(i)
So, if the selection is changed in Outlook between these two lines of code you may get out of range exception at runtime. Instead, I'd recommend caching the selection object and use it through the code to make sure it remains the same:
Set myOlExp = Application.ActiveExplorer
Set myOlSel = myOlExp.Selection
For x = 1 To myOlSel.Count
If myOlSel.Item(x).Class = OlObjectClass.olMail Then
' do something here
End If
Next
Another important thing is that a folder may contain different types of items. You'd need to check their message class to distinguish different kind of Outlook items.
I have a word file and I want to delete some pages in it. I use this Kutools codes for deleting
Sub DeletePagesInDoc()
Dim xRange As Range
Dim xPage As String
Dim xDoc As Document
Dim xArr
Dim I, xSplitCount As Long
Application.ScreenUpdating = False
Set xDoc = ActiveDocument
xPage = InputBox("Enter the page numbers of pages to be deleted: " & vbNewLine & _
"use comma to separate numbers", "KuTools for Word", "")
xArr = Split(xPage, ",")
xPageCount = UBound(xArr)
For I = xPageCount To 0 Step -1
Selection.GoTo wdGoToPage, wdGoToAbsolute, xArr(I)
xDoc.Bookmarks("\Page").Range.Delete
Next
Application.ScreenUpdating = True
End Sub
Some pages are deleted but some pages aren't. The word gives me this error The range cannot be deleted. Why I get this error?
Need help to modify this VBA code to read multiple tables from a Word document. It only reads one table, but I would like to import more than one into the same Excel sheet.
Sub ImportWordTables()
'Imports a table from Word document
Dim wdDoc As Object
Dim wdFileName As Variant
Dim TableNo As Integer 'number of tables in Word doc
Dim iTable As Integer 'table number index
Dim iRow As Long 'row index in Excel
Dim iCol As Integer 'column index in Excel
wdFileName = Application.GetOpenFilename("Word files (*.doc*),*.doc*", , _
"Browse for file containing table to be imported")
If wdFileName = False Then Exit Sub '(user cancelled import file browser)
Set wdDoc = GetObject(wdFileName) 'open Word file
With wdDoc
TableNo = wdDoc.tables.Count
If TableNo = 0 Then
MsgBox "This document contains no tables", _
vbExclamation, "Import Word Table"
ElseIf TableNo > 1 Then
TableNo = InputBox("This Word document contains " & TableNo & " tables." & vbCrLf & _
"Enter table number of table to import", "Import Word Table", "1")
End If
With .tables(TableNo)
'copy cell contents from Word table cells to Excel cells
For iRow = 1 To .Rows.Count
For iCol = 1 To .Columns.Count
Cells(iRow, iCol) = WorksheetFunction.Clean(.cell(iRow, iCol).Range.Text)
Next iCol
Next iRow
End With
End With
Set wdDoc = Nothing
End Sub
So this is the code, but it doesn't entirely answer my questions.
I just need the tables from the pdf.
Sub Imp_Into_XL(PDF_File As String, Each_Sheet As Boolean)
'This procedure get the PDF data into excel by following way
'1.Open PDF file
'2.Looping through pages
'3.get the each PDF page data into individual _
sheets or single sheet as defined in Each_Sheet Parameter
Dim AC_PD As Acrobat.AcroPDDoc 'access pdf file
Dim AC_Hi As Acrobat.AcroHiliteList 'set selection word count
Dim AC_PG As Acrobat.AcroPDPage 'get the particular page
Dim AC_PGTxt As Acrobat.AcroPDTextSelect 'get the text of selection area
Dim WS_PDF As Worksheet
Dim RW_Ct As Long 'row count
Dim Col_Num As Integer 'column count
Dim Li_Row As Long 'Maximum rows limit for one column
Dim Yes_Fir As Boolean 'to identify beginning of page
Li_Row = Rows.Count
Dim Ct_Page As Long 'count pages in pdf file
Dim i As Long, j As Long, k As Long 'looping variables
Dim T_Str As String
Dim Hld_Txt As Variant 'get PDF total text into array
RW_Ct = 0 'set the intial value
Col_Num = 1 'set the intial value
Application.ScreenUpdating = False
Set AC_PD = New Acrobat.AcroPDDoc
Set AC_Hi = New Acrobat.AcroHiliteList
'set maximum selection area of PDF page
AC_Hi.Add 0, 32767
With AC_PD
'open PDF file
.Open PDF_File
'get the number of pages of PDF file
Ct_Page = .GetNumPages
'if get pages is failed exit sub
If Ct_Page = -1 Then
MsgBox "Pages Cannot determine in PDF file '" & PDF_File & "'"
.Close
GoTo h_end
End If
'add sheet only one time if Data retrive in one sheet
If Each_Sheet = False Then
Set WS_PDF = Worksheets.Add(, Worksheets(Sheets.Count))
WS_PDF.Name = "PDF3Text"
End If
'looping through sheets
For i = 1 To Ct_Page
T_Str = ""
'get the page
Set AC_PG = .AcquirePage(i - 1)
'get the full page selection
Set AC_PGTxt = AC_PG.CreateWordHilite(AC_Hi)
'if text selected successfully get the all the text into T_Str string
If Not AC_PGTxt Is Nothing Then
With AC_PGTxt
For j = 0 To .GetNumText - 1
T_Str = T_Str & .GetText(j)
Next j
End With
End If
If Each_Sheet = True Then
'add each sheet for each page
Set WS_PDF = Worksheets.Add(, Worksheets(Sheets.Count))
End If
'transfer PDF data into sheet
With WS_PDF
If Each_Sheet = True Then
.Name = "Page-" & i
'get the PDF data into each sheet for each PDF page
'if text accessed successfully then split T_Str by VbCrLf
'and get into array Hld_Txt and looping through array and fill sheet with PDF data
If T_Str <> "" Then
Hld_Txt = Split(T_Str, vbCrLf)
For k = 0 To UBound(Hld_Txt)
T_Str = CStr(Hld_Txt(k))
If Left(T_Str, 1) = "=" Then T_Str = "'" & T_Str
.Cells(k + 1, 1).Value = T_Str
Next k
Else
'information if text not retrive from PDF page
.Cells(1, 1).Value = "No text found in page " & i
End If
Else
'get the pdf data into single sheet
If T_Str <> "" Then
Hld_Txt = Split(T_Str, vbCrLf)
Yes_Fir = True
For k = 0 To UBound(Hld_Txt)
RW_Ct = RW_Ct + 1
'check begining of page if yes enter PDF page number for any idenfication
If Yes_Fir Then
RW_Ct = RW_Ct + 1
.Cells(RW_Ct, Col_Num).Value = "Text In Page - " & i
RW_Ct = RW_Ct + 2
Yes_Fir = False
End If
'check for maximum rows if exceeds start from next column
If RW_Ct > Li_Row Then
RW_Ct = 1
Col_Num = Col_Num + 1
End If
T_Str = CStr(Hld_Txt(k))
If Left(T_Str, 1) = "=" Then T_Str = "'" & T_Str
.Cells(RW_Ct, Col_Num).Value = T_Str
Next k
Else
RW_Ct = RW_Ct + 1
.Cells(RW_Ct, Col_Num).Value = "No text found in page " & i
RW_Ct = RW_Ct + 1
End If
End If
End With
Next i
.Close
End With
Application.ScreenUpdating = True
MsgBox "Imported"
h_end:
Set WS_PDF = Nothing
Set AC_PGTxt = Nothing
Set AC_PG = Nothing
Set AC_Hi = Nothing
Set AC_PD = Nothing
End Sub
You can use this to do something with each table in the document:
Dim oTbl As Table
For Each oTbl In ActiveDocument.Tables
' Do something
Debug.Print oTbl.Columns.Count & " " & oTbl.Rows.Count
Next
You'll need to figure out how you want the user to specify which table/tables to work with.
Something like this, perhaps:
Sub UserChosenTables()
Dim oTbl As Table
Dim sTemp As String
Dim aTables() As String
Dim x As Long
sTemp = InputBox("Which tables", "Select tables")
If Len(sTemp) = 0 Then ' user entered nothing
Exit Sub
End If
aTables = Split(sTemp, ",")
' of course you'll want to add more code to CYA in case the user
' asks for a table that's not there or otherwise enters something silly.
' You might also want to let them enter e.g. ALL if they want you to do all of them
' (but don't know how many there are)
For x = LBound(aTables) To UBound(aTables)
Set oTbl = ActiveDocument.Tables(CLng(aTables(x)))
' do [whatever] with table here
Debug.Print oTbl.Columns.Count & " " & oTbl.Rows.Count
Next
End Sub
I want to update Powerpoint Graph 2010 from Excel 2010.
Code looks for the Objects and finds the range with name similar in powerpoint, it applies changes to the graph. Graph format should be same only data must be updated.
Code is as follow, it is not able to find charts, either able to update it.
Option Explicit
Private Const NAMED_RANGE_PREFIX = "Export_"
Private Const NAMED_RANGE_PREFIX_TEXT = "ExportText"
Private m_sLog As String
Private Sub CommandButton1_Click()
On Error GoTo Catch
Dim pptApp As PowerPoint.Application
Dim pptPresentation As PowerPoint.Presentation
Dim pptSlide As PowerPoint.Slide
Dim pptShape As PowerPoint.Shape
Dim mgrChart As Chart
Dim mgrDatasheet As Graph.DataSheet
Dim rngData As Excel.Range
Dim iRow As Long, iCol As Long
Dim sTag As String
Dim nFound As Long, nUpdated As Long
Dim nFoundText As Long, nUpdatedText As Long
Dim i As Integer
Dim fLog As frmLog
Dim Box1Status As VbMsgBoxResult
m_sLog = ""
'Prompt to Export
Box1Status = MsgBox("Export and Save to Powerpoint Template?" & Chr(13) & "Reminder: Please use a clean template for export and be sure to back up the template beforehand. " & Chr(13) & Chr(13) & "PLEASE SAVE ANY OTHER OPEN POWERPOINT DOCUMENTS AS ALL UNSAVED WORK WILL BE LOST!", vbQuestion + vbYesNo, "Confirm Export")
If Box1Status = vbNo Then Exit Sub
i = 1
UpdateStatus "Opening Powerpoint presentation '" & Range("fileloc")
Set pptApp = New PowerPoint.Application
pptApp.Activate
Set pptPresentation = pptApp.Presentations.Open(Range("fileloc"))
pptApp.WindowState = ppWindowMinimized
'Looks for (tagged) charts to update
UpdateStatus "Searching presentation for charts..."
For Each pptSlide In pptPresentation.Slides
For Each pptShape In pptSlide.Shapes
If pptShape.Type = msoEmbeddedOLEObject Then
If TypeOf pptShape.OLEFormat.Object Is Graph.Chart Then
nFound = nFound + 1
Set mgrChart = pptShape.OLEFormat.Object
Set mgrChart = pptShape.Chart
Set mgrDatasheet = mgrChart.Application.DataSheet
With mgrDatasheet
sTag = .Cells(1, 1)
If Left(sTag, 6) = "Export" Then UpdateStatus "Found chart on slide '" & pptSlide.SlideNumber & "' with tag '" & sTag & "'. Searching Excel workbook for same tag..."
Set rngData = RangeForChart(sTag)
If rngData Is Nothing Then
' This chart has no data in this Excel workbook
If Left(sTag, 6) <> "Export" Then
UpdateStatus "Found chart on slide '" & pptSlide.SlideNumber & "' with no tag, skipping"
Else
UpdateStatus "'" & sTag & "' does not exist in workbook, skipping."
End If
Else
' Update the PowerPoint chart with the Excel data
UpdateStatus "Found '" & sTag & "' at named range '" & rngData.Name & "'. Updating presentation..."
.Cells.ClearContents
For iRow = 0 To rngData.Rows.Count - 1
For iCol = 0 To rngData.Columns.Count - 1
.Cells(iRow + 1, iCol + 1) = rngData.Cells(iRow + 1, iCol + 1)
Next iCol
Next iRow
.Application.Update
UpdateStatus "Chart with tag '" & sTag & "' updated."
nUpdated = nUpdated + 1
End If
End With
Set mgrDatasheet = Nothing
mgrChart.Application.Quit
Set mgrChart = Nothing
End If
'End If
Next pptShape
i = i + 1
Next pptSlide
UpdateStatus "Finished searching presentation. Closing PowerPoint."
pptPresentation.Save
pptPresentation.Close
Set pptPresentation = Nothing
pptApp.Quit
Set pptApp = Nothing
UpdateStatus "Done. " & nFound & " charts found and " & nUpdated & " charts updated. " & nFoundText & " text boxes found and " & nUpdatedText & " text boxes updated."
Set fLog = New frmLog
fLog.Caption = "Update of Powerpoint Template Complete"
fLog.txtLog.Text = m_sLog
fLog.Show
Unload fLog
Set fLog = Nothing
Exit Sub
Catch:
MsgBox "An unexpected error occurred while updating: " & Err.Number & " " & Err.Description, vbCritical
ForceCleanup mgrChart, mgrDatasheet, pptPresentation, pptApp
End Sub
Private Property Get RangeForChart(sTag As String) As Range
Dim sChartTag As String
Dim iUpdate As Long
Dim NameList As Range
'Dim nRow As Range
Set NameList = Range("Name_List")
If Left(sTag, 6) <> "Export" Then Exit Property
'For Each nRow In NameList.Rows
Do While sChartTag <> sTag
iUpdate = iUpdate + 1
' This will error if there is no named range for "Export_", which means that sTag does not
' exist in the workbook so return nothing
On Error Resume Next
sChartTag = ActiveWorkbook.Names(NAMED_RANGE_PREFIX & NameList(iUpdate, 1).Value).RefersToRange.Cells(1, 1)
If Err.Number <> 0 Then
' Return nothing
Exit Property
End If
On Error GoTo 0
Loop
'Next nRow
Set RangeForChart = ActiveWorkbook.Names(NAMED_RANGE_PREFIX & NameList(iUpdate, 1).Value).RefersToRange
End Property
Private Property Get RangeForText(sTag As String) As Range
Dim sTextTag As String
Dim iUpdate As Long
If Left(sTag, 10) <> "ExportText" Then Exit Property
Do While sTextTag <> sTag
iUpdate = iUpdate + 1
' This will error if there is no named range for "ExportText" & iUpdate, which means that sTag does not
' exist in the workbook so return nothing
On Error Resume Next
sTextTag = NAMED_RANGE_PREFIX_TEXT & iUpdate
If Err.Number <> 0 Then
' Return nothing
Exit Property
End If
On Error GoTo 0
Loop
Set RangeForText = ActiveWorkbook.Names(NAMED_RANGE_PREFIX_TEXT & iUpdate).RefersToRange
End Property
Private Sub UpdateStatus(sMessage As String)
m_sLog = m_sLog & Now() & ": " & sMessage & vbNewLine
Application.StatusBar = Now() & ": " & sMessage
DoEvents
End Sub
Private Sub ForceCleanup(mgrChart As Graph.Chart, mgrDatasheet As Graph.DataSheet, pptPresentation As PowerPoint.Presentation, pptApp As PowerPoint.Application)
On Error Resume Next
mgrChart.Application.Quit
Set mgrChart = Nothing
mgrDatasheet.Application.Quit
Set mgrDatasheet = Nothing
pptPresentation.Close
Set pptPresentation = Nothing
pptApp.Quit
Set pptApp = Nothing
End Sub
I don't think you need a bunch of code for this.
Build the charts in Excel, copy them, go to PowerPoint, use Paste Special - Link. Change the data in Excel, and the Excel charts update. Then open the PowerPoint presentation, and if necessary, update links.
In the data sheet for your powerpoint graph, you can "link" the cells to your excel data file by typing in one of the cells (path and file name are made up here)
=c:\PPTXfiles\excelfiles[excelfiles.xlsx]sheetname'!a1
This will create a link that doesn't show up in the links section of powerpoint, but can be updated just by opening both files and double clicking on the chart to activate it.
Sometime the paste by link feature isn't feasible to use since the end user of the file wants to "break it up" and send out parts. That is not possible without the source excel file, since the end users want to be able to edit the chart or the data.
If you can do this and then copy and paste the data sheet by values in VBA, before sending to the enduser that would be fantastic.
Bam!
Sub UpdateLinks()
Dim ExcelFile
Dim exl As Object
Set exl = CreateObject("Excel.Application")
'Open a dialog box to promt for the new source file.
ExcelFile = exl.Application.GetOpenFilename(, , "Select Excel File")
Dim i As Integer
Dim k As Integer
'Go through every slide
For i = 1 To ActivePresentation.Slides.Count
With ActivePresentation.Slides(i)
'Go through every shape on every slide
For k = 1 To .Shapes.Count
'Turn of error checking s that it doesn 't crash if the current shape doesn't already have a link
On Error Resume Next
'Set the source to be the same as teh file chosen in the opening dialog box
.Shapes(k).LinkFormat.SourceFullName = ExcelFile
If .Shapes(k).LinkFormat.SourceFullName = ExcelFile Then
'If the change was successful then also set it to update automatically
.Shapes(k).LinkFormat.Update
End If
On Error GoTo 0
Next k
End With
Next i
End Sub