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

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

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

Re[21]: パネル内の座標値、そして座標値の範囲を設定す


(過去ログ 31 を表示中)

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

■14280 / inTopicNo.1)  パネル内の座標値、そして座標値の範囲を設定する方法
  
□投稿者/ Tetsu (4回)-(2008/02/14(Thu) 14:29:30)
Tetsu さんの Web サイト

分類:[C#] 

開発環境:Visual Studio 2005
使用言語:C#

先日、パネルへの折れ線描画についてこちらで質問させていただいた者です。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=14149

まだこの掲示板でのルールがあまりわかっていないので、頻度が多く質問をしてはいけないのかもしれませんが、質問させていただきます。

先日は、パネルへの折れ線の描画方法について質問させていただきましたが、今回は、

「描画をするパネルの座標値をどうやってコードの中で設定できるのか」

ということについて質問させていただきます。座標は普通Locationで与えられていますが、LocationはForm上での座標になります。私が行いたいのは、「パネル内での座標値をどう設定するか」ということです。具体的には、パネル内では左上の座標が(0, 0)ですが、その値を変更することが可能なのかどうか、知りたいのです。

私が行いたい作業を図にしてウェブ上にアップロードしました。panel.pdfというファイルになります。ご覧いただけると嬉しいです。
http://tetsuo.koba.googlepages.com/home

私がやりたいことは、

1.データベースから、x座標、y座標を含む点のデータをクエリする。
2.点データを取得する。
3.取得した点データのx座標、y座標、それぞれの最小値、最大値(コードでは、xMin, yMin, xMax, yMax)を求める。
◎4.それら最大値、最小値を、パネルの座標に設定する。具体的には、普通はパネルの一番左上の座標が(0, 0)ですが、それを(xMin, yMax)に設定し、そして、パネルの一番右下の座標を(xMax, yMin)に設定したいと思っています。
5.折れ線を、4で座標を設定しなおしたパネル上に描く。

ということです。◎がついている、4番のやり方がわかりません。下記のコードではForm上にあるボタンをクリックすると折れ線を描画するようになっています。その中で、

//パネルの座標値を設定する方法がわかりません

となっている場所に上記の4番の作業をしたいと思っています。どなたか教えていただけないでしょうか。よろしくお願いします。




        public partial class Form1 : Form
        {
            DrawingMOD myDraw; //Form1で共通に使用するオブジェクト変数の宣言

            public Form1()
            {
                InitializeComponent();
                this.myDraw = new DrawingMOD(this.panel1);
                myDraw.DrawPanel += new DrawOnPanel(myDraw_DrawPanel);

            }

            //描画に使用する3点の座標 (データベースからクエリされたものと仮定)
            private float xOne = 50.01f;
            private float yOne = 100.01f;
            private float xTwo = 100.01f;
            private float yTwo = 100.01f;
            private float xThree = 120.01f;
            private float yThree = 120.01f;

      //クエリされた点すべての座標の中で、x座標、y座標の最大値、最小値
            private float xMin;
            private float yMin;
            private float xMax;
            private float yMax;

            private void button1_Click(object sender, EventArgs e)
            {
                this.myDraw.DrawMovingObjects();
            }

            //myDraw_DrawPanelイベントハンドラ
            private void myDraw_DrawPanel(object sender, PaintEventArgs e)
            {
                //パネルのインスタンスを作成
                Panel panel = sender as Panel;
                e.Graphics.Clear(Color.Green);

                //パネルに設定する座標の最大値、最小値を求める。仮定として作った点座標から計算
                xMin = 50.01f;
                yMin = 100.01f;
                xMax = 120.01f;
                yMax = 120.01f;

                //パネルの座標値を設定する方法がわかりません
                panel.Location = new PointF(xMin, yMin);
                panel.Width = Math.Abs(xMax - xMin);
                panel.Height = Math.Abs(yMax - yMin);

                //ペンの色を定義
                int cRed = 200;
                int cGreen = 100;
                int cBlue = 100;

                //折れ線に使用する3点をPointF[]に格納する
                PointF[] myPoints = new PointF[3];
                myPoints[0] = new PointF(xOne, yOne);
                myPoints[1] = new PointF(xTwo, yTwo);
                myPoints[2] = new PointF(xThree, yThree);

                Pen pen = new Pen(Color.FromArgb(cRed, cGreen, cBlue), 4);//ペンを作成

                pen.EndCap = LineCap.ArrowAnchor; //折れ線を矢印にする
                e.Graphics.DrawLines(pen, myPoints); //折れ線を描く
            }

            ////////e.Dispose(); //Graphicsオブジェクトの破棄
        }

引用返信 編集キー/
■14281 / inTopicNo.2)  Re[1]: パネル内の座標値、そして座標値の範囲を設定する方法
□投稿者/ やじゅ (159回)-(2008/02/14(Thu) 14:47:39)
No14280 (Tetsu さん) に返信
> ◎4.それら最大値、最小値を、パネルの座標に設定する。
> 具体的には、普通はパネルの一番左上の座標が(0, 0)ですが、それを(xMin, yMax)に設定し、
> そして、パネルの一番右下の座標を(xMax, yMin)に設定したいと思っています。

 算数的な問題では?
 各点の座標を、最小値の(xMin, yMax)分だけ引いて、(0, 0)を基準とすればいいですよね。
引用返信 編集キー/
■14282 / inTopicNo.3)  Re[1]: パネル内の座標値、そして座標値の範囲を設定する方法
□投稿者/ シャノン (291回)-(2008/02/14(Thu) 14:49:18)
No14280 (Tetsu さん) に返信

原点の平行移動でよいのなら、Graphics.TranslateTransform が使えそうです。
他にも、Graphics.ナントカTransform というメソッドで、様々な座標変換ができます。
引用返信 編集キー/
■14307 / inTopicNo.4)  Re[2]: パネル内の座標値、そして座標値の範囲を設定する方法
□投稿者/ Tetsu (6回)-(2008/02/14(Thu) 22:26:53)
Tetsu さんの Web サイト
やじゅさん

ご返答ありがとうございます。

> 算数的な問題では?
> 各点の座標を、最小値の(xMin, yMax)分だけ引いて、(0, 0)を基準とすればいいですよね。

これは平行移動の場合ですよね?では、もし、点の座標が元のパネルのサイズを超えてしまう場合は、どうしたらいいのでしょうか。比率を計算して、そのパネルの中に収まるように点の座標を変換すればいいのでしょうか。
引用返信 編集キー/
■14309 / inTopicNo.5)  Re[3]: パネル内の座標値、そして座標値の範囲を設定する方法
□投稿者/ Tetsu (7回)-(2008/02/14(Thu) 22:33:17)
Tetsu さんの Web サイト
シャノンさん、ご返答ありがとうございます。

> 原点の平行移動でよいのなら、Graphics.TranslateTransform が使えそうです。
> 他にも、Graphics.ナントカTransform というメソッドで、様々な座標変換ができます。

ありがとうございます。もう一つの疑問は、点のデータの座標がパネルのサイズを大きく超えてしまい、パネル上に表示されないことです。パネルをスクロールすることは可能なのでしょうか。プロパティのAutoScrollをTrueにしましたが、それをTrueにしても、結局パネルに折れ線が表示される範囲(パネルのサイズ)は変わりませんでした。平行移動ももちろんできるようにしたいのですが、拡大、縮小もしたいと思っています。これもメソッドの一つでできるのでしょうか。もしご存知でしたら教えていただけないでしょうか。自分でもさっそく「なんとかTransform」メソッドを探してみます。
引用返信 編集キー/
■14314 / inTopicNo.6)  Re[4]: パネル内の座標値、そして座標値の範囲を設定する方法
□投稿者/ やじゅ (162回)-(2008/02/14(Thu) 23:26:26)
やじゅ さんの Web サイト
No14309 (Tetsu さん) に返信
>パネルをスクロールすることは可能なのでしょうか。

プロパティのAutoScrollをTrueにすればいいですが、中に別コントロールを
入れる必要があります。
中に別コントロールのサイズを変えればスクロールされるようになります。

PictureBoxコントロールに描画するとかパネルの中にパネルを入れるとか
すればいいかも

スクロールバーを付けて画像を表示する
http://dobon.net/vb/dotnet/graphics/scrollimage.html
引用返信 編集キー/
■14321 / inTopicNo.7)  Re[5]: パネル内の座標値、そして座標値の範囲を設定する
□投稿者/ Tetsu (8回)-(2008/02/15(Fri) 05:16:03)
Tetsu さんの Web サイト
2008/02/15(Fri) 10:44:58 編集(投稿者)
2008/02/15(Fri) 08:11:30 編集(投稿者)
<pre><pre>2008/02/15(Fri) 08:08:42 編集(投稿者)
<pre><pre>2008/02/15(Fri) 08:03:13 編集(投稿者)
<pre><pre>2008/02/15(Fri) 08:02:11 編集(投稿者)

<pre><pre>やじゅさん、ありがとうございます。

> PictureBoxコントロールに描画するとかパネルの中にパネルを入れるとかすればいいかも
> 
> スクロールバーを付けて画像を表示する
> http://dobon.net/vb/dotnet/graphics/scrollimage.html

上記のサイトで掲載されているものを参考にし、パネル(panel1)の中にパネル(panel2)を入れ、panel2上に折れ線を描くコードを作成しました。
panel2のWidthとHeightをpanel1よりも大きい範囲に設定したところ、スクロールバーが現れました。
しかし、肝心の折れ線が表示されないのです。正確には、

「コードを走らせると、一瞬だけ折れ線がパネル上に表示され、その後折れ線が消え、その後は黒い背景がずっと映っている」

ようになってしまいます。
黒い背景は私が設定したものなので、背景が映っているのですが、描かれた折れ線がなぜか一瞬映って消えてしまいます。
背景色を設定しなくとも、同じような結果になります。
パネルのプロパティの設定に問題があるのではないかと思い、いろいろと値を変更してみましたが、解決できませんでした。

また、何度かコードを走らせると、たまに折れ線がちゃんと描画されます。
その時にスクロールでパネルを動かすと、一度パネル上から消えた折れ線は、再び描画されなくなってしまいます。
再描画をする必要があるのでしょうか。この点についてもよくわかりません。
以下に私が作成しましたコードをお知らせします。

なお、panel2のプロパティは以下のように設定しました。
Location:(0, 0)
AutoSize:true
Width:1000
Height:1000

panel1のプロパティは以下のように設定しました。
AutoScroll:true

なお、panel1 と panel2 はあらかじめForm1上に作成し、panel2をpanel1の中に入れてあります。
問題点をまとめますと、以下のようになります。

・アプリケーションを起動すると、折れ線が一瞬パネルに描かれ、
すぐに消えてしまう。

・折れ線が表示されたパネルをスクロールし、再び元の場所まで戻ると、
それまで描かれていた折れ線が消えてしまう。

という2点です。アドバイスをいただけると嬉しいです。何度も申し訳ありませんが、よろしくお願いします。トピックと質問が少しかみ合わなくなっているので、新しい質問として掲載したほうが良いのかもしれませんね。



     public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //折れ線を描くのに使用する3点の座標を定義
        private float xOne = 50.01f;
        private float yOne = 100.01f;
        private float xTwo = 100.01f;
        private float yTwo = 100.01f;
        private float xThree = 120.01f;
        private float yThree = 120.01f;

        //panel1 の中にpanel2をいれ、panel2上に折れ線を描く
        private void panel2_Paint(object sender, PaintEventArgs e)
        {
            //折れ線を描くpanel2 を作成
            //Panel panel2 = sender as Panel;

            //背景の色を黒に設定
            //e.Graphics.Clear(Color.Black);

            //折れ線を絵がくために使用する3点の配列
            PointF[] myPoints = new PointF[3];

            //RGB color parameters
            int cRed = 200;
            int cGreen = 100;
            int cBlue = 100;

            //ペンを定義
            Pen pen = new Pen(Color.FromArgb(cRed, cGreen, cBlue), 4);

            //折れ線の位置をずらして3本の折れ線を描画
            for (int i = 0; i < 3; i++)
            {
                //点を配列に格納
                myPoints[0] = new PointF(xOne, yOne);
                myPoints[1] = new PointF(xTwo, yTwo);
                myPoints[2] = new PointF(xThree, yThree);

                //折れ線を矢印にする
                pen.EndCap = LineCap.ArrowAnchor;

                //折れ線を描く
                e.Graphics.DrawLines(pen, myPoints);

                //折れ線の位置を変える
                xOne += 200f;
                yOne += 200f;
                xTwo += 200f;
                yTwo += 200f;
                xThree += 200f;
                yThree += 200f;

                //折れ線の色を変える
                cRed += 20;
                cGreen += 40;
                cBlue += 20;
            }
            //パネルを消去
            //e.Graphics.Dispose();
        }
    }</pre></pre></pre></pre></pre></pre></pre></pre>

引用返信 編集キー/
■14332 / inTopicNo.8)  Re[6]: パネル内の座標値、そして座標値の範囲を設定する
□投稿者/ やじゅ (163回)-(2008/02/15(Fri) 12:46:19)
No14321 (Tetsu さん) に返信
> その時にスクロールでパネルを動かすと、一度パネル上から消えた折れ線は、再び描画されなくなってしまいます。
> 再描画をする必要があるのでしょうか。この点についてもよくわかりません。

再描画をする必要があります。

一案ですが、
折れ線グラフを、Bitmapイメージで作成しpictureBoxコントロールにてそのBitmapイメージを表示させるようにすれば、
スクロールさせても自動的に描画されます。

ようは折れ線グラフを一度画像にするってことです。
引用返信 編集キー/
■14348 / inTopicNo.9)  Re[7]: パネル内の座標値、そして座標値の範囲を設定する
□投稿者/ Tetsu (9回)-(2008/02/15(Fri) 17:57:13)
Tetsu さんの Web サイト
やじゅさん

度々ご返答ありがとうございます。感謝しています。
 
> 再描画をする必要があります。
> 
> 一案ですが、
> 折れ線グラフを、Bitmapイメージで作成しpictureBoxコントロールにてそのBitmapイメージを表示させるようにすれば、
> スクロールさせても自動的に描画されます。
> 
> ようは折れ線グラフを一度画像にするってことです。

ということは、画像にしていないと再描画されないということでしょうか。
その後の作業の関係上、なるべくBitmapにはしたくないと思っているのです。
他に何も方法がない、という時はBitmapにするかもしれませんが。
現在取り組んでいるのは、グラフではなく、GPSで取得した位置データを描画しようとしているのです。

Update()やInvalidate()などを使ってみましたが、どうもうまくいきません。
Application.DoEvents();をforループの前につけたところ、アプリケーション起動時には折れ線は描くことができました。
しかし、画面をスクロールすると、やはり描画されていた折れ線は消えてしまいます。

画面をスクロールした時に再描画をさせるしかけを作らねばならない、ということになるでしょうか。
画面をスクロールした時に再描画する方法、というのは存在するのでしょうか。
私なりに調べてみましたが、みつかりませんでした。
ご存知でしたら教えていただけないでしょうか。



            //折れ線の位置をずらして3本の折れ線を描画
            for (int i = 0; i < 3; i++)
            {
                Application.DoEvents();

                //点を配列に格納
                myPoints[0] = new PointF(xOne, yOne);
                myPoints[1] = new PointF(xTwo, yTwo);
                myPoints[2] = new PointF(xThree, yThree);

                //折れ線を矢印にする
                pen.EndCap = LineCap.ArrowAnchor;

                //折れ線を描く
                e.Graphics.DrawLines(pen, myPoints);


                
                //折れ線の位置を変える
                xOne += 300f;
                yOne += 300f;
                xTwo += 300f;
                yTwo += 300f;
                xThree += 300f;
                yThree += 300f;

                //折れ線の色を変える
                cRed += 20;
                cGreen += 40;
                cBlue += 20;


            }

引用返信 編集キー/
■14350 / inTopicNo.10)  Re[8]: パネル内の座標値、そして座標値の範囲を設定する
□投稿者/ 魔界の仮面弁士 (630回)-(2008/02/15(Fri) 18:20:44)
No14348 (Tetsu さん) に返信
> しかし、画面をスクロールすると、やはり描画されていた折れ線は消えてしまいます。

最初は、
 float xOne = 50.01f;
であった変数が、Paint イベントを処理するたびに、
 xOne += 200f;
が繰り返されるからでしょう。
再描画が発生するたびに、描画先の座標が変わってしまっていますよね。


あと、Pen を解放し忘れています。
引用返信 編集キー/
■14361 / inTopicNo.11)  Re[9]: パネル内の座標値、そして座標値の範囲を設定する
□投稿者/ Tetsu (10回)-(2008/02/16(Sat) 00:23:16)
Tetsu さんの Web サイト
魔界の仮面弁士さん

ご返答ありがとうございます。

> 最初は、
>  float xOne = 50.01f;
> であった変数が、Paint イベントを処理するたびに、
>  xOne += 200f;
> が繰り返されるからでしょう。
> 再描画が発生するたびに、描画先の座標が変わってしまっていますよね。

そうですか。では、このforループを使用している以上、再描画をしても私がやりたいことは達成できない、ということでしょうか。
どうしてもforループは私のこのコードには必要なのです。
実際ににやりたいことは、

xOne += 200f;

というように始めの座標をどんどん変えていくのではなく、データベースから読んできたx,y座標を一つずつ使って折れ線を描くのですが、
やはりその場合も魔界の仮面弁士さんがおっしゃっているように「再描画が発生するたびに、描画先の座標が変わってしまっています」から、このままでは不可能なのでしょうか。
もしこのままの手法でスクロールした後の再描画が困難な場合は、

・Bitmapとして表示をするか(やじゅさんのコメントより)

あるいは、

・描画する前に座標を変換し、パネルの中に全ての座標が収まるようにし、スクロールが必要ないようにする

という2つの方法のどちらかが有効ではないかと思うのですが、いかがでしょうか。


> あと、Pen を解放し忘れています。

了解しました。こちらについてはすぐにやってみます。
本当にありがとうございます。

引用返信 編集キー/
■14364 / inTopicNo.12)  Re[10]: パネル内の座標値、そして座標値の範囲を設定する
□投稿者/ やじゅ (167回)-(2008/02/16(Sat) 03:40:41)
やじゅ さんの Web サイト
No14361 (Tetsu さん) に返信
>
>最初は、
> float xOne = 50.01f;
> どうしてもforループは私のこのコードには必要なのです。

forループはいいとして、float xOne = 50.01f;を、
panel2_Paint内に定義するとかしないと、描画するたびにそれていくのでは

引用返信 編集キー/
■14366 / inTopicNo.13)  Re[10]: パネル内の座標値、そして座標値の範囲を設定する
□投稿者/ 魔界の仮面弁士 (631回)-(2008/02/16(Sat) 09:27:52)
2008/02/16(Sat) 09:48:12 編集(投稿者)

No14361 (Tetsu さん) に返信
> では、このforループを使用している以上、再描画をしても私がやりたいことは達成できない、ということでしょうか。
単純修正では、forループを抜けた直後に、
 xOne = 50.01f;
などのように、元の値を設定しなおすだけで済むと思いますよ。


ただしそもそもは、xOne を使いまわしているのが問題なのだと思います。
「xOne の初期値」を取っておく変数と「描画用」の変数は分ける必要があるので、今回の場合は

 private float xOneInit = 50.01f;
   :
 void panel2_Paint(object sender, PaintEventArgs e)
 {
   :
  float xOne = xOneInit;
   :
  for (int i = 0; i < 3; i++)
  {
    :
   myPoints[0] = new PointF(xOne, yOne);
    :
   e.Graphics.DrawLines(pen, myPoints);
   xOne += 200f;
    :
  }
 }
のようにした方が良いでしょう。もちろん、xOne 以外の座標についても同様です。


> データベースから読んできたx,y座標を一つずつ使って折れ線を描くのですが、
その場合、Paint イベントの中で myPoints 配列を決定するのでは無く、
Paint イベントに入る前に、myPoints 配列を用意しておけばよいと思いますよ。
(xMin, yMin, xMax, yMax なども、Paint イベントの発生前に事前に計算しておく)

また、それらの描画座標(myPoints 配列等)が変更された場合には、
Invalidate を呼び出して、Paint イベントを再発生させると良いでしょう。


> ・Bitmapとして表示をするか(やじゅさんのコメントより)
描画内容が複雑であり、再描画に時間を要する場合などでは、その方法がおすすめです。

ただし、描画内容が頻繁に変化する場合には(心電図など)、Bitmap や Metafile を
用意するよりも、やはり Paint で描画した方が良いでしょう。
(変化の少ない部分だけを Bitmap として持ち、変化の多い部分を Paint で担当という手もあり)

また、現在の 1000x1000 という程度のキャンバスなら、デスクトップの壁紙程度のサイズなので
さほど問題は無いですが、もしも巨大なキャンバスが必要な場合は、全体を一つの Bitmap として
表示させるという方法では、負荷が高いかも知れません。


> ・描画する前に座標を変換し、パネルの中に全ての座標が収まるようにし、スクロールが必要ないようにする
座標変換というと、このあたりですね。
http://msdn.microsoft.com/library/ja/cpguide/html/_gdiplus_Coordinate_Systems_and_Transformations_about.asp

現在のキャンバスである panel2 の Size は、1000, 1000 ですよね。
もしもそれに収まるなら、縮小のための座標変換は不要だと思います。

もし、1000,1000 では収まりきれないほどの内容を、縮小せずにスクロールで表現したいなら、
Panel 重ね合わせではなく、HScrollBar/VScrollBar コントロールとの組み合わせで、
表現するという方法もあります。
http://msdn2.microsoft.com/ja-jp/library/b2xw7sx1.aspx
引用返信 編集キー/
■14368 / inTopicNo.14)  Re[11]: パネル内の座標値、そして座標値の範囲を設定する
□投稿者/ Tetsu (11回)-(2008/02/16(Sat) 11:02:00)
Tetsu さんの Web サイト
やじゅさん、魔界の仮面弁士さん、

コメント、ありがとうございます。早速試してみます。結果を報告させていただきます。
引用返信 編集キー/
■14448 / inTopicNo.15)  Re[12]: パネル内の座標値、そして座標値の範囲を設定する
□投稿者/ Tetsu (12回)-(2008/02/19(Tue) 01:59:45)
Tetsu さんの Web サイト
やじゅさん、魔界の仮面弁士さん、

ここ2日間くらいプログラミングをする時間をもてなかったのですが、アドバイスどおりにやってみたところ、解決できました。やはり基本的には変数をどこで定義しているのかに問題があったみたいです。panel2_Paint内でxOne〜yThreeの座標を初期化したら、ちゃんと再描画されるようになりました。座標系変換やHScrollBar/VScrollBar コントロールについてもこれから勉強し、プログラムを改良していきたいと思います。

何度もお付き合いいただき、本当にありがとうございました。
解決済み
引用返信 編集キー/
■14454 / inTopicNo.16)  Re[13]: パネル内の座標値、そして座標値の範囲を設定す
□投稿者/ Tetsu (13回)-(2008/02/19(Tue) 08:24:11)
Tetsu さんの Web サイト
2008/02/19(Tue) 08:26:47 編集(投稿者)
すみません、解決済みにチェックしてしまいましたが、もう一つ質問させていただきたいです。
先日回答していただいたコードより少し改良しようと思い、

「ボタンを押すと、panel1の中に入っているpanel2上に折れ線が描画される」

というものにしようとしました。
その際、DrawingMODというクラスを作り、そこにデリゲートを作成しました。
そして、Formのコード上にある、ボタンをクリックするイベントに、折れ線を描くというイベントとイベントハンドラの関連付けを行いました。
しかし、問題画発生しました。Form1のコードの最初に定義している、

        //描画に使用する3点の座標 (データベースからクエリされたものと仮定)
        private float xOne = 50.01f;
        private float yOne = 100.01f;
        private float xTwo = 100.01f;
        private float yTwo = 100.01f;
        private float xThree = 120.01f;
        private float yThree = 120.01f;

が「変数が定義されているが一度も使われていない」というふうにWarningで出てしまいます。
英語のメッセージなのですが、

「Warning 1 The private field 'test_panel.Form1.xOne' is assigned but its value is never used」

となってしまいます。以下にDrawingMODクラスのコードとForm1のコードをお知らせします。
私としては、PaintEventArgsのeの取り扱い方に問題があるのではないかと思うのですが、よくわかっていません。
試しにコードを走らせると、panel2上に3本描かれるべき折れ線のうち、最初のもののみが描かれました。
また、再描画されなくなってしまいました。

どこに問題があるのか、ご指摘いただけないでしょうか。よろしくお願いします。



【DrawingMODクラスのコード】
    public delegate void DrawOnPanel(object sender, PaintEventArgs e);//デリゲート

    class DrawingMOD
    {
        public event DrawOnPanel DrawPanel; //イベントフィールド
        
        private Control m_control;

        //コンストラクタ
        public DrawingMOD(Control c)
        {
            this.m_control = c;
        }

        //パネルに折れ線を描画するメソッド
        public void DrawMovingObjects()
        {
            PaintEventArgs e = new PaintEventArgs(m_control.CreateGraphics(), m_control.ClientRectangle);
            this.DrawPanel(this.m_control, e); 
            e.Graphics.Dispose();
        }
    }


【Form1のコード】

    public partial class Form1 : Form
    {
        DrawingMOD myDraw; //Form1で共通に使用するオブジェクト変数の宣言

        //描画に使用する3点の座標 (データベースからクエリされたものと仮定)
        private float xOne = 50.01f;
        private float yOne = 100.01f;
        private float xTwo = 100.01f;
        private float yTwo = 100.01f;
        private float xThree = 120.01f;
        private float yThree = 120.01f;

        public Form1()
        {
            InitializeComponent();
            this.myDraw = new DrawingMOD(this.panel2);
            myDraw.DrawPanel += new DrawOnPanel(myDraw_DrawPanel);

        }


        private void button1_Click(object sender, EventArgs e)
        {
            this.myDraw.DrawMovingObjects();
        }

        //myDraw_DrawPanelイベントハンドラ
        private void myDraw_DrawPanel(object sender, PaintEventArgs e)
        {

            //パネルのインスタンスを作成
            Panel panel2 = sender as Panel;
            this.panel2.AutoSize = true;

            //set the background color
            e.Graphics.Clear(Color.Black);

            //Initialize the coordinates
            float xOne = 50.01f;
            float yOne = 100.01f;
            float xTwo = 100.01f;
            float yTwo = 100.01f;
            float xThree = 120.01f;
            float yThree = 120.01f;
            
            //ペンの色を定義
            int cRed = 200;
            int cGreen = 100;
            int cBlue = 100;

            Pen pen = new Pen(Color.FromArgb(cRed, cGreen, cBlue), 4); //ペンを作成

            //折れ線に使用する3点をPointF[]に格納する
            PointF[] myPoints = new PointF[3];
            myPoints[0] = new PointF(xOne, yOne);
            myPoints[1] = new PointF(xTwo, yTwo);
            myPoints[2] = new PointF(xThree, yThree);

            for (int i = 0; i < 3; i++)
            {
                pen.EndCap = LineCap.ArrowAnchor; //折れ線を矢印にする
                e.Graphics.DrawLines(pen, myPoints); //折れ線を描く

                //change the location for another line
                xOne += 200f;
                yOne += 200f;
                xTwo += 200f;
                yTwo += 200f;
                xThree += 200f;
                yThree += 200f;

                //change the color of lines
                cRed += 20;
                cGreen += 40;
                cBlue += 20;
            }
        }

    }

引用返信 編集キー/
■14457 / inTopicNo.17)  Re[14]: パネル内の座標値、そして座標値の範囲を設定す
□投稿者/ 魔界の仮面弁士 (636回)-(2008/02/19(Tue) 09:17:18)
No14454 (Tetsu さん) に返信
> が「変数が定義されているが一度も使われていない」というふうにWarningで出てしまいます。
実際、使われていませんよね?
『private float xOne = 50.01f;』の行を削除しても、動作するわけですし。

> 英語のメッセージなのですが、
英語版の Visual Studio をお使いですか?


> 私としては、PaintEventArgsのeの取り扱い方に問題があるのではないかと思うのですが、よくわかっていません。
Paint イベント内の
 「float xOne = 50.01f;」
で定義された変数と、フォームの
 「private float xOne = 50.01f;」
は、どちらも同じ xOne という変数名ですが、それぞれ異なる変数を意味します。

Paint イベント内にて、単に「xOne」と書けば前者の変数を意味します。
逆に後者の変数を利用したいのであれば、「this.xOne」となります。

No14366 の私の投稿では、そうした同名変数はわかりにくいので、
>> private float xOneInit = 50.01f;
>> void panel2_Paint(object sender, PaintEventArgs e)
>> {
>>  float xOne = xOneInit;
のように、あえて、それぞれ異なる変数名にしています。


> 試しにコードを走らせると、panel2上に3本描かれるべき折れ線のうち、最初のもののみが描かれました。
> また、再描画されなくなってしまいました。
ループ中で、
 e.Graphics.DrawLines(pen, myPoints);
を行っていますが、この myPoints の座標を、ループ中では変更していないからです。
そのため、同じ座標に対して 3回重ね描きしていることになっています。
引用返信 編集キー/
■14461 / inTopicNo.18)  Re[15]: パネル内の座標値、そして座標値の範囲を設定す
□投稿者/ Tetsu (14回)-(2008/02/19(Tue) 10:57:51)
Tetsu さんの Web サイト
2008/02/19(Tue) 10:59:08 編集(投稿者)
2008/02/19(Tue) 10:58:24 編集(投稿者)

<pre><pre>魔界の仮面弁士さん

ご回答ありがとうございます。早速、

> No14366 の私の投稿では、そうした同名変数はわかりにくいので、
> >> private float xOneInit = 50.01f;
> >> void panel2_Paint(object sender, PaintEventArgs e)
> >> {
> >>  float xOne = xOneInit;
> のように、あえて、それぞれ異なる変数名にしています。

のアドバイスをもとに、変数名を変えてみました。そうしたところ、「変数が使われていない」というメッセージはなくなりました。
初歩的なミスです。すみません。
まだC#、そしてオブジェクト指向プログラミングというものを始めて1ヶ月なのと、
周りに誰も質問できる人がいない状況で、この掲示板でご迷惑をおかけしてしまっていると思います。

>>英語のメッセージなのですが、
> 英語版の Visual Studio をお使いですか?

はい。現在アメリカに住んでおり、英語版のVisual Stuio 2005を使っています。


> ループ中で、
>  e.Graphics.DrawLines(pen, myPoints);
> を行っていますが、この myPoints の座標を、ループ中では変更していないからです。
> そのため、同じ座標に対して 3回重ね描きしていることになっています。

これについてですが、以下のようにコードを書き直したところ、ちゃんと3本の折れ線が描かれました。
こちらも単純なミスでした。
点座標を配列に格納する部分をループの中に入れました。

                //折れ線に使用する3点をPointF[]に格納する
                PointF[] myPoints = new PointF[3];
                myPoints[0] = new PointF(xOne, yOne);
                myPoints[1] = new PointF(xTwo, yTwo);
                myPoints[2] = new PointF(xThree, yThree);

あとは再描画の問題のみなのですが、画面をスクロールしてから再度ボタンを押すと、再描画されることがわかりました。
スクロール時に自動的に再描画されるようにするには、スクロールバーの部分を設定する(HScrollBar/VScrollBar コントロール)
必要があるということになるのでしょうか。
ループの後にxOne〜yThreeの値をxOneInit〜yThreeInitに戻してみましたが、変化はありませんでした。



【Form1のコード】
    public partial class Form1 : Form
    {
        DrawingMOD myDraw; //Form1で共通に使用するオブジェクト変数の宣言

        //描画に使用する3点の座標 (データベースからクエリされたものと仮定)
        private float xOneInit = 50.01f;
        private float yOneInit = 100.01f;
        private float xTwoInit = 100.01f;
        private float yTwoInit = 100.01f;
        private float xThreeInit = 120.01f;
        private float yThreeInit = 120.01f;

        public Form1()
        {
            InitializeComponent();
            this.myDraw = new DrawingMOD(this.panel2);
            myDraw.DrawPanel += new DrawOnPanel(myDraw_DrawPanel);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.myDraw.DrawMovingObjects();
        }

        //myDraw_DrawPanelイベントハンドラ
        private void myDraw_DrawPanel(object sender, PaintEventArgs e)
        {

            //パネルのインスタンスを作成
            Panel panel2 = sender as Panel;
            //this.panel2.AutoScroll = true;
            this.panel2.AutoSize = true;

            //set the background color
            e.Graphics.Clear(Color.Black);

            //Initialize the coordinates
            float xOne = xOneInit;
            float yOne = yOneInit;
            float xTwo = xTwoInit;
            float yTwo = yTwoInit;
            float xThree = xThreeInit;
            float yThree = yThreeInit;
  
            //ペンの色を定義
            int cRed = 200;
            int cGreen = 100;
            int cBlue = 100;

            Pen pen = new Pen(Color.FromArgb(cRed, cGreen, cBlue), 4); //ペンを作成
            pen.EndCap = LineCap.ArrowAnchor; //折れ線を矢印にする

            for (int i = 0; i < 3; i++)
            {
                //折れ線に使用する3点をPointF[]に格納する
                PointF[] myPoints = new PointF[3];
                myPoints[0] = new PointF(xOne, yOne);
                myPoints[1] = new PointF(xTwo, yTwo);
                myPoints[2] = new PointF(xThree, yThree);

                e.Graphics.DrawLines(pen, myPoints); //折れ線を描く

                //change the location for another line
                xOne += 200f;
                yOne += 200f;
                xTwo += 200f;
                yTwo += 200f;
                xThree += 200f;
                yThree += 200f;

                //change the color of lines
                cRed += 20;
                cGreen += 40;
                cBlue += 20;

            }

            xOne = xOneInit;
            yOne = yOneInit;
            xTwo = xTwoInit;
            yTwo = yTwoInit;
            xThree = xThreeInit;
            yThree = yThreeInit;
        }

    }

</pre></pre>

引用返信 編集キー/
■14463 / inTopicNo.19)  Re[16]: パネル内の座標値、そして座標値の範囲を設定す
□投稿者/ 魔界の仮面弁士 (637回)-(2008/02/19(Tue) 12:17:12)
2008/02/19(Tue) 13:04:10 編集(投稿者)
No14461 (Tetsu さん) に返信
> スクロール時に自動的に再描画されるようにするには、スクロールバーの部分を設定する(HScrollBar/VScrollBar コントロール)
> 必要があるということになるのでしょうか。
HScrollBar/VScrollBar を使う必要は無いはずですよ。
Panel を入れ子にして、AutoScroll でスクロールさせている分には。


// 何もコントロールを貼っていないフォームに対して、以下のコードを実行してみてください。
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public partial class Form1 : Form
    {
        private PointF One = new PointF(50.01f, 100.01f);
        private PointF Two = new PointF(100.01f, 100.01f);
        private PointF Three = new PointF(120.01f, 120.01f);

        CheckBox checkBox1 = new CheckBox();
        Panel panel1 = new Panel();
        Panel panel2 = new Panel();
        public Form1()
        {
            InitializeComponent();

            checkBox1.Text = "描画する";
            checkBox1.AutoSize = true;
            checkBox1.Location = Point.Empty;
            this.Controls.Add(checkBox1);

            panel1.AutoScroll = true;
            panel1.Dock = DockStyle.Fill;
            panel2.AutoSize = true;
            panel2.Size = new Size(1000, 1000);
            panel2.Location = Point.Empty;

            checkBox1.CheckedChanged += checkBox1_CheckedChanged;

            checkBox1.Checked = true;
            panel1.Controls.Add(panel2);
            this.Controls.Add(panel1);

            this.Size = new Size(400, 400);
        }

        void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked)
            {
                panel2.Paint += panel2_Paint;
            }
            else
            {
                panel2.Paint -= panel2_Paint;
            }
            panel2.Invalidate();
        }

        void panel2_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(Color.Black);

            int cRed = 200;
            int cGreen = 100;
            int cBlue = 100;

            PointF[] myPoints = new PointF[3];
            myPoints[0] = One;
            myPoints[1] = Two;
            myPoints[2] = Three;

            for (int i = 0; i < 3; i++)
            {
                using (Pen pen = new Pen(Color.FromArgb(cRed, cGreen, cBlue), 4))
                {
                    pen.EndCap = LineCap.ArrowAnchor;
                    e.Graphics.DrawLines(pen, myPoints);
                }
                myPoints[0] += new Size(200, 200);
                myPoints[1] += new Size(200, 200);
                myPoints[2] += new Size(200, 200);

                cRed += 20;
                cGreen += 40;
                cBlue += 20;
            }
        }
    }
}


> ループの後にxOne〜yThreeの値をxOneInit〜yThreeInitに戻してみましたが、変化はありませんでした。
戻しても意味はないと思いますよ。
ループ後に、それらの変数値が利用されることは無いのですから。

# 行き当たりばったりでコーディングするのではなく、個々の変数の変化を
# きちんと把握して開発していかないと、なかなか先に進めませんよ。

>   this.panel2.AutoSize = true;
AutoSize 設定は、そのイベントが発生するたびに再設定しなければいけないのでしょうか?

>   Pen pen = new Pen(Color.FromArgb(cRed, cGreen, cBlue), 4); //ペンを作成
No14350 の繰り返しになりますが、Pen の解放処理(Dispose メソッドあるいは using ブロック)を忘れています。

引用返信 編集キー/
■14473 / inTopicNo.20)  Re[17]: パネル内の座標値、そして座標値の範囲を設定す
 
□投稿者/ Tetsu (15回)-(2008/02/19(Tue) 15:10:10)
Tetsu さんの Web サイト
魔界の仮面弁士さん

回答ありがとうございます。いただいたコードを使ってみましたところ、ちゃんと動きました(当たり前ですが)。

> # 行き当たりばったりでコーディングするのではなく、個々の変数の変化を
> # きちんと把握して開発していかないと、なかなか先に進めませんよ。

はい、そのとおりです。もう一度、魔界の仮面弁士さんからいただいたコードと自分のコードをしっかり見て、
自分のコードの欠陥を見つけ、修正してみます。

>> this.panel2.AutoSize = true;
> AutoSize 設定は、そのイベントが発生するたびに再設定しなければいけないのでしょうか?

これは設定する必要はないですね。すみません。

>> Pen pen = new Pen(Color.FromArgb(cRed, cGreen, cBlue), 4); //ペンを作成
> No14350 の繰り返しになりますが、Pen の解放処理(Dispose メソッドあるいは using ブロック)を忘れています。

はい、これも付け加えます。

また報告させていただきます。本当にありがとうございます。
引用返信 編集キー/

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

管理者用

- Child Tree -