Es gibt drei Möglichkeiten, die Aktualisierung der Ansicht eines
Forms oder Steuerelements zu unterbinden, während Operationen
ausgeführt werden, die eine Aktualisierung mehrfach kurz
hintereinander verursachen würden. Die dabei mitunter sichtbaren
Flackereffekte sehen nicht nur unschön aus oder wirken gar
störend, sondern die wiederholte Aktualisierung kostet auch Zeit.
Die Ausführung der Operationen dauert wesentlich länger, als wenn
die Aktualisierung unterbleiben würde. Besonders betroffen sind
etwa Steuerelemente wie ListBox, ComboBox, TreeView und ListView.
Leider bieten weder Visual Basic-Forms noch die meisten
Steuerelemente eine direkte Möglichkeit an, die Aktualisierung
vorübergehend auszuschalten - Sie sind diesbezüglich auf eigene
Tricks angewiesen.
Die erste Möglichkeit beruht auf reinen VB-Bordmitteln. Machen
Sie das Form oder das Steuerelement einfach für die Zeit
unsichtbar, während die Operationen ausgeführt werden. Wenn Sie
Glück haben, verschwindet das Form bzw. Steuerelement gar nicht,
sondern wird nur einmal am Ende der Operationen aktualisiert wieder
dargestellt, nachdem Sie es wieder sichtbar gemacht haben. Das kann
dann daran liegen, dass das Windows-System in der Zwischenzeit
einfach keine Gelegenheit bekommen hat, das jeweils übergeordnete
Fenster (bei Forms wäre das der Desktop oder das MDI-Hauptfenster,
bei Steuerelementen das Form oder übergeordnete Steuerelement) zu
aktualisieren. Allerdings können Sie sich nicht auf dieses Glück
verlassen - in den meisten Fällen wird mindestens ein kurzes
Aufflackern bemerkbar sein, oder das Form bzw. Steuerelement
verschwindet tatsächlich eine Zeit lang von der Bildfläche.
IrgendeinControl.Visible = False
' ...Code
IrgendeinControl.Visible = True
Die zweite Möglichkeit besteht in einem paarweisen Aufruf der
API-Funktion LockWindowUpdate.
Public Declare Function LockWindowUpdate Lib "user32" _
(ByVal hwndLock As Long) As Long
Beim ersten Aufruf übergeben Sie zum Sperren der Aktualisierung
ihr das Fenster-Handle (hWnd-Eigenschaft) des Forms bzw.
Steuerelements. Die Freigabe und endgültige Aktualisierung erfolgt
mit dem zweiten Aufruf mit dem Wert 0 als Parameter.
LockWindowUpdate Me.hWnd
' ...Code
LockWindowUpdate 0
Diese Variante hat allerdings den Nachteil, dass Sie damit nur
ein einziges Fenster unter Kontrolle halten können. Rufen Sie
LockWindowUpdate zwischendurch mit einem anderen Fenster-Handle auf,
wird die Sperre des ersten Fensters wieder aufgehoben. Außerdem
bewirkt LockWindowUpdate zwar tatsächlich eine Sperre der
Aktualisierung eines Fensters. Bei der Aktualisierung nach der
Freigabe kann es jedoch dazu kommen, dass auch der gesamte Desktop
flackert, weil dieser (aus nicht immer nachvollziehbaren Gründen,
meistens dann, wenn sich Positionen und Größen von Fenstern im
übergeordneten Fenster oder auf dem Desktop verändert haben
könnten) ebenfalls von Windows aktualisiert wird. Treffen Sie auf
dieses Phänomen, hilft es oftmals, nicht das betroffene Form bzw.
Steuerelement selbst zu sperren, sondern statt dessen das
übergeordnete Form bzw. Steuerelement oder gar den gesamten Desktop
(dessen Fenster-Handle erhalten Sie über die API-Funktion GetDesktopWindow).
Es ist jedoch nur dann ratsam, die Aktualisierung des Desktops zu
sperren, wenn die in der Zwischenzeit ausgeführten Operationen
nicht allzu lange andauern. Denn die Desktop-Sperre bewirkt, dass
auch alle anderen laufenden Anwendungen wie eingefroren wirken.
Die dritte Möglichkeit bietet Ihnen eine genau auf das
betreffende Form bzw. Steuerelement beschränkte Sperre der
Aktualisierung und der Freigabe.
Public Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long
Public Const WM_SETREDRAW = &HB
Ein Aufruf der API-Funktion SendMessage
mit der Nachricht WM_SETREDRAW
sperrt die Aktualisierung, wenn im Parameter wParam 0 übergeben
wird (lParam ist ohne Belang - dort wird immer 0 übergeben). Zum
Beispiel:
SendMessage Me.hWnd, WM_SETREDRAW, 0, 0
Mit wParam = 1 wird die Sperre wieder aufgehoben:
SendMessage Me.hWnd, WM_SETREDRAW, 1, 0
Dies ist tatsächlich wörtlich zu nehmen, denn im Gegensatz zu
LockWindowUpdate wird wirklich nur die Sperre aufgehoben. Eine
Aktualisierung wird dadurch nicht unbedingt automatisch ausgelöst.
Sollte die Aktualisierung unterbleiben, reicht in den meisten
Fällen ein Aufruf der Refresh-Methode des wieder freigegebenen
Forms bzw. Steuerelements.
Bewirkt dieser Aufruf nichts oder keine saubere oder
vollständige Aktualisierung, hilft meistens ein Aufruf der
API-Funktion InvalidateRect
mit dem Fenster-Handle des Forms bzw. Steuerelements. Normalerweise
kann im zweiten Parameter ein Rechteck festgelegt werden, das den
tatsächlich zu aktualisierenden Bereich festlegt - dementsprechend
lautet auch die Deklaration der API-Funktion in Visual Basic:
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Declare Function InvalidateRect Lib "user32" _
(ByVal hwnd As Long, lpRect As RECT, ByVal bErase As Long) _
As Long
Da Visual Basic an sich sowieso nichts mit zu aktualisierenden
Teilbereichen anfangen kann, können Sie Angabe eines Rechtecks auch
unterlassen und statt dessen 0 übergeben, damit der gesamte
Arbeitsbereich (ClientRect) des Fensters aktualisiert wird. Dazu ist
jedoch eine abweichende Deklaration erforderlich, bei der dieser
Parameter als "As Any" deklariert wird. Damit diese
abweichende Deklaration nicht gegebenenfalls mit der ursprünglichen
in Konflikt gerät, nennen wir sie InvalidateClientRect (die
Deklaration der benutzerdefinierten Variablen RECT kann dann
hierfür entfallen):
Declare Function InvalidateClientRect Lib "user32" _
Alias "InvalidateRect" (ByVal hwnd As Long, lpRect As Any, _
ByVal bErase As Long) As Long
Im dritten Parameter übergeben Sie am besten den Wert True, der
dafür sorgt, dass der sichtbare Bereich des Forms bzw.
Steuerelements in jedem Fall gelöscht wird (ähnlich wie bei
Form.Cls). Manche Steuerelemente löschen nämlich nicht immer
automatisch den Hintergrund bei einer Aktualisierung - die dann
sichtbar werdenden Effekte mögen vielleicht interessant aussehen,
aber bestimmt nicht das gewünschte Resultat darstellen.
|