Visual Basic Text API Routines
SendMessage: Programmatically Scroll a Text Box Vertically
     
Posted:   Friday July 10, 1998
Updated:   Monday December 26, 2011
     
Applies to:   VB4-32, VB5, VB6, and VB3, VB4-16 with appropriate declarations
Developed with:   VB5, Windows 95
OS restrictions:   None
Author:   VBnet - Randy Birch
     
 Prerequisites
None.

txvscroll.gif (5612 bytes)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.

 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter