none
Form1とForm2間の双方向のデータのやりとり RRS feed

  • 質問

  • 初めてこのフォーラムに投稿します。
    宜しくお願い致します。
    VC++.NET でWindowsアプリケーション(マネージプログラミング)を作成しています。
    その中でForm1の中でForm2のtextBox1->Text に"STEP"を表示し、
    そのごForm2のなかで任意の文字を textBox1->Text いれてクリックすると
    Form1のtextBox1->Textにその内容が表示される処理です。
    Form1 から Form2 への表示はできるのですが、その逆の方法うまく行きません。
    C#ではうまく行きましたので、c#での自動作成部分を省略し掲載します。

    尚、過去に
    http://forums.microsoft.com/msdn-ja/ShowPost.aspx?PostID=689783&SiteID=7
    が有ったのですがうまく行きません。
    >public: System::Windows::Forms::CheckBox^  checkBox1;   // publicに変更
    >private: Form2^ f2; // 追加
    Form2の型が宣言されてないエラーがでます。
    #include "Form2.h" ではさらにエラーがでます.
    Form2で #include "Form2.h"をしているためかな?
    できればc#のような方法が良いのですが、アドバイスをお願い致します。

     

    /// VC++  ////////////////////////////////////////////////////////////////////////////
    /// Form1 /////
    #include "Form2.h"
    private: System::Void button1_Click(System:Surprisebject *  sender, System::EventArgs *  e)
    {

         Form2* dlg = __gc new Form2();
         dlg->Owner = this;
         dlg->textBox1->Text="STEP";
         dlg->Show();

    }

    //Form2 //////
    private: System::Void button1_Click(System:Surprisebject *  sender, System::EventArgs *  e)
    {

         textBox1->Text="123";
         //ここで Form1の textBox1->Text に "123" を表示する処理を追加したい

    }


    ///////////////////////////////////////////////////////////////////////////////////////
    下記のC#の様に常にForm1でForm2のクリックを監視するような方法があれば良いのですが。
    宜しくお願い致します。

    以下c#で作成した例です

    ///// FORM1 ///////////////
    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Data;

    namespace CSMalti
    {
     /// <summary>
     /// Form1 の概要の説明です。
     /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {private System.Windows.Forms.Button button1;
         private System.Windows.Forms.TextBox textBox1;

         private System.ComponentModel.Container components = null;

         public Form1()

         {

              InitializeComponent();

         }
         protected override void Dispose( bool disposing )
         {
                if( disposing )
                 {
                            if (components != null)
                           {
                                   components.Dispose();
                           }
                 }
                 base.Dispose( disposing );
         }

        #region Windows フォーム デザイナで生成されたコード
        private void InitializeComponent()
        {
                 this.button1 = new System.Windows.Forms.Button();
                 略
                 this.textBox1.Location = new System.Drawing.Point(88, 152);
                 略
                 this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
                 略
        }
      #endregion

      [STAThread]
      static void Main()
      {
            Application.Run(new Form1());
      }

      //追加/////////VC でもこのようなことが出来ればいいのですが////
      private void button1_Click(object sender, System.EventArgs e)
      {
                Form2 dlg = new Form3();
               dlg.Owner = this;
               dlg.textBox1.Text="STEP";
               /// 下記の処理 でForm2のイベントを監視している
              dlg.Changed += new EventHandler(TESTChanged);
              dlg.Show();
      }
      void TESTChanged(object obj, EventArgs ea)
      {

               //Form2でクリックしたらForm1にtextBoxの内容を表示
               Form2 dlg = (Form2) obj;
               textBox1.Text=dlg.textBox1.Text;
      }
      /////////////////////////////////////////////////////
    }
    }


    ///////FORM2/////////////
    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;

    namespace CSMalti
    {

     public class Form2 : System.Windows.Forms.Form
     {
           private System.Windows.Forms.Button button1;
           public System.Windows.Forms.TextBox textBox1;

           private System.ComponentModel.Container components = null;

     

           //追加 イベントハンドラー Changed を作成。 VCではこの方法が出来なかった

          public event EventHandler Changed;

     

          public Form3()
          {
                  InitializeComponent();
          }

         protected override void Dispose( bool disposing )
         {
                  if( disposing )
                  {
                           if(components != null)
                          {
                                  components.Dispose();
                          }
                  }
                 base.Dispose( disposing );
          }

          #region Windows フォーム デザイナで生成されたコード
         private void InitializeComponent()
         {
                    this.button1 = new System.Windows.Forms.Button();
           略
                    this.textBox1.Location = new System.Drawing.Point(64, 144);
           略
                    this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
                    略
         }
         #endregion

     

       //追加////////////////////
      private void button1_Click(object sender, System.EventArgs e)
      {
         //Form1に信号をおくる
               if (Changed != null)
               Changed(this, new EventArgs());  
      }
      //////////////////////////
     }
    }

    2007年11月15日 9:45

すべての返信

  • C++/CLI でもイベントは使用・宣言・定義できますよ。

    http://msdn2.microsoft.com/en-us/library/4b612y2s(VS.80).aspx

     

    // どなたか仕様を訳して公開なさってる方がいたような気がしましたが、NotFound ですなぁ。

    2007年11月15日 13:15
  • Hongliangさん

    こんにちわ

    いろんなところに掲示板があるんですね。

    どうも紹介有難うございます。

    似たような質問がたくさんありました。

    しかしながら見つけることはできなかったのですが、この作業中きずいたのですが

     

    this->button1->Click += new System::EventHandler(this, button1_Click);

    となっていました。(自動で作成しているもの)

    そうすると

    public: event EventHandler* Changed; ではなく

    public: EventHandler* Changed; ですね。

    これでコンパイルしたらエラーがとれました。

    それで、

    ”作成するイベント ハンドラは、EventHandler クラスのデリゲート定義と同一のパラメータを持つ必要があります。 ”

    とのHelpの指示で

    private: System::Void button1_Click(System:Surprisebject *  sender, System::EventArgs *  e)

    {

       if (Changed != null)
             Changed(this, new EventArgs()); 

    }

    を追加しました。(c#と同じ)

    (#define null 0L の宣言を追加) VC++では null は無いのだろうか?

     

    これが出来たので、Form1側は

    #include "Form2.h"

    int Form_on;

    を追加して
     private: System::Void button1_Click(System:Surprisebject *  sender, System::EventArgs *  e){
              if (Form_on ==0 )

         //Form2が開いているとき作動しない(しかし再起動できないので改良が必要
              {
                    Form2* dlg = __gc new Form2();
                    dlg->Owner = this;
                    dlg->textBox1->Text="STEP";
                    dlg->Changed += new EventHandler(this,&VCMalti::Form1::TESTChanged);
                    dlg->Show();
                }
     }

     void TESTChanged(Object* obj, EventArgs* ea)
       {
        //Form2でクリックしたらForm1にtextBoxの内容を表示
        //Form2* dlg = (Form2*) obj;
             try {
                     Form2* dlg = __try_cast<Form2*>(obj);
                     textBox1->Text=dlg->textBox1->Text;
              }
             catch(System::InvalidCastException*) {
                     MessageBox:Tongue Tiedhow("Could not cast 'obj' to Form2*");
              }
       }

     

    以上の変更でやっとどうにか動くことができました。

    しかしながら

    1).Form2での public: EventHandler* Changed; の宣言

    2).今回エラーが発生したため追加した __try_cast の使い方

    は正等な方法でしょうか。

    どなたかアドバイスを頂ければ嬉しいのですが

     

     

     

    2007年11月16日 1:28
  • あわわ、すいません Managed C++ でしたか。見たくないものを見ない機構が働いてしまいました。

    Managed C++ は記事もあんまりないですが、MSDN(2じゃない方)には Managed C++ の仕様があります。

    イベントについてはこちら。

    http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/vcmxspec/html/vcManagedExtensionsSpec_10.asp

     

    イベントには(マルチキャスト)デリゲートのラップ表現と言う側面があります。

    公開されたイベントに対し、外部の人はハンドラ呼び出しやハンドラの置き換えができません。

    1).Form2での public: EventHandler* Changed; の宣言

    これはデリゲート型メンバ変数の公開と言うことになります。外部の人が勝手に NULL を代入できたりしてしまいます。

     

    マネージドの例外機構についてはこちら。

    http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/vcmxspec/html/vcManagedExtensionsSpec_14_2.asp
    2007年11月16日 3:21
  • Hongliangさんへ

    いずれも当方で確認済みでしたが

    public: EventHandler* Changed;

    private にするとエラーになります。

    2007年11月16日 8:42
  • ……?

    指した先にはイベントを使ったサンプルがそのまま書いてありますよね? 宣言側と使用側の両方。

    宣言側にデリゲートフィールドは必要ありませんよ。内部で使用されるデリゲートは「暗黙に」宣言されます。

    もちろん、ほかの人が使うために「イベントは」public に置く必要がありますが。

     

    あと、「エラーになります」と言われても反応に困ります。

    2007年11月16日 11:41
  • Hangliangさんへ

    コメント有難うございます。

    今日はちょっと無理なので明日コメントします。

     

     

     

    2007年11月16日 13:54
  • おはようございます。

    Hangliangさんへ

     

    1).指した先にはイベントを使ったサンプルがそのまま書いてありますよね? 宣言側と使用側の両方。

    2).宣言側にデリゲートフィールドは必要ありませんよ。

    この意味がわかりません。

    宜しくお願い致します。

    2007年11月16日 23:31
  • 意味を教えてと言われても、書かれてる通りとしか言いようがないですが……。

     

    コード ブロック

    // __events.cpp

    // compile with: /clr /LD

    #using <mscorlib.dll>

    using namespace System;

     

    __delegate void ClickEventHandler(int, double);

    __delegate void DblClickEventHandler(String*);

    __gc class EventSource {

    public:

        __event ClickEventHandler* OnClick; // declare the event OnClick

        __event DblClickEventHandler* OnDblClick; // declare OnDblClick

     

        void FireEvents() {

            OnClick(7, 3.14159);

            OnDblClick("Hello");

        }

    };

     

    このサンプルではどこにも HogeEventHandler をメンバ変数として保持していませんよね?

    イベントの型として存在しているだけです。

    2007年11月17日 12:19
  •  

    >  HogeEventHandler をメンバ変数として保持していませんよね

     

    ?? HogeEventHandler これは?

    2007年11月17日 23:57
  • レスを立てたのでまとめておきます。
    Form1,Form2間でデータの交換が出来ました。

    質問を考えている内に頭の中が整理できたのが良かったと思います。
    稼動する基本的な内容のみを記載し解きます。


    一応、これで終了させて頂きます。

    (もし別の方法で良い考え方、もしくは誤りが有りましたら
    具体的に指摘して頂ければ有りがたいです。)

     

    Form1,Form2のそれぞれにButton1とtextBox1を追加
    --Form1に下記を追加---
    #include "Form2.h"
    private :Form2* dlg;
    private: System::Void button1_Click(System:Surprisebject *  sender, System::EventArgs *  e)
    {
         dlg->Owner = this;
         dlg->textBox1->Text=textBox1->Text;
         dlg->Changed += new EventHandler(this,&VCMalti::Form1::TESTChanged);
         dlg->Show();
    }

    void TESTChanged(Object* obj, EventArgs* ea)
    {
         try
         {
              Form2* dlg = __try_cast<Form2*>(obj);
              textBox1->Text=dlg->textBox1->Text;
         }
         catch(System::InvalidCastException*)
         {
              MessageBox:Tongue Tiedhow(S"Could not cast 'obj' to Form2*");
         }
    }

    private: System::Void Load_Form1(System:Surprisebject *  sender, System::EventArgs *  e)
    {

         dlg = __gc new Form2(); /* ここでForm2を造る用変更しました*/

    }

     

    --Form2に下記を追加--
    public: EventHandler* Changed;

    #define null 0L
    private: System::Void button1_Click(System:Surprisebject *  sender, System::EventArgs *  e)

         if (Changed != null)
              Changed(this, new EventArgs());
    }

    2007年11月18日 8:52