DukeSilver
DukeSilver

Reputation: 748

Get two VBA textboxes to scroll together

I have a macro that produces two multi-line TextBoxes of related data (sometimes hundreds of rows long). The boxes always have the same number of lines of text in them, with each line corresponding to the adjacent line in the other TextBox. I looked into using a two-column ListBox, but decided to use TextBoxes so that the data can be copied out/highlighted/selected as desired by the user.

I want to make it so that if a user scrolls down, both TextBoxes scroll together (i.e., the lines stay synced up).

Upvotes: 0

Views: 1721

Answers (1)

DukeSilver
DukeSilver

Reputation: 748

After much digging and experimenting, I figured it out! By adding a ScrollBar, I was able to use the ScrollBar_Change() event to adjust the text boxes. On my form, I now have two TextBoxes and a ScrollBar object. Then I have a few necessary subs in my Userform code:

'This constant affects whether the ScrollBar appears or _
   not, as well as some of the movement graphics of the _
   ScrollBar.
'This MUST be reset if the TextBoxes are resized
'I made it a UserForm-level Const because I use it _
   elsewhere, but it could also live in SetUpScrollBar
Private Const TEXTBOX_MAX_LINES_IN_VIEW as Long = 21

Private Sub SetUpScrollBar()
'I call this whenever I show my Userform (happens after a _
   separate macro determines what to put in the TextBoxes). _
   It determines whether the ScrollBar should be shown, and _
   if so, sets the .Max property so it scrolls in accordance _
   to the number of lines in the TextBoxes.

    Dim linesInTextBox as Long

    With Me.TextBox1
        .SetFocus
        linesInTextBox = .LineCount - 1 
        'Need to subtract 1 or you'll get an error _
           when dragging the scroll bar all the way down.
    End With

    'If there are fewer lines than the max viewing area, hide the scroll bar.
    Select Case linesInTextBox > TEXTBOX_MAX_LINES_IN_VIEW
    Case is = True
        ShowScrollBar True
        With Me.ScrollBox
            .Min = 0 'I believe this is the default, but I set it just in case
            .Max = maxLinesInTextBox
            .Value = 0
        End With
    Case is = False
        ShowScrollBar False
    End Select
End Sub

Private Sub ShowScrollBar(show As Boolean)
'A simple way of showing or hiding the scrollbar
    With Me.ScrollBar1
        .Enabled = show
        .Visible = show
    End With
End Sub

Private Sub ScrollBar1_Change()
'When the scrollbar position changes (either by dragging _
   the slider or by clicking it), set the CurLine property _
   of each TextBox to the current ScrollBar value.

    With Me.TextBox1
        'Need to set focus to the box to get or adjust the CurLine property
        .SetFocus
        .CurLine = Me.ScrollBar1.value
    End With

    With Me.TextBox2
        'Need to set focus to the box to get or adjust the CurLine property
        .SetFocus
        .CurLine = Me.ScrollBar1.value
    End With 
End Sub



This seems to work quite well for my purposes. It allows me to keep the text-selecting/copying benefits of using TextBoxes while keeping my data synced together.

Some issues I've yet to solve:

  • Scrolling works fine, but if you try to click the arrows (particularly to go in the opposite direction that you just scrolled), you have to click until your cursor gets to the top of the TextBoxes. For me, this is 21 clicks. A bit annoying, but I'm sure there's a workaround.
  • Scrolling is not live like with a normal scrollbar. This means you can drag the scrollbar, but it won't update the TextBoxes until you let go.
  • If a user clicks into a TextBox and starts to navigate with their arrow keys, the two boxes will become out of sync. They'll resync the next time the user clicks the ScrollBar. This is very problematic if the user tries to select more lines than are visible in the window: one TextBox will scroll as they drag their selection but the other TextBox stays in place

Upvotes: 1

Related Questions