総合 ゲーム 画像動画

WPF Canvasにマウスで図形を描画する方法

今回はキャンバス内にマウスで図形を描画する方法を紹介します。オブジェクトの選択などを行うときに視覚的に分かりやすくするために使えます。


 

概要とソースコード

ソースコード

xamlとコードはGithubの方で公開しています。
https://github.com/kame-chan/WPF/tree/master/DrawCanvasWithMouse

 

概要

マウスの左クリックを押している間にマウスの位置に対応した図形を描画します。

このプログラムから学べること

  • マウスと図形の位置取得
  • 動的な描画
  • 既存の描画コントロールの削除

マウスの始点と終点を取得できるのでCanvas上にあるコントロールを複数選択することも可能です。今回は紹介しませんが既存のコントロールもリストへ格納しておくと良い。

WPF Canvas内の要素を複数選択する方法

 

 

コード解説

MainWindow.xaml.cs

private Point init; //マウスクリック時の初期位置
private bool isDrag; //ドラッグ判定
private List<UIElement> canvasStock = new List<UIElement>(); //再描画する際に既存のパスを消す用の格納リスト

// パスを描画する
private void DrawRectangle(Point p)
{
    text1.Text = "X:"+ init.X.ToString() +"-"+ p.X.ToString() +" Y:"+ init.Y.ToString() + "-" + p.Y.ToString();
    var canvas = canvas1 as Canvas;

    //既存のパスを削除
    foreach (UIElement ui in canvasStock)
    {
        canvas1.Children.Remove(ui);
    }

    //描画用パス
    Rectangle rect = new Rectangle();
    double width;
    double height;
    rect.Stroke = new SolidColorBrush(Colors.Red);
    rect.StrokeThickness = 1;
    width = Math.Abs(init.X - p.X);
    height = Math.Abs(init.Y - p.Y);
    rect.Width = width;
    rect.Height = height;

    //マウスの位置により配置を変える
    if (init.X < p.X)
    {                
        Canvas.SetLeft(rect, init.X);
    }
    else
    {
        Canvas.SetLeft(rect, p.X);
    }

    if (init.Y < p.Y)
    {                
        Canvas.SetTop(rect, init.Y);
    }
    else
    {
        Canvas.SetTop(rect, p.Y);
    }

    //キャンバスの子と削除用に格納するのを忘れずに
    canvas1.Children.Add(rect);
    canvasStock.Add(rect);
}

こちらはマウス移動時のイベントで呼ぶ関数です。

レクタングルで四角形を作り、横幅や高さ線の色を指定します。線の太さThicknessもお忘れなく。描画用のパスはキャンバスの子としてツリーへ登録するのと、キャンバス内に位置をしていして配置する必要があります。

SetLeftSetTopで配置、
canvas1.Children.Add(rect)でツリーへ登録しています。

 

キャンバス内に描かれたものは勝手に消えないので自分で消す必要があります。

キャンバス内の全ての要素を削除する場合はcanvas.Children.Clear();

特定の要素を消す場合はRemoveRemoveAtなどがあります。今回はRemoveで直接要素を指定して削除します。

Remove(要素)に渡す要素ですが、関数を利用して探す方法もありますが面倒で負荷的にもよろしくないのでリストへ格納しておくのが良い。

この関数の頭の方で削除する要素が入ったリスト内をループで全て削除しています。最後には作ったレクタングルをリストへ格納してあります。

 

// canvas1上で左クリック時
private void canvas1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Canvas c = sender as Canvas;
    init = e.GetPosition(c);
    c.CaptureMouse();
    isDrag = true;
}

// canvas1上で移動時
private void canvas1_MouseMove(object sender, MouseEventArgs e)
{
    if (isDrag)
    {
        Point imap = e.GetPosition(canvas1); //キャンバス上のマウスの現在地
        DrawRectangle(imap); //再描画
    }
}

// canvas1上で左クリック離した時
private void canvas1_MouseUp(object sender, MouseButtonEventArgs e)
{
    if (isDrag)
    {
        Canvas c = sender as Canvas;
        isDrag = false;
        c.ReleaseMouseCapture();
    }

    //既存のパスを削除
    foreach (UIElement ui in canvasStock)
    {
        canvas1.Children.Remove(ui);
    }
}

init = e.GetPosition(c);でマウスの初期位置を取得しています。

Point imap = e.GetPosition(canvas1);で移動中のマウスの位置を取得しています。描画用関数の引数として渡します。

クリックを離した時も格納リストからレクタングルを削除しています。

 

動的に作成、描画したものを再利用するにはFindなどで探すより作成時にリストへ格納しておきましょう!

キャンバスのバックグラウンドを設定するのも忘れずに、xamlの方でBackground=”Transparent”に設定すると良いです。

コメントを残す。

メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。URLを含むコメントは承認待ちになります。