Heading

This is some text inside of a div block.
This is some text inside of a div block.
This is some text inside of a div block.
min read

Disable screen updates more

Word • Macros • Editing • Classes
Peter Ronhovde
22
min read

Frequent content manipulation on the screen, particularly in large documents, can slow a macro and cause unpleasant screen flickering while it runs. Today, we improve two previous macros to toggle several screen settings. The finish line is the same, but with this version, we safeguard against subsequent calls in other macros prematurely restoring the settings.

Thanks for your interest

This content is part of a paid plan.

Toggle Screen Updates

Of course, removing inefficiencies is the most important way to upgrade a slow macro, but we can also tweak a few Word settings to improve the speed and presentation of our macros. This version also allows us to restore some settings to their original settings rather than always turning them off and then back on.

We also encounter some limitations of VBA in the process. There is some overlap with this article and the free version.

What’s the plan?

Turning off screen updates during macro execution will prevent Word from repeatedly updating the display until our macro is finished. This also ensures our macro runs cleaner without displaying all the unsightly text manipulations in progress. Users just see the final result.

We can further limit some calculations Word does while the macro is running since Word is constantly checking and updating the document under the hood while you work. In real-time use, this is inconsequential, but it can affect macros since the changes happen much faster. However, with just flip a few simple switches, Word will wait until we’re done before resuming regular document analysis or updates.

What do we change?

How do we make the advertised changes?

Screen updates

The screen updates setting is part of the top-level Application object. Assuming the macros are written reasonably well, turning it off will improve the speed of many macros.

Application.ScreenUpdating = False ' or True

As the name implies, we set it to True or False value depending on whether we want to enable or disable screen updates, respectively.

Document pagination

If a macro makes any sizeable changes to documents, particularly large ones, it may also help to temporarily disable document pagination.

Options.Pagination = False ' or True

Of course, False disables Word recalculating the page layout of the document in real time as the macro runs. At the end of the macro, we turn it back on, and Word can recalculate the pagination just once.

Spelling and grammar

We can also turn off real-time grammar and spell checking since Word is constantly checking the document as you write.

Options.CheckSpellingAsYouType = False ' or True

This controls whether Word checks spelling in real-time while you type.

Options.CheckGrammarWithSpelling = False ' or True

This setting controls whether Word also checks grammar while it checks the spelling in the document.

Of course, if you always work with spell checking turned off, you can omit these settings.

In practice, I haven’t had much problem with grammar and spell checking hindering my macros, but it makes sense to toggle them off while we’re running a complicated macro.

Problems with previous solution

Our earlier, simpler approach used only subroutines (called procedural programming) to toggle the screen settings. Most macros in VBA work well with this approach since they are usually handling isolated tasks.

More specifically, the previous subroutines enabled and disabled several document settings during macro execution. They did the job, but any macro or function could still toggle the settings back on at any time. Admittedly in VBA, we can’t stop a user from flipping these switches manually anywhere since the individual settings are always available, but we can tighten our own controls a little while also making the process easier to manage.

Also as you work on more complicated macros, are you always going to remember which macros also toggle the screen settings? It would be nice if our macros took care of that for us.

If we try to stay with the procedural approach, we would probably need to resort to using global variables to store information since we would have multiple functions accessing the same variables (“static” variables would work for a lone function). In general, using global variables is probably a poor(er) solution because they can be changed anywhere at any time. It’s like having a toybox where the neighborhood kids can enter your room and ravage your toys whenever they wish. Imagine owning a toy, but the pieces scattered across the room every time you want to play with it. That doesn't sound like fun to me.

Class Version

Most people don’t tinker with a car’s engine when stopped at a red light. The manufacturer provides a gas pedal and a brake. They probably also include air conditioning and other assorted controls. Maybe some blinking lights and such.

The driver just tells the car what to do, turns a knob, or flips a switch here or there, and the car handles the details. Most people don’t want to work on the engine or anything of the sort even after they get home. The car is just an important tool to get other work done.

What are classes?

That’s kind of like a class. They are the software equivalents of real-life objects, and indeed they’re called “objects” in programming also.

We give the user some defined data (properties) and actions (methods). The user writes a macro using these higher-level commands, and the class handles most of the details. The class provides some structure, so she can solve bigger problems elsewhere.

Before we get started, this lesson isn’t meant to be a tutorial on classes in VBA. That’s a much bigger topic than our implementation merits.

Why use a class for this problem?

I initially resisted creating a class here, but I eventually realized that we have several pieces of data in the form of screen settings and several actions we can take when using that data.

Connecting data and actions on that data is the essence of “object-oriented programming”. We put the two together to form a cohesive, logical object hopefully making it easier to understand and use, and classes are how we implement these objects.

Creating a class to solve this particular problem is a little overkill, but it simultaneously gives us more control over the process while also making it easier to use.

What’s the new problem to solve?

What happens when multiple functions try to toggle the screen settings in succession?

In more complicated problems, we might have macros calling other macros. We could easily forget which macros toggle the screen updates, so we would like the class to control the process and ignore any attempts to restore the screen settings when inside any later functions that are called from the main macro.

While we’re at it, it would be nice if the class allows us to restore some settings to their starting values rather than always on or off.

What do we need to do?

We have several specific things we need the class to do.

  • Initialize any saved variables (whatever they are) but just on first use in most cases
  • Disable the screen settings, but ignore any subsequent attempts to disable them while they are already disabled. Also, store any unique ID given by the user for later validation.
  • Enable the screen settings but only if currently disabled and only they’re being changed by the original macro that disabled them when using a unique ID
  • Check the current disabled status (usually obvious based on general use cases, but we might need it sometime)

Screen settings class

The following class is probably the cleanest overall way VBA allows us to implement screen setting toggles during macro execution.

Create a new class module

Create a new class module in the VBA editor. From the menu, use Insert → Class Module.

In the Properties information panel (use the menu View → Properties Windows if it's not visible), give the class an appropriate name like TScreenSettings. I include the preceding "T" just to ensure I remember it's a data type not just a variable name, but it's not required.

Then insert the following code into the empty module (full text is below).

Screen settings data

Private variables and methods prevent anyone from manually changing or using them from anywhere outside the class. In this simple class, there isn’t a need for anyone to directly access them anyhow. To declare a class variable as private, we literally just insert Private before the variable name.

' Private data inaccessible from outside functions
' Store current spell check and grammar settings
Private SpellCheckStart As Boolean
Private GrammarCheckStart As Boolean

Of course, we also need to give a variable type (if we want to be specific). Here we use Boolean variables since we’re storing True-False screen settings.

' InProgress is True if screen settings are disabled and False if enabled (regular state)
Private InProgress As Boolean

InProgress records whether the disabled state is in progress. It is True if screen settings are disabled and False if enabled. Of course, "enabled" screen settings is the regular working state in Word unless the user has turned off spelling and grammar checking.

' Macro ID allows some control over which macro can restore screen settings
' Relies on user to provide a unique ID in the main macro
' Does not prevent screen settings changes from other variable instances
Private sMacroID As String

The sMacroID variable allows us to identify which macro or function initially disables the screen settings. If provided, the macro ID is stored during a successful Disable command (see below). A successful call to a subsequent Restore method below would require the correct macro ID. This prevents unintended macros from restoring the screen settings too early before the main macro finishes.

The ID usage does not prevent screen settings changes from other variable instances since they cannot talk to each other easily (see Gotchas below), but general class usage only requires one global ScreenSettings variable.

The class allows any macro to toggle the screen settings on or off if sMacroID is an empty string “”.

Class subroutines

The following two private subroutines are only for the class to create or destroy itself.

Private Sub Class_Initialize()
InProgress = False ' Regular screen settings
Initialize ' Store certain current settings
End Sub

Class_Initialize is run automatically by VBA when the object is first created.

We initialize InProgress to False since nothing is happening yet, and we store the initial spelling and grammar settings using the Initialize method below.

Private Sub Class_Terminate()
Restore ' Restore settings before terminating
End Sub

Class_Terminate is run automatically by VBA when the object is deleted. In case the user forgot, we make sure to Restore the screen settings just before the object is terminated. There is a gotcha here though when using global variables (see below).

Public methods

Public means anyone can use these methods, and public is the default in VBA if Public or Private are both omitted. These are the functions that the class creator expects a typical person to use.

Initialize settings

We need to store the current values for selected settings.

Sub Initialize()
' Reinitialize stored settings (generally not necessary)
SpellCheckStart = Options.CheckSpellingAsYouType
GrammarCheckStart = Options.CheckGrammarWithSpelling
End Sub

For now, we only store the spell check and grammar settings since we’ll always toggle the ScreenUpdates or Options Pagination on or off for restore or disable them, respectively.

This initialization is a separate subroutine in case we want to do so separately sometime, but it probably won’t be needed in most cases since the class initializes the screen settings and other variables automatically.

Restore screen settings

The Restore subroutine checks to make sure we’re InProgress before restoring the screen settings.

Sub Restore(Optional CallingMacroID As String = "")
' Restore settings to default or saved values
If InProgress And IsMatchMacroID(CallingMacroID) Then
' Always reset these settings to True
Application.ScreenUpdating = True
Options.Pagination = True

' Reset these settings to original values
Options.CheckSpellingAsYouType = SpellCheckStart
Options.CheckGrammarWithSpelling = GrammarCheckStart

' Clear any saved macro ID to reset
sMacroID = ""

InProgress = False
End If
End Sub

If provided, the macro ID must match the stored value before anything is changed. This helps us control which macro can turn the settings back on. The ID is stored in the Disable method below, if desired.

Restoring the settings consists of turning ScreenUpdating and Pagination back on and resetting the stored values of grammar and spell checking.

InProgress is always False when leaving the Restore method.

Disable screen settings

The Disable subroutine checks to make sure we’re not already InProgress before disabling any screen settings.

Sub Disable(Optional CallingMacroID As String = "")
' Disable all used settings if not in progress already
If Not InProgress Then
' Always toggle these settings off
Application.ScreenUpdating = False
Options.Pagination = False
Options.CheckSpellingAsYouType = False
Options.CheckGrammarWithSpelling = False

If (sMacroID = "" And CallingMacroID <> "") Then
' Set calling macro ID
sMacroID = CallingMacroID
End If

InProgress = True
End If
End Sub

Disabling the settings consists of turning ScreenUpdating, Pagination, grammar, and spell checking all off.

InProgress is always True when leaving the Disable method meaning we are inside a macro (possibly also calling other macros or functions) making document changes that would be otherwise be shown on the screen.

Macro ID stored

If a macro ID is provided, it is stored for later validation during a Restore attempt. The intention is only the starting or main macro can restore the screen settings later.

Macro ID issues

This approach requires the user to provide a unique ID in each macro or function where Disable and Restore are used.

Ideally, we would obtain a unique identifier of some sort from the main macro and use that as a better ID without requiring user input. The user wouldn’t even have to know the ID value. Unfortunately, VBA gives us no way to identify either the function address nor the function name within a macro (without third party tools which is very much overkill for this problem). As a result, we’re stuck with requesting a unique macro ID string from the user.

This is not as “safe” in the sense that we allow more chances for mistakes to creep into the process, but VBA doesn’t give us much choice.

Get status

The GetStatus function is mostly in case a macro wants to check whether the screen settings are disabled. It is included for completeness, but it should not be needed in general.

Function GetStatus() As Boolean
' Returns the current progress status:
' True if Disabled is active but False if inactive
GetStatus = InProgress
End Function

Does macro ID match?

A macro ID controls which macro is allowed to restore the screen settings. With this in mind, it is convenient to provide a separate method to validate whether an ID is correct or not.

Function IsMatchMacroID(CallingMacroID As String) As Boolean
' Return whether given macro ID string argument matches the current variable I'd
' Empty string sMacroID will value always return True
' Only restrictions on valid ID are characters
IsValidMacroID = (CallingMacroID = sMacroID Or sMacroID = "")
End Function

The method is public, meaning anyone could check a valid macro ID string, but in practice, it probably wouldn’t be necessary.

It returns a True-False value based two criteria:

Is the macro ID defined?

Not defined is when sMacroID is an empty string "", and it results in a True value for this method.

Does the given macro ID match the stored ID?

We literally just compare the two strings which must match exactly.

The macro ID is initially stored when the Disable command is first used, and a subsequent Restore can reverse the change if the command has a matching ID.

No data properties

A typical class would probably give a user access to the data using “properties” (which are basically functions that control access to the internal class data), but this class and its use cases are simple and general enough that it’s cleaner to just restrict any data access from outside the class.

Gotchas

These gotchas cannot necessarily be solved, but we should still be aware of them.

Not turning screen updates back on

What happens if a macro doesn’t turn screen updates back on perhaps because it crashes before the macro ends. In my experience, Word won’t let screen updates nor the pagination option stay off after the macro finishes, so we’re probably safe. However, I have seen rare cases where it seemed like screen updates did not get toggled back on correctly when a macro crashed. Fortunately, in a worst-case scenario, you could just save the document and restart Word.

However, it’s bad manners and risky to take chances with sloppy assumptions, so you should definitely restore the settings by the end of the main macro.

The class approach attempts to catch this in the termination method if the user forgets, but since the screen setting is declared as a global variable, it doesn’t actually get deleted until Word quits. This means the user is still responsible for restoring the screen settings.

If you want to be safer, see the extended content in the previous article where we introduce using some simple error handling to ensure screen settings are restored properly even if there is an error in the main macro.

Navigation pane is still updated

Unfortunately, the navigation pane is still updated during macro execution even when screen updates are turned off. There doesn’t seem to be much we can do about that as regular users, so you’ll probably still see the navigation pane text jiggle if you have it visible.

Why not declare a different ScreenSettings object in each macro?

If we declare a new ScreenSettings object in each macro, then we could guarantee the settings are restored when the macro ends. The terminate method would automatically restore the screen settings before deleting the variable.

There are at least two problems with this approach:

Multiple variables would not communicate

If we use multiple ScreenSettings variables, they do not communicate well with each other (see below). In the end, we would have to regularly check and probably locally store what the current screen settings state was upon entering the macro before allowing it to restore any settings at the end. Unfortunately, this defeats the whole point of using the class to solve the original problem. The class is supposed to handle the details for us.

If you’re familiar with other programming languages, you might start to interject:

“But static variables—”

Hold on. They don’t work the same way here …

Cannot access VBA static variables in multiple functions

Generally, something like this would be handled with a “static” class variable which exists once for the class as opposed to separately for each variable instance of the class. We would then use that static variable to store which function disabled the screen settings and whether they are currently disabled. This unique information would be visible to all instances of the class.

And you hear the but coming ...

Unfortunately, VBA doesn’t implement static class variables in the same way as other programming languages. That is, static variables exist in VBA classes but at a procedure level meaning the variable stays local to the procedure.

Why? I don’t know.

But if we want to access InProgress and sMacroID from different class methods to validate the status or ID before taking some action, we can’t use VBAs version of static variables.

Ughhh.

Thus, the best way to track whether it’s “in progress” or which macro disabled the screen settings across multiple of them is by using a single global screen settings variable.

This is another VBA shortcoming. While VBA is nice overall, making macros far more approachable to write for regular users, it doesn’t quite match the capabilities of some other languages.

Verdict

In the end, none of the various possible solutions are ideal in VBA, but I this seems to be the best of the available approaches (as far as I can tell) to control screen settings without getting into potential trouble with overlapping calls to enable or disable them.

Revised Screen Settings Class with ID

Putting it all together, the screen settings class includes:

' Private data inaccessible from outside functions
' Store current spell check and grammar settings
Private SpellCheckStart As Boolean
Private GrammarCheckStart As Boolean

' InProgress is True if screen settings are disabled and False if enabled (in regular states)
Private InProgress As Boolean

' Function ID allows some control over which macro restores the screen settings
' Relies on user to provide a unique ID in the main macro
' Does not prevent screen settings changes from other variable instances
Private sMacroID As String

' Private subroutines

Private Sub Class_Initialize()
InProgress = False ' Start with regular screen settings
Initialize ' Store certain current settings
End Sub
Private Sub Class_Terminate()
Restore ' Restore settings before terminating
End Sub
' Publicly available functions and subroutines
Sub Initialize()
' Reinitialize stored settings (generally not necessary)
SpellCheckStart = Options.CheckSpellingAsYouType
GrammarCheckStart = Options.CheckGrammarWithSpelling
End Sub
Function IsMatchMacroID(CallingMacroID As String) As Boolean
' Return whether given macro ID string argument matches the current variable ID
' Empty string sMacroID will value always return True
' Only restrictions on valid ID are characters
IsValidMacroID = (CallingMacroID = sMacroID Or sMacroID = "")
End Function
Sub Restore(Optional CallingMacroID As String = "")
' Restore settings to default or saved values
' If sMacroID is not an empty string, it must match calling macro ID

If InProgress And IsMatchMacroID(CallingMacroID) Then
' Always reset these settings to True
Application.ScreenUpdating = True
Options.Pagination = True

' Reset these settings to original values
Options.CheckSpellingAsYouType = SpellCheckStart
Options.CheckGrammarWithSpelling = GrammarCheckStart

' Clear any saved macro ID to reset
sMacroID = ""

InProgress = False
End If
End Sub
Sub Disable(Optional CallingMacroID As String = "")
' Disable all used settings if not in progress already

If Not InProgress Then
Initialize ' Store certain current settings

' Always toggle these settings off
Application.ScreenUpdating = False
Options.Pagination = False
Options.CheckSpellingAsYouType = False
Options.CheckGrammarWithSpelling = False

If (sMacroID = "" And CallingMacroID <> "") Then
' Set calling macro ID
sMacroID = CallingMacroID
End If

InProgress = True
End If
End Sub
Function GetStatus() As Boolean
' Returns the current progress status
' True if disabled is active but False if inactive
GetStatus = InProgress
End Function

How to use the screen settings class

How do we actually use this class to toggle screen settings?

Declare global variable

At the top of the main module in the VBA editor, declare the global screen settings variable like so:

Public ScreenSettings As New TScreenSettings

This will automatically run the initialization function (called a “constructor” in other languages) and set up to allow a macro in the project to toggle the screen settings.

But you said—

Yes, this uses a global variable that I said was generally a bad thing, but the class controls access to the specific settings in a way that the user only needs to enable or disable them. This is safer and cleaner than just having the “raw” settings visible to everything in your project.

Only one screen settings variable needed

There should be no need to create another screen setting variable since the global one does everything we need (but see last gotcha above).

Using screen settings class

Once the variable has been declared at the top of your main module, inside any macro, function, or subroutine where you want to toggle the settings, just use:

ScreenSettings.Disable("UniqueID")

Before you exit the main macro, add the command:

ScreenSettings.Restore("UniqueID")

The UniqueID can be omitted, but it will allow any macro or function to Restore the settings. The macro ID allows us to restrict a proper restoration of the screen settings only at the end of the original macro used to disable the settings. If you happen to enable and disable the screen settings multiple times across other macros, the class will only honor the last Restore command inside the starting macro.

Affiliate Links

If you're interested in using Word or another tool related to the article, check out these affiliate links. I may make a small commission if you purchase when using them, but there is no increase in cost for you, and it helps to support this site and associated content.

I've been using Microsoft for Business for commercial use (that's us writers) on one of the lower pricing tiers for years. I get to use my macros, have online storage, and don't have to worry about software updates.