Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Is the Autoscroll facility for forms and panels any good? I notice two problems with it straightaway - it doesn't show up if a control is off the left or top of the container, only if it is off the right or bottom, and if a partly obscured control gets focus it scrolls into view, which I don't really like.

 

Is there a way to fix these or should I forget it and use my own scrollbars?

  • Administrators
Posted

Why would you want a control to have focus and not be scrolled into view? As a user I couldn't think of anything more annoying than having to constantly scroll around to find the control with focus.

Admittedly not showing the scroll bars when items are to the left is a bad thing but why would you have a starting point with items alread off the left handside?

Personally if I have aform with a lot of controls I would use a tab control and organise the layout into a more structured form rather than relying on the autoscroll mechanism.

Posting Guidelines FAQ Post Formatting

 

Intellectuals solve problems; geniuses prevent them.

-- Albert Einstein

Posted
The form is an MDI child form. The MDI form has resizable panels. The controls can be moved around by the user in the child form to better see the relationship between them. So there are two ways that they could be obscured - by the user moving them or the user resizing the panels. Maybe the fact that they scroll into view when they get focus is acceptable, but the fact that no scrollbar shows when they are off at the left is definitely not.
  • Leaders
Posted
Maybe the fact that they scroll into view when they get focus is acceptable' date=' but the fact that no scrollbar shows when they are off at the left is definitely not.[/quote']

I would have to agree with you. My best advice: when a control is moved, check its coordinates. If it is off to the left, move everything to the right. If it is above the top, move everything down. It's that or implement your own scrolling.

[sIGPIC]e[/sIGPIC]
  • 1 month later...
Posted

Figured out a way to do this. You just need a form with a single Panel on it at design time. The Panel should be undocked and neither it nor the form should have AutoScroll on. Any comments welcome.

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 Panel1's left isn't the same as D's left, then will be adjusting Panel1's 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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...