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

lonelyxmas lonelyxmas     2022-12-22     380

关键词:

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

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

咋看起来,实现这个功能也不是很难, ScaleTransform类里面定义了CenterXCenterY两个属性就是用来设置缩放的原点坐标的。将这两个属性分别赋予鼠标的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;

       

鼠标缩放实现,以鼠标位置为中心 [算法]

】鼠标缩放实现,以鼠标位置为中心[算法]【英文标题】:Mousescaleimplementation,centeredtomouseposition[Algorithmic]【发布时间】:2022-01-2106:41:13【问题描述】:如何实现鼠标位置的放大/缩小中心?例如(在一维示例中)Cthepositionofthecenter... 查看详情

以鼠标位置为中心的图像缩放

】以鼠标位置为中心的图像缩放【英文标题】:Imagezoomcenteredonmouseposition【发布时间】:2015-07-1204:47:29【问题描述】:我正在用Fabric.js编写一个脚本来在当前鼠标位置缩放图像。我已经取得了一些进展,但是某处出现了错误。案... 查看详情

winform如何实现鼠标位置获取picturebox的焦点,然后焦点放大

...谷歌地图的那种效果,不过我用的几个东西很简单,在panel里面放一张图片,然后滚动鼠标滑轮,通过获取鼠标当前在图片上的位置,实现图片在鼠标焦点放大缩小,具体要用到哪些类,麻烦各位帮忙解决一下,现在我急需在pannel里面放一... 查看详情

鼠标位置上的 WPF 缩放画布中心

】鼠标位置上的WPF缩放画布中心【英文标题】:WPFZoomCanvasCenteronMousePosition【发布时间】:2018-03-0712:59:28【问题描述】:<utils:ScrollViewerx:Name="ImageViewer"VerticalScrollBarVisibility="Auto"HorizontalScrollBarVisibility="Auto"Grid.Row="2"Current 查看详情

【缩放】实现svg以鼠标为焦点缩放

...ght控制缩放。在当前视窗内,改变viewBox的width与height即可实现以左上角为原点的缩放,故只需计算以左上角为焦点缩放后和以鼠标位置为焦点缩放后两个原点的偏移量即可。后文不再赘述scale与viewbox的关系。以鼠标位置为基准计... 查看详情

wpf精修篇缩放scaletransform

...p;ScaleY Y轴缩小值正常为1 CenterY,CenterX 中心点位置设置中心点会按照中心点位置缩小 这里做效果一个张图片  左侧设置了缩小中心点默认为左上角 右侧设置了中心点为XY各为100 在缩小会发生位置变... 查看详情

MapView 以用户坐标为中心缩放

...时间】:2012-11-1206:58:58【问题描述】:我有一个显示用户位置的地图视图。用户位置显示为地图视图的中心。但是当地图视图放大时,我必须将用户位置显示为中心。但目前它并没有显示出来。用户位置远离中心。即使地图被缩... 查看详情

wpf实现鼠标拖动控件并带有中间动效(代码片段)

一.前提要实现鼠标对控件的拖拽移动,首先必须知道下面几点:WPF中的鼠标左键按下、鼠标移动事件,有时候通过XAML界面添加的时候并有没有作用;如果在移动时候要持续修改控件的属性,我们通过改变RenderTransform来修改呈现... 查看详情

如何以特定位置为中心然后缩放到当前位置

】如何以特定位置为中心然后缩放到当前位置【英文标题】:HowdoIcenteroveraspecificlocationandthenzoomtocurrentlocation【发布时间】:2011-09-0222:33:07【问题描述】:这里是新手,请原谅我的无知。我花了一些时间试图了解我错过了什么,... 查看详情

鼠标滚轮时的oxyplot轴锁定中心

】鼠标滚轮时的oxyplot轴锁定中心【英文标题】:oxyplotaxislockingcenterwhenmousewheel【发布时间】:2017-05-2417:42:24【问题描述】:我是wpf和oxyPlot的新手。现在,我想创建一个像示波器一样的动态折线图,但是我不知道如何在鼠标滚轮... 查看详情

在放大的图像上查找缩放中心坐标

...2021-01-1215:20:56【问题描述】:我正在尝试在图像上实现以鼠标光标为中心的放大/缩小。为简单起见,假设我只需要在水平轴上放大/缩小。我使用Qt和QPainter来绘制我的场景,并使用QWidget::mouseWheelEvent覆盖来计算缩放因子和缩放位... 查看详情

qwt 在重新缩放或缩放光标后绘制移动曲线

...:21【问题描述】:我在绘图中有一条经典曲线,我想通过鼠标滚轮事件在光标位置设置缩放。为此,我想:设置重新缩放:QwtPlotMagnifier::rescale(factor);(这已经完成并且有效)将绘图的中心设置为光标的位置(我可以在这部分、... 查看详情

为啥 WPF 中的鼠标位置不正确,而缩放桌面上的 Winforms 则不正确?

】为啥WPF中的鼠标位置不正确,而缩放桌面上的Winforms则不正确?【英文标题】:WhyismousepositionincorrectinWPFandnotWinformsonscaleddesktops?为什么WPF中的鼠标位置不正确,而缩放桌面上的Winforms则不正确?【发布时间】:2021-09-0417:24:33【... 查看详情

关于wpf中popup跟随鼠标移动显示

最近在做一个画图工具,里面有一个功能是需要实现,当鼠标移动的时候在,鼠标的旁边显示坐标信息。第一反应是想到了tooltip,但是tooltip有许多的限制,查询资料的过程中看到了popup,popup比tooltip更加灵活,下面讲讲tooltip跟p... 查看详情

WPF 控件是不是可以以其父控件为中心,但也可以仅使用 xaml 尊重其兄弟控件的位置?

...其父控件为中心,但也可以仅使用xaml尊重其兄弟控件的位置?【英文标题】:CanaWPFcontrolbecenteredarounditsparentbutalsorespectthepositionofitssiblingcontrolusingxamlonly?WPF控件是否可以以其父控件为中心,但也可以仅使用xaml尊重其兄弟控件的位... 查看详情

c#wpf实现任意控件拖动(代码片段)

...件拖动(本章)第四章窗口拖动第五章附加属性实现任意拖动文章目录系列文章目录前言一、如何实现?1.注册鼠标事件2.记录位置3.跟随鼠标移动4.恢复标识二、示例总结前言在《C#wpf实现Grid内控件拖动》和《C#wpf实... 查看详情

画图放大镜怎么缩小

...工具,在绘图空间拖拉出一个框,将要放大的图形包括在里面,再点击一下鼠标,这个框就会充满整个视窗显示,图形就被放大了。点击 查看详情

使用ivx实现通过角标调整图片的经验总结

...做一个调整图片的demo,要求能够通过拖动图片的角标来实现旋转和等比放缩的操作,核心设计思路就是通过鼠标移动的位置和图片原位置的坐标进行数学计算,重新设置图片的宽高、坐标和旋转角度等属性。一.布局案例中图片... 查看详情