在WPF里面实现以鼠标位置为中心缩放移动图片

原文:在WPF里面实现以鼠标位置为中心缩放移动图片

在以前的文章使用WPF Resource以及Transform等技术实现鼠标控制图片缩放和移动的效果里面,介绍了如何在WPF里面移动和放大缩小图片,程序也支持使用滚轮的方式缩放图片。然而前面文章里介绍的缩放功能只能以图片中心为原点来实现,但是这种功能往往并不是客户想要的,我们看图片的时候,往往都喜欢以鼠标放在图片的焦点为原点进行图片的缩放。

咋看起来,实现这个功能也不是很难, ScaleTransform类里面定义了CenterX和CenterY两个属性就是用来设置缩放的原点坐标的。将这两个属性分别赋予鼠标的X, Y坐标值,就可以实现对原始图片,以鼠标位置为原点缩放图片了。但是,请注意,我说的原始图片是指没有移动之前的图片,如果图片缩放并且移动了,再次缩放的时候,就是另外一个故事了。

画个图说明一下吧,比如下图里面右下方方块是一个WPF程序里面的一个图片,大小是40 x 40,里面的黑点是预备缩放的原点,假设黑点的坐标是(10, 10),在运行程序的时候,用户首先将方块移动到左边的位置,当然原点(黑点)也移动了,假如这个时候图片移动了50个像素。

接着用户在移动后的位置上,将图片缩放,比如说放大了2倍,这个操作也会移动原点(黑点)在最终图片的位置。因为放大图片,实际上就是将原始图片的各个像素移动到新的位置(红点),这个时候,新的原点(红点)的坐标应该是(20, 20),相邻两个像素的空间使用插值的方法填充。这个时候,

ScaleTransform.ScaleX = 2;

ScaleTransform.ScaleY = 2;

这个时候,用户打算放大图片当中的另外一个区域,再放大一倍(即放大到原图的3倍),下图里是蓝点,假设坐标是(50, 50),因为无论图片缩放与否,用户只会以他在实际图片看到的内容来判断新的缩放焦点:

如果我们直接盲目地将ScaleTransform的各个属性设置为类似下面的值的话:

ScaleTransform.ScaleX = 3;

ScaleTransform.ScaleY = 3;

ScaleTransform.CenterX = 50;

ScaleTransform.CenterY = 50;

就发生问题了, 因为ScaleX = 3表示新图是原图的3倍,然而我们的原点却是在2倍图片上设置的—原图的大小只有40 x 40。解决方案当然是将蓝点的位置转换回在原始图片的位置,注意原始图片应该是下图右下方的图片,而不是左边的—用户最初已经移动了图片。

看起来转换起来有点麻烦,不过WPF提供了一个 函数TransformGroup.Inverse,可以把转换后图片上的坐标转换会在原始图片的坐标。当然啦,如果你熟悉图形学和线性代数的话,实际上,图片的缩放和移动就是将原始图片乘上一个矩阵,而TransformGroup.Inverse函数就是执行矩阵求逆操作。

下面就是关键代码:

XAML代码:

<Grid.Resources>

<TransformGroup x:Key="ImageCompareResources">

<ScaleTransform />

<TranslateTransform/>

</TransformGroup>

</Grid.Resources>

<ScrollViewer HorizontalScrollBarVisibility="Disabled"

VerticalScrollBarVisibility="Disabled" Grid.Row="0" Grid.Column="0" x:Name="MasterScrollViewer" Margin="5" Background="WhiteSmoke">

<ContentControl x:Name="TestContentControl1"

MouseLeftButtonDown="MasterImage_MouseLeftButtonDown"

MouseLeftButtonUp="MasterImage_MouseLeftButtonUp"

MouseMove="MasterImage_MouseMove"

MouseWheel="MasterImage_MouseWheel">

<Image RenderOptions.BitmapScalingMode="NearestNeighbor"

x:Name="MasterImage" Source="{Binding Path=MasterImagePath}" Stretch="Uniform"

RenderTransform="{StaticResource ImageCompareResources}"/>

</ContentControl>

</ScrollViewer>

C#代码:

private void MasterImage_MouseWheel(object sender, MouseWheelEventArgs e)

{

ContentControl image = sender as ContentControl;

if (image == null)

{

return;

}

TransformGroup group = ImageComparePanel.FindResource("ImageCompareResources") as TransformGroup;

Debug.Assert(group != null, "Can‘t find transform group from image compare panel resource");

Point point = e.GetPosition(image);

double scale = e.Delta * 0.001;

ZoomImage(group, point, scale);

}

private static void ZoomImage(TransformGroup group, Point point, double scale)

{

Debug.Assert(group != null, "Oops, ImageCompareResources is removed from current control‘s resouce");

Point pointToContent = group.Inverse.Transform(point);

ScaleTransform transform = group.Children[0] as ScaleTransform;

if (transform.ScaleX + scale < 1)

{

return;

}

transform.ScaleX += scale;

transform.ScaleY += scale;

TranslateTransform transform1 = group.Children[1] as TranslateTransform;

transform1.X = -1 * ((pointToContent.X * transform.ScaleX) - point.X);

transform1.Y = -1 * ((pointToContent.Y * transform.ScaleY) - point.Y);

}

private void MasterImage_MouseMove(object sender, MouseEventArgs e)

{

ContentControl image = sender as ContentControl;

if (image == null)

{

return;

}

if (this.isMouseLeftButtonDown && e.LeftButton == MouseButtonState.Pressed)

{

this.DoImageMove(image, e.GetPosition(image));

}

}

private void DoImageMove(ContentControl image, Point position)

{

TransformGroup group = ImageComparePanel.FindResource("ImageCompareResources") as TransformGroup;

Debug.Assert(group != null, "Can‘t find transform group from image compare panel resource");

TranslateTransform transform = group.Children[1] as TranslateTransform;

transform.X += position.X - this.previousMousePoint.X;

transform.Y += position.Y - this.previousMousePoint.Y;

this.previousMousePoint = position;

}

原文地址:https://www.cnblogs.com/lonelyxmas/p/9473607.html

时间: 2024-10-09 22:39:40

在WPF里面实现以鼠标位置为中心缩放移动图片的相关文章

以鼠标位置为中心缩放平移图片(图片map)

最近一个项目使用一张图片实现地图类似的效果,即图片以鼠标位置为中心缩放.平移:通过度娘搜索找到几个版本,最终下面这个版本真正实现该功能:具体代码是网上Copy的,若有版权或其他问题,请联系我予以处理,有不当之处,请原作者原谅. <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>移动缩放图片</title>

WPF,强制捕获鼠标事件,鼠标移出控件外依然可以执行强制捕获的鼠标事件

在WPF中,只有鼠标位置在某个控件上的时候才会触发该控件的鼠标事件.例如,有两个控件都注册了MouseDown和MouseUp事件,在控件1上按下鼠标,不要放开,移动到控件2上再放开.在这个过程中,控件1只会触发MouseDown事件,而控件2则只会触发MouseUp事件,鼠标不在控件上他们就收不到对应的鼠标事件.同样的如果某个控件注册了MouseMove事件,当鼠标移动到控件外之后,控件将不会接收到MouseMove事件.但是在很多情况下我们需要在鼠标移动到控件外之后还能接收鼠标事件.例如按住

MFC的OnMouseMove移动位置和OnMouseWheel缩放实现

1. 基本作用 OnMouseMove响应鼠标移动时间 OnMouseWheel响应鼠标中键的滚动 2. 参数说明 afx_msgvoidOnMouseMove(UINTnFlags, CPointpoint); nFlags说明:指示虚拟按键是否按下 ,此参数可以是任何下列值的组合 MK_CONTROL 当CTRL键按下时 MK_LBUTTON 当鼠标左键按下时 MK_MBUTTON 当鼠标中键按下时(滚动不属于按下) MK_RBUTTON 当鼠标右键按下时. MK_SHIFT 当SHIFT按

WPF 程序鼠标在窗口之外的时候,控件拿到的鼠标位置在哪里?

原文:WPF 程序鼠标在窗口之外的时候,控件拿到的鼠标位置在哪里? 在 WPF 程序中,我们有 Mouse.GetPosition(IInputElement relativeTo) 方法可以拿到鼠标当前相对于某个 WPF 控件的位置,也可以通过在 MouseMove 事件中通过 e.GetPosition(IInputElement relativeTo) 方法拿到同样的信息.不过,在任意时刻去获取鼠标位置的时候,如果鼠标在窗口之外,将获取到什么点呢? 本文将介绍鼠标在窗口之外时获取到的鼠标位

如何获取鼠标位置

获取鼠标位置,首先需要加载js文件: 然后设置一个div,给定大小: 最后进行具体操作: //首先要先设置一个div,给定大小 <div id="m"></div> //进行操作 <script type="text/javascript"> var x,y,T,L; T=$("#m").offset().top;//div离开左端的距离 L=$("#m").offset().left;//

C++获取鼠标位置及全局检测鼠标行为

1.获取鼠标位置(在屏幕的位置)  CPoint m_mouse; GetCursorPos(&m_mouse); 2. 屏幕转化为客户端(控件的相对位置)& 客户端位置转化为屏幕位置 ClientToScreen(this->m_hwnd,m_mouse);  //客户端位置转化为屏幕位置 ScreenToClient(this->m_hwnd,m_mouse) ;  //屏幕转化为客户端 3.获取控件关于在屏幕的位置 CRect  rc GetWindowRect(&

鼠标位置(跨浏览器)

一.鼠标事件属性 1.clientX,clientY 相对于可见视点(visual viewport)的鼠标位置,即当前浏览器显示区域(窗口)的位置,点击客户端矿口的左上角时 clientX 和 clientY 都为0,即使用户拖动了水平或垂直滚动条 document.onclick=function(e){ var event=e||window.event; console.log(event.clientX+","+ event.clientY); } 2.screenX,scr

JS魔法堂:关于元素位置和鼠标位置的属性

一.关于鼠标位置的属性   1. 触发鼠标事件的区域 盒子模型中的border,padding,content区域会触发鼠标事件,点击margin区域将不触发鼠标事件.   2. 鼠标事件对象MouseEvent下的属性 [a].  evt.pageX/Y :以页面左上角为参考点,表示当前触发点离页面左上角的水平和垂直距离. 注意:1. IE5.5~8不支持该属性,polyfill方法pageX = clientX + scrollLeft 2. 页面左上角并不是指html或body标签的盒子模

js获取浏览器宽高、网页宽高、屏幕宽高、鼠标位置等(带图片说明)

网页可见区域宽: document.body.clientWidth;网页可见区域高: document.body.clientHeight;(点击查看大图) 网页可见区域宽: document.body.offsetWidth (包括边线的宽);网页可见区域高: document.body.offsetHeight (包括边线的宽);(点击查看大图)有没有发现,offsetWidth和clientWidth的区别,offsetWidt是连滚动条一起包含在内的. 网页正文全文宽: documen