System.Windows.Shapes.Line
マウスクリックで直線(Line)を描画
3年前にWindowsFormとVBだったのをWPFとC#で試してみた
クリックしたところを始点(X1,Y1)にして、カーソル位置を終点(X2,Y2)にしている
デザイン画面
C#のコード
using System.Windows;
using System.Windows.Input;
namespace _20180605_クリックで直線ShapeLine
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyCanvas.MouseLeftButtonDown += MyCanvas_MouseLeftButtonDown;
MyCanvas.MouseMove += MyCanvas_MouseMove;
}
private void MyCanvas_MouseMove(object sender, MouseEventArgs e)
{
Point p = e.GetPosition(MyCanvas);
MyLine.X2 = p.X;
MyLine.Y2 = p.Y;
}
private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(MyCanvas);
MyLine.X1 = p.X;
MyLine.Y1 = p.Y;
}
}
}
Lineが残るようにしてみただけ
デザイン画面
C#のコード
using System.Windows;
using System.Windows.Input;
namespace _20180605_クリックで直線ShapeLine2
{
public partial class MainWindow : Window
{
bool IsDraw;
public MainWindow()
{
InitializeComponent();
MyCanvas.MouseLeftButtonDown += MyCanvas_MouseLeftButtonDown;
MyCanvas.MouseMove += MyCanvas_MouseMove;
}
private void MyCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (IsDraw == true)
{
Point p = e.GetPosition(MyCanvas);
MyLine.X2 = p.X;
MyLine.Y2 = p.Y;
}
}
private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(MyCanvas);
if (IsDraw == true)
{
IsDraw = false;
MyLine.X2 = p.X;
MyLine.Y2 = p.Y;
}
else
{
IsDraw = true;
MyLine.X1 = p.X;
MyLine.Y1 = p.Y;
}
}
}
}
System.Windows.Shapes.Path
Pathを使ってクリックした場所を直線で繋いで描画
Lineは1本の直線の図形なので複数の直線は繋げられないようだったので
Pathを使ってみた
C#コード、書き直す前
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace _20180605_クリックで直線PathGeometry
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyCanvas.MouseMove += MyCanvas_MouseMove;
MyCanvas.MouseLeftButtonDown += MyCanvas_MouseLeftButtonDown;
MyCanvas.MouseRightButtonDown += MyCanvas_MouseRightButtonDown;
}
private void MyCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
iPath.Data = null;//PathDataの初期化
}
private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(MyCanvas);
if (iPath.Data == null)
{
MyPathStartPoint(p);//最初のクリック時
}
else
{
//クリックした座標をLineSegmentとして追加する
var pg = (PathGeometry)iPath.Data;
PathFigure pf = pg.Figures[0];
pf.Segments.Add(new LineSegment(p, true));
}
}
//マウス移動時は最後にクリックした点から伸びる線を描画する
private void MyCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (iPath.Data != null)
{
Point p = e.GetPosition(MyCanvas);//マウスカーソル位置
var pg = (PathGeometry)iPath.Data;
PathSegmentCollection psc = pg.Figures[0].Segments;
PathSegment pathSegment = psc[psc.Count - 1];//終端
//SetValueで終端座標を指定(マウスカーソルの位置)
pathSegment.SetValue(LineSegment.PointProperty, p);
}
}
//最初のクリック時にPathのDataになるPathGeometryを作成
//開始点と次点を指定する
private void MyPathStartPoint(Point p)
{
PathFigure pathFigure = new PathFigure();
pathFigure.StartPoint = p;//開始点
//次点をLineSegmentで作成してSegmentsに追加
pathFigure.Segments.Add(new LineSegment(p, true));
PathFigureCollection pathFigureCollection = new PathFigureCollection();
pathFigureCollection.Add(pathFigure);
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures = pathFigureCollection;
//
iPath.Data = pathGeometry;
}
}
}
PathのDataプロパティにPathGeometryを指定
クリックした座標を追加していくところはPathSegmentCollectionで
Pathからたどっていくと
Path.Data
PathGeometry.Figures
PathFigureCollection
PathFigure.Segments
PathSegmentCollection
LineSegment
LineSegmentのPointプロパティにx,y座標を指定してPathSegmentCollectionに追加していく
今見てて思ったのがPathSegmentCollectionは特に作成していないけど、73行目でAddでいいんだなあと、ってことは79行目もFiguresにPathFigureCollectionを指定しているけど、これも直接Addで追加できるのかなと思って
このほうがラクだわ
左クリック時はクリックした座標を追加
マウス移動時は最後にクリックした点から伸びる直線を描画
これが
これの最後にあるLineSegmentの座標を今のマウスカーソルの座標にするので
最後のインデックスはCount-1
これでPathSegmentを取得して、60行目
62行目で座標を指定している、指定するのにSetValueとか分かりづらいのを使っている
今思ったのが、60行目でPathSegmentじゃなくてLineSegmentにキャストして取得すればいいのでは、ってことで書き直して
右クリック時はPath.Dataの消去
C#コード、書き直し後
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace _20180605_クリックで直線PathGeometry
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyCanvas.MouseMove += MyCanvas_MouseMove;
MyCanvas.MouseLeftButtonDown += MyCanvas_MouseLeftButtonDown;
MyCanvas.MouseRightButtonDown += MyCanvas_MouseRightButtonDown;
}
private void MyCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
iPath.Data = null;//PathDataの初期化
}
private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(MyCanvas);
if (iPath.Data == null)
{
MyPathStartPoint(p);//最初のクリック時
}
else
{
//クリックした座標をLineSegmentとして追加する
var pg = (PathGeometry)iPath.Data;
PathFigure pf = pg.Figures[0];
pf.Segments.Add(new LineSegment(p, true));
}
}
//マウス移動時は最後にクリックした点から伸びる線を描画する
private void MyCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (iPath.Data != null)
{
Point p = e.GetPosition(MyCanvas);//マウスカーソル位置
var pg = (PathGeometry)iPath.Data;
PathSegmentCollection psc = pg.Figures[0].Segments;
LineSegment lineSegment = (LineSegment)psc[psc.Count - 1];//終端
//終端座標を指定(マウスカーソルの位置)
lineSegment.Point = p;
}
}
//最初のクリック時にPathのDataになるPathGeometryを作成
//開始点と次点を指定する
private void MyPathStartPoint(Point p)
{
PathFigure pathFigure = new PathFigure();
pathFigure.StartPoint = p;//開始点
//次点をLineSegmentで作成してSegmentsに追加
pathFigure.Segments.Add(new LineSegment(p, true));
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(pathFigure);
//
iPath.Data = pathGeometry;
}
}
}
コード全部
WindowsFormと比べるとWPFは直線一つなら同じ感じだけど、複数の直線を繋げた描画は少しややこしいかなあ、もっとラクな方法ないかしら
参照したところ
ジオメトリの概要 | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/framework/wpf/graphics-multimedia/geometry-overview
方法 : PathGeometry で LineSegment を作成する | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/framework/wpf/graphics-multimedia/how-to-create-a-linesegment-in-a-pathgeometry
関連記事
2015/1/21
マウスクリックでPictureBoxに直線を描くテスト、VisualBasic2013 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/12634284.html