none
自作のクラスの中で、Pictureboxの値をかえるためには? RRS feed

  • 質問

  • こんにちは、プログラム中困ったことがあったので、質問させていただきました。

    開発環境は「Visual Studio 2005」で、プロジェクトはC#の「windous アプリケーション」です。


    実は前回pictureboxの透過処理の方法を教えていただいたのですが(参照 題名「pictureboxを重
    ねて描画する 」・・・のURLを張りたかったのですが、URLを張ってしまうと自分のアカウント
    でログインした状態になってしまう恐れがあるので題名だけ><)この方法をやるためにはフォーム
    に張り付けたPictureboxの設定を変えなければいけません。
    そのため自分で作ったクラスの中でフォームに張り付けたPicturebox(例、Picturebox1)の値を変えた
    いのですが、ソースコードで説明すると
    namespace tesuto
    {
        public partial class Form1 : Form
        {
            public class Design//自分で作ったクラス
            {
                void touka()
                {
                           Picturebox1.BackColor = ・・・//実際にPicturebox1を呼び出すことはできない
                    } 
             }
         }
    }
    というような処理をしたいのですが、自作クラスの中ではフォームに張り付けたPictrebox1を呼び出
    すことができなくて困っています。引数でPicturebox1を持ってくる等々いろいろな方法を考えました
    がよくかんがえてみれば、windous アプリケーションを立ち上げると自動的につくるForm。このフ
    ォームのクラスはForm1っていうのはわかるんですけど、インスタンスが一体何という名前なのかがわ
    かりません。

    この自動的に作られたフォームのインスタンス名ってなんなんでしょうか?
    また、自分のクラスの中でどうやればフォームにはりつけたPicturebox1の値を変えれますか?
    よければ御回答ください。

     

    PS.正直この質問をしている今現在でも、自分の中でかなり問題がこんがらがっており、又自分の
    オブジェクト指向に対する理解もまだまだ浅はかなのも災いし、意味不明な点があるかもしれません。
    不明瞭な点等がございましたら大変お手数ですが聞いていただけると助かります。

    また大変恐縮ですが、自分はまだ学生でプログラムを初めて間もないので、少し初心者向けの回答に

    していただけると助かります

     

    2008年11月24日 18:26

回答

  • こんばんは!(^^)!ふ~です。

    Form1の継承を使ってます。

    Code Snippet

    using System;
    using System.Drawing;
    using System.Windows.Forms;

    namespace WinAppTest1
    {
        public partial class Form1 : Form
        {
            public Point ptMyPicBox;

            public Form1()
            {
                InitializeComponent();
                ptMyPicBox = pictureBox1.Location;
                pictureBox1.Paint +=
                    new PaintEventHandler(pictureBox1_Paint);
            }

            void pictureBox1_Paint(object sender, PaintEventArgs e)
            {
                MyClass myclass = new MyClass();
            }
        }

        public class MyClass : Form1
        {
            public MyClass()
            {
                // PictureBoxの背景色を設定する
                Form1.ActiveForm.GetChildAtPoint(ptMyPicBox).BackColor =
                    System.Drawing.Color.Red;
            }
        }
    }

     

     

    Formがアクティブであれば、(Paintのタイミング)PictureBoxにアクセスできるようです。

    2008年11月25日 18:11

すべての返信

  • 外池と申します。

     

    まず、安直な応答から。お示し頂いたコードで基本的にOKですよ? 「実際にPicturebox1を呼び出すことはできない」とはどういう状況なのでしょうか? プログラムを走らせてみてもエラーが出るのでしょうか? どのようなエラーでしょうか?

     

    一方、「インスタンス」、「インスタンスの名前」、などの考え方ですが、あともう1つ大事なものとして「インスタンスへの参照を保持する変数」というものがあります。プログラムに具体的にどのように書いてあるかは一度横においておいて、プログラムが実行されている状態の外観から始めます。

     

    例えば、ディプレイにいわゆるウィンドウが1つ現れます。これは、1つのインスタンスです。そのウィンドウにPictureBoxが2つ含まれていれば、PictureBoxの2つのインスタンスがあります。で、それぞれのインスタンスには表示の内容、外観の形や色など具体的な「姿」があり、その「姿」はパソコンの内部ではメモリー上に格納されている「データ」です。

     

    で、インスタンスに名前があるか? と問われると、微妙です。名前があってもなくてもいいです。あえて名前を付けるようなプログラムになっていれば名前を付けられますが、プログラムされていなければ名前は付けられません。(Formのデザイン時にPictureBoxのプロパティーウィンドウにNameという欄が現れますが・・・、これがご質問を呼び起こした元凶か?)

     

    しかし、メモリー上のどこに(どのアドレスに)、どのインスタンスの「姿」「データ」が格納されているかは、確実に把握しておかなければなりません。そうじゃないと、OSがウィンドウやPictureBoxをディスプレイに描こうとしても何に基づいて描けば良いかわからなくなってしまいます。プログラマーにとっても、インスタンスの「姿」を変えるようにプログラムしようにもメモリー上のどこのデータにアクセスしたらよいか分からなくなります。ですので、インスタンスがメモリーのどこに格納されているのかを覚えておくための変数が必要になります。これが「インスタンスへの参照を保持する変数」です。

     

    長くなりましたが、Picturebox1とプログラムの中に書かれてるものは、「インスタンスへの参照を保持する変数」です。あくまで変数です。で、この変数の名前を、上述のFormのデザイン時にプロパティーウィンドウに現れるNameという欄で指定します。そうすることで、指定した変数名で宣言される(プログラムのある場所に自動的に宣言文が書き込まれる)わけです。

     

    この変数は、今の段階では、書き換えることは考えないでください。プログラムの実行が始まって終わるまで、あるひとつのインスタンスを指し示すものと考えたほうが簡単です。(もちろん書き換えることもできますが、下手に書き換えると、もともと指し示していたインスタンスのメモリー上の場所が二度と判らなくなってしまうこともありますので。)

     

    2008年11月25日 1:11
  • 丁寧なお返事ありがとうございます。

     

    <<「実際にPicturebox1・・・

    どういうエラーかというと、こういう変数って入力しようとしたら、候補の一覧がでるじゃないですか。あれの中にPicturebox1がないんです。他の状況によってはでるんです。その状況を書いていきますね。

     

    namespace tesuto
    {
        public partial class Form1 : Form
        {
            public class Design//自分で作ったクラス
            {
                void touka()
                {

                           Form1 form1 = new Form1();
                           form1.Picturebox1.BackColor = ・・・//これは呼び出せる
                    } 
             }
         }
    }

     

    この方法なら、呼び出せるんですがここで変更したステータスは実際のフォームに張り付けたPicturebox1には反映されていないんです。

    実はこれが質問を呼び起こした元凶なんです。

    確かに、自分で新しくつくったform1のPicturebox1の値を変更しても、それとフォームのPicturebox1の値は別物だから、影響がないのはわかるんですが、ならばいったいあのフォームのPicturebox1は何者なのか? という疑問が浮かんだんです。

     

    また

    namespace tesuto
    {
        public partial class Form1 : Form
        {
            private void Form1_Load(object sender, EventArgs e)//フォーム作成時に勝手に作られる
            {
               Picturebox1.BackColor = ・・・//これは呼び出せる    
            }
         }
    }

     

    フォームが作られたときに自動的に作られるForm1_Loadの中でなら、普通にPicturebox1を呼び出せますし、ここで変更したステータスはフォーム上のPicturebox1にも反映されます。

    ですが、自分としてはこういう処理は自分で作ったデザインクラスで一括してやりたいため、できれば使いたくありません。

     

     

    <<一方、「インスタンス」、「インスタンスの名前」

    なるほど・・・Picturebox1というのは「インスタンスへの参照を保持する変数」という位置づけだったのですね。

    確かに、ユーザーがそのインスタン名を知っている必要性はありませんもんね。

    またひとつ勉強になりました。

     

     

    大変御手数をおかけいたしますが、よければもうしばらくお付き合いください。返信お待ちしております。

    2008年11月25日 6:08
  • 外池です。

     

    本来なら、Form1に貼り付けられたPictureBoxを指し示すForm1のメンバー変数PictureBox1は、Form1のコードの中でいきなりPictureBox1.~ と書いても呼び出せるはずです。これは、2番目に示した頂いたコードの通りですね? これはOKですね。

     

    次に、最初に示して頂いたコードですが、Form1のコードの中に、入れ子にしてもうひとつクラスDesignが宣言されてそのなかにtoukaがありますが、なぜ、Designというクラスが必要なのでしょう?

     

    「一括してやりたい」という気持ちは理解できますが、toukaをForm1の直下に置いたのではダメなんでしょうか・・・。

     

    もしかして、推測ですが、touka以外にも外観を変えるためのメソッドがいくつもあって、それらを、とにかくDesignというものでひと括りにしておきたい、しかも、それをForm1の中において置きたいということでしょうか? だとすれば・・・、Designをクラスにするのは、クラスの使い方とは違うように思います。(示して頂いた1番目のコードは、これは、実際には何も実行しないはずです。)

     

    Designというメソッドにしておいて、そこから、さらにtoukaやらなんやらの下請けメソッドを呼び出す感じにすべきかと。でも、DesignというメソッドはLoadイベントから呼び出すことになりますが。

     

    2008年11月25日 6:50
  • ちょっと状況がはっきりわかっていないので外している部分があるかもしれませんが、内容としては間違っていないと思います。

     

     SE_lain さんからの引用

    このフォームのクラスはForm1っていうのはわかるんですけど、インスタンスが一体何という名前なのかがわかりません。

     

    敢えて言うのであれば、私なら「Form1の分身1」と名付けるでしょうか。newするごとに「Form1の分身2」、「Form1の分身3」、・・・ですね。敢えてといったのは、通常はインスタンスはインスタンス変数にその在りかを入れて、インスタンス変数として扱うので、インスタンス本体をコードから扱うことがなく、気にする必要がないからです。インスタンス変数にはインスタンス本体そのものが入っているのではなく、インスタンス本体の在りかが書かれているだけです。在りかですので、一つのインスタンス本体を指すインスタンス変数を複数用意することもできます。

     

    Form1が起動する時にPictureBoxクラスをnewして作成されたインスタンスの在りかが、インスタンス変数であるPicturebox1にセットされています。それでForm1からはForm1の内部にあるPicturebox1を利用してそのインスタンス本体に辿り着けるのです。この段階ではインスタンス本体への在りかが格納されているのはPicturebox1というインスタンス変数だけです。

     

    クラスは自分のクラスのことしかわかりませんので、自作されたクラスは自分の中でPicturebox1を探しますが、そんなものは存在しないので見つけることができません。なのでインテリセンスにも出てきません。

    自作されたクラスが欲しいのはPicturebox1ではなく、そこに格納されたインスタンス本体への在りかを記したものです。これをインスタンスへの参照といいます。それを知ることができるのであればインスタンス変数はPicturebox1だろうがPicturebox10だろうがPicturebox100だろうが何でも良いのです。だから、もし自作されたクラスが自分のクラスの中を探して、そのインスタンス本体への参照が入ったインスタンス変数を見つけることができれば、PictureBoxのインスタンス本体へ辿り着けるわけです。くどいですが、このインスタンス変数の名前は何だっていいんです。ただ、わかりやすい名前にして下さいね。

     

    #わかりやすいようにと思い、ところどころインスタンス本体と敢えて書きましたが、それは強調しているだけであり、一般的には全てインスタンスと表現されます。

    2008年11月25日 9:34
    モデレータ
  •  



    void touka()
    {
        Form1 form1 = new Form1();
        form1.Picturebox1.BackColor = ・・・//これは呼び出せる
    }

     

     touka メソッドの中で新しい Form1 のインスタンスを作っているため、touka を呼び出しているであろう(表示されている)Form1 のインスタンスとは別のものを操作しているわけです。
     そこまで、理解はされていると思われるのですが、次の「ならばいったいあのフォームのPicturebox1は何者なのか? という疑問が浮かんだ」が、よくわかりません。あのフォームの PictureBox1 は、あのフォームに所属している PictureBox1 であって、それ以外の何者でもありません。例えば、ここで touka メソッドを、


    void touka()
    {
        Form1 form1 = new Form1();
        form1.Picturebox1.BackColor = ・・・//これは呼び出せる
        form1.Show();
    }

     

    と変えてみます。すると、PictureBox1 が透過になっているフォームが、もう一枚表示されます(そして、その中から touka が呼ばれるでしょうから、無限連鎖して落ちる)。

     ここまでわかれば、「今表示しているものを Design クラスのインスタンスに渡してやればよい」に、進めると思うのですが。。。

     で、「こういう処理は自分で作ったデザインクラスで一括してやりたい」というのは、どうかと思います。もちろん、case by case なのですが。特に Load で行うのであれば、設計時にプロパティとして設定してしまえば、表には出てこない partial なところで設定が行われます。
     多数のフォームで同じようなことを行うので、コードをまとめるため…という理由であっても、やはりどうかと思います。オブジェクト指向は、責任の所在を明らかにします。今、PictureBox1 の表示状態を変更する責任を持っているのは PictureBox 自体であり、それを保持している Form ではないでしょうか。もちろん責任を delegate することもできますが。

     それから、class 定義の中で class を定義するのも、どうかと思います。もちろん、case by case です。

    2008年11月25日 12:34
  • ちょっと訂正します。

     

     trapemiya さんからの引用

    クラスは自分のクラスのことしかわかりませんので、自作されたクラスは自分の中でPicturebox1を探しますが、そんなものは存在しないので見つけることができません。

     

    "クラスは自分のクラスのことしかわかりませんので"と書きましたが、これはインスタンスに関することであって、static変数などクラスレベルのものは見つけることができます。

    2008年11月25日 14:56
    モデレータ
  • お返事ありがとうございます。

     

    <<次に、最初に示して頂いたコードですが、Form1・・・

    なるほど・・・、確かに言われてみればそうですね。少し自分自身クラスにこだわりすぎていたかもしれませんね。

     

    <<touka以外にも外観を変えるための

    一応いまんとこはこのメソッドだけです。本来は配列などのデータを、フォームに映すためのクラスという設計でした。

     

    自分がクラスの選択を間違えていたかもしれませんね。とはいえ、このままだと少しずつ本題からずれていってしまいそうなのでまた、設計についての疑問はいつか別のスレッドでさせていただきますね。

    2008年11月25日 15:12
  • わかりやすいお返事ありがとうございます。

     

    <<クラスは自分のクラスのことしかわかりませんので

    なるほど・・・そうですよね。といことは「インスタンスへの参照」を引数として、Designクラスに渡せばPictureboxの本体を変更することができるということであってますよね?

     

    わかりやすいように噛み砕いて説明していただいて助かりました。

    2008年11月25日 15:25
  • 丁寧なお返事ありがとうございます。

     

    <<オブジェクト指向は、責任の所在を明らかにします

    たしかにそうですよね。今一度、どのクラスがどういう動作をするかを設計しなおしたほうがいいかもしれませんね。

     

    たくさんの方々からお返事をいただいて、なぜこのような質問をするにあたったかの大きな原因がようやくわかりました。

    自分は自動的にForm1クラスが作成されていることを認識していなかったようです。

    Form1_Load等々の自動的に作られているメソッドはすべて、Form1クラスのメソッドだったんですね。

    この事実を踏まえた上で考えなおしてみると実にしっくりときました(よくみるとForm1クラスの中に自作のクラス作ってます・・・全部外に放り出すべきですね・・・・)。

     

    お返事をくれた方々実に感謝です。     と書くと質問終わりみたいになってしまいますが、この考えた方であっているかお返事をいただけると助かります。
    2008年11月25日 15:41
  • こんばんは!(^^)!ふ~です。

    Form1の継承を使ってます。

    Code Snippet

    using System;
    using System.Drawing;
    using System.Windows.Forms;

    namespace WinAppTest1
    {
        public partial class Form1 : Form
        {
            public Point ptMyPicBox;

            public Form1()
            {
                InitializeComponent();
                ptMyPicBox = pictureBox1.Location;
                pictureBox1.Paint +=
                    new PaintEventHandler(pictureBox1_Paint);
            }

            void pictureBox1_Paint(object sender, PaintEventArgs e)
            {
                MyClass myclass = new MyClass();
            }
        }

        public class MyClass : Form1
        {
            public MyClass()
            {
                // PictureBoxの背景色を設定する
                Form1.ActiveForm.GetChildAtPoint(ptMyPicBox).BackColor =
                    System.Drawing.Color.Red;
            }
        }
    }

     

     

    Formがアクティブであれば、(Paintのタイミング)PictureBoxにアクセスできるようです。

    2008年11月25日 18:11
  •  SE_lain さんからの引用

    <<クラスは自分のクラスのことしかわかりませんので

    なるほど・・・そうですよね。といことは「インスタンスへの参照」を引数として、Designクラスに渡せばPictureboxの本体を変更することができるということであってますよね?

     

    合ってます。

    2008年11月26日 2:12
    モデレータ
  • お返事ありがとうございます。

     

    なるほど・・・この方法を使えば引数使わずにでも、Pictureboxにアクセスできますね。

    勉強になりました、ありがとうございます。

    2008年11月26日 5:10
  • お返事ありがとうございます。

    お付き合いくださって感謝です。

    2008年11月26日 5:12