您的位置:首页 > 其它

WPF/Silverligh实现图片的放大缩小拖动

2016-05-16 11:41 501 查看


实现功能如下

以滚轮中心点对图片容器进行放大和缩小
对放大后的图片进行拖动
对拖动的范围进行控制

由于在后续的功能中需要动态加载不同的图片,所以此示例中是针对grid的放大和缩小,图片是自动填充的!

本人头脑比较笨,用最简单的原理来实现的,实现原理如下:


1.放大操作



假设我们要对(1.5,1.5)这个点为中心进行放大,那么放大1倍后,应该是矩形2的位置,需要将(3,3)的点移动到原来点的位置,需要将矩形2向上移动1.5,向左移动1.5

ScaleTransform放大1倍,TranslateTransform移动为(-1.5,-1.5).得出如下图所示




2.移动后放大,放大后移动再放大等情况

看下图的情况:我们将矩形1向左移动1个单位后,再放大1倍



当我们点击相对于原点(2.5,1.5)的点时,实际上我们想放大的是相对于矩形1(1.5,1.5)的点!那么我们首先利用矩阵的逆变换得到相对于矩形1的点。然后对矩形1的点(1.5,1.5)进行放大1倍的处理,重复步骤1(放大操作)。



然后再计算出(2.5,1.5)与逆变换后(1.5,1.5)的偏移距离,将TranslateTransform再次移动(1,0)。即得到所要的矩形2,如下图



下面是实现的代码:

界面层,我使用grdMap来作为变换的对象,grdMap的内容为1.jpg图片(也可以是其他控件等各类元素)。这里使用grdRelative作为参照物(起到原点的作用,原始图片位置)。注意里面的元素数据绑定,可以做到自适应屏幕,所有宽度和高度不指定。slider可用可不用,自己修改。

[html] view
plain copy

<Window x:Class="WpfMap.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="MainWindow"

Height="350"

Width="525">

<Grid x:Name="grd">

<Grid x:Name="grdRelative"

HorizontalAlignment="Center"

VerticalAlignment="Center"

Width="{Binding ActualWidth, ElementName=grdMap}"

Height="{Binding ActualHeight, ElementName=grdMap}"></Grid>

<Grid x:Name="grdMap"

MouseWheel="grdMap_MouseWheel"

MouseLeave="grdMap_MouseLeave"

MouseDown="grdMap_MouseDown"

MouseUp="grdMap_MouseUp"

MouseMove="grdMap_MouseMove"

HorizontalAlignment="Center"

VerticalAlignment="Center"

RenderTransformOrigin="0,0">

<Grid.RenderTransform>

<TransformGroup>

<ScaleTransform ScaleX="{Binding Value, ElementName=slider}"

ScaleY="{Binding Value, ElementName=slider}" />

<SkewTransform />

<RotateTransform />

<TranslateTransform />

</TransformGroup>

</Grid.RenderTransform>

<Image Source="1.jpg" />

</Grid>

<Slider x:Name="slider"

HorizontalAlignment="Left"

VerticalAlignment="Center"

Orientation="Vertical"

Width="20"

Height="200"

Maximum="3"

Minimum="1" />

</Grid>

</Window>

后台代码:

[csharp] view
plain copy

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace WpfMap

{

/// <summary>

/// MainWindow.xaml 的交互逻辑

/// </summary>

public partial class MainWindow : Window

{

public MainWindow()

{

InitializeComponent();

this.Loaded += new RoutedEventHandler(MainWindow_Loaded);

}

ScaleTransform st;

TranslateTransform tt;

TransformGroup group;

bool isDrag = false;

Point startPoint;

void MainWindow_Loaded(object sender, RoutedEventArgs e)

{

group = (TransformGroup)grdMap.RenderTransform;

st = group.Children[0] as ScaleTransform;

tt = group.Children[3] as TranslateTransform;

}

private void grdMap_MouseWheel(object sender, MouseWheelEventArgs e)

{

var point = e.GetPosition(grdRelative); // 实际点击的点

var actualPoint = group.Inverse.Transform(point); // 想要缩放的点

slider.Value = slider.Value + (double)e.Delta / 1000;

tt.X = -((actualPoint.X * (slider.Value - 1))) + point.X - actualPoint.X;

tt.Y = -((actualPoint.Y * (slider.Value - 1))) + point.Y - actualPoint.Y;

}

private void grdMap_MouseDown(object sender, MouseButtonEventArgs e)

{

isDrag = true;

startPoint = e.GetPosition(grdRelative);

}

private void grdMap_MouseUp(object sender, MouseButtonEventArgs e)

{

isDrag = false;

}

private void grdMap_MouseLeave(object sender, MouseEventArgs e)

{

isDrag = false;

}

private void grdMap_MouseMove(object sender, MouseEventArgs e)

{

if (isDrag)

{

Point p = e.GetPosition(grdRelative);

Point topPoint = grdMap.TranslatePoint(new Point(0, 0), grdRelative);

Point bottomPoint = grdMap.TranslatePoint(new Point(grdMap.ActualWidth, grdMap.ActualHeight), grdRelative);

double moveX = p.X - startPoint.X;

double moveY = p.Y - startPoint.Y;

//向上向下移动条件判断(会有一点点的小偏移,如果想更精确的控制,那么分向上和向下两种情况,并判断边距)

if ((moveY < 0 && bottomPoint.Y > grdRelative.ActualHeight) || (moveY > 0 && topPoint.Y < 0))

{

tt.Y += (p.Y - startPoint.Y);

startPoint.Y = p.Y;

}

//向左向右移动条件判断

if ((moveX < 0 && bottomPoint.X > grdRelative.ActualWidth) || (moveX > 0 && topPoint.X < 0))

{

tt.X += (p.X - startPoint.X);

startPoint.X = p.X;

}

}

}

}

}

代码很简单,也没有写过多的注释!

下载代码需要2个积分,其实以上的代码段已经包含所有代码了!

以下是源码地址,vs2010,可直接运行!

http://download.csdn.net/detail/wuwo333/5308725
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: