PDA

View Full Version : Table Code Oddity



gmaxey
02-23-2014, 05:37 PM
Maybe it is known and documented but this is the first time I've encountered this oddity:


Sub ScratchMacroOddity()
'A basic Word macro coded by Greg Maxey
Dim lngIndex As Long
Dim oTbl As Word.Table
'Add a 3x3 table
Set oTbl = ActiveDocument.Tables.Add(Selection.Range, 3, 3)
On Error GoTo Err_NoRow
For lngIndex = 1 To 5
'I would expect a RTE 5941 - The requested memeber of the collection does not exist, but it doesn't occur.
oTbl.Cell(lngIndex, 1).Range.Text = lngIndex & "-1"
oTbl.Cell(lngIndex, 2).Range.Text = lngIndex & "-2"
oTbl.Cell(lngIndex, 3).Range.Text = lngIndex & "-3"
'Even though rows 4 and 5 don't exists the data is written to the "last" row.
Next lngIndex
lbl_Exit:
Exit Sub
Err_NoRow:
oTbl.Rows.Add
Resume
End Sub

Sub ScratchMacroWorking()
'A basic Word macro coded by Greg Maxey
Dim lngIndex As Long
Dim oTbl As Word.Table
Set oTbl = ActiveDocument.Tables.Add(Selection.Range, 3, 3)
On Error GoTo Err_NoRow
For lngIndex = 1 To 5
oTbl.Rows(lngIndex).Cells(1).Range.Text = lngIndex & "-1"
oTbl.Rows(lngIndex).Cells(2).Range.Text = lngIndex & "-2"
oTbl.Rows(lngIndex).Cells(3).Range.Text = lngIndex & "-3"
Next lngIndex
lbl_Exit:
Exit Sub
Err_NoRow:
MsgBox Err.Number & " " & Err.Description
oTbl.Rows.Add
Resume
End Sub

macropod
02-23-2014, 07:55 PM
Odd!

fumei
02-23-2014, 10:50 PM
Hmmmm. Odd indeed.

fumei
02-23-2014, 11:16 PM
What is interesting is if you put an arbitrary number:

lngIndex = 23
oTbl.Cell(lngIndex, 3).Range.Text = lngIndex & "-3"

into the first procedure, it puts 23-3 into the last cell. No error. Even though Cell should be Cell(Row as Long, Column as Long), apparently VBA does not give a crap about whether the number makes sense. Weird.

lngIndex = 23
oTbl.Cell(lngIndex, 2).Range.Text = lngIndex & "-2"
oTbl.Cell(44, 2).Range.Text = "whatever"

the 44,2 replaces (at least the weirdness is consistent) 23-2 with "whatever". Note that this weirdness works on the Rows, but not Columns.

44,2 put the text in cell(2), but 44,7 gives an error. Rows do not really get validated, but columns do? Or more accurately, the Row parameter value of CELL does not seem to get validated - clearly as shown in the second procedure the INDEX value of Row does get validated.

Nice one Greg.

fumei
02-23-2014, 11:20 PM
This seems like an extremely glaring bug.

macropod
02-24-2014, 12:08 AM
This seems like an extremely glaring bug.
Not likely to be fixed in a hurry, though - it goes back at least as far as Word 2003 and this is the first time I've seen it mentioned.

fumei
02-24-2014, 12:32 AM
Me too. I have heard of this before. But then whenever I work through rows I would do something more explicit - that is getting a real value - like:

For lngIndex = 1 to oTbl.Rows.Count rather than an arbitrary number. Greg, how did you come across this? Why did you use 5 when you put in 3 as the row count?

And no, there is no chance that this is going to be fixed any time soon...or ever. It does seem a very odd and incredibly sloppy hole. I mean they catch the error if it is the column value.

gmaxey
02-24-2014, 05:56 AM
Gerry,

5 was just a arbitrary number for to illustrate the issue. I came across the issue while attempting to insert a pre-defined buildingblock table with three rows and then fill it with the contents of a listbox. In several cases the listbox had more list entries than the table had rows and I need to add rows. So .listEntries.ListCount - 1 isn't really an arbitrary number and I thought I could detect the need for an additional row by error handling:


Private Sub AddAndFillTable_Click()
Dim oRng As Word.Range
Dim oTmp As Template
Dim lngIndex As Long
Selection.Paragraphs(1).Style = "Normal"
Set oRng = Selection.Range
Set oRng = ThisDocument.AttachedTemplate.BuildingBlockTypes(wdTypeCustomTextBox).Categ ories("Tables") _
.BuildingBlocks("Selection Condition Box").Insert(Where:=Selection.Range, RichText:=True)
Set oTbl = oRng.Tables(1)
On Error GoTo Err_NoRow
For lngIndex = 0 To 5 'listEntries.ListCount - 1
oTbl.Cell(lngIndex + 2, 1).Range.Text = lngIndex & "-1" 'listEntries.List(lngIndex, 0)
oTbl.Cell(lngIndex + 2, 2).Range.Text = lngIndex & "-2" 'listEntries.List(lngIndex, 1)
oTbl.Cell(lngIndex + 2, 2).Range.Text = lngIndex & "-3" 'listEntries.List(lngIndex, 2)
Next lngIndex
oRng.Collapse wdCollapseEnd
Unload Me
lbl_Exit:
Exit Sub
Err_NoRow:
oTbl.Rows.Add
Resume
End Sub

Frosty
02-24-2014, 11:20 AM
Ah, tables. What a disaster... and has been since Word 97 (at least).
You could try to write your own function so that your error handling would work...

Public Function fGetCell(lRow As Long, lColumn As Long, oTable As Word.Table) As Word.Cell
Dim oRet As Word.Cell
On Error GoTo l_err
If lRow > oTable.Rows.Count Then
'what microsoft *should* do
GoTo l_exit
'what microsoft *does*
'lRow = oTable.Rows.Count
End If
Set oRet = oTable.Cell(lRow, lColumn)

l_exit:
Set fGetCell = oRet
Exit Function
l_err:
Set oRet = Nothing
Resume l_exit
End Function

gmaxey
02-24-2014, 11:30 AM
Jason,

Thanks. Using the row method instead of cell above worked fine, so I'm not going to bother going back and changing it.

Frosty
02-24-2014, 11:31 AM
I suspect the behavior is because what microsoft is really doing is iterating through the .Cells collection off the table's .Range... and then exiting the loop once it runs out of cells in the table, rather than validating that the number is correct. The help file clearly states it can be an integer (despite being a long parameter) between 1 and the .Count of the rows/columns.

But you could also just validate your table before trying to go through your loop (if your error trapping is just going to add a row... then add rows until your .Rows.Count is the same as your highest desired row value to insert text in.

Pretty weird, but after running into bugs in the Table object when I selected the entire table from the bottom right of the table to the top left (instead of the top left down to the bottom right), I cease to be surprised at any bugs in the table object anymore. You just work around them. There are so many ways to break how you reference elements of a table, that there is no "right" approach to avoid bugs, just the one that works for that particular code.

Frosty
02-24-2014, 11:34 AM
Yeah, if you don't have to worry about merged cells anywhere, it's pretty easy to work around. But if you do, then working off the .Rows object will cause problems, where the .Cell Method is more "robust" (albeit, "robust" can also mean "doesn't cause an error when you want it to").

gmaxey
02-24-2014, 11:50 AM
It all makes sense. Or sort of. Or maybe not :confused4

fumei
02-24-2014, 08:36 PM
Ah, yes Word tables. As I have posted elsewhere, it sometimes seems like Word programmers are castoff (read rejected and sloppy) failed Excel programmers...