What's New
Q & A
Tip Jar
C# Helper...
Follow VBHelper on Twitter
MSDN Visual Basic Community
TitleMake a scrolled window that the user can drag with the mouse (as Adobe Acrobat Reader does)
Keywordsscrolled window, drag, drag window, Adobe Acrobat Reader, Acrobat Reader, Acrobat
CategoriesControls, Graphics
Create a horizontal scroll bar named VBar, a vertical scroll bar named HBar, and a PictureBox named picOuter. Inside picOuter, create another PictureBox named picInner. The program scrolls the picture by moving picInner inside picOuter.

Set picInner.AutoSize = True, picInner.BorderStyle = None, and picOuter.BorderStyle = Fixed Single.

The most interesting part of the program is subroutine ArrangeScrollBars. It begins by determining how much room the picture needs and how much room is available. It compares the available width with the needed width to see if the horizontal scroll bar is needed.

Next the routine compares the available height with the needed height to see if the vertical scroll bar is necessary. If it is, that scroll bar takes up some of the available width so the routine checks again to see if the horizontal scroll bar is needed.

The subroutine then positions picOuter, and either hides or positions the scroll bars as appropriate. It sets the scroll bars' Max property to the maximum amount it will need to move the picture during scrolling. It sets LargeChange to the area visible. If the user clicks beside the scroll bar thumb, the picture moves by its visible width or height.

' Arrange the scroll bars.
Private Sub ArrangeScrollBars()
Dim have_wid As Single
Dim have_hgt As Single
Dim need_wid As Single
Dim need_hgt As Single
Dim need_hbar As Boolean
Dim need_vbar As Boolean

    ' Don't bother if we're minimized.
    If WindowState = vbMinimized Then Exit Sub

    ' See how much room we need and
    ' how much room we have.
    need_wid = picInner.Width + (picOuter.Width - _
    need_hgt = picInner.Height + (picOuter.Height - _
    have_wid = ScaleWidth
    have_hgt = ScaleHeight

    ' See which scroll bars we need.
    need_hbar = (need_wid > have_wid)
    If need_hbar Then have_hgt = have_hgt - HBar.Height

    need_vbar = (need_hgt > have_hgt)
    If need_vbar Then
        ' This takes away a little width so we
        ' might need the horizontal scroll bar now.
        have_wid = have_wid - VBar.Width
        If Not need_hbar Then
            need_hbar = (need_wid > have_wid)
            If need_hbar Then have_hgt = have_hgt - _
        End If
    End If

    ' Position the outer PictureBox leaving room
    ' for the scroll bars.
    picOuter.Move 0, 0, have_wid, have_hgt

    ' Position or hide the scroll bars.
    If need_hbar Then
        HBar.Move 0, have_hgt, have_wid
        HBar.Min = 0
        HBar.Max = picOuter.ScaleWidth - picInner.Width
        HBar.LargeChange = picOuter.ScaleWidth
        HBar.SmallChange = picOuter.ScaleWidth / 5
        HBar.Visible = True
        HBar.Visible = False
    End If

    If need_vbar Then
        VBar.Move have_wid, 0, VBar.Width, have_hgt
        VBar.Min = 0
        VBar.Max = picOuter.ScaleHeight - picInner.Height
        VBar.LargeChange = picOuter.ScaleHeight
        VBar.SmallChange = picOuter.ScaleHeight / 5
        VBar.Visible = True
        VBar.Visible = False
    End If
End Sub
After this setup, the scrolling is easy. The scroll bars use their values to move picInner inside picOuter.
Private Sub HBar_Change()
    picInner.Left = HBar.Value
End Sub

Private Sub HBar_Scroll()
    picInner.Left = HBar.Value
End Sub

Private Sub VBar_Change()
    picInner.Top = VBar.Value
End Sub

Private Sub VBar_Scroll()
    picInner.Top = VBar.Value
End Sub
To allow the user to drag the image, the picInner control tracks mouse events. The MouseDown event sets m_Dragging = True to indicate that a drag is in progress. It also saves the mouse's current position.

The MouseMove event handler determines how far the mouse has been dragged horizontally and vertically, and updates the scroll bar values appropriately. The scroll bars adjust the image's position.

The MouseUp event handler sets m_Dragging = False to indicate that a drag is no longer in progress.

Private m_Dragging As Boolean
Private m_X As Single
Private m_Y As Single

Private Sub picInner_MouseDown(Button As Integer, Shift As _
    Integer, X As Single, Y As Single)
    m_Dragging = True
    m_X = X
    m_Y = Y
End Sub

Private Sub picInner_MouseMove(Button As Integer, Shift As _
    Integer, X As Single, Y As Single)
Dim new_hbar As Single
Dim new_vbar As Single

    If Not m_Dragging Then Exit Sub

    new_hbar = HBar.Value + (X - m_X)
    If new_hbar < HBar.Max Then new_hbar = HBar.Max
    If new_hbar > HBar.Min Then new_hbar = HBar.Min
    HBar.Value = new_hbar

    new_vbar = VBar.Value + (Y - m_Y)
    If new_vbar < VBar.Max Then new_vbar = VBar.Max
    If new_vbar > VBar.Min Then new_vbar = VBar.Min
    VBar.Value = new_vbar
End Sub

Private Sub picInner_MouseUp(Button As Integer, Shift As _
    Integer, X As Single, Y As Single)
    m_Dragging = False
End Sub
Note that you cannot store an arbitrarily large image in picInner. In that case, you will need to display only the piece of the scrolled area that should be visible. It is also more efficient to draw that area for some pictures such as maps that are more easily drawn than stored in a picture.

For more information on this type of scrolling and other image display issues, see my book Visual Basic Graphics Programming.

Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.