Creating a scrollable text window

(Visual Basic 6)

Often in an application you may want to display read-only text in a TextBox, but with slightly different behaviour than that normally offered by a TextBox control. When viewing (for example) a web page in a web browser, or reading an email message in your mail client, you will almost certainly have a read-only TextBox, but with no caret (the edit cursor) visible. The window also scrolls differently; every time you press the cursor up or down key, the text immediately scrolls one line in the appropriate direction (normally in a TextBox you would have to move the caret all the way to the top or bottom of the TextBox before scrolling takes place).

This article shows a simple way to create such a TextBox in Visual Basic. The article demonstrates modification of just a single instance of a TextBox, but it would be very straightforward to wrap the functionality in an ActiveX control is required.

To demonstration the TextBox, create a new standard exe project in Visual Basic. On the form that is created, add a TextBox (we'll call it Text1) that has enough room for several lines of text (at least four or five). Set the properties of the TextBox as follows:

LockedTrue
MultiLineTrue
ScrollBars2 - Vertical

Paste the code below into your form and run the project to see the new behaviour of the TextBox.

Option Explicit 'Declarations required for the scrollable text window Private Declare Function HideCaret Lib "user32" (ByVal hwnd As Long) As Long Private Declare Function ShowCaret Lib "user32" (ByVal hwnd As Long) As Long 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 Const WM_VSCROLL = &H115 Private Const SB_LINEUP = 0 Private Const SB_LINEDOWN = 1 Private Const SB_PAGEUP = 2 Private Const SB_PAGEDOWN = 3 Private Sub Form_Load() Dim szFilename As String 'Add some text to the TextBox szFilename = Dir$("C:\", vbDirectory) Do Until szFilename = "" Text1.Text = Text1.Text & szFilename & vbCrLf szFilename = Dir$ Loop End Sub Private Sub Text1_GotFocus() HideCaret Text1.hwnd End Sub Private Sub Text1_LostFocus() ShowCaret Text1.hwnd End Sub Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer) 'Scroll the TextBox if appropriate Select Case KeyCode Case vbKeyDown 'Scroll the text up VScrollTextBox Text1, True, False Case vbKeyUp 'Scroll the text down VScrollTextBox Text1, False, False Case vbKeyPageDown 'Scroll the text up VScrollTextBox Text1, True, True Case vbKeyPageUp 'Scroll the text down VScrollTextBox Text1, False, True End Select End Sub Public Sub VScrollTextBox(ByRef TBox As TextBox, _ ByVal ScrollDown As Boolean, ByVal PageMode As Boolean) Dim lParam As Long 'Determine which scroll type to perform If PageMode Then If ScrollDown Then lParam = SB_PAGEDOWN Else lParam = SB_PAGEUP End If Else If ScrollDown Then lParam = SB_LINEDOWN Else lParam = SB_LINEUP End If End If 'Scroll the TextBox Call SendMessage(TBox.hwnd, WM_VSCROLL, lParam, 0) End Sub

What the code does

The Form_Load event adds some text to the TextBox so that you can see how the control behaviour has been modified. It does this by listing all the files in your C:\ directory. If there aren't enough files here to fill the TextBox, modify Form_Load so that it adds some additional lines of text to the TextBox.

Once the project is running, click inside the TextBox. You'll notice that no caret appears, just like when using a web browser or reading an email message. Press the cursor up/down and page up/down keys. The text immediately scrolls in the appropriate direction. You can still select and copy areas of text as normal.

How it works

There are two main elements to this TextBox. The first is to hide the caret when the control gets focus. This stops the flashing insertion point that is normally seen in all Enabled TextBoxes, even if they are locked.

Secondly, the cursor up, cursor down, page up and page down keys are intercepted within the Text1_KeyDown event. These are examined and used to send a WM_SCROLL message to the TextBox, which causes it to immediately scroll in the direction specified. This stops the user from having to continually press the cursor key until the caret (even if it is hidden) reaches the top or bottom of the visible text.

Things to be aware of

When the focus is taken away from a TextBox whose caret is hidden and is then set back to that TextBox, the caret is automatically displayed again. This isn't a problem normally, as the GotFocus event in the TextBox will hide the caret once more. However, if you switch the focus away to another application and then return to your VB form, the GotFocus event will not fire (it only triggers when receiving focus from another control or form within your own VB application). This means that the caret will become visible under these circumstances. Can anyone suggest a nice way to resolve this, without resorting to subclassing?

If you have any comments or suggestions regarding this article, please don't hesitate to contact me.

This article is copyright © Adam Dawes, 2000.