简体   繁体   中英

how to zoom at a point in picturebox in c#?

This question is asked before but since it doesn't work and my lack of reputation point(I tried to comment at question but I couldn't) I had to ask this question again.

This is the link of the quustion asked before; How to zoom at a point in picturebox

I used the code which is shown in the link but when I run it the point or shape disappear.

here is my code;

public partial class Form1 : Form
{
    private Matrix transform = new Matrix();     
    private double m_dZoomscale = 1.0;    
    public static double s_dScrollValue = .1;
 }
private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        g.Transform = transform;
        Pen mypen = new Pen(Color.Red,5);
        Rectangle rect = new Rectangle(10, 10, 30, 30);
        e.Graphics.DrawRectangle(mypen, rect);
    }
    protected override void OnMouseWheel(MouseEventArgs mea)
    {
        pictureBox1.Focus();
        if (pictureBox1.Focused == true && mea.Delta != 0)
        {
            ZoomScroll(mea.Location, mea.Delta > 0);
        }
    }
      private void ZoomScroll(Point location, bool zoomIn)
    {
        transform.Translate(-location.X, -location.Y);
        if (zoomIn)
            transform.Scale((float)s_dScrollValue, (float)s_dScrollValue);
        else
            transform.Scale((float)-s_dScrollValue, (float)-s_dScrollValue);

        transform.Translate(location.X, location.Y);

        pictureBox1.Invalidate();
    }

The answer you are referencing cannot possibly work. I have no idea why it was accepted, nor up-voted. Except that at some time in the past, I apparently up-voted it as well. I don't know what I was thinking.

Anyway, that code has some problems:

  1. It uses the mouse coordinates passed in directly, rather than converting them to the coordinate system for the PictureBox control. The coordinates passed to the OnMouseWheel() method are relative to the Form itself, so only if the PictureBox top-left coincides with the Form 's upper-left corner would that work.
  2. More problematically, the code is completely misusing the Matrix.Scale() method, passing a value that seems intended to be a delta for the scale, when in fact the Scale() method accepts a factor for the scale. This has two implications:
    • Passing a negative value is wrong, because negative values flip the coordinate system, rather than reducing the scale, and
    • Passing an increment value is wrong, because the value passed will be multiplied with the current scaling to get the new scaling.
  3. Also problematic is that the code applies the matrix transformations in the wrong order, because the default order is "prepend", not "append" (I find the latter more natural to work with, but I assume there's some reason known to those who specialize in matrix math that explains why the default is the former).

There is also the relatively minor issue that, even ignoring the above, allowing the user to adjust the scale factor arbitrarily will eventually lead to an out-of-range value. It would be better for the code to limit the scale to something reasonable.

Here is a version of your code, modified so that it addresses all of these issues:

private Matrix transform = new Matrix();
private float m_dZoomscale = 1.0f;
public const float s_dScrollValue = 0.1f;

public Form1()
{
    InitializeComponent();
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;
    g.Transform = transform;
    Pen mypen = new Pen(Color.Red, 5);
    Rectangle rect = new Rectangle(10, 10, 30, 30);
    e.Graphics.DrawRectangle(mypen, rect);
}

protected override void OnMouseWheel(MouseEventArgs mea)
{
    pictureBox1.Focus();
    if (pictureBox1.Focused == true && mea.Delta != 0)
    {
        // Map the Form-centric mouse location to the PictureBox client coordinate system
        Point pictureBoxPoint = pictureBox1.PointToClient(this.PointToScreen(mea.Location));
        ZoomScroll(pictureBoxPoint, mea.Delta > 0);
    }
}

private void ZoomScroll(Point location, bool zoomIn)
{
    // Figure out what the new scale will be. Ensure the scale factor remains between
    // 1% and 1000%
    float newScale = Math.Min(Math.Max(m_dZoomscale + (zoomIn ? s_dScrollValue : -s_dScrollValue), 0.1f), 10);

    if (newScale != m_dZoomscale)
    {
        float adjust = newScale / m_dZoomscale;
        m_dZoomscale = newScale;

        // Translate mouse point to origin
        transform.Translate(-location.X, -location.Y, MatrixOrder.Append);

        // Scale view
        transform.Scale(adjust, adjust, MatrixOrder.Append);

        // Translate origin back to original mouse point.
        transform.Translate(location.X, location.Y, MatrixOrder.Append);

        pictureBox1.Invalidate();
    }
}

With this code, you will find that no matter where you place the mouse before adjusting the mouse wheel, the rendered image will scale while keeping the point under the mouse fixed in place.


Note:

I took a look at some of the similar questions on Stack Overflow, and there are a few that might also be useful to you. Some of the answers overcomplicate things, in my opinion, but all should work. See:

Zoom To Point Not Working As Expected
Zoom in on a fixed point using matrices
Zooming graphics without scrolling

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM