You can use a form’s Painting property to disable updates to that form and the Application.Echo method to disable updates to the Access window, but some activities still seem to show through or cause flashing on the screen. Is there any way to really hide screen activity?
Sometimes you need more control over screen repainting than you get with either Application.Echo or Form.Painting. You’ve already exhausted the options that Access provides for controlling the screen display. But there is one more alternative: Windows itself, through calls to the Windows API, allows you to disable screen updates for a window and all its children. Because Access makes it easy to retrieve the handle for the main Access window, you can disable all updates to that (or any other) window. This solution demonstrates a method of truly shutting off screen updates to the Access window. (Before you try it, however, be sure to read the cautions in Section 4.4.3.)
Load and run frmLockScreen (Figure 4-9) from
04-04.MDB
. This sample form simply opens three
reports in design mode and then closes them. The form includes a
checkbox that allows you to run the test with screen updates enabled
or disabled. Try it both ways; you should see a clear difference
between the two ways of running the test. With the checkbox set, the
underlying code disables screen updates, so you shouldn’t see
the reports’ icons pop up. Without the checkbox set, you will
see the icons.
To use the Windows API to disable screen updates in your own applications, follow these steps:
Import the module basLockScreen from
04-04.MDB
. This module includes the API declarations and code to disable updates to the Access main window.When you want to disable screen updates, call the acbShowUpdates subroutine, passing it a
False
value. To reenable screen updates, call the subroutine again, passing it aTrue
value. In other words, your code that uses acbShowUpdates should take the following form:Call acbShowUpdates(False) ' Do your work in here... Call acbShowUpdates(True)
The acbShowUpdates subroutine (in basLockScreen) does its work by calling the Windows API function LockWindowUpdate (aliased as acb_apiLockWindowUpdate). This function takes as its only parameter a window handle. If that handle is nonzero, Windows simply stops updating the contents of that window on screen. If the handle is 0, Windows reenables screen updates to the locked window.
Because the only window you care about locking in Access is the main
Access window itself, the acbShowUpdates routine
shields you from any of the details. If you pass it a
False
value, it blocks window updates. If you pass
it a True
value, it reenables updates. It finds
the Access window handle for you, if necessary, and then calls
LockWindowUpdate. Its source code is simple:
Sub acbShowUpdates (fShow As Integer) If fShow Then acb_apiLockWindowUpdate 0 Else acb_apiLockWindowUpdate Application.hWndAccessApp End If End Sub
Tip
In Access 2.0, finding the window handle (the unique integer that identifies every window) for the main Access window was difficult. It required a good deal of work with multiple Windows API functions. In later versions, the Application object exposes the hWndAccessApp property, which returns the window handle of the main Access window.
Though effective, this method of
disabling screen updates isn’t perfect. Because Access has no
idea that you’ve turned them off, Access itself occasionally
turns on screen updates. For example, depending on how you open forms
and reports in design mode, completely hiding the properties sheet
may be difficult. In the sample application,
04-04.MDB
, the reports’ properties sheet
isn’t showing. If you open one of the reports, open the
properties sheet, and then save the report, no combination of
Application.Echo and calls to LockWindowUpdate
will completely remove that properties sheet from the screen when you
open the report in design view.
In older versions of Access, you had
to resort to hacks to hide reports in design view. Fortunately, that
is no longer necessary in Access 2002, because Microsoft has finally
supplied a WindowMode
parameter that can
be used to hide a report when you open it, even if it’s opened
in design view. Also, many of the printer settings that made it
necessary to open reports in design view are no longer necessary in
Access 2002 because of the new Printer object (see Chapter 5 for several examples).
If you are working in Access 97, you can take advantage of an undocumented but effective technique for hiding the hard-to-hide properties windows of reports that are open in design view. Be warned, however, that this method is totally undocumented, is unsupported by Microsoft, and doesn’t work in Access 2000 or later.
The Application object in Access supports the GetOption and SetOption methods, which allow you to get and set global options. Most of these options are documented (see the online help topics for GetOption/SetOption), while a few items are not documented but do useful work. One such option allows you to retrieve and set the coordinates for the form or report properties sheet (in versions of Access prior to Access 2000) and to set whether or not you want the properties sheet to be visible when you open a form or report in design view.
To retrieve the information about the report properties sheet in Access 97 or 95, use a call like this:
strInfo = Application.GetOption("_26")
This will retrieve a string containing information on the report properties sheet’s location and whether or not to display it when you open a report in design view. The string will be in this format:
open?;left;top;width;height;
For example, it might look like this:
1;510;433;835;683;
indicating that the properties sheet will be visible when you load a report and that when it does show up it will be at 510, 433 with a width of 835 and a height of 683.
To make sure that your application doesn’t show the properties sheet while it does its work, you can retrieve this property, set the first character to 0, and then save it. The code might look like this:
Dim strInfo As String strInfo = Application.GetOption("_26") strInfo = "0" & Mid(strInfo, 2) Application.SetOption "_26", strInfo
The only way this will have any influence is if you call this code before you’ve loaded any reports in design mode. Access looks at this information only once, when it loads the properties sheet for the first time. Once it has loaded the properties sheet, it doesn’t look at these values again. Every time you leave design mode Access stores information about the properties sheet, so if you’re going to try to set these values for the next time you start Access, make sure you do it when there’s no report open in design mode. Otherwise, Access will override your settings when it saves them itself.
To use this technique for forms, use option “_24” instead. It’s not nearly as useful with forms as it is with reports, however, because in older versions of Access you can open hidden forms but not hidden reports.
Be aware that although
setting Application.Echo to False
does disable
updates to the Access MDI client window (the window that contains all
the Access objects), setting it back to True
causes a repaint of the entire Access MDI client window. This is why,
when you run the sample in 04-04.MDB
with screen
updates showing, the report icons appear at the bottom of the screen.
Each time the code in acbOpenReport opens a
report, it sets Application.Echo back to True
. As
a generic routine, it must do this—any routine that turns off a
screen display should turn it back on. The subroutine that calls
acbOpenReport, then, must surround the code with
calls to acbShowUpdates, turning off the entire
display before opening the three reports and turning it back on once
all three reports are closed:
If Me!chkHideUpdates.Value = True Then Call acbShowUpdates(False) End If For intI = 1 To 3 intSuccess = acbOpenReport("rptReport" & intI, acDesign) Next intI ' You could modify your reports in design mode here if necessary. For intI = 1 To 3 DoCmd.Close acReport, "rptReport" & intI Next intI
As an example of an error handler that resets screen updates, the code executed by frmLockScreen handles errors by using the normal exit route from the routine:
Private Sub cmdOpenReports_Click( ) Dim intI As Integer Dim intSuccess As Integer On Error GoTo HandleErr If Me!chkHideUpdates.Value = True Then Call acbShowUpdates(False) End If For intI = 1 To 3 intSuccess = acbOpenReport("rptReport" & intI, acDesign) Next intI For intI = 1 To 3 DoCmd.Close acReport, "rptReport" & intI Next intI ExitHere: If Me!chkHideUpdates.Value = True Then Call acbShowUpdates(True) End If Exit Sub HandleErr: MsgBox Err.Number & ": " & Err.Description Resume ExitHere End Sub
If an error occurs while this subroutine is active, the code will
jump to the HandleErr
label and from there will
resume at the ExitHere
label. The code will
reenable screen updates and then exit the routine. Your own code may
not look exactly like this, but you must handle errors so that the
screen never remains locked up when an error occurs.
Get Access Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.