Recompute Panel AutoScrollPosition after zoom

2019-03-01 12:09发布

Have C# forms application with PictureBox embedded in Panel, to take advantage of Panel AutoScroll as suggested in other posts when image and thus PictureBox need to be scrolled horizontally or vertically. Want to zoom the image and recompute AutoScrollPosition to keep same Point visible after zooming. Can double size of PictureBox, then recopy source image, accomplishing zoom. But AutoScrollPosition remains unchanged, thus what was visible before zoom has moved off screen. How to recompute AutoScrollPosition to keep image focus after zoom?

1条回答
在下西门庆
2楼-- · 2019-03-01 12:44

There are three typical types of zooming:

  1. zoom into the center, triggered by zoom buttons
  2. zoom into the mouse position, triggered by clicking or scroll-wheeling
  3. zoom into a rectangle, by drawing a rectangle

I assume the typical setup: A PictureBox set to SizeMode=Zoom nested in a Panel with AutoScroll=true and zooming that takes care to keep the aspect ratios of Image and PictureBox equal.

Let's start by introducing terminology:

  • There is an Image we call bitmap and
  • it is displayed by a PictureBox; let's call it canvas..
  • .. which is nested in a Panel we call frame

User-friendly zooming needs a fixed point, that is a point that shall stay put.

For 1) it is the center of the frame, for 2) it is the mouse location and for 3) it is the center of the rectangle.

Before zooming we calculate the old zoom ratio, the fixed point in the frame, the fixed point in the canvas and finally the fixed point in the bitmap.

After zoming we calculate the new zoom ratio and the new fixed point in the canvas. Finally we use it to move the canvas to bring the fixed canvas point to the fixed frame point.


Here is an example for zooming into the (current) center; it is a common click event for two buttons and it only doubles and halves the zoom ratio.

Much finer grained factors are of course simple to implement; even better is a fixed list of zoom levels, like Photoshop has!

private void zoom_Click(object sender, EventArgs e)
{
    PictureBox canvas = pictureBox1;
    Panel frame = panel1;

    // Set new zoom level, depending on the button
    float zoom = sender == btn_ZoomIn ? 2f : 0.5f;

    // calculate old ratio:
    float ratio = 1f * canvas.ClientSize.Width / canvas.Image.Width;
    // calculate frame fixed pixel:
    Point fFix = new Point( frame.Width / 2,  frame.Height / 2);
    // calculate the canvas fixed pixel:
    Point cFix =  new Point(-canvas.Left + fFix.X, -canvas.Top + fFix.Y );
    // calculate the bitmap fixed pixel:
    Point iFix = new Point((int)(cFix.X / ratio),(int)( cFix.Y / ratio));

    // do the zoom
    canvas.Size = new Size( (int)(canvas.Width *  zoom), (int)(canvas.Height *  zoom) );

    // calculate new ratio:
    float ratio2 = 1f * canvas.ClientSize.Width / canvas.Image.Width;
    // calculate the new canvas fixed pixel:
    Point cFix2 = new Point((int)(iFix.X * ratio2),(int)( iFix.Y * ratio2));
    // move the canvas:
    canvas.Location = new Point(-cFix2.X + fFix.X, -cFix2.Y + fFix.Y);
}

Note that while one can try to restore the relative AutoScrollValues this is not only hard, because their values are a little quirky but it is also won't be adaptable to the other zoom types.

查看更多
登录 后发表回答