Prerequisites |
None. |
|
The
following code demonstrates two things. First, and the reason for this code, is how to use the SendMessage API to programmatically scroll a
textbox vertically by any number of lines. The second is to demonstrate rather vividly the overhead involved when a control's property is
referenced during a complex operation, over the recommend method of using temporary variables for this purpose.
Microsoft, in talking about optimizing Visual Basic applications, emphasizes the fact that referencing a control's property is slow, and
recommend using temporary variables. It was therefore surprising to discover in their Knowledge Base code for this example that they in fact
used the text property when building the textbox string (as in InitializeTextBoxSlow code below). I rewrote it to utilize their
elsewhere-recommended temporary variable, with a considerable corresponding increase in speed.
Every time a control or a control's property is referenced, VB must check that the control is a valid control, that a control by that name
exists, and that the property referenced in the operation is valid for that type of control. This adds significant overhead to a running
application, with the result that to the user, the application appears slow. Add to that the screen redraw each time a control is updated,
and the time required to clear and repopulate a textbox, and the application not only appears slow, but flickers as well.
The status label in the project is provided to assure that the selected operation is in fact in progress (as opposed to locked up), and the
code clearly demonstrates that in all but a simple assignment, either a control's value should be saved to a variable, or a variable used to
compile any data, assigning it to the property only when completed. |
|
BAS
Module Code |
None. |
|
|
|
Form
Code |
|
To a form add a large text box (Text1), a small text box
(Text2), 4 command buttons (Command1, Command2, Command3 & Command4), and a label (Label1) corresponding to the illustration layout. Add
the following code to the form: |
|
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
' applications, but you may not reproduce
' or publish this code on any web site,
' online service, or distribute as source
' on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
Private Declare Function PutFocus Lib "user32" _
Alias "SetFocus" _
(ByVal hwnd As Long) As Long
Private Const EM_LINESCROLL = &HB6
Sub Form_Load()
Me.Move (Screen.Width - Me.Width) \ 2, (Screen.Height - Me.Height) \ 2
Label1.Caption = "Waiting for command"
Command1.Caption = "Fast Load"
Command2.Caption = "Slow Load"
Command3.Caption = "Scroll"
Command4.Caption = "End"
End Sub
Private Sub Command3_Click()
'Scroll text lines upward by the value specified in Text2
Dim numLines As Integer
numLines = Val(Text2.Text)
Call ScrollText(Text1, numLines)
End Sub
Private Sub Command1_Click()
InitializeTextBoxFast
Label1.Caption = "Waiting for command"
End Sub
Private Sub Command2_Click()
InitializeTextBoxSlow
Label1.Caption = "Waiting for command"
End Sub
Private Sub Command4_Click()
Unload Me
End Sub
Private Sub InitializeTextBoxSlow()
'This routine assigns the string to the textbox text property
'as the string is being built. This is the method that
'the MS VBKB detailed. I named it InitializeTextBoxSlow.
Dim i As Integer
Dim j As Integer
Text1.Text = ""
Label1.Caption = "Performing slow load..."
'just a pause to let the textbox and label update
DoEvents
For i = 1 To 100
Text1.Text = Text1.Text + "This is line " + Str$(i)
'Add 10 words to a line of text.
For j = 1 To 10
Text1.Text = Text1.Text + " ...Word " + Str$(j)
Next j
'Force a carriage return and linefeed
'VB3 users need to use chr$(13) & chr$(10)
Text1.Text = Text1.Text + vbCrLf
Next i
Text1.Text = Text1.Text
End Sub
Private Sub InitializeTextBoxFast()
'This routine assigns the string to temporary string variable
'as the string is being built.
Dim tmp As String
Dim i As Integer
Dim j As Integer
Text1.Text = ""
Label1.Caption = "Performing fast load..."
'just a wee pause to let the textbox and label update
DoEvents
For i = 1 To 100
tmp = tmp + "This is line " + Str$(i)
'Add 10 words to a line of text
For j = 1 To 10
tmp = tmp + " ...Word " + Str$(j)
Next j
'Force a carriage return and linefeed
'VB3 users need to use chr$(13) & chr$(10)
tmp = tmp + vbCrLf
Next i
'Now assign it to the text property.
Text1.Text = tmp
End Sub
Function ScrollText(TextBox As Control, vLines As Integer) As Long
Dim Success As Long
Dim SavedWnd As Long
Dim moveLines As Long
'save the window handle of the control that currently has focus
SavedWnd = Screen.ActiveControl.hwnd
moveLines = vLines
'Set the focus to the passed control (text control)
TextBox.SetFocus
'Scroll the lines.
Success = SendMessage(TextBox.hwnd, EM_LINESCROLL, 0, ByVal moveLines)
'Restore the focus to the original control
Call PutFocus(SavedWnd)
'Return the number of lines actually scrolled
ScrollText = Success
End Function |
|
Comments |
Save the app & run. Try the Fast Load button first,
then the Slow Load, and note the considerable time difference (be patient .. on a P166 with 64 megs of memory, the Slow method takes about 13
seconds). Note too that the two Initialize routines are identical, differing only that the "Fast" method uses a temporary string
variable. |
|