WPF使用Canvas繪製可變矩形
阿新 • • 發佈:2019-01-05
1、問題以及解決辦法
最近因為專案需要,需要實現一個位置校對的功能,大致的需求如下:有一個圖片,有一些位置資訊,但是位置資訊可能和實際有些偏差,需要做簡單調整,後面會對這張圖片進行切割等,做些處理。(位置資訊連線起來是一個個小矩形。)
解決以上問題的大致思路如下:使用canvas進行繪製,把圖片作為canvas的背景,在canvas上繪製矩形,類似於qq截圖一樣,矩形框可以使用滑鼠拖動調整大小。然後在記下修改後的位置,提供給後面切割圖片使用。目前的關鍵問題就是實現類似qq截圖那樣可以拖動的矩形。
2、實現的效果預覽
以上是實現的demo的效果。主要由定位點和連線組成。
3、可變矩形實現
- 定位點
定位點主要用於描述在矩形上的小方框,滑鼠拖動的事件就是由它觸發,它位置的移動會聯動相關線的移動。
定位點主要是定位點的一些基本屬性和基本方法,主要包括繪製方法,移動方法。
其中: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;
}
- 可變矩形
這部分主要實現繪製矩形功能,主要程式碼如下:
如上程式碼: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事件。
具體程式碼不在貼上了,如果需要程式碼,可以去下載原始碼 - 矩形線聯動
矩形線聯動,主要是以點帶線,通過判斷線是否和動點相關聯,聯動相關的線。主要程式碼如下: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; } } }
- 定位點聯動
點的聯動,和線的聯動方法類似,但是點的聯動要比線的聯動複雜,主要在以下三個方面: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();
}
}
}
以上為單個關聯點改變的情況的程式碼,兩個關聯點都變動的程式碼和這個類似。