WPF使用Canvas繪製可變矩形

一、問題以及解決辦法

最近由於項目須要,須要實現一個位置校對的功能,大體的需求以下:有一個圖片,有一些位置信息,可是位置信息可能和實際有些誤差,須要作簡單調整,後面會對這張圖片進行切割等,作些處理。(位置信息鏈接起來是一個個小矩形。)git

解決以上問題的大體思路以下:使用canvas進行繪製,把圖片做爲canvas的背景,在canvas上繪製矩形,相似於qq截圖同樣,矩形框能夠使用鼠標拖動調整大小。而後在記下修改後的位置,提供給後面切割圖片使用。目前的關鍵問題就是實現相似qq截圖那樣能夠拖動的矩形github

二、實現的效果預覽


以上是實現的demo的效果。主要由定位點和連線組成。canvas

三、可變矩形實現

  1. 定位點
    定位點主要用於描述在矩形上的小方框,鼠標拖動的事件就是由它觸發,它位置的移動會聯動相關線的移動。


定位點主要是定位點的一些基本屬性和基本方法,主要包括繪製方法,移動方法。
其中:AnchorPointType爲定位點的類型;this

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

draw()方法用於繪製矩形:spa

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);
         }
    如上代碼:
    如上代碼:
    一、按x軸,y軸分類
    二、繪製豎線,橫線
    三、設置定位點
    四、繪製定位點而且添加事件監聽
    五、給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. 定位點聯動

點的聯動,和線的聯動方法相似,可是點的聯動要比線的聯動複雜,主要在如下三個方面:一、點的移動須要聯動中點的聯動。二、在矩形的四個頂點變更時,須要聯動其餘兩個相鄰的頂點,和相鄰兩條線的中點的聯動。三、不一樣的方向點的聯動,不同,會有不少if else。
因爲代碼較長,就不粘貼了,須要源代碼能夠去獲取源代碼。
線中點聯動:線的中點聯動須要考慮,移動的點是否關聯到計算這個中點的兩個點或者一個點,關聯到中點的這兩個點若是有改變,則這個中點就須要改變。主要代碼以下:code

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();
                }
            }
        }

以上爲單個關聯點改變的狀況的代碼,兩個關聯點都變更的代碼和這個相似。orm

四、獲取源代碼

因爲文字表達能力有限,另外說清點和線的關係,特別是點和線的聯動,確實有點困難,若是感興趣的話,強烈建議下載代碼進行調試閱讀。
https://github.com/wangyan9110/ProjectDemos/tree/master/WPFCanvasDemoxml

相關文章
相關標籤/搜索