| | |
How do I zoom to a target point and update the scrollbars in C#?
Please support our C# advertiser: Intel Parallel Studio Home
![]() |
•
•
Join Date: Feb 2009
Posts: 2
Reputation:
Solved Threads: 0
Hello,
I am attempting to develop a custom control that allows the user to
zoom to a specific point on an image, typically a map. The problem
that I am having is when I attempt to adjust the scrollbar position,
the update of the image is very jerky. For example, in the code below,
when the user selects a point on the image, the image is zoomed in on
the point and the scroll bar position is updated to the new origin of
the viewport. When the image is updated, it appears to be drawn at its
original position and scale, then the control's OnPaint method is
called and the image is drawn correctly. This gives the appearance of
the image moving left and up before snapping to the zoomed point. The
problem seems to be exacerbated when double buffering is enabled. Has
anyone else experienced this?
Here's the example code:
I am attempting to develop a custom control that allows the user to
zoom to a specific point on an image, typically a map. The problem
that I am having is when I attempt to adjust the scrollbar position,
the update of the image is very jerky. For example, in the code below,
when the user selects a point on the image, the image is zoomed in on
the point and the scroll bar position is updated to the new origin of
the viewport. When the image is updated, it appears to be drawn at its
original position and scale, then the control's OnPaint method is
called and the image is drawn correctly. This gives the appearance of
the image moving left and up before snapping to the zoomed point. The
problem seems to be exacerbated when double buffering is enabled. Has
anyone else experienced this?
Here's the example code:
C# Syntax (Toggle Plain Text)
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Drawing.Imaging; using System.Drawing.Drawing2D; using System.Drawing; namespace Zoom { public class ZoomPoint : ScrollableControl { enum ZoomDirection { In, Out } #region Private Data private float _zoom = 1.0f; private PointF _origin = new PointF(0, 0); private Image _image = null; #endregion public ZoomPoint() { SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.OptimizedDoubleBuffer, true); SetStyle(ControlStyles.ResizeRedraw, true); this.AutoScroll = true; UpdateScroll(); } public Image Image { get { return _image; } set { _image = value; _origin = PointF.Empty; _zoom = 1.0F; UpdateScroll(); Invalidate(); } } protected override void OnPaintBackground(PaintEventArgs e) { // don't allow the background to be painted } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; ClearBackground(g); float dx = -_origin.X; float dy = -_origin.Y; g.Transform = new Matrix(_zoom, 0, 0, _zoom, dx, dy); g.FillRectangle(Brushes.Blue, 100, 100, 5, 5); DrawImage(g); } private void ClearBackground(Graphics g) { g.Clear(SystemColors.Window); } protected override void OnScroll(ScrollEventArgs se) { base.OnScroll(se); if (se.ScrollOrientation == ScrollOrientation.HorizontalScroll) { _origin.X += se.NewValue - se.OldValue; } else { _origin.Y += se.NewValue - se.OldValue; } Invalidate(); } protected override void OnMouseWheel(MouseEventArgs e) { if (e.Delta > 0) { ZoomToPoint(e.Location, ZoomDirection.In); } else { ZoomToPoint(e.Location, ZoomDirection.Out); } Invalidate(); } protected override void OnMouseClick(MouseEventArgs e) { ZoomToPoint(e.Location, ZoomDirection.In); Invalidate(); } private void UpdateScroll() { if (_image != null) { Size scrollSize = new Size( (int)Math.Round(_image.Width * _zoom), (int)Math.Round(_image.Height * _zoom)); Point position = new Point( (int)Math.Round(_origin.X), (int)Math.Round(_origin.Y)); this.AutoScrollMinSize = scrollSize; this.AutoScrollPosition = position; } else { this.AutoScrollMargin = this.Size; } } private void ZoomToPoint(Point viewPoint, ZoomDirection direction) { // get the model point PointF modelPoint = ToModelPoint(viewPoint); if (direction == ZoomDirection.In) { // Increase the zoom _zoom *= 1.25F; } else { // decrease the zoom _zoom *= .75F; } // calculate the new origin _origin.X = (modelPoint.X * _zoom) - viewPoint.X; _origin.Y = (modelPoint.Y * _zoom) - viewPoint.Y; UpdateScroll(); } private PointF ToModelPoint(Point viewPoint) { PointF modelPoint = new PointF(); modelPoint.X = (_origin.X + viewPoint.X) / _zoom; modelPoint.Y = (_origin.Y + viewPoint.Y) / _zoom; return modelPoint; } private void DrawImage(Graphics g) { if (null != _image) { // set the transparency color for the image ImageAttributes attr = new ImageAttributes(); attr.SetColorKey(Color.White, Color.White); Rectangle destRect = new Rectangle(0, 0, _image.Width, _image.Height); g.DrawImage(_image, destRect, 0, 0, _image.Width, _image.Height, GraphicsUnit.Pixel, attr); } } protected override void Dispose(bool disposing) { if (disposing) { if (null != _image) { _image.Dispose(); _image = null; } } base.Dispose(disposing); } }
•
•
Join Date: Aug 2008
Posts: 1,735
Reputation:
Solved Threads: 186
Well
Rather than the code, you need to take the zoom and work out the new size of the scrollbar.. as what is now subject to the scrollbar is no longer the same size.
Rather than the code, you need to take the zoom and work out the new size of the scrollbar.. as what is now subject to the scrollbar is no longer the same size.
Did I just hear "You gotta help us, Doc. We've tried nothin' and we're all out of ideas" ? Is this you? Dont let this be you! I will put in as much effort as you seem to.
•
•
Join Date: Feb 2009
Posts: 2
Reputation:
Solved Threads: 0
I don't think I see what you mean. The size of the srollbar, or the AutoScrollMinSize, is calculated as the zoomed image size. That part seems to work fine. The scroll position is then set to the origin of the viewport, which seems to be exactly where I want it. But when I do set the position, there seems to be a major flicker.
After some experiments, I found that If I perform the following steps, I don't get the same flicker.
1. Call ZoomToPoint
2. Set the AutoScrollMinSize property based on the scaled image size
3. Call Invalidate
4. Set the AutoScrollPosition property to the origin.
After some experiments, I found that If I perform the following steps, I don't get the same flicker.
1. Call ZoomToPoint
2. Set the AutoScrollMinSize property based on the scaled image size
3. Call Invalidate
4. Set the AutoScrollPosition property to the origin.
![]() |
Similar Threads
- Help with automatic update problem and more (Viruses, Spyware and other Nasties)
Other Threads in the C# Forum
- Previous Thread: WPF Animations
- Next Thread: Recursive Combinators
| Thread Tools | Search this Thread |
.net access algorithm array backup barchart bitmap box broadcast buttons c# check checkbox client clock combobox control conversion csharp custom database datagrid datagridview dataset datetime degrees developer development draganddrop drawing dynamiccreation encryption enum excel file form format forms function gdi+ hospitalmanagementsystems httpwebrequest image index input install interface java label list listbox mandelbrot math microsystems mouseclick mysql operator password path photoshop picturebox pixelinversion post priviallages. programming property radians regex remoting richtextbox running... serialization server sleep soap socket sql sqlserver stack statistics stream string table temperature text textbox thread time timer update usercontrol validation visualstudio webbrowser windows windowsformsapplication winforms wpf write xml






