我正在尝试在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得到了Translate
,Scale
,Translate
的想法(我正在尝试做的很好的例子)。在我尝试之前,我没有意识到MatrixOrder.Append
是.NET
中的关键。但问题仍然存在。尝试在WinForms应用程序中加载控件,你会明白我的意思。有谁知道这个问题是什么?
编辑:我需要手动计算矩形的原因是因为我将绘制更多而不仅仅是图像。它是一个像Visio一样的画布。我还需要一种转换特定Point
的方法。
编辑2 :我知道我可以Invert()
使用Matrix
然后使用TransformPoints()
来获得正确的转换点,但它仍然无法解决鼠标运动不稳定的问题。我正在考虑从图像上角的位置计算Origin
,但它不起作用。
答案 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);