2017-10-06 7 views
0

私が欲しい機能は、マウスを使ってイメージ上のいくつかのオブジェクトの輪郭を描くことです。イメージ上に輪郭を表示し、輪郭データをエクスポートすることができます。私はここにcyotek.imageboxを使用していますhttps://github.com/cyotek/Cyotek.Windows.Forms.ImageBox、画像を表示するためのカスタムコントロール。 ここに私のアプローチです。Cyotek.ImageBoxでC#winformでマウスで輪郭を描きます。

private List<List<Point>> contours = new List<List<Point>>(); //a list to store all contours 

private List<Point> contour_temp= new List<Point>(); //a list to store the contour the user is drawing 

private bool mousedown // a flag that change when mouse up/mouse down event is triggered 

private void imageBox_MouseDown(object sender, MouseEventArgs e) 
{ 
    mousedown = true; 
} 

private void imageBox_MouseUp(object sender, MouseEventArgs e) 
{ 
    mousedown = false; 
} 

private void imageBox_MouseMove(object sender, MouseEventArgs e) 
{ 
    //drawing occurs when mouse is down, a contour is finish drawing when mouse is up 
    // when a contour finish drawing. it will be added to the contours list and the contour temp will be clear 

    if (draw_on) // a flag for this function to be active 
    { 
     if (contour_temp.Count > 0) 
     { 
      if (mousedown) 
      { 
       if (imageBox.IsPointInImage(e.Location)) //function cyotek.imagebox provides , it translate the mouse location to pixel location 
       { 
        Point p = this.imageBox.PointToImage(e.Location); 
        if (p != contour_temp[contour_temp.Count - 1]) 
         contour_temp.Add(p); 
       } 
      } 
      else 
      { 
       if (contour_temp.Count > 2) 
       { 
        contours.Add(contour_temp); 
        contour_temp.Clear(); 
       } 
      } 
     } 
     else 
     { 
      if (mousedown) 
      { 
       contour_temp = new List<Point>(); 
       Point p = this.imageBox.PointToImage(e.Location); 
       contour_temp.Add(p); 
      } 
     } 
     imageBox.Invalidate(); 
    } 
} 

private void imageBox_Paint(object sender, PaintEventArgs e) 
{ 
    //at the painting function, always paint all the contours stored 
    //if mouse is down, print the temporary contour the user is currently drawing 
    foreach (List<Point> contour in contours) 
    { 
     Point p0 = contour[0]; 
     foreach (Point p1 in contour) 
     { 
      e.Graphics.DrawLine(new Pen(Color.Red), imageBox.GetOffsetPoint(p0), imageBox.GetOffsetPoint(p1));//Cyotek.ImageBox provided, get the correct point even after zooming 
      p0 = p1; 
     } //draw all contours 

    } 

    if(draw_on && mousedown && contour_temp.Count>0) 
    { 

     Point p0 = contour_temp[0]; 
     foreach (Point p1 in contour_temp) 
     { 
      e.Graphics.DrawLine(new Pen(Color.Green), imageBox.GetOffsetPoint(p0), imageBox.GetOffsetPoint(p1)); 
      p0 = p1; 
     }// draw the contour user is drawing 

    } 
    } 

draw contour_tempパーツが問題なく動作します。しかし、輪郭が完成した図面が破損し、System.ArgumentOutOfRangeExceptionを 'mscorlib.dll'に投げたときにプログラムがクラッシュする。 いくつかのテストの後、塗装機能のすべての輪郭を描画することが何とか間違っている。私はリストのインデックス が範囲外であると言って、例外に関するいくつかの調査を行った。しかし、私が "foreach"を使用しているとどうしてそれが起こるのですか?

答えて

0

ここでの問題は、これらの線が原因である:

最初のケースで
contours.Add(contour_temp); 
contour_temp.Clear(); 

、あなたはあなたのメインリストcontoursへの一時的なポイントcontour_tempのリストを追加することが、List<T>として、あなたがしているreference typeありますポイントのコピーを追加するのではなく、同じリストへの参照 - これをクリアすると、contoursは実際には空のリストで構成されます。しかし、あなたのペインティングルーチンは、それらのリストが少なくとも1つのポイントを含むことを期待しています。つまり、アイテムが存在しないリストの最初のアイテムを取得しようとしているときにペイントしようとするとArgumentOutOfRangeExceptionです。

私は、これは、このようにポイントを保存し、リストのコピーを作成します

contours.Add(new List<Point>(contour_temp)); 

に最初の行を変更して、デモ・プログラムを修正しました。私はあなたのデモプログラムをこの訂正でテストしたところ、正常に動作しました。

これが役に立ちます。 ImageBoxを使用していただきありがとうございます!

+0

ありがとうございました。今それは完璧に動作します! –

+0

また、便利なイメージボックスコントロールについてもう一度感謝します。 ところで、私はimageboxについてのCyotekフォーラムの別の質問をしました。あなたは見てみることができますか? –