rbulph Posted November 2, 2005 Posted November 2, 2005 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? Quote
Administrators PlausiblyDamp Posted November 3, 2005 Administrators Posted November 3, 2005 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. Quote Posting Guidelines FAQ Post Formatting Intellectuals solve problems; geniuses prevent them. -- Albert Einstein
rbulph Posted November 3, 2005 Author Posted November 3, 2005 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. Quote
Leaders snarfblam Posted November 3, 2005 Leaders Posted November 3, 2005 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. Quote [sIGPIC]e[/sIGPIC]
rbulph Posted December 12, 2005 Author Posted December 12, 2005 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 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.