缩放到点不按预期工作

时间:2010-08-16 11:45:15

标签: c# .net winforms

我正在尝试在WinForms中实现一个简单的“缩放到点”功能。当鼠标位于同一点并且鼠标滚轮滚入/滚出时,它的效果很好。当鼠标位置在滚动之间更改时,它会跳转到该位置并且非常不稳定。以下是您可以添加到Form进行测试的控件代码:

public class Canvas : Control
{

    private Bitmap Image;
    private TextureBrush ImageBrush;
    private Point Origin;
    private Matrix TransformMatrix;

    public float ZoomScale
    {
        get;
        set;
    }

    public Canvas()
    {
        this.SetStyle(ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);

        this.Image = // Load your picture here.
        this.ImageBrush = new TextureBrush(this.Image, WrapMode.Clamp);
        this.ZoomScale = 1.0f;

        this.TransformMatrix = new Matrix();

    }

    protected override void OnPaint(PaintEventArgs e)
    {
        float zs = this.ZoomScale;

        var matrix = this.TransformMatrix.Clone();
        e.Graphics.Transform = matrix;

        var c = e.ClipRectangle;

        // Transform the clip rectangle, is this even right?
        var x = (int)Math.Round(c.X / zs - matrix.OffsetX / zs);
        var y = (int)Math.Round(c.Y / zs - matrix.OffsetY / zs);
        var w = (int)Math.Round(c.Width / zs);
        var h = (int)Math.Round(c.Height / zs);

        // Draw the image scaled and translated.
        e.Graphics.FillRectangle(this.ImageBrush, x, y, w - 1, h - 1);

    }

    protected override void OnMouseWheel(MouseEventArgs e)
    {
        if (e.Delta > 0)
        {
            this.ZoomScale += 0.1f;
        }
        else
        {
            this.ZoomScale -= 0.1f;
        }

        this.ZoomToPoint(e.Location);
        this.Refresh();
    }

    private void ZoomToPoint(Point origin)
    {
        this.Origin = origin;
        float zoomScale = this.ZoomScale;

        // The important part.
        var matrix = new Matrix(1, 0, 0, 1, 0, 0);
        matrix.Reset();
        matrix.Translate(-origin.X, -origin.Y, MatrixOrder.Append);
        matrix.Scale(zoomScale, zoomScale, MatrixOrder.Append);
        matrix.Translate(origin.X, origin.Y, MatrixOrder.Append);
        this.TransformMatrix = matrix;
    }

    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        this.ZoomToPoint(this.Origin);
    }

}

所以重要的部分显然是affine transformation。我知道它在Adobe Flex中,但我从this website得到了TranslateScaleTranslate的想法(我正在尝试做的很好的例子)。在我尝试之前,我没有意识到MatrixOrder.Append.NET中的关键。但问题仍然存在。尝试在WinForms应用程序中加载控件,你会明白我的意思。有谁知道这个问题是什么?

编辑:我需要手动计算矩形的原因是因为我将绘制更多而不仅仅是图像。它是一个像Visio一样的画布。我还需要一种转换特定Point的方法。

编辑2 :我知道我可以Invert()使用Matrix然后使用TransformPoints()来获得正确的转换点,但它仍然无法解决鼠标运动不稳定的问题。我正在考虑从图像上角的位置计算Origin,但它不起作用。

1 个答案:

答案 0 :(得分:3)

阿公顷!我找到了!在分析了我发布的链接之后,我意识到“嘿,他没有在任何地方设置”缩放比例“。然后我发现了问题。我每次都在创建一个新的Matrix。这不是正确的方法它应该扩展/翻译当前的转换:

private void ZoomToPoint(float scale, Point origin)
{
    var matrix = this.TransformMatrix;
    matrix.Translate(-origin.X, -origin.Y, MatrixOrder.Append);
    matrix.Scale(scale, scale, MatrixOrder.Append);
    matrix.Translate(origin.X, origin.Y, MatrixOrder.Append);

    this.TransformMatrix = matrix;
}

对此的呼吁就像:

// Zoom in
this.ZoomToPoint(6 / 5.0f, e.Location);

// Zoom out
this.ZoomToPoint(5 / 6.0f, e.Location);