I'm trying to set AutoFitBehavior of a Word table to fit both content and window - clicking 'AutoFit Contents' button, then 'AutoFit Window' gives the result I want to get. The problem is, when I do this using VBA, the formatting is different. Interestingly enough, when I run the macro Step By Step (F8) it gives expected result (same as UI).
Here's my code:
Documents(1).Activate
With ActiveDocument.Tables(2)
.AllowAutoFit = True
.AutoFitBehavior 1
.AutoFitBehavior 2
End With
As you can see, it's pretty simple - I can't find any reason for it to work incorrectly.
Also I don't think the issue is related to using 'ActiveDocument' property, as in the full macro this code is executed directly on a newly created, named document, so I'm sure it's addressing a correct table in a correct file.
I am aware that I can set column widths with PreferredWidth property, but it would be much simpler to use AutoFit, as I don't always know what length will my data have.
Is there a way to make this method work as when called from UI?
Edit:
As per Cindy Meister's request, I'm adding snippet from actual code I'm using:
Set wordApp = CreateObject("Word.Application")
Set wordDoc = wordApp.Documents.Add(strPath)
With wordDoc
.Tables.Add Range:=wordDoc.Bookmarks("tableBookmark").Range, NumRows:=licenceRows, NumColumns:=3
'[omitted: populating the table]
.Tables(1).Split(splitRow)
With .Tables(2)
.Range.Collapse Direction:=0
.Range.InsertBreak Type:=7
.AllowAutoFit = True
.AutoFitBehavior 1
.AutoFitBehavior 2
End With
End With
It's called from an Excel macro I'm using to create a report file from template. I'm using Office 2013.
Also I've noticed another thing today: when I set wordApp.Visible = True, scroll to the table and literally look at the method working - it formats correctly. It's like Word application won't use this method correctly, until it has to show you every single step (as with step-by-step run).
Thanks to Cindy's answer and following comment I realised my mistake - I thought Auto Fit would make columns fit to any text, including text with line-breaking characters like spaces. Comes out it doesn't work that way.
In the end, to format the table as I wanted (window-wide table, columns fit to content) I used the following code:
'Table should fit the page and fit the contents
Sub TestFormatTableStructure()
Dim wordApp As Word.Application
Dim wordDoc As Word.Document
Dim tbl1 As Word.Table, tbl2 As Word.Table
On Error GoTo ErrHandler
Set wordApp = New Word.Application
Set wordDoc = wordApp.Documents.Add
wordApp.ScreenUpdating = False
With wordDoc
Set tbl1 = .Tables.Add(Range:=wordDoc.Paragraphs.Last.Range, _
NumRows:=6, NumColumns:=3, _
DefaultTableBehavior:=wdWord9TableBehavior, _
AutoFitBehavior:=wdAutoFitContent) 'autofit content
With tbl1
'[omitted: populating the table]
.PreferredWidthType = wdPreferredWidthPercent
.PreferredWidth = 100
End With
Set tbl2 = tbl1.Split(4)
'dont have to set formatting again for second table, its inherited
With tbl2
'[do things]
End With
End With
ErrHandler:
wordApp.Visible = True
wordApp.ScreenUpdating = True
Set tbl1 = Nothing
Set tbl2 = Nothing
Set rngtlb = Nothing
Set wordDoc = Nothing
Set wordApp = Nothing
End Sub
Thanks for the additional info. For the future, in such a case it would help if you include the automation code for running from Excel, as well, since the issue could be with that interface...
I ran the following code in Office 2013 (as well as in 2010) and it worked as expected: the table fit the width of the page (margin to margin) and the cells expanded to fit the content.
In contrast to what you have, I've used the optional arguments in Tables.Add to set the default behavior to allow AutoFit when creating the table. Then I didn't need to set all of them after-the-fact.
Notice also my use of object variables for the tables and the Ranges, releasing the objects, and updating the screen.
'Table should fit the page and fit the contents
Sub TestFormatTableStructure()
Dim wordApp As Word.Application
Dim wordDoc As Word.Document
Dim tbl1 As Word.Table, tbl2 As Word.Table
Dim rngTbl As Word.Range
On Error GoTo ErrHandler
Set wordApp = New Word.Application
Set wordDoc = wordApp.Documents.Add
wordApp.ScreenUpdating = False
With wordDoc
Set tbl1 = .Tables.Add(Range:=wordDoc.Paragraphs.Last.Range, _
NumRows:=6, NumColumns:=3, _
DefaultTableBehavior:=wdWord9TableBehavior, _
AutoFitBehavior:=2)
'[omitted: populating the table]
Set tbl2 = tbl1.Split(4)
With tbl2
Set rngTbl = .Range
rngTbl.Collapse Direction:=0
rngTbl.InsertBreak Type:=7
'.AllowAutoFit = True
'.AutoFitBehavior 1
.AutoFitBehavior 2
End With
End With
ErrHandler:
wordApp.Visible = True
wordApp.ScreenUpdating = True
Set tbl1 = Nothing
Set tbl2 = Nothing
Set rngtlb = Nothing
Set wordDoc = Nothing
Set wordApp = Nothing
End Sub
Related
I know, I have seen this link: Word 2016- VBA- How To Insert Row Below Selected Row In A Table?
But, unfortunately, even if it may be trivial, I don't understand how to do it.
Here is what I want to do: 1)to add row(s) (from docSource) at the end of a Table (first part working well) OR 2)to add row(s) (from docSource) above the selected row (row selected on docTarget) (second part struggling to find the right way).
Dim docTarget As Document
Dim docSource As Document
Set docTarget = ActiveDocument
Set docSource = Documents.Open(strFileName)
IF SOMETHING THEN
'1) Working code
Dim myRange As Object
Set myRange = docTarget.Content
myRange.Collapse Direction:=wdCollapseEnd
myRange.FormattedText = docSource.Tables(2).Range.FormattedText
ELSE
'2) Can't figure it out
Dim myRange2 As Object
Set myRange2 = docTarget.Content
myRange2.Select 'What? - the row I already highlighted -
Selection.InsertRowsBelow
myRange2.FormattedText = docSource.Tables(2).Range.FormattedText
ENDIF
docSource.Close (0)
Set docSource = Nothing
Set docTarget = Nothing
For information, my tables from docSource or docTarget got 3 columns and no merge cells.
I welcome any ideas or tips.
Thanks.
I think I found the answer, thanks to the patience of Timothy Rylatt. But if you have any positive critics or improvements (better coding), please do not hesitate to comment.
First, before opening my userform, I got this:
mySelectedRow = Selection.Information(wdEndOfRangeRowNumber)
mySlectedRow declare as Public
Second, in the userform, I got this:
Private Sub btnOK_Click()
Dim strFileName As String
strFileName = ActiveDocument.Path & "\something\" & cboFileOption.Text
' Open selected item as docSource and assign docTarget to this document
Dim docTarget As Document
Dim docSource As Document
Set docTarget = ActiveDocument
Set docSource = Documents.Open(strFileName)
' Fill docTarget with the content of docSource
Dim myRange As Object
Set myRange = docTarget.Content
If Me.optEndTable.Value = True Then
myRange.Collapse Direction:=wdCollapseEnd
myRange.FormattedText = docSource.Tables(2).Range.FormattedText
Else
docSource.Tables(2).Range.FormattedText.Copy
docTarget.Content.Tables(1).Rows(mySelectedRow).Select
Selection.Rows(Selection.Rows.Count).Range.Paste
End If
' Close selected item (docSource) without saving
docSource.Close (0)
Set docSource = Nothing
Set docTarget = Nothing
' End
Me.Hide
End Sub
Hope that make sense.
Thanks
got a problem with the right alignment from columns in a word document.
I'm creating a word document with a table from one of our systems. The first time creating the table and selecting the columns for alignment will work without problems. If the user now creates a new document, overwriting the old one, it will crash. If the new word document is created, without overwriting an old one, no errors occur.
So the combination out of overwriting an existing document, there aren't any word processes running, and selecting columns for right alignment will crash. This is how I try to align the columns.
objTable.Columns(4).Select
Selection.ParagraphFormat.Alignment = wdAlignParagraphRight
objTable.Columns(5).Select
Selection.ParagraphFormat.Alignment = wdAlignParagraphRight
objTable.Columns(6).Select
Selection.ParagraphFormat.Alignment = wdAlignParagraphRight
Does anyone have an idea how to fix this?
Thanks
€dit:
We have software, where a user can create a Word document. The word document loads a Word Template, in which a bookmark marks the location for creating the table. Before the table is created, the new document from the template will be saved on a network path. If there is already a document from that template, it should be overwritten. After saving the document for the first time and giving the right name, my method creates the table and fills it with content. The creating part will crash as soon as my method tries to align the columns(alignment-part in the code above) if there was a document created before. I took a look at the task manager there were no running word processes left after the first run. If a new word document is created, without overwriting an existing one, there are no problems with the alignment. So I guess the combination of overwriting an existing document and the alignment is responsible for the error.
€dit2 - My Code (I removed unneccessary lines of code like variable declaration):
'That is kind of strange, because even though it should be nothing it skipped that part - But if it tries to use the existing word instance - it crashes with the 462 - remote-server-computer is not available.
If app is Nothing Then
Set app = New Word.Application
Exit Function
End If
Set document = app.Documents.Add(Template:=Template, NewTemplate:=False, DocumentType:=0)
Dim settings As settings
settings = exportWord (document,...)
Private Function exportWord (oDoc As Word.Document, ...) As settings
On Error GoTo Err_WordExport
Dim sets As settings
With sets
.export = False
End With
exportWord = sets
Dim objRange As Word.Range
Dim objTable As Word.Table
With oDoc
Set objRange = .Bookmarks("tbl").Range
.Tables.Add objRange, positionen.Count + 1, 6
Set objTable = .Bookmarks("tbl").Range.Tables(1)
End With
With objTable
With .Rows(1)
.Cells(1).Range.Text = ""
.Cells(2).Range.Text = ""
.Cells(3).Range.Text = ""
.Cells(4).Range.Text = ""
.Cells(5).Range.Text = ""
.Cells(6).Range.Text = ""
.Cells(1).Range.Font.Bold = True
.Cells(2).Range.Font.Bold = True
.Cells(3).Range.Font.Bold = True
.Cells(4).Range.Font.Bold = True
.Cells(5).Range.Font.Bold = True
.Cells(6).Range.Font.Bold = True
End With
End With
Dim i As Long
i = 2
For Each ItemPos In Positionen
'fill the content
Next ItemPos
With objTable.Rows(1).Borders(wdBorderBottom)
.Visible = True
.LineStyle = wdLineStyleDouble
End With
objTable.Columns(4).Select
Selection.ParagraphFormat.Alignment = wdAlignParagraphRight
objTable.Columns(5).Select
Selection.ParagraphFormat.Alignment = wdAlignParagraphRight
objTable.Columns(6).Select
Selection.ParagraphFormat.Alignment = wdAlignParagraphRight
objTable.Columns.AutoFit
oDoc.SaveAs2 pathToSave
With sets
.export = True
.PathToFile = pathToSave
End With
exportWord = sets
Set objTable = Nothing
End Function
You can avoid selecting the columns by looping through the cells. You can also simplify your code as below:
Set objTable = oDoc.Tables.Add(oDoc.Bookmarks("tbl").Range, Positionen.Count + 1, 6)
With objTable
Dim wdCell As Word.Cell
With .Rows(1).Borders(wdBorderBottom)
.Visible = True
.LineStyle = wdLineStyleDouble
End With
For Each wdCell In .Rows(1).Cells
With wdCell.Range
.Text = ""
.Font.Bold = True
End With
Next wdCell
Dim colIndex As Long
For colIndex = 4 To 6
For Each wdCell In .Columns(colIndex).Cells
wdCell.Range.ParagraphFormat.Alignment = wdAlignParagraphRight
Next wdCell
Next colIndex
End With
You can refine this even further simply by adding a 2 row table into the template with the formatting already applied. Then all you need is:
Set objTable = oDoc.Bookmarks("tbl").Range.Tables(1)
Dim i As Long
For i = 1 To positionen - 1
objTable.Rows.Add
Next i
I have a large Lotus Notes project, a small part of which uses Word to create PDFs. In one piece, it pastes some text into a new Word document and saves as a PDF, like this:
Set wrdApp = createObject("Word.Application")
wrdApp.visible = True
Set wrdDoc = wrdApp.documents.add()
Set selection=wrdApp.Selection
selection.InsertBefore(doc.body(0))
strSaveFilename = "HelloWorld.pdf"
wrddoc.Saveas strSaveFileName, 17
Call wrddoc.close(0)
Set wrddoc = Nothing
Call wrdapp.quit(0)
Set wrdapp = Nothing
and in another part of the same chunk, it opens a Word document and then saves it as a PDF, like this:
Set MCwrdApp = createObject("Word.Application")
McwrdApp.visible = true
Dim wrdDoc As Variant 'word document
strfilename = "HelloWorld.docx"
Set wrddoc = MCwrdApp.documents.Open(strfilename)
f2 = "HelloWorld.pdf"
wrddoc.ExportAsFixedFormat f2, 17, 0, 1
wrddoc.close(0)
Set wrddoc = Nothing
Call Mcwrdapp.quit(0)
Set McwrdApp = Nothing
The problem I'm having is that since we upgraded to Office 2016, occasionally WINWORD.EXE gets left running and I have to kill it with Task Manager. The last time it happened Word was started in the sub that does the copy/paste. But that's not the question. The question is, are there differences between using .SaveAs and .ExportAsFixedFormat in this scenario? Why would the developer (not me) have used one in one place and the other somewhere else?
I need a VBA code to update my word file. It which consists of some tables That has to be updated from excel file. Excel file consists of bearing data with different bearing numbers. And my report has to be updated with the bearing values. Like for my next report if I just enter the different bearing file it must read all the bearing data from that file.
This has to be done in 3 steps. I have attached a sample image. firstly identify the bearing name which is always in A column (In this case I need to find (248_R), 38,7 % ). Then select 6*6 matrix data (suppose I find the bearing data to be in A946 then I need to record data from B950 to G955) and then transfer to word file(Only the values to the table). I am a newbee in VBA coding please can someone help?
image of sample bearing name with matrix underneath
Image of what the tables look like in the word document:
The first part of copying the range you want is relatively easy. You can use the following code to copy your desired matrix. I am not sure about pasting to a word document yet, give me some more time on that.
(For now, if you run this macro, the range you want will be copied. You can then switch to your word document and hit Ctrl+V to paste it into the desired table.
Also, please check and see whether the following references have been added:
Option Explicit
Sub findBearingDataAndPasteToWord()
Dim i As Integer
Dim aCell As Range, rng As Range
Dim SearchString As String
Set rng = Range("A750:A1790")
SearchString = "(248_R), 38,7 %"
For Each aCell In rng
If InStr(1, aCell.Value, SearchString, vbTextCompare) Then
ActiveSheet.Range(Cells(aCell.row + 4, 1), Cells(aCell.row + 9, 6)).Copy
Dim wrdApp As Word.Application
Dim docWd As Word.Document
MsgBox "Please select the word document that you want to paste the copied table data into (after pressing OK)" & _
vbNewLine & vbNewLine & "Script written by takanuva15 with help from Stack Overflow"
docFilename = Application.GetOpenFilename()
If docFilename = "False" Then Exit Sub
Set docWd = getDocument(docFilename)
Set wrdApp = docWd.Application
wrdApp.Selection.EndKey Unit:=wdStory
wrdApp.Selection.TypeParagraph
wrdApp.Selection.TypeParagraph
wrdApp.Selection.PasteExcelTable False, True, False
Exit Sub
Else: End If
Next aCell
End Sub
'Returns the document with the given filename
'If the document is already open, then it returns that document
Public Function getDocument(ByVal fullName As String) As Word.Document
On Error Resume Next
Set wrdApp = GetObject(, "Word.Application")
If wrdApp Is Nothing Then Set wrdApp = CreateObject("Word.Application")
wrdApp.Visible = True
Dim fileName As String
Dim docReturn As Word.Document
fileName = Dir(fullName)
Set docReturn = Word.Documents(fileName)
If docReturn Is Nothing Then
Set docReturn = Word.Documents.Open(fullName)
End If
On Error GoTo 0
Set getDocument = docReturn
End Function
I am new to VBA and I am trying to put together a macro in Excel. This macro is to search a Word document for a specific text string and return the page number where it is located (i.e. the column will say "### is found on page # of the document").
I seem to be very close to what I want. The macro finds the text and I can get it to tell me it found/didn't find it. However, when I run it with code to return the page number, it tells me the index is out of range. I'm sure the difficulty is with my limited understanding of the objects and their properties.
Any help is appreciated!
Sub OpenWordDoc()
Set wordapp = CreateObject("word.Application")
wordapp.Visible = True
wordapp.Activate
wordapp.Documents.Open "filename.docx"
Set findRange = Sheet1.Range("D4:D8")
For Each findCell In findRange.Cells
Set rngFound = wordapp.ActiveDocument.Range.Find
rngFound.Text = findCell.Value
rngFound.Execute
If rngFound.Found Then
findCell.Offset(columnOffset:=1) = rngFound.Parent.Information(wdActiveEndPageNumber)
Else
findCell.Offset(columnOffset:=1) = findCell.Value
End If
Next findCell
wordapp.Quit
Set wordapp = Nothing
End Sub
Edit 1: I have tried this on a completely different computer and different versions of Word and Excel. The same message pops up. The error is this piece - rngFound.Parent.Information(wdActiveEndPageNumber) - and I think the rngFound.Parent is not acting as a "selection". I also tried replacing the wdActiveEndPageNumber with wdNumberOfPagesInDocument just to see if it was the specific value and got the same error message.
Try something like this:
Sub OpenWordDoc()
Dim wordapp As Word.Application
Dim findRange As Excel.Range
Dim findCell As Excel.Range
Dim rngFound As Word.Range
Set wordapp = CreateObject("word.Application")
wordapp.Visible = True
wordapp.Activate
wordapp.Documents.Open "filename.docx"
Set findRange = Sheet1.Range("D4:D8")
For Each findCell In findRange.Cells
Set rngFound = wordapp.ActiveDocument.Range
With rngFound.Find
.Text = findCell.Value
.Execute
End With
If rngFound.Find.Found Then
findCell.Offset(columnOffset:=1) = rngFound.Information(wdActiveEndPageNumber)
Else
findCell.Offset(columnOffset:=1) = findCell.Value
End If
Next findCell
wordapp.Quit
Set rngFound = Nothing
Set findCell = Nothing
Set findRange = Nothing
Set wordapp = Nothing
End Sub
Hope that helps