• WPF使用Canvas绘制可变矩形


    1、问题以及解决的方法

    近期由于项目须要。须要实现一个位置校对的功能,大致的需求例如以下:有一个图片,有一些位置信息。可是位置信息可能和实际有些偏差。须要做简单调整,后面会对这张图片进行分割等,做些处理。

    (位置信息连接起来是一个个小矩形。)

    解决以上问题的大致思路例如以下:使用canvas进行绘制,把图片作为canvas的背景,在canvas上绘制矩形,类似于qq截图一样,矩形框能够使用鼠标拖动调整大小。然后在记下改动后的位置,提供给后面分割图片使用。眼下的关键问题就是实现类似qq截图那样能够拖动的矩形

    2、实现的效果预览


    以上是实现的demo的效果。

    主要由定位点和连线组成。

    3、可变矩形实现

    1. 定位点
      定位点主要用于描写叙述在矩形上的小方框,鼠标拖动的事件就是由它触发,它位置的移动会联动相关线的移动。


    定位点主要是定位点的一些基本属性和基本方法,主要包含绘制方法,移动方法。
    当中:AnchorPointType为定位点的类型;

        public enum AnchorPointType
        {
            /// <summary>
            /// 上下
            /// </summary>
            NS,
            /// <summary>
            /// 左右
            /// </summary>
            WE,
            /// <summary>
            /// 右上
            /// </summary>
            NE,
            /// <summary>
            /// 左下
            /// </summary>
            SW,
            /// <summary>
            /// 右下
            /// </summary>
            NW,
            /// <summary>
            /// 左上
            /// </summary>
            SE
        }
    

    draw()方法用于绘制矩形:

            public Rectangle Draw() 
            {
                double offset = this.Width / 2;
                Rectangle retc = new Rectangle()
                {
                    Margin = new Thickness(this.X - offset, this.Y - offset, 0, 0),
                    Width = this.Width,
                    Height = this.Height,
                    Fill = Brushes.LightGoldenrodYellow,
                    Stroke = Brushes.Black,
                    StrokeThickness = 1,
                    DataContext = this.Key
                };
                this.retc = retc;
                return retc;
            }
    

    move()方法用户改变定位点位置

            public void Move(double x,double y)
            {
                double offset = this.Width / 2;
                this.retc.Margin = new Thickness(x-offset,y-offset,0,0);
                this.X = x;
                this.Y = y;
            }
    
    1. 可变矩形
      这部分主要实现绘制矩形功能,主要代码例如以下:
          public void Init()
           {
               //按x轴分类
               IEnumerable<IGrouping<double, Point>> pointXs = points.GroupBy(o => o.X);
               //按y周分类
               IEnumerable<IGrouping<double, Point>> pointYs = points.GroupBy(o => o.Y);
               //绘制竖线
               DrawXLine(pointXs);
               //绘制横线
               DrawYLine(pointYs);
               //设置定位点
               AddAnchorPoints();
               //绘制定位点而且加入事件
               foreach (AnchorPoint anchorPoint in anchorPoints)
               {
                   Rectangle rec=anchorPoint.Draw();
                   rec.MouseLeftButtonDown += new MouseButtonEventHandler(rec_MouseLeftButtonDown);
                   rec.MouseMove += new MouseEventHandler(rec_MouseMove);
                   canvas.Children.Add(rec);
               }
               //canvas加入事件
               canvas.MouseLeftButtonUp += new MouseButtonEventHandler(canvas_MouseLeftButtonUp);
               canvas.MouseMove += new MouseEventHandler(canvas_MouseMove);
               canvas.MouseLeave += new MouseEventHandler(canvas_MouseLeave);
           }
      
      如上代码:
      如上代码:
      1、按x轴,y轴分类
      2、绘制竖线,横线
      3、设置定位点
      4、绘制定位点而且加入事件监听
      5、给canvas加入事件
      给每一个定位点加入鼠标MouseMove和MouseLeftButtonDown事件,给canvas加入MouseMove,MouseLeave,MouseLeftButtonUp事件。


      详细代码不在粘贴了,假设须要代码。能够去下载源码

    2. 矩形线联动
      矩形线联动,主要是以点带线,通过推断线是否和动点相关联,联动相关的线。主要代码例如以下:
           private void MoveLines(double x, double y)
           {
               List<Line> moveLines = new List<Line>();
               moveLines = lines.Where(o => o.Y1 == curAnchorPoint.Y
                   || o.Y2 == curAnchorPoint.Y
                   || o.X1 == curAnchorPoint.X
                   || o.X2 == curAnchorPoint.X).ToList();
               foreach (Line line in moveLines)
               {
                   if (line.Y1 == curAnchorPoint.Y)
                   {
                       line.Y1 = y;
                   }
                   if (line.Y2 == curAnchorPoint.Y)
                   {
                       line.Y2 = y;
                   }
                   if (line.X1 == curAnchorPoint.X)
                   {
                       line.X1 = x;
                   }
                   if (line.X2 == curAnchorPoint.X)
                   {
                       line.X2 = x;
                   }
               }
           }
      
    3. 定位点联动

    点的联动,和线的联动方法类似,可是点的联动要比线的联动复杂,主要在下面三个方面:1、点的移动须要联动中点的联动。

    2、在矩形的四个顶点变动时,须要联动其它两个相邻的顶点,和相邻两条线的中点的联动。3、不同的方向点的联动。不一样,会有非常多if else。
    因为代码较长,就不粘贴了。须要源码能够去获取源码。


    线中点联动:线的中点联动须要考虑,移动的点是否关联到计算这个中点的两个点或者一个点,关联到中点的这两个点假设有改变。则这个中点就须要改变。主要代码例如以下:

            private void MoveRefAnchorPoint(double x, double y,AnchorPoint movedAnchorPoint)
            {
                foreach (AnchorPoint anchorPoint in anchorPoints)
                {
                    if (anchorPoint.RefPoint.Length == 2)
                    {
                        if (anchorPoint.RefPoint[0].X == x && anchorPoint.RefPoint[0].Y == y)
                        {
                            anchorPoint.RefPoint[0].X = movedAnchorPoint.X;
                            anchorPoint.RefPoint[0].Y = movedAnchorPoint.Y;
                        }
                        else if (anchorPoint.RefPoint[1].X == x && anchorPoint.RefPoint[1].Y == y)
                        {
                            anchorPoint.RefPoint[1].X = movedAnchorPoint.X;
                            anchorPoint.RefPoint[1].Y = movedAnchorPoint.Y;
                        }
                        anchorPoint.X = (anchorPoint.RefPoint[0].X + anchorPoint.RefPoint[1].X) / 2;
                        anchorPoint.Y = (anchorPoint.RefPoint[0].Y + anchorPoint.RefPoint[1].Y) / 2;
                        anchorPoint.Move();
                    }
                }
            }
    

    以上为单个关联点改变的情况的代码,两个关联点都变动的代码和这个类似。

    4、获取源码

    因为文字表达能力有限。另外说清点和线的关系。特别是点和线的联动。确实有点困难。假设感兴趣的话,强烈建议下载代码进行调试阅读。


    https://github.com/wangyan9110/ProjectDemos/tree/master/WPFCanvasDemo


  • 相关阅读:
    微软的权限框架Asp.Net Identity
    排序算法
    在线编辑器
    It's only too late if you decide it is. Get busy living, or get busy dying(转)
    一个程序员的四年经历反思(转)
    wamp的安装使用(转)
    JDBC连接数据库经验技巧(转)
    重写ResultSet实现分页功能(最好的分页技术)(转)
    import android.provider.Telephony cannot be resolved
    linux-多线程
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5220586.html
Copyright © 2020-2023  润新知