• 締切済み

Form オブジェクトの戻り値の設定

はじめまして。Porome です。 Excel 2003 の VBA を使ってプログラミングをしています。 Form オブジェクトの戻り値の設定方法/受取方法について教えてください。 実装したいプログラムの概要は、以下の通りです。 標準モジュールに記載したサブルーチンから Form オブジェクトを 生成し、Form オブジェクトで入力されたデータを標準モジュール側 で取得する…というものです。 書きたいソースコードのイメージは以下の通りです。 Sub MySub1() dim i_Form As New MyForm1 dim i_Name As String dim i_Age As String dim i_Ret As Integer 'MyForm1OK, MyForm1Cancel が戻ってくるまで、じっと待つ i_Ret = i_Form.Show, vbModal Select Case i_Ret 'MyForm1 で OK ボタンが押された Case MyForm1OK: i_Name = i_Form1.txtName.Value i_Age = i_Form1.txtAge.Value MsgBox(i_Name & " さんの年齢は " & i_Age & " 歳です") 'MyForm1 で Cancel ボタンが押された Case MyForm1Cancel: MsgBox("処理はキャンセルされました") 'MyForm1 では、MyForm1 では、MyForm1OK, MyForm1Cancel 以外は '戻さない仕様とします。 Case Else '何もしない(ここには来てはいけない) End Select End Sub こういったことを実現するためには ・MyForm1 では、 OK ボタンを押したら、MyForm1OK を Show メソッドの戻り値として セットし、処理を MySub1 に戻す Cancel ボタンを押したら、MyForm1Cancel を Show メソッドの戻り値としてセットし、処理を MySub1 に戻す OK ボタン、Cancel ボタン Click 以外の Form イベントでは、MyForm1 での処理が継続され、MySub1 は MyForm1 の戻り値(MyForm1OK/MyForm1Cancel)を、じっと待つ といったことが必要になってくるかと思います。 こういった処理を実装するには、呼び出し元 (MySub1)、呼び出し先 (MyForm1) では、それぞれどのようなコードを記載すればよろしいでしょうか? 説明が下手で申し訳ありませんが、アドバイスをお願いいたします

みんなの回答

  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.2

こんばんは。 解説はコードにあるコメントを読んで下さい。基本的な Tips はだい たい盛り込んであるかと。。 ' ■ 標準モジュール ----------------------------------------- Option Explicit ' // 標準モジュールで Public 定数として宣言しておく必要がある Public Const MyForm1OK   As Long = 1 Public Const MyForm1Cancel As Long = 2 Sub MySub1()   Dim i_Form   As MyForm1   Dim i_Name   As String   Dim i_Age    As String   Dim i_Ret    As Integer      ' // i_Form のインスタンスを生成   ' // フォームがメモリにロードされて表示される   ' // Dim xxxx As New MyForm1 はインスタンスが残る可能性がある   ' // ので、意味をよく分かっていない場合は使うべきでない。   ' // 次のように Set ステートメントで New を使う   Set i_Form = New MyForm1   'MyForm1OK, MyForm1Cancel が戻ってくるまで、じっと待つ   ' ↓   ' // 単純にフォームを表示するだけで良い   ' // Form が閉じられるか、Hide されると次行に処理フローが戻る   i_Form.Show vbModal      ' // [X]で閉じられた場合は、プロパティーを参照するとエラーが   ' // 発生するので、エラーハンドラに飛ばして Cancel 扱いの   ' // 処理をおこなう   On Error GoTo Err_UserClose   i_Ret = i_Form.Value ' <------ココ。エラー発生の可能性あり        ' // エラーハンドラから Resume Next でここに戻る   ' // エラー処理の初期化   On Error GoTo 0   ' // i_Ret の値で条件分岐処理   Select Case i_Ret     Case MyForm1OK:   'MyForm1 で OK ボタンが押された       i_Name = i_Form.txtName.Value       i_Age = i_Form.txtAge.Value       MsgBox (i_Name & " さんの年齢は " & i_Age & " 歳です")     Case MyForm1Cancel: 'MyForm1 で Cancel ボタンが押された       MsgBox ("処理はキャンセルされました")     Case Else       '何もしない(ここには来てはいけない)   End Select      ' // フォームをメモリーから開放   Unload i_Form Terminate: ' // 終了処理   ' // オブジェクト変数の破棄   Set i_Form = Nothing   Exit Sub    Err_UserClose: ' // [X]ボタンによるエラーハンドラ   ' // キャンセル扱いとする   i_Ret = MyForm1Cancel   ' // エラーハンドラから処理を戻すときは必ずエラーをクリアする   Err.Clear   Resume Next End Sub ' ■ MyForm1モジュール ------------------------------------- Option Explicit ' // Value プロパティー用のモジュールレベル変数 Private mlValue As Long ' // Value プロパティー(読み取り専用)を用意 Public Property Get Value() As Long   Value = mlValue   ' // Public 変数を使うという手もあるが Property プロシージャ   ' // にした方が様々な処理を同時に行える。読み取り専用の   ' // プロパティー、書き込み専用プロパティーなど柔軟な処理が   ' // 可能。 End Property ' // イベントプロシージャ Private Sub UserForm_Initialize()   ' // 初期値などを設定する   mlValue = MyForm1Cancel End Sub Private Sub CommandButton1_Click()   mlValue = MyForm1OK   ' // Hide すると処理フローは MySub1 に戻るが MyForm1 は   ' // オンメモリのままなので、Unload されるまでは、   ’// プロパティー等にアクセス可能。   Me.Hide End Sub Private Sub CommandButton2_Click()   mlValue = MyForm1Cancel   Me.Hide End Sub

Porome
質問者

お礼

なるほど。 たくさんのエッセンスが盛り込まれていて、サンプルコードを 読ませていただくだけで、すごく勉強になります。 エラーハンドリングを除くと、ポイントとなるのは ・Form.Hide を実行したタイミングで、呼び出し元に処理が戻る。  ただし、Hide にしただけではオンメモリのままなので、呼び出し元  で、Unload するまでは、プロパティアクセスが可能 ということですね。 インスタンスの生成やエラーハンドリングなど、細かいところまで アドバイスをいただき、お忙しいところお手数をおかけして申し訳 ありませんでした。 ソースコードはコメントのおかげもあって、ほぼ理解できました。 ありがとうございました。

  • Nayuta_X
  • ベストアンサー率46% (240/511)
回答No.1

Public を使用します。 例: 以下の様にすると Public で、宣言された、変数は、Form からでも モジュールからでも 使用できます。 Public i_Form As New MyForm1 Public i_Name As String Public i_Age As String Public i_Ret As Integer Sub MySub1()

Porome
質問者

お礼

返事が遅くなって大変失礼しました。 たしかに、Public な(グローバルな)変数を定義してしまえば 機能としては十分だと思います。 今回、私が考えていたのは、事前に、VbMsgBoxResult (MsgBox の戻り値) のようなものを定義しておき、 UserForm から VbMsgBoxResult のような戻り値を 返してもらって、その値によって、呼び出し側で 処理を変更する(UserForm のプロパティを参照する) といったことができないかな…ということでした。 わかりにくい説明で申し訳ありませんでした。

関連するQ&A

  • form2がボタンを押すと消えてしまう

    vb2010で、作成しています。form1から、form2を呼び出し、okボタンまたは、cancelボタンを押すと、無条件でform2が消えてしまいます。私がしたいのは、form2(パスワード入力ウィンドウ)でテキストボックスにパスワードを入力してokボタンを押して、それが正しい(1234)ときのみform2を消去することです。現在のところ、入力したパスワードが間違っていてもokボタンを押すと、form2は消えてしまいます。 form1側のコードとform2側のコードは以下です。お手数ですが御教示いただけると幸いです。 /////////Form1 Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim f As New Form2() f.TextBox1.PasswordChar = "*"c '//入力文字をマスクする If f.ShowDialog(Me) = DialogResult.OK Then If f.TextBox1.Text = "1234" Then f.Dispose() End If End If End Sub End Class /////////Form2 Public Class Form2 Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click Dim f As Form1 f = Me.Owner Me.DialogResult = DialogResult.OK End Sub Private Sub btncancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btncancel.Click Dim f As Form1 f = Me.Owner Me.DialogResult = DialogResult.Cancel End Sub End Class

  • 戻り値がクラスオブジェクト

    VB初心者でわからないので教えてください。 ある関数を呼び出して戻り値を取得するのですが、その戻り値がクラスオブジェクトとなっています。いろいろ調べてみましたが、いい結果にヒットしなかったので今回質問してみました。 言語はVB6.0です Function 関数A(A as String, B as String) dim C as Class1 set C = new Class1 Class1で宣言された変数に値を入れる処理     関数A = C end Function イメージはこんな感じです。 すみませんが解決策を教えてください。。。。

  • Formオブジェクトについて

    Formオブジェクトに関する質問です。 ある関数にフォームオブジェクトを引数として渡してやりたいのですが、何かよい方法はありますでしょうか? 例) Private Sub cmdTest_Click(Index as Integer) Dim frm as Form If Index = 0 then Load_Test(Form 2) Else Load_Test(Form 3) End if End Sub Private Sub Load_Test(frm as Form) frm.Show frm.Label1.Caption = "TEST” End Sub

  • オブジェクトの消滅と関数の戻り値オブジェクト

    public sub test1() { dim hoge as classX = tes2() test2.getHogehoge() } public Function test2() as classX { dim ret As New classX("初期化") return ret } 大変簡略化してますが上記2つの関数があった場合 関数test1でclassX型のアドレスhogeに、test2()が返す classX型オブジェクトの参照を代入しています。 でこの実体というかインスタンスretはtest2()の中の スコープで消滅する自動変数として生成されています。 んで実際関数test2を抜けるときretのインスタンスは 破棄されるのにtest1ではそれをhogeアドレスに代入して 使用していいのでしょうか?

  • 複数のオブジェクトをループで処理したい場合

    以下のような処理をしたい場合 Dim objData1 As Object Dim objData2 As Object Dim objData3 As Object Dim objData4 As Object Dim i As Integer For i=0 to 4 ここでオブジェクトの1~4を順番に処理 Next 変数iをobjData[i]の様にしたいのですが どのようにすればいいのでしょうか?

  • vb.netでオブジェクトの種類を知りたい

    こんばんわ vb.netでオブジェクトの種類を知る方法はないでしょうか? 例 form上にtextbox1を配置した上で 'メインルーチン public sub main() dim ret = test(textbox1) msgbox("textbox1は" & ret & "です") endsub 'サブルーチン public function test(obj) dim ret as string 'ここでobjがtextboxかcheckboxか判別したい return ret end function このようなことが可能でしょうか? 可能なようでしたらどうすればよいかご教授お願いします。

  • 引数で戻り値を取得するプログラム

    以下のように、引数で戻り値を取得するプログラムを書きたいのですが どのように書けば正しいでしょうか? VB6とVB2005の両方の書き方を教えてください。 sub kekka(byval src as string, byref dst() as string) dim ret() as string ret(0) = "abc" ret(1) = "efg" kekka = ret end sub kekka("xxx", dat() ) msgbox(dat(0)) msgbox(dat(1))

  • オブジェクト名

    複数のWinsockを使用したいです。 オブジェクト名Winsock1~Winsock6があるとします。 例えば Dim i As Integer Dim strWinsock As String For i = 1 to 6 strWinsock = Winsock & i //処理 Next 上記のようなループで文字列strWinsockを、オブジェクト名として使用することはできないのでしょうか? また、もし他の方法があるようでしたら、教えて下さい。

  • (VB2008EEです)Form1からForm2をモーダレスで表示(S

    (VB2008EEです)Form1からForm2をモーダレスで表示(Show(Me))したのち、 Form2を、(Form2の)閉じるボタン(右上にあるXボタン)で閉じるときに、 単にHideするだけの処理に変更することは可能でしょうか。 デフォルトでは、閉じるボタンですと、Close()と同様、 Close(&Dispose)となると思いますが、Hide()処理に 変えられるかということです。 。。。 試しに、FormClosingイベントハンドラでHide()→e.cancel=Trueって やってみたところ、(再度同じForm2のインスタンスを使ってShowができ、 さらに前回のText表示などが残っているなど)その場はうまく行ったように 見えたのですが、そうすると、アプリ(Form1)が閉じるボタンで終了しなくなって しまいました。 (Application.Exitでもダメ、Endでは(強制終了とのことなので)OKですが) Form2のClose処理をCancelしているからだ、とは思いますが。 ShowDialog→Xボタン(同じ記述のまま) の後では、終了可能です。 では、Show→Xボタンのあとで、同じインスタンスで、上記と同じように、 ShowDialog→Xボタンとしたあと、Form1のXボタンでアプリを 終了させようとするとどうなるか。 結果は、終了不能でした。 一度Show→Xしたらそれをどこかに覚えている?ってことなのでしょうか。。。 ここらへんの現象まで、合わせて説明できる方がいらっしゃったら 合わせてご説明いただけませんでしょうか。 。。。 なお、なぜこんなことするの?という実際論はここではなしで 純粋に技術論でお願いいたします。

  • VB.net エラー「オブジェクト参照がオブジェクトインスタンスに設定されていません」

    タイトル通り『オブジェクト参照がオブジェクトインスタンスに設定されていません』というエラーが発生し、全く僕の脳では解決しないので、ここに質問させて頂きます。 VB.netでフォームロード時に、Accessに登録されている件数分だけテキストコントロールを動的に配置(配列処理をしています)、そこにAccessからデータを取り込みます。 追加ボタンで一件分のテキストコントロールを一番下の行になるよう配置。そこにユーザがデータを入力し、更新ボタンを押すことで、Access上にINSERTする。 というような処理です。 で、INSERTはされるのですが、その後textboxの中身を配列の最初から確認しようしたり、データを入れようとしたり、空にしようとしたりすると上のエラーが表示されます。 'テキストの配列' Private field_text(,) As System.Windows.Forms.TextBox Sub s_insert() ' ’ 更新ボタン時の処理 ' Const strinsert As String = "INSERT INTO 社員マスター (SNO,SNAME) VALUES (@sCode,@sName)" Dim oConn As New System.Data.OleDb.OleDbConnection Dim oCommand As New OleDbCommand Dim i As Integer Dim j As Integer Dim insert_ok As Integer 'DB接続のための処理(省略)      'SQL文の設定 oCommand.CommandText = strinsert insert_ok = 0 oCommand.Parameters.Add(New OleDbParameter("@sCode", OleDbType.Char, 10)) oCommand.Parameters("@sCode").Value = field_text(更新する行の値, 0).Text oCommand.Parameters.Add(New OleDbParameter("@syainName", OleDbType.Char, 20)) oCommand.Parameters("@sName").Value = field_text(更新する行の値, 1).Text insert_ok = oCommand.ExecuteNonQuery() 'SQL文を実行' If insert_ok > 0 Then MessageBox.Show("新規登録完了", "メッセージ") End If 'DB接続を閉じる処理(省略) For i = 0 To 登録行数 - 1 For j = 0 To 1 f_text(i, j).Text = ""  ←ここでエラー Next j Next i End Sub 随分と省いてあり、意味の分からない部分が多数あると思いますが、何か気付いたことや他の部分を書け!という場所があれば教えてください。 一日やっても解決せずに、本当に困り果てています。

専門家に質問してみよう