C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[11]: 取得するマウスの座標をクライアント領域内に限定するには


(過去ログ 117 を表示中)

[トピック内 24 記事 (1 - 20 表示)]  << 0 | 1 >>

■68762 / inTopicNo.1)  取得するマウスの座標をクライアント領域内に限定するには
  
□投稿者/ yoto (6回)-(2013/11/12(Tue) 20:15:02)

分類:[C#] 

 こんばんは、VC#2010初心者の私は現在、マウスの左ボタンをドラッグしている間、ピクチャボックスに取得した座標に円と各円の間に直線を描き、マウスの軌跡を表現するというプログラムを組んでおります。
 軌跡そのものはピクチャボックスに描けました。
 しかし、ピクチャボックスをはみ出すようにドラッグをするとピクチャボックスのクライアント領域を超えても軌跡が描画されてしまいます。
 この動作を、もし軌跡がピクチャボックスを超えるようにドラッグしたら描画される範囲をピクチャボックスのクライアント領域に限定するようなことはできないでしょうか?
 よろしければ、皆さまのお手をお借ることができれば幸いです。
 以降に自分のプログラムの動作と改善したい理想の動作、あと自分の作成したプログラムのソースコードを記述します。
 よろしくお願いいたします。
 
 自分が考える動作は以下のようなものになります

 自分のプログラムでの実際の動作:
 
 -----------------------
 (Form) 
        ●(実際は見えていない)
    ↑  ↓
 ---------------------
 | ↑  ↓      |
  | ○  ○          |
  | ↑                |
  |  ○                |
  |              |
  |(ピクチャボックス )|


 理想の動作:
-----------------------
 (Form) 
     
 ---------------------
 |           |
  | ○ → ○        |
  | ↑                |
  |  ○                |
  |              |
  |(ピクチャボックス )|

 自分の作成したソースコード:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;


namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        int Drag_Flag = 0;
        List<Point> drawPoints; // 座標を格納するList
        List<Point> before_drawPoints;// 軌跡の始点となる座標を格納するList
        System.Drawing.Point before_p;
        System.Drawing.Point sp;
        System.Drawing.Point cp;
        Bitmap bmp = (Bitmap)System.Drawing.Image.FromFile(@"C:\\Users\\yoto\\Desktop\\実験画像フォルダ\\WhiteBack.png"); 
      
        public Form1()
        {
            InitializeComponent();
            drawPoints = new List<Point>();
            before_drawPoints = new List<Point>();
            pictureBox1.MouseMove += new MouseEventHandler(pictureBox1_MouseMove);
        }


        //マウスイベント(マウスを動かした時)
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            //ドラッグ時の処理(ドラッグフラグを立てる)
            if (e.Button == MouseButtons.Left)
            {
                this.Text = "スタート";
                Drag_Flag = 1;
            }

            else//ドラッグしていないときは動作しない(ドラッグフラグを下げる、立てない)
            {
                this.Text = "ストップ";
                Drag_Flag = 0;
            }

        }

        //サンプリング間隔(1s)ごとに起きるイベント
        private void timer1_Tick_1(object sender, EventArgs e)
        {
            if(Drag_Flag == 1)//サンプリング間隔 かつ ドラッグしている時
            {  
                Chase_MousePoint();//マウスの座標に円と軌跡を描く

            }

            else if (Drag_Flag == 0)//サンプリング間隔 かつ ドラッグしてない時
            {
                Get_MousePoint();//マウスの座標を取得

            }       
        } 
   
        private void Get_MousePoint()//マウスの座標を取得
        {
            //ImageオブジェクトのGraphicsオブジェクトを作成する
            Graphics g = Graphics.FromImage(bmp);
            
            // 画像座標でのマウスポインタの位置を取得する
            sp = System.Windows.Forms.Cursor.Position;
            //画面座標をクライアント座標(ピクチャボックス座標)に変換する
            cp = pictureBox1.PointToClient(sp);
            drawPoints.Add(new Point(cp.X , cp.Y ));
            before_p = cp;
              
            //リソースを解放する
            g.Dispose();
            //PictureBox1に表示する
            pictureBox1.Image = bmp;
        }

        private void Chase_MousePoint()//円と軌跡を描く
        {
            //ImageオブジェクトのGraphicsオブジェクトを作成する
            Graphics g = Graphics.FromImage(bmp);

            // 画像座標でのマウスポインタの位置を取得する
            sp = System.Windows.Forms.Cursor.Position;
            //画面座標をクライアント座標(ピクチャボックス座標)に変換する
            cp = pictureBox1.PointToClient(sp);
            drawPoints.Add(new Point(cp.X, cp.Y));    
            
            foreach (Point p in drawPoints )//リストに格納されている要素数すべて繰り返す
            {
                //マウスの位置に11x11の四角を赤色で描く
                g.DrawRectangle(Pens.Red, p.X - 6, p.Y - 6, 11, 11);//円の中心を得るために11×11なので
                //先に描いた四角に外接する楕円を黒で描く            //6ずつ描画する座標をずらす
                g.DrawEllipse(Pens.Black, p.X - 6, p.Y - 6, 11, 11);//マウスの座標を円で描画
            }
            Pen pen = new Pen(Color.DarkRed);
            pen.Width = 5;
            pen.EndCap = LineCap.ArrowAnchor;//終点に矢印をつける
            
            g.DrawLine(pen, before_p.X,before_p.Y,cp.X,cp.Y);//マウスの動いた軌跡を描画
            
            before_p = cp;      
            
            //リソースを解放する
            g.Dispose();
            //PictureBox1に表示する
            pictureBox1.Image = bmp;
        }

    }
}



引用返信 編集キー/
■68763 / inTopicNo.2)  Re[1]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ しま (39回)-(2013/11/12(Tue) 21:33:42)
No68762 (yoto さん) に返信
>  こんばんは、VC#2010初心者の私は現在、マウスの左ボタンをドラッグしている間、ピクチャボックスに取得した座標に円と各円の間に直線を描き、マウスの軌跡を表現するというプログラムを組んでおります。
>  軌跡そのものはピクチャボックスに描けました。
>  しかし、ピクチャボックスをはみ出すようにドラッグをするとピクチャボックスのクライアント領域を超えても軌跡が描画されてしまいます。
>  この動作を、もし軌跡がピクチャボックスを超えるようにドラッグしたら描画される範囲をピクチャボックスのクライアント領域に限定するようなことはできないでしょうか?
>  よろしければ、皆さまのお手をお借ることができれば幸いです。
>  以降に自分のプログラムの動作と改善したい理想の動作、あと自分の作成したプログラムのソースコードを記述します。
>  よろしくお願いいたします。
>  
>  自分が考える動作は以下のようなものになります
>
>  自分のプログラムでの実際の動作:
>
> -----------------------
>  (Form) 
> ●(実際は見えていない)
>   ↑  ↓
>  ---------------------
>  | ↑  ↓      |
> | ○  ○ |
> | ↑ |
> | ○ |
> |         |
> |(ピクチャボックス )|
>
>
> 理想の動作:
> -----------------------
>  (Form) 
>
>  ---------------------
>  |           |
> | ○ → ○ |
> | ↑ |
> | ○ |
> |         |
> |(ピクチャボックス )|
>

マウスの軌跡を描画するときに、描画範囲を超えているかどうか判定して
領域内に収まる様に描画させれば良いかと考えます
1.0)i-1 番目の座標(x, y) と i 番目の座標(xi, yi) との軌跡を引く時に
1.1)どちらも領域内ならそのまま描画する
1.2)(x, y) が領域内で、(xi, yi) が領域外なら (x, y) から 領域内の点 (xi*, yi*) を計算で求めて
1.2)新たな点までの軌跡を描画する
****新たな点 (xi*, yi*) は始点(x, y) から終点(xi, yi) と領域の矩形(四角)の交点の座標
1.3)(x, y) が領域外で、(xi, yi) が領域内なら領域の矩形の交点の座標 (x*, y*) を計算で求めて描画する
1.4)両者が領域外なら描画しない
というのはどうでしょうか

質問・疑問です
A)タイマーを使ってマウス座標を取得していますが、「そうしたい」又は「そうしなければならない」理由があるのですか?
B)今のままだと、マウス移動中に左ボタンを押して、左ボタンを押したままで移動を止(や)めてもタイマーが効いてその都度
 ビットマップに繰返し描画していますがこれはあなたの望む動作ですか?
 又、マウスの移動中でないと左ボタンの様子を検出していないので、左ボタンが離れた状態でマウスが止まっている時に
 左ボタンを押してもタイマーが効いているので、マウス座標をどんどん追加しますがこれはあなたの望む動作ですか?

引用返信 編集キー/
■68767 / inTopicNo.3)  Re[2]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ yoto (7回)-(2013/11/13(Wed) 10:58:07)
No68763 (しま さん) に返信

> 質問・疑問です
> A)Q、タイマーを使ってマウス座標を取得していますが、「そうしたい」又は「そうしなければならない」理由があるのですか?
 A、はい、このプログラムは部活の顧問の先生からの「タイマーイベントごとにマウスの座標を取得する。かつドラッグされていれば軌跡を描く」という課題なので意図してそのようにしています
> B)Q、今のままだと、マウス移動中に左ボタンを押して、左ボタンを押したままで移動を止(や)めてもがこれはあなたの望む動作ですか? 
  A、ドラッグされていれば軌跡を描きたいので、左ボタンを押したままで移動を止(や)めても軌跡が描画されるのは修正すべき点です。
    ご指摘されて気がつきました。ありがとうござます。
    また、軌跡を描くのは一度ではなくタイマーが動いている間は何度でも軌跡を描きたいのでタイマーが効いてその都度
>    ビットマップに繰返し描画するのは意図した動作です。
    

>  Q、又、マウスの移動中でないと左ボタンの様子を検出していないので、左ボタンが離れた状態でマウスが止まっている時に
>    左ボタンを押してもタイマーが効いているので、マウス座標をどんどん追加しますがこれはあなたの望む動作ですか?
  A、はい、望んでいる動作です。
   課題の中で先生から「マウスが止まっている間もマウス座標を取得する。しかし、円は描画しない」という動作をするように、と言われたので
   そのようにしています。
   ですが、「マウスが止まっている」という状態が明確でないので、左ボタンを押している。かつ、マウスが止まっているのを条件に
   「マウスが止まっている」という風に判断するように修正したいと思います

   質問の意図通りに返せていなかったら申し訳ございません。
   よろしくお願いします
引用返信 編集キー/
■68768 / inTopicNo.4)  Re[1]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ Jitta (89回)-(2013/11/13(Wed) 20:52:05)
Jitta さんの Web サイト
No68762 (yoto さん) に返信
 ドラッグ中であるなしにかかわらず、
drawPoints に追加しているように見えるのは、気のせい?
「ドラッグ・ドラッグせずに移動・ドラッグ」と操作したとき、
2本の線が引かれるのを期待するけど、
線は1本になるのではないかな?

 サンプリングした点が少ないときはいいけど、
点が増える毎に全部再描画しているので、
どんどん遅くなっていきますよね?

引用返信 編集キー/
■68770 / inTopicNo.5)  Re[2]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ yoto (8回)-(2013/11/14(Thu) 13:55:14)
No68768 (Jitta さん) に返信
> ■No68762 (yoto さん) に返信
>  ドラッグ中であるなしにかかわらず、
> drawPoints に追加しているように見えるのは、気のせい?
> 「ドラッグ・ドラッグせずに移動・ドラッグ」と操作したとき、
> 2本の線が引かれるのを期待するけど、
> 線は1本になるのではないかな?

 はい、実際にそのようになっているのでがんばって修正してみます

>  サンプリングした点が少ないときはいいけど、
> 点が増える毎に全部再描画しているので、
> どんどん遅くなっていきますよね?
>
 なるほど、そういうこともありえるのですね。
 リストが要素数が一定以上になれば、RemoveAt(0)を使って不要になった要素を削除するようにしてみます。
 でも、これだけじゃ一度描かれた円と線を消せませんよね?
 pictureBox1.Invalidate()を使って、画像の更新でもしたらいいのでしょうか?

 
引用返信 編集キー/
■68771 / inTopicNo.6)  Re[3]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ yoto (9回)-(2013/11/14(Thu) 15:16:51)

 ひとまず、皆さんのご指摘を受けて何とか当初の問題であったクライアント座標の範囲内に限定して軌跡が描けるようになりました。
 お付き合いいただきありがとうございました。

 目下の問題は、Jitta さんに指摘された現状のままだと永遠と軌跡が描画されてしまう点へと移り変わりました。
 このまま次の問題の質問をこのトピックス内で続けてもよろしいのでしょうか?

 それとも別のトピックスを新規に立ち上げた方がよろしいでしょうか?

 よろしくお願い致します

引用返信 編集キー/
■68772 / inTopicNo.7)  Re[4]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ 島 (1回)-(2013/11/14(Thu) 15:54:33)
No68771 (yoto さん) に返信
>
>  目下の問題は、Jitta さんに指摘された現状のままだと永遠と軌跡が描画されてしまう点へと移り変わりました。
>  このまま次の問題の質問をこのトピックス内で続けてもよろしいのでしょうか?
>

私もその件については触れているつもりでしたが、分かりにくかったでしょうか?

>  それとも別のトピックスを新規に立ち上げた方がよろしいでしょうか?
>

別のスレッド(話題の流れ)にしなくてもいいのではないでしょうか
引用返信 編集キー/
■68773 / inTopicNo.8)  Re[5]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ yoto (10回)-(2013/11/14(Thu) 16:16:39)
 島さんへ、自分の理解が及んでいなかったみたいで申し訳ありません。

 >別のスレッド(話題の流れ)にしなくてもいいのではないでしょうか
 では、お言葉に甘えましてもう一度お付き合いをお願い致します。

  ひとまず現状のままだと永遠と軌跡が描画されてしまうという問題に対して、RemoveAt(0)を使って不要になったリスト内の要素を削除するようにしてみました。
  そうすることで不要となった古いデータを破棄します。
  そして、タイマーイベントごとに画像を更新することで破棄された座標には円や直線が描かれず、永遠と円や直線が描かれて画面が埋まるという問題は解決できると思いました。
  ですが、どうもpictureBox1.Refresh()やpictureBox1.Invalidate()などの更新命令をタイマーイベントに組み込んでも自分の思っている通りに動作いたしませんでした。

 以下に自分のプログラムのソースコードを記述します。
 添削、修正お願い致します

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;


namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        int Drag_Flag = 0;
        int max_point = 11;
        int max_movepoint = 6;
        List<Point> MousePoints; // 取得したマウス座標をすべて格納するリスト
        List<Point> Move_MousePoints; //円や直線を描画先のマウス座標を格納するリスト
        System.Drawing.Point before_p;
        System.Drawing.Point sp;
        System.Drawing.Point cp;
        System.Drawing.Point dp;
        Bitmap bmp;
        public Form1()
        {
            InitializeComponent();
            MousePoints = new List<Point>();
            Move_MousePoints = new List<Point>();
            pictureBox1.MouseDown += new MouseEventHandler(pictureBox1_MouseDown);
            pictureBox1.MouseMove += new MouseEventHandler(pictureBox1_MouseMove);
            //pictureBox1.MouseUp += new MouseEventHandler(pictureBox1_MouseUp);

            bmp = (Bitmap)System.Drawing.Image.FromFile(@"C:\\Users\\yoto\\Desktop\\実験画像フォルダ\\WhiteBack.png");
            //PictureBox1に表示する
            pictureBox1.Image = bmp;
        }

        //マウスの左ボタンを押したイベント(指先を検出した時)
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            //左ボタンを押すと、タイマースタートかつその時のマウス座標取得
            if (e.Button == MouseButtons.Left)
            { 
                timer1.Enabled = true;
                Get_MousePoint();
                Drag_Flag = 0;
            }
      
            //右ボタンを押すと、実行結果確認のためにテキストボックスに表示
            if (e.Button == MouseButtons.Right)
            {
                foreach (Point p in MousePoints)//リストに格納されている要素数すべて繰り返す
                {
                    textBox1.AppendText("座標" + p + "\r\n"); 
                }
                foreach (Point p in Move_MousePoints)
                {
                    textBox2.AppendText("座標" + p + "\r\n"); 
                }
            }
        }

        //マウスを動かした時のイベント(ジェスチャーを始めた時)
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            //ドラッグ時の処理(ドラッグフラグを立てる)
            if (e.Button == MouseButtons.Left)
            {
                this.Text = "追跡スタート";
                Drag_Flag = 1;
            }

            else//ドラッグしていないときは動作しない(ドラッグフラグを下げる、立てない)
            {
                this.Text = "追跡ストップ";
                Drag_Flag = 0;
            }
        }

        //サンプリング間隔(1s)ごとに起きるイベント
        public void timer1_Tick_1(object sender, EventArgs e)
        {
            if (Drag_Flag == 1)//サンプリング間隔 かつ ドラッグしている時
            {
                Chase_MousePoint();//マウス座標に円と軌跡を描く
            }

            else if (Drag_Flag == 0)//サンプリング間隔 かつ ドラッグしてない時
            {
                Get_MousePoint();//マウス座標を取得
            }

            List_Check();//古いリストの要素を削除する

            //ここに更新命令を記述する//
            //pictureBox1.Refresh()やInvalidate();ではだめでした//
        }

        private void Get_MousePoint()//マウスの座標を取得
        {
            Graphics g = Graphics.FromImage(bmp);
           
            // 画像座標でのマウスポインタの位置を取得する
            sp = System.Windows.Forms.Cursor.Position;
            //画面座標をクライアント座標(ピクチャボックス座標)に変換する
            cp = pictureBox1.PointToClient(sp);

            if (cp.X > 0 && cp.Y > 0)
            {
                if (cp.X < 600 && cp.Y < 400)
                {
                    dp = cp;
                    MousePoints.Add(new Point(dp.X, dp.Y));
                    before_p = cp;
                }
            }

            pictureBox1.Refresh(); // PictureBoxを更新(再描画させる)
        }

        private void Chase_MousePoint()//円と軌跡を描く
        {
            Graphics g = Graphics.FromImage(bmp);
            
            // 画像座標でのマウスポインタの位置を取得する
            sp = System.Windows.Forms.Cursor.Position;
            //画面座標をクライアント座標(ピクチャボックス座標)に変換する
            cp = pictureBox1.PointToClient(sp);

            if (cp.X > 0 && cp.Y > 0)
            {
                if (cp.X < 600 && cp.Y < 400)
                {
                    dp = cp;
                    Move_MousePoints.Add(new Point(dp.X, dp.Y));
                    MousePoints.Add(new Point(dp.X, dp.Y));
                }
            }

            foreach (Point p in Move_MousePoints)//リストに格納されている要素数すべて繰り返す
            {
                //マウスの位置に21x21の四角を赤色で描く
                g.DrawRectangle(Pens.Red, p.X - 6, p.Y - 6, 11, 11);//円の中心を得るために11×11なので
                //先に描いた四角に外接する楕円を黒で描く            //6ずつ描画する座標をずらす
                g.DrawEllipse(Pens.Black, p.X - 6, p.Y - 6, 11, 11);//マウスの座標を円で描画
            }

            Pen pen = new Pen(Color.DarkRed);
            pen.Width = 5;
            pen.EndCap = LineCap.ArrowAnchor;//終点に矢印をつける
            g.DrawLine(pen, before_p.X, before_p.Y, dp.X, dp.Y);//マウスの動いた軌跡を描画

            if (cp.X > 0 && cp.Y > 0)
            {
                if (cp.X < 600 && cp.Y < 400)
                {
                    before_p = cp;
                }
            }

            //リソースを解放する
            g.Dispose();
            //PictureBox1に表示する
            pictureBox1.Image = bmp;
         }

        private void List_Check()//古いリストの要素を削除する
        {
             // マウス座標を格納する最大数以上なら先頭の座標をリストから削除
             if (MousePoints.Count >=  max_point)
             {
                 MousePoints.RemoveAt(0);
             }

             if (Move_MousePoints.Count >= max_movepoint)
             {
                 Move_MousePoints.RemoveAt(0);
             }    
        }
    }
}
 
  
 

引用返信 編集キー/
■68775 / inTopicNo.9)  Re[6]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ an (1回)-(2013/11/14(Thu) 18:16:30)
No68773 (yoto さん) に返信

>> サンプリングした点が少ないときはいいけど、
>> 点が増える毎に全部再描画しているので、
>> どんどん遅くなっていきますよね?

> 目下の問題は、Jitta さんに指摘された現状のままだと永遠と軌跡が描画されてしまう点へと移り変わりました。

データを破棄したことと、「永遠と軌跡が描画されてしまう点」は今回のプログラム的には関係ないかと思います。

タイマーイベントで呼び出されるChase_MousePointメソッドにて、
破棄していない残っているポイントのみForEachで再描画されるようなので、
Jittaさんの指摘は解消されていると思います。

しかし、「永遠と軌跡が描画されてしまう点」についてはコードを見た限りでは
毎回描画さているのではなく、
「前に描画されているのが残っている」という表現のほうが正しい感じがします。

具体的に言うと、Form1クラスのメンバ「bmp」を使用している各メソッドについて、
描画したbmpを使いまわしているのが問題だと思いますので、
ローカル変数として定義し、毎回pngファイルを初期化した上で描画すれば
よいのではないでしょうか?

そもそもForm1クラスのメンバ「bmp」は、Form1クラスのメンバとしての存在意義が不明です。
他のメンバについても同様ですので、ローカル変数で済むものはローカル変数で
定義するよう見直したほうがよいかと思います。



引用返信 編集キー/
■68776 / inTopicNo.10)  Re[7]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ yoto (11回)-(2013/11/14(Thu) 18:32:04)
No68775 (an さん) に返信
> ■No68773 (yoto さん) に返信
>
> >> サンプリングした点が少ないときはいいけど、
> >> 点が増える毎に全部再描画しているので、
> >> どんどん遅くなっていきますよね?
>
>>目下の問題は、Jitta さんに指摘された現状のままだと永遠と軌跡が描画されてしまう点へと移り変わりました。
>
> データを破棄したことと、「永遠と軌跡が描画されてしまう点」は今回のプログラム的には関係ないかと思います。
>
> タイマーイベントで呼び出されるChase_MousePointメソッドにて、
> 破棄していない残っているポイントのみForEachで再描画されるようなので、
> Jittaさんの指摘は解消されていると思います。
>
> しかし、「永遠と軌跡が描画されてしまう点」についてはコードを見た限りでは
> 毎回描画さているのではなく、
> 「前に描画されているのが残っている」という表現のほうが正しい感じがします。
>
> 具体的に言うと、Form1クラスのメンバ「bmp」を使用している各メソッドについて、
> 描画したbmpを使いまわしているのが問題だと思いますので、
> ローカル変数として定義し、毎回pngファイルを初期化した上で描画すれば
> よいのではないでしょうか?
>
> そもそもForm1クラスのメンバ「bmp」は、Form1クラスのメンバとしての存在意義が不明です。
> 他のメンバについても同様ですので、ローカル変数で済むものはローカル変数で
> 定義するよう見直したほうがよいかと思います。
>
 ご返信ありがとうございます
 
 なにぶん自分自身、まだまだC#というよりプログラム初心者で無駄にグローバル変数にする癖があるので、
 自分ではどういった部分をローカル変数とすべき所が判断しきれず、よければ他にもローカル変数で済む部分がありましたらお教え頂けないでしょうか? 

 他の点もご指摘された内容を修正してみます。
 
引用返信 編集キー/
■68778 / inTopicNo.11)  Re[3]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ Jitta (90回)-(2013/11/14(Thu) 21:29:43)
Jitta さんの Web サイト
No68770 (yoto さん) に返信

あれ?進んでる。まぁ、昼過ぎに書いたものだけど、そのまま上げちゃう。

-----
>  でも、これだけじゃ一度描かれた円と線を消せませんよね?
 消す必要があるのですか?
考え方を変えると、「再生するが、途中は飛ばす」ことで消すこともできますよ?

> List<Point> drawPoints; // 座標を格納するList
> List<Point> before_drawPoints;// 軌跡の始点となる座標を格納するList
 今のコードでは、before_drawPoints は使用されていないので、
どのようなことをお考えなのか分かりませんが、
2本の線を引こうと思ったら、「2組の点のリスト」が必要です。
2本で済むはずはないので、「点のリストのリスト」が必要ではないでしょうか。

→before_drawPoints が無くなって、move_mousePoints になりましたね。


> pictureBox1_MouseMove
 「pictureBox1 上でマウスが動いた」時に、マウスのボタンの状態を調べていますが、
これは、「マウスのボタンを押したまま pictureBox1 上へ入ってきた」ことを検出するためでしょうか。
それとも、MouseMove イベントに、ボタンの状態が入った情報があるためでしょうか。

 線を引き始めるのが必ず pictureBox1 上であるなら、
pictureBox1 上で「マウスのボタンが押された」イベントが、
線を引き始めるトリガーと判断できるのではないでしょうか。
同様に、「マウスのボタンを離した」イベントが、
線を終わるトリガーになります。

> Chase_MousePoint
 線を描く Graphics を、bmp から作成しています。
ところで、2回目に Chase_MousePoint に入ってきたとき、
1回目に入ったときに描いたはずの線は、どうなっているでしょうか?
残っているなら、全ての要素を繰り返し描く必要はなく、
前回の点から今回の点へ線を引けばいいのではないでしょうか。


とりあえず、私の作ったコードを貼っておきます。
新しいWindowsForm プロジェクトに、PictureBox と、Timer を置きました。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
	public partial class Form1 : Form
	{
		private Bitmap picture;
		// 線のデータ
		private List<List<Point>> drawLines = new List<List<Point>>();
		// 今引いている線のデータ
		private List<Point> targetLine;
		private bool isRecording = false;

		public Form1()
		{
			InitializeComponent();
			this.pictureBox1.Dock = DockStyle.Fill; // DocStyle を Fill にしたので、PictureBox の大きさは絵よりも大きくなる。

			this.picture = new Bitmap(400, 400); //これを Load に
			using (Graphics g = Graphics.FromImage(this.picture))
			{ // バックを真っ黒にする
				g.FillRectangle(Brushes.Black, 0, 0, this.picture.Width, this.picture.Height);
			}

			this.pictureBox1.Image = this.picture;
			this.timer1.Interval = 1000;
			this.timer1.Start();
		}

		private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
		{
			this.isRecording = true;
			this.targetLine = new List<Point>();
			this.Record(true);
		}

		private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
		{
			this.isRecording = false;
			this.drawLines.Add(this.targetLine);
			this.targetLine = null;
			this.Record();
		}

		private void Record(bool force = false)
		{
			Point pos = this.pictureBox1.PointToClient(Cursor.Position);
			Rectangle rect = new Rectangle(0, 0, this.picture.Width, this.picture.Height);
			if (rect.Contains(pos) == false && force == false)
			{
				return;
			}

			if (this.targetLine != null)
			{
				using (Graphics g = Graphics.FromImage(this.picture))
				{
					g.FillEllipse(Brushes.Red, pos.X - 6, pos.Y - 6, 11, 11);
					if (this.targetLine.Count > 0)
					{
						g.DrawLine(Pens.White, this.targetLine[this.targetLine.Count - 1], pos);
					}
				}

				this.pictureBox1.Image = this.picture;
				this.targetLine.Add(pos);
			}
		}

		private void timer1_Tick(object sender, EventArgs e)
		{
			if (this.isRecording == false)
			{
				return;
			}

			this.Record();
		}
	}
}

引用返信 編集キー/
■68783 / inTopicNo.12)  Re[4]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ an (2回)-(2013/11/15(Fri) 11:43:08)
まずは前回のレスの修正。
> ローカル変数として定義し、毎回pngファイルを初期化した上で描画すれば

> ローカル変数として定義し、毎回pngファイルで初期化した上で描画すれば
の間違いです。

-----

> ■No68770 (yoto さん) に返信
> 自分ではどういった部分をローカル変数とすべき所が判断しきれず、よければ他にもローカル変数で済む部分がありましたらお教え頂けないでしょうか? 

答えを伝えるのは簡単ですが、

> A、はい、このプログラムは部活の顧問の先生から〜以下略

> 課題の中で先生から〜以下略

とあるので、ある程度自分で考える必要があると思います。
(とはいえ、自分はyotoさんが考えている動作を100%理解しているわけではないので、
 100%な答えを伝えるのは難しいのですが・・・)

ですが、考え方として以下のように考えればよいと思います。

・各メソッドで共通して使用する値かどうか
 (型や意味ではなく、その値自身を共有する必要があるか)
・1つのメソッドにおいて、複数回実行される場合に、前回の値として使用する値かどうか
・上記値は引数で行えるかどうか
・etc

すべてのパターンが上記条件で賄えるわけではありませんが
(性能等を考慮して敢えて例外的に行うケースもあるかも?)
一般的には対象のスコープを極力限定すべきと思います。



さて、今回のメンバbmpについて考えてみます。
メンバbmpはyotoさんのサンプルソースですと
・コンストラクタで使用(初期化のみ)
・Get_MousePointで使用(再初期化なし)
・Chase_MousePointで使用(再初期化なし)
の3か所で使用されています。

ですが、Get_MousePointを見ますと、
Graphics型のローカル変数gの初期化の値として使用していますが、
ローカル変数g自体がGet_MousePointで使用されていませんので、
Get_MousePointでのbmpの使用は不必要と考えられます。

結果的に、Chase_MousePointで初期化されていませんので、
「永遠と軌跡が描画されてしまう」という状況になっていました。
仮にChase_MousePointで初めで初期化したとしましょう。
これで前回描画された軌跡がなくなります。
しかし、コンストラクタとChase_MousePointのメソッド間で
およびChase_MousePointが数回呼ばれた時の各Chase_MousePoint実行時に
bmpの値を共有しているでしょうか?
Chase_MousePointの初めで初期化されたのであれば、
共有していないと言えると思います。
結論としてはメンバbmpはローカル変数で十分という考えになると思います。

では、以下の他のメンバはどうでしょうか?
> int Drag_Flag = 0;
> int max_point = 11;
> int max_movepoint = 6;
> List<Point> MousePoints;
> List<Point> Move_MousePoints;
> System.Drawing.Point before_p;
> System.Drawing.Point sp;
> System.Drawing.Point cp;
> System.Drawing.Point dp;
以上の観点から考えてみてください。

ちなみに、max_point、max_movepointについては、
処理上では値の変更がないので、定数として定義すべきかと思います。



> なにぶん自分自身、まだまだC#というよりプログラム初心者で無駄にグローバル変数にする癖があるので、

その癖は早めに解消することをお勧めします。
(それが一番の近道かも?)
本来は各変数の意味を考え、必要に応じてスコープを確定するべきですが、
癖という観点で考えますと、
まずは、とにかくローカルで宣言し、必要に応じて拡張していく方が良いと思います。
1度スコープの広いもので宣言しますと、
コンパイラではエラーとして教えてくれないので、
動作的に問題があっても今回のようにそのまま放置されてしまう可能性が高くなります。
(もちろんその逆もありますが・・・。)

変数等のスコープはローカル、private、public、etc・・・とあるので、
(ローカルの中でもさらにブロック単位に狭めるものもあり)
極力意味のあるスコープにしないと、プログラムとしても誤作動しやすいです。
また、仮にスコープの広い変数を使用しても、初期化等を正しく行えば
正常に動作するとは思いますが、
後でプログラムを見た時や他の人が見たときに勘違いする可能性があるので、
意味のあるものにすべきでしょう。



蛇足ですが、
コンストラクタの処理について、
メンバbmpはローカル変数にもせず、
直接pictureBox1のImageプロパティをそのまま使用する方法もあります。
public Form1()
{
〜省略〜
pictureBox1.Image = (Bitmap)System.Drawing.Image.FromFile(@"ファイルパス");
}
Chase_MousePointの方の処理については、
ある条件において再描画しないといったような
後での拡張を考えるとローカル変数でもよい気はしますが・・・。
引用返信 編集キー/
■68792 / inTopicNo.13)  Re[5]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ yoto (12回)-(2013/11/15(Fri) 20:26:09)
Jitaさんソースコードを記述していただきありがとうございます。

ソースコード拝見しました。
なるほど、こういうプログラムの仕方があるのかととてもためになりました。
ありがとうございます
引用返信 編集キー/
■68793 / inTopicNo.14)  Re[6]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ yoto (13回)-(2013/11/15(Fri) 20:35:02)
 anさんご指摘していただきありがとうございます
 
 頑張ってご指摘していただいた部分について、自分なりに考えてプログラムを組んでみます。
 ありがとうございます。
 
引用返信 編集キー/
■68799 / inTopicNo.15)  Re[7]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ 羆(ひぐま) (1回)-(2013/11/17(Sun) 00:40:20)
国産でも、セイコーのグランドセイコー、オリエントのロイヤルオリエントも実用時計としてレベルは高いですね。
大きく分けて、機械式時計とクォーツ時計に分かれますが???
これはデザインだけの時計を作ります。
http://www.sotokelya.com/leather-bottrgabag/
引用返信 編集キー/
■68803 / inTopicNo.16)  Re[8]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ yoto (14回)-(2013/11/17(Sun) 18:00:47)
 ひとまず、

> 具体的に言うと、Form1クラスのメンバ「bmp」を使用している各メソッドについて、
> 描画したbmpを使いまわしているのが問題だと思いますので、
> ローカル変数として定義し、毎回pngファイルを初期化した上で描画すれば
> よいのではないでしょうか?

 というご指摘を元にプログラムを修正してみました。
 今まではbmp1で全ての描画を回していたので、新しくbmp2を追加しました。
 描画先はbmp2に行ない、それを表示する。
 そして、実行毎にbmp1を読込、初期化を行うことで達成できると思いまし。
 ですが、前回と同じ今まで描画した円や直線が残ったままになってしまいました。
 自分の力だけではこれ以上修正できず、添削・修正お願いできませんでしょうか?

 public partial class Form1 : Form
    {
        int Drag_Flag = 0;
        private int max_point = 6;
        private int max_movepoint = 6;
        private List<Point> MousePoints; // 取得したマウス座標をすべて格納するリスト
        private List<Point> Move_MousePoints; //円や直線を描画先のマウス座標を格納するリスト
        System.Drawing.Point before_p;
        System.Drawing.Point sp;
        System.Drawing.Point cp;
        System.Drawing.Point dp;
        Bitmap bmp1 = (Bitmap)System.Drawing.Image.FromFile(@"C:\\Users\\yoto\\Desktop\\実験画像フォルダ\\WhiteBack.png");
 
        public Form1()
        {
            InitializeComponent();
            MousePoints = new List<Point>();
            Move_MousePoints = new List<Point>();
            pictureBox1.MouseDown += new MouseEventHandler(pictureBox1_MouseDown);
            pictureBox1.MouseMove += new MouseEventHandler(pictureBox1_MouseMove);
            //PictureBox1に表示する
            pictureBox1.Image = bmp1;
        }


    〜 中略 〜

    private void Chase_MousePoint()//円と軌跡を描く
        {             
            Bitmap bmp2 = bmp1; //描画先をbmp2に変更した。実行毎にbmp1から元画像を取得し、bmp2を初期化
            Graphics g = Graphics.FromImage(bmp2);
            
            // 画像座標でのマウスポインタの位置を取得する
            sp = System.Windows.Forms.Cursor.Position;
            //画面座標をクライアント座標(ピクチャボックス座標)に変換する
            cp = pictureBox1.PointToClient(sp);

            if (cp.X > 0 && cp.Y > 0)
            {
                if (cp.X < 600 && cp.Y < 400)
                {
                    dp = cp;
                    Move_MousePoints.Add(new Point(dp.X, dp.Y));
                    MousePoints.Add(new Point(dp.X, dp.Y));
                }
            }

            foreach (Point p in Move_MousePoints)//リストに格納されている要素数すべて繰り返す
            {
                //マウスの位置に11x11の四角を赤色で描く
                g.DrawRectangle(Pens.Red, p.X - 6, p.Y - 6, 11, 11);//円の中心を得るために11×11なので
                //先に描いた四角に外接する楕円を黒で描く            //6ずつ描画する座標をずらす
                g.DrawEllipse(Pens.Black, p.X - 6, p.Y - 6, 11, 11);//マウスの座標を円で描画
            }

            Pen pen = new Pen(Color.DarkRed);
            pen.Width = 5;
            pen.EndCap = LineCap.ArrowAnchor;//終点に矢印をつける
            g.DrawLine(pen, before_p.X, before_p.Y, dp.X, dp.Y);//マウスの動いた軌跡を描画

            if (cp.X > 0 && cp.Y > 0)
            {
                if (cp.X < 600 && cp.Y < 400)
                {
                    before_p = cp;
                }
            }

            //リソースを解放する
            g.Dispose();
            //PictureBox1に表示する
            pictureBox1.Image = bmp2;
         }

     private void List_Check()//古いリストの要素を削除する
        {
             // マウス座標を格納する最大数以上なら先頭の座標をリストから削除
             if (MousePoints.Count >=  max_point)
             {
                 MousePoints.RemoveAt(0);
             }

             if (Move_MousePoints.Count >= max_movepoint)
             {
                 Move_MousePoints.RemoveAt(0);
             }    
        }
    }
}

 

引用返信 編集キー/
■68804 / inTopicNo.17)  Re[9]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ Azulean (238回)-(2013/11/17(Sun) 18:25:53)
No68803 (yoto さん) に返信
>  今まではbmp1で全ての描画を回していたので、新しくbmp2を追加しました。
>  描画先はbmp2に行ない、それを表示する。
>  そして、実行毎にbmp1を読込、初期化を行うことで達成できると思いまし。

考え方はよさそうですが、.NET における「参照型」の理解が足りていないように見受けられます。

>     private void Chase_MousePoint()//円と軌跡を描く
> {
> Bitmap bmp2 = bmp1; //描画先をbmp2に変更した。実行毎にbmp1から元画像を取得し、bmp2を初期化

たぶん、yoto さんは bmp2 = bmp1 で新しい bmp2 ができたと思っているのかもしれませんが、違います。
bmp1 も bmp2 も同じビットマップを指し示す参照型の変数に過ぎません。
(C 言語の理解があるのであれば、ポインタとほぼ同じと思っていただいて結構です)

コピーが欲しいの出れば、Clone メソッドを呼ぶか、new Bitmap(bmp1) というようにコピーするためのコンストラクタを呼ぶ必要があります。
ただし、コピーとなるので、無尽蔵にコピーするとリソースが足りなくなります。
不要になった段階で Dispose しなければなりません。

このあたりが理解につながらない場合は、参照型や Dispose について調べてみてください。


>  自分の力だけではこれ以上修正できず、添削・修正お願いできませんでしょうか?

個人的にはなぜ、部活の先生・先輩・同級生に相談しないのかが疑問に感じています。
Web ベースで顔も知らない相手に仕様を説明し、困っていることを説明し、解決を導くこともできますが、労力が大きくなります。
顔をつきあわせて話をできる人に相談した方が理解も早いですし、解決も早いですよ。

今回の課題で終わりではないのでしょうから、何か手を考えたいところです。
引用返信 編集キー/
■68805 / inTopicNo.18)  Re[9]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ Jitta (91回)-(2013/11/17(Sun) 23:05:49)
Jitta さんの Web サイト
No68803 (yoto さん) に返信
>  というご指摘を元にプログラムを修正してみました。
>  今まではbmp1で全ての描画を回していたので、新しくbmp2を追加しました。
>  描画先はbmp2に行ない、それを表示する。
>  そして、実行毎にbmp1を読込、初期化を行うことで達成できると思いまし。
>  ですが、前回と同じ今まで描画した円や直線が残ったままになってしまいました。

えーっと、これって、 No 68771 の、この部分ですよね?

> 目下の問題は、Jitta さんに指摘された現状のままだと永遠と軌跡が描画されてしまう点へと移り変わりました。

で、私の指摘というのが、 No 68768 の、

>  ドラッグ中であるなしにかかわらず、
> drawPoints に追加しているように見えるのは、気のせい?
> 「ドラッグ・ドラッグせずに移動・ドラッグ」と操作したとき、
> 2本の線が引かれるのを期待するけど、
> 線は1本になるのではないかな?

の部分、ってことで良いでしょうか。

で、私の指摘は、「ドラッグ − 離して移動 − ドラッグ」という動作において、
「ドラッグ」の期間が2つあるので、2本の線が引かれることを期待するが、
当時のコードでは、「離して移動」の部分でも線が引かれ続けている、、、というものです。
離したときに以前の線を「消す」のであれば、「2本の線」ではなく、
「新しくドラッグしはじめた1本の線」になります。
もちろん、「離したとき」に消すのか、「新しく押したとき」に消すのか、という問題もあります。

ここのところ、仕様が伝わっていないと思います。
Azuleanさんがおっしゃっている、
「なぜ、部活の先生・先輩・同級生に相談しないのか」
というのは、部活の先生であれば、ここであなたが説明を端折った説明もご存じである、
つまり、部活の先生に話を聞く方が、ここで問題を解決しようとするより、
短時間で解決できるはずである、ということです。
また、部活の先生に聞くということは、先生にとっては生徒のやる気が見えてうれしいことです。
確かに、外部に説明して、答えを引き出してくるだけの力がある、というのがわかることもうれしいですけど。
はい、「外部に質問して」ではなく、「外部に説明して」なんです。
ここ、間違わないでくださいね。
私たちには、「質問をしないでください」。
そうではなく、あなたが実現したいこと、行ったこと、得た結果、考えたことを、「説明してください」。
それが、「答え」を得る、一番速い方法です。

もちろん、早さなんていらない、というなら、質問でかまいません。
引用返信 編集キー/
■68813 / inTopicNo.19)  Re[10]: 取得するマウスの座標をクライアント領域内に限定するには
□投稿者/ yoto (15回)-(2013/11/19(Tue) 00:21:46)
Jittaさん、自分の説明がしきれていなかったようで申し訳ございません。

なので、自分の行っていきたいと思っている内容を説明させていただきます。

自分は現在、マウスの左ボタンをドラッグしている間、円と直線を描画し、軌跡を表現したいと思っています。
ですが、皆さまのご指摘で
1.ドラッグをしている間その座標をリストに格納し続けていると動作が遅くなると言う問題

2.軌跡を描きつづけていると画面が見づらくなってしまうと言う問題
に気が付きました。

なので、リストの要素が一定数に達したら要素[0]を削除する。
そして、その不要な要素を削除したリストを元に円と直線を描画する。
こうすることで、上記の二つの問題が解決できると思いました。

実際に68775でのanさんのご指摘と自分でプログラムを組んでみました。
結果、1の問題は解決できました。
しかし、2の問題において円が問題なく削除しながら円をリストの要素分描画できるのですが、
直線が一本しか描くことができませんでした。

自分としてはそれは描画先であるbmp2を描画されるたびに初期化しているためだと考えました。
なので、円とおなじく直線の描画するdrawlineをforeachでリストの要素数分だけ処理を回すように修正してみました。

foreach (Point p in Move_MousePoints)//リストに格納されている要素数すべて繰り返す
{
//マウスの位置に11x11の四角を赤色で描く
g.DrawRectangle(Pens.Red, p.X - 6, p.Y - 6, 11, 11);//円の中心を得るために11×11なので
//先に描いた四角に外接する楕円を黒で描く //6ずつ描画する座標をずらす
g.DrawEllipse(Pens.Black, p.X - 6, p.Y - 6, 11, 11);//マウスの座標を円で描画
g.DrawLine(pen, before_p.X, before_p.Y, p.X, p.Y);//マウスの動いた軌跡を描画
}


が、実行結果を見ると円と円の間直線は描けているのですが、
どうもbefore_p.Xとbefore_p.Yから要素分だけp.Xとp.Yで複数直線が描かれてしまって思うようにはなりませんでした。


他にもDrawLines(Pen pen, Point[] points);なども試してみたのですがうまくいかず、
友人らにも聞いても解決法が見つからなかったので、他によい方法はないでしょうか?

以下にDrawLinesを組みこんでみたプログラムのソースコードを記述します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;


namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
int Drag_Flag = 0;
int i=1;
private int max_point = 6;
private int max_movepoint = 6;
private List<Point> MousePoints; // 取得したマウス座標をすべて格納するリスト
private List<Point> Move_MousePoints; //円や直線を描画先のマウス座標を格納するリスト
System.Drawing.Point before_p;
System.Drawing.Point sp;
System.Drawing.Point cp;
System.Drawing.Point dp;
Point[] Pt = new Point[6];
Bitmap bmp1 = (Bitmap)System.Drawing.Image.FromFile(@"C:\\Users\\yoto\\Desktop\\実験画像フォルダ\\WhiteBack.png");

public Form1()
{
InitializeComponent();
MousePoints = new List<Point>();
Move_MousePoints = new List<Point>();
pictureBox1.MouseDown += new MouseEventHandler(pictureBox1_MouseDown);
pictureBox1.MouseMove += new MouseEventHandler(pictureBox1_MouseMove);
//PictureBox1に表示する
pictureBox1.Image = bmp1;
}

//マウスの左ボタンを押したイベント(指先を検出した時)
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
//左ボタンを押すと、タイマースタートかつその時のマウス座標取得
if (e.Button == MouseButtons.Left)
{ 
timer1.Enabled = true;
Get_MousePoint();
Drag_Flag = 0;
}
      
//右ボタンを押すと、実行結果確認のためにテキストボックスに表示
if (e.Button == MouseButtons.Right)
{
foreach (Point p in MousePoints)//リストに格納されている要素数すべて繰り返す
{
textBox1.AppendText("座標" + p + "\r\n"); 
}
foreach (Point p in Move_MousePoints)
{
textBox2.AppendText("座標" + p + "\r\n"); 
}
}
}

//マウスを動かした時のイベント(ジェスチャーを始めた時)
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
//ドラッグ時の処理(ドラッグフラグを立てる)
if (e.Button == MouseButtons.Left)
{
this.Text = "追跡スタート";
Drag_Flag = 1;
}

else//ドラッグしていないときは動作しない(ドラッグフラグを下げる、立てない)
{
this.Text = "追跡ストップ";
Drag_Flag = 0;
}
}

//サンプリング間隔(1s)ごとに起きるイベント
public void timer1_Tick_1(object sender, EventArgs e)
{
if (Drag_Flag == 1)//サンプリング間隔 かつ ドラッグしている時
{
Chase_MousePoint();//マウス座標に円と軌跡を描く
}

else if (Drag_Flag == 0)//サンプリング間隔 かつ ドラッグしてない時
{
Get_MousePoint();//マウス座標を取得
}

List_Check();//古いリストの要素を削除する
}

private void Get_MousePoint()//マウスの座標を取得
{
// 画像座標でのマウスポインタの位置を取得する
sp = System.Windows.Forms.Cursor.Position;
//画面座標をクライアント座標(ピクチャボックス座標)に変換する
cp = pictureBox1.PointToClient(sp);

if (cp.X > 0 && cp.Y > 0)
{
if (cp.X < 600 && cp.Y < 400)
{
dp = cp;
MousePoints.Add(new Point(dp.X, dp.Y));
Pt[0]=dp;
}
}
}

private void Chase_MousePoint()//円と軌跡を描く
{
Bitmap bmp2 = new Bitmap(bmp1); //描画先をbmp2に変更した。実行毎にbmp1から元画像を取得し、bmp2を初期化
Graphics g = Graphics.FromImage(bmp2);


// 画像座標でのマウスポインタの位置を取得する
sp = System.Windows.Forms.Cursor.Position;
//画面座標をクライアント座標(ピクチャボックス座標)に変換する
cp = pictureBox1.PointToClient(sp);

if (cp.X > 0 && cp.Y > 0)
{
if (cp.X < 600 && cp.Y < 400)
{
dp = cp;
Move_MousePoints.Add(new Point(dp.X, dp.Y));
MousePoints.Add(new Point(dp.X, dp.Y));
//before_p = cp;
Pt[i] = dp;
i++;
}
}

Pen pen = new Pen(Color.DarkRed);
pen.Width = 5;
pen.EndCap = LineCap.ArrowAnchor;//終点に矢印をつける
foreach (Point p in Move_MousePoints)//リストに格納されている要素数すべて繰り返す
{
//マウスの位置に11x11の四角を赤色で描く
g.DrawRectangle(Pens.Red, p.X - 6, p.Y - 6, 11, 11);//円の中心を得るために11×11なので
//先に描いた四角に外接する楕円を黒で描く //6ずつ描画する座標をずらす
g.DrawEllipse(Pens.Black, p.X - 6, p.Y - 6, 11, 11);//マウスの座標を円で描画
//g.DrawLine(pen, before_p.X, before_p.Y, dp.X, dp.Y);//マウスの動いた軌跡を描画
}

g.DrawLines(pen, Pt);

/*if (cp.X > 0 && cp.Y > 0)
{
if (cp.X < 600 && cp.Y < 400)
{
before_p = cp;
}
}*/

//リソースを解放する
g.Dispose();
//PictureBox1に表示する
pictureBox1.Image = bmp2;
}

private void List_Check()//古いリストの要素を削除する
{
// マウス座標を格納する最大数以上なら先頭の座標をリストから削除
if (MousePoints.Count >= max_point)
{
MousePoints.RemoveAt(0);
}

if (Move_MousePoints.Count >= max_movepoint)
{
Move_MousePoints.RemoveAt(0);
}
}
}
}

よろしくおねがいします













引用返信 編集キー/
■68815 / inTopicNo.20)  Re[11]: 取得するマウスの座標をクライアント領域内に限定するには
 
□投稿者/ しま (41回)-(2013/11/19(Tue) 09:05:03)
No68813 (yoto さん) に返信
> Jittaさん、自分の説明がしきれていなかったようで申し訳ございません。
>
> なので、自分の行っていきたいと思っている内容を説明させていただきます。
>
> 自分は現在、マウスの左ボタンをドラッグしている間、円と直線を描画し、軌跡を表現したいと思っています。
> ですが、皆さまのご指摘で
> 1.ドラッグをしている間その座標をリストに格納し続けていると動作が遅くなると言う問題
> と
> 2.軌跡を描きつづけていると画面が見づらくなってしまうと言う問題
> に気が付きました。
>
> なので、リストの要素が一定数に達したら要素[0]を削除する。
> そして、その不要な要素を削除したリストを元に円と直線を描画する。
> こうすることで、上記の二つの問題が解決できると思いました。
>
> 実際に68775でのanさんのご指摘と自分でプログラムを組んでみました。
> 結果、1の問題は解決できました。
> しかし、2の問題において円が問題なく削除しながら円をリストの要素分描画できるのですが、
> 直線が一本しか描くことができませんでした。
>
> 自分としてはそれは描画先であるbmp2を描画されるたびに初期化しているためだと考えました。
> なので、円とおなじく直線の描画するdrawlineをforeachでリストの要素数分だけ処理を回すように修正してみました。
>
> foreach (Point p in Move_MousePoints)//リストに格納されている要素数すべて繰り返す
> {
> //マウスの位置に11x11の四角を赤色で描く
> g.DrawRectangle(Pens.Red, p.X - 6, p.Y - 6, 11, 11);//円の中心を得るために11×11なので
> //先に描いた四角に外接する楕円を黒で描く //6ずつ描画する座標をずらす
> g.DrawEllipse(Pens.Black, p.X - 6, p.Y - 6, 11, 11);//マウスの座標を円で描画
> g.DrawLine(pen, before_p.X, before_p.Y, p.X, p.Y);//マウスの動いた軌跡を描画
> }
>
>
> が、実行結果を見ると円と円の間直線は描けているのですが、
> どうもbefore_p.Xとbefore_p.Yから要素分だけp.Xとp.Yで複数直線が描かれてしまって思うようにはなりませんでした。
>
だってそうしているから。
起点 before_p の値は固定なので、終点 p が次々に変わる度に放射状に線を引くのは当り前のことだと思います。
before_p をどう使いたかったのか説明して欲しいと思います。
若し、Mouse_MovePoints に n 点あって、i番目の点から i+1 番目の点に線を引く場合、 before_p は i 番目の点で
p が i+1 番目の点として線を引きたいのならどうすべきなのか考えてみましょう
(0 <= i < i+1 < n の関係があるとする)
そして、次の点に移ったときには before_p と p との関係はどうあって欲しいのでしょうか?
before_p は i+1 番目の点で、p が i+2 番目の点であって欲しいのでしょうか?


引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -