WPF 中Canvas图形移动缩放代码

Posted windspiral

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF 中Canvas图形移动缩放代码相关的知识,希望对你有一定的参考价值。

从Flash转C#,很多内容一知半解,边摸索边前进,代码粗糙,权当留个脚印。

只是想得到一个基础的移动和缩放功能的界面,找了很久都是画线、画矩形等基础形状的代码,移动和缩放说的并不清晰,只能自己努力来解决一下。

素材准备:

WPF项目的屏幕上放一个Canvas控件,名称为canvas1。

代码如下:

  1 using System;
  2 using System.Windows;
  3 using System.Windows.Media;
  4 using System.Windows.Input;
  5 using System.Windows.Shapes;
  6 using System.Windows.Controls;
  7 
  8 namespace WpfcanvasDrawing
  9 {
 10     /// <summary>
 11     /// MainWindow.xaml 的交互逻辑
 12     /// </summary>
 13     public partial class MainWindow : Window
 14     {
 15         //移动标志
 16         bool isMoving = false;
 17         //鼠标按下去的位置
 18         Point startMovePosition;
 19 
 20         TranslateTransform totalTranslate = new TranslateTransform();
 21         TranslateTransform tempTranslate = new TranslateTransform();
 22         ScaleTransform totalScale = new ScaleTransform();
 23         Double scaleLevel = 1;
 24 
 25         public MainWindow()
 26         {
 27             InitializeComponent();
 28 
 29             canvas1.Focusable = true;//重要:默认条件下不接收鼠标事件
 30 
 31             DrawingLine(new Point(100, 100), new Point(300, 200));
 32             DrawingLine(new Point(100, 200), new Point(300, 100));
 33         }
 34 
 35         private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
 36         {
 37             //问题一:点击窗口最大化按钮时未能改变Canvas尺寸
 38             //if (this.WindowState == WindowState.Maximized) {}
 39             canvas1.Width = this.Width;
 40             canvas1.Height = this.Height;  
 41           
 42         }
 43 
 44         protected void DrawingLine(Point startPt, Point endPt)
 45         {
 46             LineGeometry myLineGeometry = new LineGeometry();
 47             myLineGeometry.StartPoint = startPt;
 48             myLineGeometry.EndPoint = endPt;
 49 
 50             Path myPath = new Path();
 51             myPath.Stroke = Brushes.Black;
 52             myPath.StrokeThickness = 1;
 53             myPath.Data = myLineGeometry;
 54 
 55             canvas1.Children.Add(myPath);
 56         }
 57 
 58         private void canvas1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 59         {
 60             // code A:
 61             //FrameworkElement element = sender as FrameworkElement;
 62             //startMovePosition = e.GetPosition(element);
 63             // code B:
 64             startMovePosition = e.GetPosition((Canvas)sender);
 65             isMoving = true;
 66         }
 67 
 68         private void canvas1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
 69         {
 70             isMoving = false;
 71             Point endMovePosition = e.GetPosition((Canvas)sender);
 72 
 73             //为了避免跳跃式的变换,单次有效变化 累加入 totalTranslate中。           
 74             totalTranslate.X += (endMovePosition.X - startMovePosition.X)/scaleLevel;
 75             totalTranslate.Y += (endMovePosition.Y - startMovePosition.Y)/scaleLevel;           
 76         }
 77 
 78         private void canvas1_MouseMove(object sender, MouseEventArgs e)
 79         {
 80             if (isMoving)
 81             {
 82                 Point currentMousePosition = e.GetPosition((Canvas)sender);//当前鼠标位置
 83                 
 84                 Point deltaPt = new Point(0, 0);               
 85                 deltaPt.X = (currentMousePosition.X - startMovePosition.X) /scaleLevel;                
 86                 deltaPt.Y = (currentMousePosition.Y - startMovePosition.Y) /scaleLevel;
 87                 
 88                 tempTranslate.X = totalTranslate.X + deltaPt.X;
 89                 tempTranslate.Y = totalTranslate.Y + deltaPt.Y;
 90 
 91                 adjustGraph();
 92             }
 93         }        
 94         
 95         private void canvas1_MouseWheel(object sender, MouseWheelEventArgs e)
 96         {
 97             Point scaleCenter = e.GetPosition((Canvas)sender);
 98 
 99             if (e.Delta > 0)
100             {
101                 scaleLevel *= 1.08;
102             }
103             else
104             {
105                 scaleLevel /= 1.08;
106             }
107             //Console.WriteLine("scaleLevel: {0}", scaleLevel);
108 
109             totalScale.ScaleX = scaleLevel;
110             totalScale.ScaleY = scaleLevel;
111             totalScale.CenterX = scaleCenter.X;
112             totalScale.CenterY = scaleCenter.Y;
113 
114             adjustGraph();
115         }
116        
117         private void adjustGraph()
118         {
119             TransformGroup tfGroup = new TransformGroup();
120             tfGroup.Children.Add(tempTranslate);
121             tfGroup.Children.Add(totalScale);
122 
123             foreach (UIElement ue in canvas1.Children)
124             {
125                 ue.RenderTransform = tfGroup;
126             }
127         }
128 
129     }
130 }

 

变量说明:

     //移动标志
        bool isMoving = false;
        //鼠标按下去的位置
        Point startMovePosition;

        TranslateTransform totalTranslate = new TranslateTransform();//多次操作中需要对总的移动量进行统计。
        TranslateTransform tempTranslate = new TranslateTransform();//单次移动过程中根据鼠标位置实时更新。
        ScaleTransform totalScale = new ScaleTransform();//缩放变量
        Double scaleLevel = 1;//缩放的级别

函数功能说明:
DrawingLine 在指定的Canvas控件中画线,用于测试。
Window_SizeChanged 屏幕大小变更时,调整Canvas的大小。
鼠标按下时,记录起始移动的位置点,标记拖动操作开始 isMoving = true。
鼠标移动过程中,对位置进行刷新,使用临时变量 tempTranslate 记录当前移动的距离。
鼠标抬起过程中,将有效的移动距离记录到总移动变量 totalTranslate 当中。
鼠标滚轮变化时,根据滚轮方向调整
缩放级别。

不同缩放级别下,屏幕中移动相同的距离,对于Canvs内的图形来说距离不同,因此需要对鼠标移动的距离进行修正,即将移动距离除以缩放级别,这样可以得到相对精确的移动位置。

遗留问题:
1、缩放后移动时,仍会有较小的抖动,细节处理上还有瑕疵。
2、窗口最大化按钮点击后,无法捕获相关事件,导致canvas1不能同时放大,请各位高手帮忙指点一下,谢谢!

以上是关于WPF 中Canvas图形移动缩放代码的主要内容,如果未能解决你的问题,请参考以下文章

canvas变换(移动,缩放等)

UnityPC端:缩放移动画面

Java AWT 图形界面编程使用鼠标滚轮放大缩小 Canvas 画布 ( 鼠标滚轮事件监听器 MouseWheelListener )

2021-09-17 WPF上位机 23-动态图形

canvas API总结

JS中canvas画布绘制中如何实现缩放,位移,旋转