JogoDaImagem

|

Jardim / Alexandre

Word :-)

|

Maximising the performance of Word tables






Article contributed by Dave Rado

















1.



As a user




2.



In code






To return to top, press Ctrl+Home, or use Alt + Left Arrow to
Go Back)



As a user































1.


Working in Normal view when you can helps, especially if you turn off Background repagination (Tools + Options + General).
Whatever you do, though, tables in Word 2000 and higher are a lot slower in
most respects than
in Word 97 – an unfortunate by-product of the new table engine created so that
Word tables could be fully HTML-compatible.


2.


If using Word 2000 and above, select Table | Table Properties | Options,
and turn off the checkbox: Automatically resize to fit contents.
As well as slowing tables down considerably, this setting gives (usually)
undesirable results, but unfortunately is automatically switched on in all new tables.


3.

Don't create a single row containing a large amount of text.
I have seen many tables containing rows which (with non-printing
characters
displayed) look something like this:



Figure 1: A badly laid out table row (shown with non-printing characters

and table gridlines visible)

Apart from anything else, laying out table
text as shown above makes it a complete nightmare to get everything to line
up, which defeats the object of using a table in the first place, the great
strength of tables being that they line text up automatically if used
properly. But in addition, rows containing many paragraphs slow tables down.

So
create a separate row for each logical element of the table, as shown in
Figure 2. Note that if you don't want horizontal borders
between some of the rows, you don't have to have them; so not wanting borders
is not a reason to add paragraphs instead of adding rows:



Figure 2: How the row in Figure 1 should have been laid out –

as six separate rows, but with no horizontal border between the rows


4.

Break long tables up (use several smaller tables rather than
one very long one), separating the sub-tables with headings. So
rather than, for instance, creating something like this:



Figure 3: Avoid putting your headings inside your tables

... split your
tables up into logical sub-tables instead, putting your headings outside the
tables (using Heading styles), like this:



Figure 4: Put your headings outside your tables


5.

Avoid using merged cells as much as possible: wherever you
can get away with it, remove unwanted borders
instead.

6.

In Word 2000 and above, use text-wrapped tables
only when really necessary. Set text-wrapping to None
whenever you can. For more on text-wrapped tables, see: Table basics.

7.

In Word 2000 and above, if your tables contain graphics,
make them inline where possible.


In code



















































1.


If using Word 2000 and above, turn off Automatically resize to fit
contents for all tables:


Selection.Tables(1).AllowAutoFit = False



Whatever you do, though, tables in Word 2000 and higher are a lot slower in
most respects
than
in Word 97 – an unfortunate by-product of the new table engine created so
that Word tables could be fully HTML-compatible (but see 5. and 7.
below for an astonishing exception to this rule).


2.


2–7 above apply to tables created with code as well. In the case of
switching views and turning off background repagination, it is polite to the
user to leave their settings as you found them, i.e.:


Dim ViewType As
Long
, PaginationSetting As Boolean

ViewType = ActiveWindow.View.Type

PaginationSetting = Options.Pagination

'rest of your code

Options.Pagination = PaginationSetting

ActiveWindow.View.Type = ViewType


Unfortunately, even with ScreenUpdating switched off, the screen flickers
when you change views. The only way to prevent this is to use the the LockWindowUpdate API (which is
beyond the scope of this article, but a Google search will turn up details on
it). So it's only worth bothering to change views for large tables.


3.

If you are putting data into a Word table using code (e.g.
if you are reading it from a database), you will get much better performance if
you initially put the data into the Word document as tab-delimited text, and
then convert the text to a table at the very end. For example (the following
code sample requires you to set a reference to DAO,
and also assumes you have the Northwind sample database installed – it is one
of the sample databases supplied with Office, so if it is not already
installed on your system, you can re-run Setup in order to install it ):


Sub GetDataIntoTable()



Dim db As Database,
rs As Recordset, MyRange As
Range
, i As Integer

Set db = OpenDatabase(Name:= _

"c:\program files\microsoft
office\office\samples\northwind.mdb")

Set rs = db.OpenRecordset(Name:="Shippers")



Set MyRange = ActiveDocument.Content

MyRange.Collapse wdCollapseEnd



MyRange.InsertAfter Text:=rs.Fields(1).Name & vbTab &
rs.Fields(2).Name & vbCr

Set MyRange = ActiveDocument.Content

MyRange.Collapse wdCollapseEnd

For i = 0 To
rs.RecordCount - 1

'Insert the data as tab-delimited text


MyRange.InsertAfter Text:=rs.Fields(1).Value & vbTab
& rs.Fields(2).Value & vbCr

rs.MoveNext

MyRange.Collapse Direction:=wdCollapseEnd

Next i

rs.Close

db.Close




'Now convert to table


MyRange.Start = ActiveDocument.Range.Start

MyRange.ConvertToTable



Set db = Nothing

Set rs = Nothing



End Sub


If some cells in your table need to contain more than one paragraph (or to
contain manual line breaks), separate those paragraphs or lines, initially, with a dummy delimiter such as a comma or a
dollar sign; and then do a Find and Replace at the end (after converting the
text to a table), to replace the delimiter with a paragraph mark or manual
line break, as desired. For a code sample that illustrates this technique,
see: How to generate a table of samples of every font on your system.


4.

If for some reason you can't insert your text in
tab-delimited format and convert to table at the end, then don't build
up your table as you go by adding a row at a time. Instead, work out in
advance the total number of rows that you'll need (e.g. by reading all your values
into an array before inserting any of them in the document) and then create
the entire table in one go; e.g.:


Set oTable = ActiveDocument.Tables.Add(Range:=MyRange, _

Numrows:=1000, numcolumns:=4)

'Word 2000 only:

oTable.AllowAutoFit = False


5.

If inserting text, use ranges rather than selections
(as illustrated in the above code sample): and also, use characters such as
vbCr
and vbTab to allow you insert as much text as possible with a single
statement – again, as illustrated in the above code sample. For instance:


MyRange.InsertAfter Text:=rs.Fields(1).Value & vbTab
& rs.Fields(2).Value & vbCr


... runs much faster than:


Selection.TypeText Text:=rs.Fields(1).Value

Selection.TypeText Text:=vbTab

Selection.TypeText Text:=rs.Fields(2).Value

Selection.TypeParagraph


6.

If inserting a large amount of text into the document, make
sure background spelling and grammar checking are switched off.


At the end of your macro,
out of politeness to the user, switch the settings back on if they were on to
start with. Also, if you know that the inserted text won't need to be spelling
or grammar checked, you can mark the inserted range as already checked,
without marking the rest of the document. (Thanks to Greg Chapman for this
tip).


Dim SpellSetting As
Boolean
, GrammarSetting As Boolean, _

MyRange As
Range




SpellSetting = Options.CheckSpellingAsYouType

GrammarSetting = Options.CheckGrammarAsYouType



With Options

.CheckSpellingAsYouType = False

.CheckGrammarAsYouType = False

End With



'Insert your text, e.g.

Set MyRange = Selection.Range

Selection.InsertFile "C:\Temp\Temp.doc"

'Or insert it from a database, whatever



'If you know that it's safe to do so, mark the inserted text as already checked,

'but don't
mark the text that you didn't insert. If inserting from a database,

'set a range to the inserted text
and operate on that range.

'If using Selection.InsertFile, use the following:



MyRange.End = Selection.End

With MyRange

.SpellingChecked = True

.GrammarChecked = True

End With



'Rest of your code, and then at the very end:

With Options

.CheckSpellingAsYouType = SpellSetting

.CheckGrammarAsYouType = GrammarSetting

End With



7.

Applying manual formatting is very resource-hungry –
apply predefined styles instead.


8.

When cycling through table cells, never refer to a table
cell by its coordinates; as that is horrendously
slow, because it forces Word to calculate from
scratch, for every single cell, where in the document the cell in question
actually is.


And don't move selection from cell to cell, as this will also slow your
code down dramatically.


Whilst it is much faster to cycle through the Cells collection, as in:


Sub
OperateOnEveryCellUsingTableObject()



Dim oCell As Cell

For Each oCell In Selection.Tables(1).Range.Cells

oCell.Range.Text = "Hi there"

Next oCell



End Sub


... a much faster method still (with screen updating switched off) is to select
the table, in code, and then cycle through the cells within the selection – don't ask me why this
should be faster, but it is:


Sub OperateOnEveryCellInSelectedTable()



Dim oCell As Cell



Application.ScreenUpdating = False

Selection.Tables(1).Select

For Each oCell In Selection.Cells

oCell.Range.Text = "Hi there"

Next oCell

Application.GoBack

Application.ScreenUpdating = True



End Sub


When I timed the above macros in Word 97 and in Word 2000, using a 350-row,
5-column table, the results were very interesting (I've rounded the results to
1 decimal place):












Word 97

Word 2000

OperateOnEveryCellUsingTableObject




38.5s




53.8s

OperateOnEveryCellInSelectedTable




5.3s



4.5s


The above results were obtained with a table created in Word 97. If the
table was created in Word 2000 (and if AllowAutoFit
was switched off), then using the Table object became significantly faster in
Word 2000 (though not in 97); but was still far slower than using a Selection object. If the
document was created in Word 2000 and then saved in Word 97, the results were similar
to the above.


I have no theories to explain these results, but they are easy to
reproduce. Tests by colleagues who have
access to Word 2002 gave broadly similar results to Word 2000.


Turning off screen updating made no difference to the speed of the OperateOnEveryCellUsingTableObject()
macro, although it dramatically speeded up the OperateOnEveryCellInSelectedTable()
macro.




9.

When operating on specific rows, or comparing the contents
of adjacent rows, use the Row object, as in the code samples at Deleting duplicate rows in a table.


10.

If you want to operate on the cells in a specific table
column, you can't cycle through the cells within the column's Range –
Ranges and Columns simply don't mix. Crazily, a table column's Range contains
many cells that are not actually within the column. This must once have seemed
like a good idea to someone at Microsoft, probably because they were suffering
from a bad hangover at the time! There is a certain pedantic logic to it: a
column's range contains all the cells starting from the top of the column,
moving through the table from left to right along each row, until you get to
the bottom of the column. From a usability perspective this was a
nightmarish design decision, though, and well worth emailing mswish@microsoft.com
about.


By far the fastest way of operating on a specific column is to select it
and then cycle though the selected cells, as in:


Sub OperateOnSelectedColumn3()



Dim
oCell As
Cell


Application.ScreenUpdating = False

'Select the third cell in the first row of the
table


Selection.Tables(1).Cell(1, 3).Select

'Select column 3


Selection.SelectColumn

'Operate on the cells in column 3


For Each oCell In Selection.Cells

oCell.Range.Text = "Hi there"

Next oCell

Application.GoBack

Application.ScreenUpdating = True



End Sub


Note that you cannot safely use the Columns object to specify which
column you want to select, as in:


Selection.Tables(1).Columns(3).Select


.. because that gives an error message: Cannot access individual columns in this collection because the table has mixed cell
widths, either if there are any merged cells,
or even if any cell anywhere in the table has a
slightly different width than the rest of the cells in the same column!
So for all practical purposes, the Column object is completely useless –
another design decision resulting from far too many Tia Marias laced
with vodka, and well worth an email to mswish@microsoft.com.


If there might be merged cells in row 1 of the table, you could select the
third cell in the last row of the table instead, and then select the
column, rather than using the first row:


Dim oRow As
Row
, oCell As Cell

Application.ScreenUpdating = False


Set
oRow = Selection.Tables(1).Rows.Last

oRow.Cells(3).Select

Selection.SelectColumn


For Each
oCell In Selection.Cells

oCell.Range.Text = "Hi there"


Next
oCell

Application.GoBack

Application.ScreenUpdating = True


Instead of selecting the column you could cycle through every cell
in the table,
operating on those cells whose ColumnIndex property matches the column
you want, as follows:


Sub OperateOnColumn3UsingRanges()



Dim
oCell As
Cell


For Each oCell In
Selection.Tables(1).Range.Cells

If oCell.ColumnIndex = 3
Then

oCell.Range.Text = "Hi
there"

End If

Next oCell



End Sub


... but this is not only much slower than selecting the column, but
also, if there are any horizontally merged cells in the table, the
ColumnIndex property gives undesirable results.


When I timed the above macros in Word 97 and in Word 2000, using a 350-row,
5-column table, the results on my machine were as follows (I've rounded the
results to 1 decimal place):












Word 97

Word 2000

OperateOnColumn3UsingRanges



7.3s



10.7s

OperateOnSelectedColumn3



0.7s



1.1s


The above results were obtained with a table created in Word 97. If the
table was created in Word 2000 (and if AllowAutoFit
was switched off), then the OperateOnColumn3UsingRanges
macro became significantly faster in Word 2000 (though not in 97); but was still far slower than using a
Selection object. If the document was created in Word 2000 but then saved in Word
97, the results were similar to the above.


As with 7. above, I have no theories to explain these results, but they are easy to
reproduce. Tests by colleagues who have
access to Word 2002 gave broadly similar results to Word 2000; and again, turning off screen updating made no difference
to the speed of the OperateOnColumn3UsingRanges()
macro, although it dramatically speeded up the OperateOnSelectedColumn3()
macro.




11.

If formatting the borders and shading of a table, it is far
more efficient, and can speed up your code dramatically (even in Word 97), if
you execute the built-in FormatBordersAndShading dialog
(without displaying it), than it is to use native VBA Methods to do the formatting. This
trick also greatly reduces the risk of getting Formatting too complex error messages.


In essence, this is
because you can execute many commands simultaneously using the dialog,
whereas, using VBA methods, you have to execute one statement at a time, and
wait for one to finish before the next can start.


For a more detailed discussion of the principles behind this, and for some code
samples to get you started, see #2 at Getting help with calling Word's built-in dialogs using VBA (and why doing so can be much more useful than you'd think),
in the section: Why use built-in dialogs?”.


12.

If doing a great deal of formatting of tables, then even all
of the above tricks combined may not prevent you from getting the odd Formatting too complex error message.















Periodically clearing the Undo buffer can help prevent this:


ActiveDocument.UndoClear.


Make sure you have turned screen updating off. If that isn't
sufficient, the LockWindowUpdate API (which is
beyond the scope of this article, but a Google search will turn up details on
it) is more efficient still, as is making the application invisible.

If you still get Formatting too complex error messages, try saving the
document periodically; or as a last resort (in really huge tables), periodically
save the document, close it and open it again.



If you use all these tricks, you will find that the performance of
tables is not an issue, even in Word 2000 and higher.

Inclusão para Nota de Exemplo com o ScribeFire

Teste do ScribeFire

|

Inclusão para Nota de Exemplo com o ScribeFire

Teste do Teste

|

Estou postando no teste do ScribeFire via ScribeFire

[Floquinhos]

Teste do Teste

|

Estou postando no teste do ScribeFire via ScribeFire

E vamos testando... agora via link pequeno embaixo à direita

|

Cliquei no link pequeno embaixo à direita para ver se de fato posta no blog
 blog it

Este post foi para o QuartoMarcador, via ScribeFire

|

Novo teste para QuartoMarcador via ScribeFire

Nota de Exemplo 1

|

Esse é um exemplo de uma nota formatada note.

Quarto Marcador

|

Texto para o Quarto Marcador

Entrada

|

Teste um

Entrada

|

TextoEntrada

Nota de Exemplo 2

|

Esse é um exemplo de uma nota comum.

Post Inicial

|

Sempre há uma primeira vez...

Decidi fazer um blog para compartilhar, comentar e discutir sobre o MsExcel, VBA e demais aplicativos do MsOffice. O BrOffice, até o momento, é incidental, e também pode ser incluído em posts... Pretendo fazer deste espaço um complemento à minha atuação junto às duas principais listas brasileiras de discussão sobre o MsExcel/VBA: ExcelBr e Excel-Avançado. Eventuais arquivos relativos aos posts, bem como outros avulsos, são depositados no eSnips.