How to use ScrollableControl with AutoScroll parameter for false

I have a custom control that scales a custom canvas of a document.

I tried using AutoScroll but did not give satisfactory results. When I set AutoScrollPosition and AutoScrollMinSize in the opposite direction (in any order), it will cause paint and cause jitter with every zooming. I assume this was because it was causing the update, not invalidate, when I changed both properties.

Now I manually set the HorizontalScroll and VerticalScroll properties with AutoScroll set to false , so every time I change the zoom level or client size:

int canvasWidth = (int)Math.Ceiling(Image.Width * Zoom) + PageMargins.Horizontal; int canvasHeight = (int)Math.Ceiling(Image.Height * Zoom) + PageMargins.Vertical; HorizontalScroll.Maximum = canvasWidth; HorizontalScroll.LargeChange = ClientSize.Width; VerticalScroll.Maximum = canvasHeight; VerticalScroll.LargeChange = ClientSize.Height; if (canvasWidth > ClientSize.Width) { HorizontalScroll.Visible = true; } else { HorizontalScroll.Visible = false; HorizontalScroll.Value = 0; } if (canvasHeight > ClientSize.Height) { VerticalScroll.Visible = true; } else { VerticalScroll.Visible = false; VerticalScroll.Value = 0; } int focusX = (int)Math.Floor((FocusPoint.X * Zoom) + PageMargins.Left); int focusY = (int)Math.Floor((FocusPoint.Y * Zoom) + PageMargins.Top); focusX = focusX - ClientSize.Width / 2; focusY = focusY - ClientSize.Height / 2; if (focusX < 0) focusX = 0; if (focusX > canvasWidth - ClientSize.Width) focusX = canvasWidth - ClientSize.Width; if (focusY < 0) focusY = 0; if (focusY > canvasHeight - ClientSize.Height) focusY = canvasHeight - ClientSize.Height; if (HorizontalScroll.Visible) HorizontalScroll.Value = focusX; if (VerticalScroll.Visible) VerticalScroll.Value = focusY; 

In this case, a FocusPoint is a PointF structure that contains the coordinates in the bitmap that the user is focusing on (for example, when the mouse wheel focuses on the current mouse at that time to zoom in). This feature works for the most part.

What doesn't work is scrollbars. If the user tries to scroll manually by clicking on the scroll bar, they will both return to 0. I do not set them anywhere in my code. I tried to write the following in the OnScroll () method:

 if (se.ScrollOrientation == ScrollOrientation.VerticalScroll) { VerticalScroll.Value = se.NewValue; } else { HorizontalScroll.Value = se.NewValue; } Invalidate(); 

But this leads to some very erratic behavior, including clicking and scrolling out of bounds.

How should I write code for OnScroll? I tried base.OnScroll but didn't do anything while AutoScroll is set to false.

+6
source share
1 answer

As a result, I created my own scrolling by creating 3 child controls: HScrollBar, VScrollBar and panel.

I hide ClientSize and ClientRectangle as follows:

 public new Rectangle ClientRectangle { get { return new Rectangle(new Point(0, 0), ClientSize); } } public new Size ClientSize { get { return new Size( base.ClientSize.Width - VScrollBar.Width, base.ClientSize.Height - HScrollBar.Height ); } } 

The layout is executed in OnClientSizeChanged:

 protected override void OnClientSizeChanged(EventArgs e) { base.OnClientSizeChanged(e); HScrollBar.Location = new Point(0, base.ClientSize.Height - HScrollBar.Height); HScrollBar.Width = base.ClientSize.Width - VScrollBar.Width; VScrollBar.Location = new Point(base.ClientSize.Width - VScrollBar.Width, 0); VScrollBar.Height = base.ClientSize.Height - HScrollBar.Height; cornerPanel.Size = new Size(VScrollBar.Width, HScrollBar.Height); cornerPanel.Location = new Point(base.ClientSize.Width - cornerPanel.Width, base.ClientSize.Height - cornerPanel.Height); } 

Each ScrollBar has its own Scroll event, subscribed to the following:

 private void ScrollBar_Scroll(object sender, ScrollEventArgs e) { OnScroll(e); } 

And finally, we can allow MouseWheel events to scroll with the following:

 protected override void OnMouseWheel(MouseEventArgs e) { int xOldValue = VScrollBar.Value; if (e.Delta > 0) { VScrollBar.Value = (int)Math.Max(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), 0); OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll)); } else { VScrollBar.Value = (int)Math.Min(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), VScrollBar.Maximum - (VScrollBar.LargeChange - 1)); OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll)); } } 

For custom painting you should use the following instruction:

 e.Graphics.TranslateTransform(-HScrollBar.Value, -VScrollBar.Value); 

This worked perfectly without crashing when using AutoScroll.

+3
source

Source: https://habr.com/ru/post/913968/


All Articles