Public Class Form1
Dim DownP As Point Point where mouse went down, in sub panel co-ordinates.
Private Declare Function SetScrollInfo Lib "user32" (ByVal hwnd As Integer, ByVal n As SCROLLBAR_FLAG, ByRef lpcScrollInfo As SCROLLINFO, ByVal bool As Boolean) As Integer
Public Enum SCROLLBAR_FLAG
SB_HORZ = 0
SB_VERT = 1
End Enum
Private HasScroll(SCROLLBAR_FLAG.SB_VERT) As Boolean Flag as to whether the scrollbars are there.
Public Structure Rect
Dim Left As Integer
Dim Top As Integer
Dim Right As Integer
Dim Bottom As Integer
End Structure
Public Enum SCROLLBAR_MASK
SIF_RANGE = &H1S
SIF_PAGE = &H2S
SIF_POS = &H4S
SIF_DISABLENOSCROLL = &H8S
SIF_TRACKPOS = &H10S
End Enum
Public Structure SCROLLINFO
Dim cbSize As Integer
Dim fMask As SCROLLBAR_MASK
Dim nMin As Integer
Dim nMax As Integer
Dim nPage As Integer
Dim nPos As Integer
Dim nTrackPos As Integer
End Structure
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
SetPanelSize()
End Sub
Private Sub Panel1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseDown
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim f As New Panel
f.BackColor = Color.Red
f.Location = New Point(e.X, e.Y)
f.Size = New Size(40, 20)
f.BorderStyle = BorderStyle.FixedSingle
Panel1.Controls.Add(f)
AddHandler f.MouseDown, AddressOf Panel_MouseDown
AddHandler f.MouseMove, AddressOf Panel_MouseMove
SetPanelSize()
ScrollSet()
End If
End Sub
Private Sub Panel_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
If e.Button = Windows.Forms.MouseButtons.Left Then DownP = New Point(e.X, e.Y)
End Sub
Private Sub Panel_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
With DirectCast(sender, Panel)
If .Capture Then
.Location = New Point(.Left + e.X - DownP.X, .Top + e.Y - DownP.Y)
SetPanelSize()
ScrollSet()
End If
End With
End Sub
Private Sub SetPanelSize()
Set the size of the panel to be big enough to contain all sub panels and to fill the client area of the form.
Dim D As Rect
D = GetUsedArea()
If Panel1s left isnt the same as Ds left, then will be adjusting Panel1s left, so need to move _
subpanels to keep them in the same relative positions.
For Each F As Panel In Panel1.Controls
F.Left = F.Left + Panel1.Left - D.Left
F.Top = F.Top + Panel1.Top - D.Top
Next
Panel1.Size = New Size(Math.Max(Me.ClientRectangle.Width, D.Right) - D.Left, Math.Max(Me.ClientRectangle.Height, D.Bottom) - D.Top)
Panel1.Location = New Point(D.Left, D.Top)
End Sub
Private Function GetUsedArea() As Rect
Find the area taken up by the subpanels in co-ordinates relative to the Form.
Dim F As Panel
Dim D As Rect
For Each F In Panel1.Controls
D.Left = Math.Min(D.Left, F.Left + Panel1.Left)
D.Top = Math.Min(D.Top, F.Top + Panel1.Top)
D.Right = Math.Max(D.Right, F.Right + Panel1.Left)
D.Bottom = Math.Max(D.Bottom, F.Bottom + Panel1.Top)
Next
GetUsedArea = D
End Function
Private Sub ScrollSet()
Dim Dirn As SCROLLBAR_FLAG
For Dirn = SCROLLBAR_FLAG.SB_HORZ To SCROLLBAR_FLAG.SB_VERT
Dim SBI As SCROLLINFO
Set up or hide horizontal and vertical scrollbars as necessary.
With SBI
.cbSize = Len(SBI)
.fMask = SCROLLBAR_MASK.SIF_RANGE Or SCROLLBAR_MASK.SIF_POS Or SCROLLBAR_MASK.SIF_PAGE
.nMax = IIf(Dirn = SCROLLBAR_FLAG.SB_HORZ, Panel1.Width, Panel1.Height)
.nPage = IIf(Dirn = SCROLLBAR_FLAG.SB_HORZ, Me.ClientRectangle.Width, Me.ClientRectangle.Height)
If .nPage <> .nMax Then
.nPos = -IIf(Dirn = SCROLLBAR_FLAG.SB_HORZ, Panel1.Left, Panel1.Top)
Else
.nMax = 0
.nPage = 0
.nPos = 0
End If
SetScrollInfo(Me.Handle.ToInt32, Dirn, SBI, True)
If HasScroll(Dirn) <> (.nPage <> .nMax) Then
HasScroll(Dirn) = (.nPage <> .nMax)
SetPanelSize() ClientRectangle size will have changed so better reset things.
Panel1.Invalidate() otherwise bits of scrollbar seem to get left lying around.
For Each F As Panel In Panel1.Controls
F.Invalidate()
Next
End If
End With
Next
End Sub
Private Sub Form1_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) Handles Me.Scroll
Dim Dirn As SCROLLBAR_FLAG
Dirn = IIf(e.ScrollOrientation = ScrollOrientation.HorizontalScroll, SCROLLBAR_FLAG.SB_HORZ, SCROLLBAR_FLAG.SB_VERT)
If HasScroll(Dirn) Then stupid event continues to fire even after the scrollbar has been removed, so have to check for this.
If Dirn = SCROLLBAR_FLAG.SB_HORZ Then
Panel1.Left = -e.NewValue
Else
Panel1.Top = -e.NewValue
End If
SetPanelSize()
ScrollSet()
End If
End Sub
Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
SetPanelSize()
ScrollSet()
End Sub
Private Sub Form1_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseWheel
If HasScroll(SCROLLBAR_FLAG.SB_VERT) Then
Form1_Scroll(sender, New ScrollEventArgs(ScrollEventType.SmallIncrement, Me.VerticalScroll.Value - CInt(e.Delta / 12), ScrollOrientation.VerticalScroll))
ElseIf HasScroll(SCROLLBAR_FLAG.SB_HORZ) Then
Form1_Scroll(sender, New ScrollEventArgs(ScrollEventType.SmallIncrement, Me.VerticalScroll.Value - CInt(e.Delta / 12), ScrollOrientation.HorizontalScroll))
End If
End Sub
End Class