[2019/06/21] 親フォームのコントロールを子フォームからアクセスする方法その2(DirectCast) (No.107)
[2019/06/03] 他のEXEファイルにあるフォームを表示する方法その2(Activator.CreateInstanceの使い方) (No.100)
[2019/06/03] 他のEXEファイルにあるフォームを表示する方法(Activator.CreateInstanceの使い方) (No.99)
[2019/05/10] フォームクラスの継承の方法について (No.98)
[2019/01/17] フォームのマウスカーソルを待機状態する方法について (No.75)
-
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
-
親フォームから表示された子フォームから、呼び出し元の親フォームのコントロールをアクセスする方法として以下の記事に在りますが、 今回はそれと似た方法ですが少し違った方法で行います。
⇒親フォームのコントロールを子フォームからアクセスする方法
今回の方法は、親フォームで子フォームを表示する時に、自分自身のフォームをオーナー(所有者)として処理します。 また、子フォームの方では自分自身のオーナーを DirectCast で親フォームだとして、親の持つコントロールへアクセスします。
以下の例では、親フォームから子フォームを呼出した時に、子フォームから親フォームのテキストボックスの 「Text」を取得し、子フォームのテキストボックスの「Text」に初期設定します。
その後、子フォームのボタンを押下することで、親フォームのテキストボックスの「Text」に 子フォームのテキストボックスの「Text」を再設定します。
以下の画像は、親フォームから子フォームを表示し、子フォームのテキストボックスに「ABCD」を入力し「親への設定」ボタンを押下した時の様子です。
以下の今回の処理のソースを示します。子フォームを表示する時に ShowDialog を使いますが、親フォームである自分自身を引数で渡します。 そうすると子フォームの Owner プロパティに親フォームオブジェクトのインスタンスが渡せます。親フォームのクラス
'''
''' 子フォームを呼出す親フォーム2 ''' Public Class frmParentCtrlMain '''''' 「サブフォーム表示」ボタンクリックイベント ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'プロパティテストウインドウ生成 Dim frmParentCtrlSub As New frmParentCtrlSub 'ウインドウ表示(指定した所有者を持つモーダルダイアログとしてフォームを表示) frmParentCtrlSub.ShowDialog(Me) 'プロパティテストウインドウ廃棄 frmParentCtrlSub.Dispose() frmParentCtrlSub = Nothing End Sub End Class子フォームのクラス
'''
''' メインフォームを参照する子フォーム ''' Public Class frmParentCtrlSub '''''' フォームロードイベント ''' Private Sub frmPropTextSub_Load(sender As Object, e As EventArgs) Handles Me.Load 'メイン側のTextBox1の内容を取得し、サブ側に設定 Me.TextBox1.Text = DirectCast(Me.Owner, frmParentCtrlMain).TextBox1.Text End Sub '''''' 「設定(プロパティ)」ボタンクリックイベント ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'メイン側のTextBox1に、サブ側のTextBox1の内容を設定 DirectCast(Me.Owner, frmParentCtrlMain).TextBox1.Text = Me.TextBox1.Text ''自分を閉じる 'Me.Close() End Sub End Class子フォームで使っている DirectCast は DirectCast 演算子と言われるもので、 指定されたオブジェクトをある型にキャストするための演算子です。
DirectCast(変数, キャスト後の型).「キャストされた型が持つプロパティ、メソッド等」
この DirectCast は「変数」を強制的にキャストされた型と処理するため、 間違った型にキャストすると当然のことながらエラーが発生します。 (存在しないプロパティを参照したり、存在しないメソッドを実行する場合)
DirectCast により直接親フォームの TextBox1 を参照していますが、 これが出来るのはなぜかと言いますと、親フォーム内で TextBox1 が Friend として宣言されているからです。 Friend 宣言のオブジェクトは同じプロジェクト内ならばどこからでも参照可能だからです。 通常フォームのデザイン画面でコントロールを張り付けた時に自動で Friend なオブジェクトとして生成されます。
ここで Friend の様な変数やクラス等の宣言のキーワードについて少し説明します。 宣言には Public, Friend, Protected, Private, Dim 等があります。
宣言キーワード アクセス可能な個所 説明 Public 全ての箇所からアクセス可能 同一プロジェクトに限らず他のプロジェクトからもアクセスできます Friend 同一プロジェクトからアクセス可能 同一プロジェクトであればどこからでもアクセスできます。 Protected 自分自身のクラス、及び派生クラスからアクセス可能 他のプロジェクトでも派生クラスであればアクセスできます。 Protected Friend 同一プロジェクトからアクセス可能
他のプロジェクトは派生クラスがアクセス可能Protected Friend の両方の機能を併せ持つ。 Private 自分自身のクラスからアクセス可能 派生クラスでもアクセス不可なので、純粋にローカルなものとして扱います。 Dim 自分自身のクラスからアクセス可能 Dim はクラスのメンバー変数や関数内の自動変数として宣言する宣言文です。
クラス内の変数はなるべく Private で宣言し、外部から操作するもののみ Public や Friend にする方が 宜しいかと思います。また、変数そのものを Public にするのではなく、プロパティとしてアクセス可能な様にするべきかと思います。
PR -
あるEXEファイルから、他のEXEファイルの中のフォームを強制的に表示する方法として以下の記事で説明しましたが、
⇒他のEXEファイルにあるフォームを表示する方法(Activator.CreateInstanceの使い方)
この方法ではフォームを表示するだけで、面白味が在りませんので、今回はフォームにプロパティとメソッドを追加して それらに対するアクセス方法を説明します。
先ずは、フォームにテキストボックスを1個追加し、それに対して値を設定したり取得するプロパティと、 テキストボックスの内容を表示するメソッドを追加します。呼び出される側のフォーム
Public Class Form1 Private mstrParamData As String 'テキストボックスに値を設定するプロパティ Public WriteOnly Property SetParamData As String Set(value As String) Me.TextBox1.Text = value End Set End Property 'テキストボックスの内容を取得するプロパティ Public ReadOnly Property GetTextData As String Get Return Me.TextBox1.Text End Get End Property '外部からアクセス可能なメソッド Public Sub DspTextBox() MessageBox.Show("TextBox1.Text : " & Me.TextBox1.Text) End Sub 'ボタンクリックイベント Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click '自分を閉じる Me.Close() End Sub End Class
上記のフォームが含まれる REF0002.EXE を呼出す側のソースは以下の通りです。
こちらの方は、特にフォームを持たずにMain() 関数からの実行となっています。呼び出す側のMainソース
Public Module Main Sub Main() '自分自身の実行ファイルのパスを取得する Dim appPath As String = _ System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) 'アセンブリ"REF0002.exe"を読み込む(「REF0002.EXE」は「REF0001.EXE」が存在するフォルダに在ります) Dim asmExe As System.Reflection.Assembly = _ System.Reflection.Assembly.LoadFile(appPath & "\REF0002.exe") 'Form1のTypeを取得する(名前空間を指定しているのでフォーム名の前に名前空間を付加) Dim typForm As Type = asmExe.GetType("REF0002.Form1") 'フォーム作成用変数 Dim frm As Form 'フォームのインスタンスを作成 Dim obj As Object = Activator.CreateInstance(typForm) 'インスタンスをフォームとして扱う frm = DirectCast(obj, Form) 'プロパティの設定 Dim pinf As System.Reflection.PropertyInfo = typForm.GetProperty("SetParamData") pinf.SetValue(frm, "Set From REF0001", Nothing) 'フォームの ShowDialog メソッドを使用する frm.ShowDialog() 'プロパティの取得 pinf = typForm.GetProperty("GetTextData") Dim str As String = CStr(pinf.GetValue(frm, Nothing)) MessageBox.Show(str) 'メソッドの利用 Dim minf As System.Reflection.MethodInfo = typForm.GetMethod("DspTextBox") minf.Invoke(frm, Nothing) End Sub End Module
プロパティの情報(System.Reflection.PropertyInfo)を取得する為に、Typeの GetProperty メソッドを使います。 その PropertyInfo の SetValue メソッドでプロパティへの値を設定します。
また、 PropertyInfo の GetValue メソッドでプロパティの値の取得を行います。
さらにメソッドの実行は、プロパティと同様にTypeの GetMethod メソッドによりメソッド情報(System.Reflection.MethodInfo)を取得し PropertyInfo の Invoke メソッドで該当するメソッドの実行を行います。
これを実行すると以下の様な表示になります。関連する記事
⇒他のEXEファイルにあるフォームを表示する方法(Activator.CreateInstanceの使い方)
-
あるEXEファイルから、他のEXEファイルの中のフォームを強制的に表示するにはどうすれば出来るのかを調べてみました。
方法として、EXEファイルの中にあるアセンブリ名(フォーム名)を指定して型情報(Type)を取得し、 そのTypeを利用して Activator.CreateInstance メソッドでフォームのインスタンスが生成されます。
そのインスタンスが持っているフォームの表示メソッドを使えば、そのフォームの表示が行えます。
先ずは、呼び出されるフォーム側のソースです。こちらの方はEXE名を REF0002.EXE となる様に設定してます。 また、名前空間も同様に REF0002 としています。呼び出される側のフォーム
Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click '自分を閉じる Me.Close() End Sub End Class
上記のフォームが含まれる REF0002.EXE を呼出す側のソースは以下の通りです。
こちらの方は、特にフォームを持たずにMain() 関数からの実行となっています。呼び出す側のMainソース
Public Module Main Sub Main() '自分自身の実行ファイルのパスを取得する Dim appPath As String = _ System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) 'アセンブリ"REF0002.exe"を読み込む(「REF0002.EXE」は「REF0001.EXE」が存在するフォルダに在ります) Dim asmExe As System.Reflection.Assembly = _ System.Reflection.Assembly.LoadFile(appPath & "\REF0002.exe") 'Form1のTypeを取得する(名前空間を指定しているのでフォーム名の前に名前空間を付加) Dim typForm As Type = asmExe.GetType("REF0002.Form1") 'フォーム作成用変数 Dim frm As Form 'フォームのインスタンスを作成 Dim obj As Object = Activator.CreateInstance(typForm) 'インスタンスをフォームとして扱う frm = DirectCast(obj, Form) 'フォームの ShowDialog メソッドを使用する frm.ShowDialog() End Sub End Module
これを実行すると以下の様な表示になります。
ソースは特に難しいところは無いかと思います。 Form1のTypeを取得するところで asmExe.GetType("REF0002.Form1") としていますが、これは REF0002.EXE での名前空間を REF0002 に 設定してあるからです。 この名前空間を空白にすれば asmExe.GetType("Form1") で可能です。関連する記事
⇒他のEXEファイルにあるフォームを表示する方法その2(Activator.CreateInstanceの使い方)
-
業務システムでは似た様なフォームを作成することがありますが、 共通となる部分を基本的なフォームクラスとして作成しておき、 それを継承することでデザインの統一を図ったりします。
今回はフォームクラスの継承の方法について順を追って説明します。
まず最初に基本となるフォームに1個のパネルを設置し、その上に1個のボタンを置く様にしました。 (フォームの名前は「BaseForm」としました。) デザイン画面は以下の様な感じです。
その後、ボタンのクリックイベントで簡単なメッセージを表示する様にしました。最初のBaseFormのソース
Public Class BaseForm Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click MsgBox("BaseForm : Button1_Click") End Sub End Class
ここで一旦このプロジェクトのビルドを行います。 その後、プロジェクトにこの「BaseForm」を利用するフォームの追加を行ってみます。 プロジェクトへの項目の追加を行うために、 「新しい項目追加」ダイアログで 「Windows Forms」 の中の 「継承されたフォーム」 を選択します。 フォーム名は Form1 のままとします。
この後で「継承ピッカー」ダイアログが表示されますので 「BaseForm」 を選択して「OK」をクリックします。
結果的に以下の様にフォームデザイン画面が表示されます。 (フォーム上のパネルとボタンの所に小さいマークが付いていますが、このデザインからは修正できない状態であるロックが掛かった状態であることを示しています。)
この後、このプロジェクトのプロパティを開いて 「スタートアップ オブジェクト」 を 「Form1」 に設定します。
このプロジェクトを実行させると以下の様になります。画面はボタンをクリックした時の状態を示します。
Form1 では特に何もソースは記述していませんが、継承されたフォームの処理が出来ることが分かると思います。
このままでは面白くないので 「BaseForm」 にボタンのタイトルを変更するプロパティを追加してみます。タイトルプロパティの追加のBaseFormのソース
Public Class BaseForm ' ボタン1タイトルに文字列設定 Public Property Button1Title As String Get Return Me.Button1.Text End Get Set(value As String) Me.Button1.Text = value End Set End Property Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click MsgBox("BaseForm : Button1_Click") End Sub End Class
Form1のソース
Public Class Form1 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load 'ボタンタイトル設定 Me.Button1Title = "ボタン" 'フォームタイトルも設定 Me.Text = "Form1 から設定されたタイトル" End Sub End Class
これを実行すると以下の様に、ボタンのタイトルが「ボタン」に変わったことが分かります。
さらに、ボタン処理を継承先から上書き変更できる様にしたいと思います。 BaseForm 側では Button1_Click メソッドに Overridable 修飾子を付加して上書き可能であることを宣言します。
Form1 側では Button1_Click メソッドを上書きすることを宣言するため Overrides 修飾子を付加します。
ボタン処理をオーバーライド指定としたBaseFormのソース
Public Class BaseForm ' ボタン1タイトルに文字列設定 Public Property Button1Title As String Get Return Me.Button1.Text End Get Set(value As String) Me.Button1.Text = value End Set End Property 'オーバーライド指定 Protected Overridable Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click MsgBox("BaseForm : Button1_Click") End Sub End Class
Form1のソース:ボタン処理をオーバーライド
Public Class Form1 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load 'ボタンタイトル設定 Me.Button1Title = "ボタン" 'フォームタイトルも設定 Me.Text = "Form1 から設定されたタイトル" End Sub Protected Overrides Sub Button1_Click(sender As Object, e As EventArgs) '別の処理にする MsgBox("Form1 からのボタン処理") End Sub End Class
これを実行すると以下の様に、ボタンクリック処理が Form1 の処理しか行われないことが分かります。
もし、継承元のボタン処理も行いたい場合には Form1 を以下の様に変更します。 これを実行し、ボタンをクリックすると2回メッセージボックスが表示されます。Form1のソース:ボタン処理をオーバーライド2
Public Class Form1 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load 'ボタンタイトル設定 Me.Button1Title = "ボタン" 'フォームタイトルも設定 Me.Text = "Form1 から設定されたタイトル" End Sub Protected Overrides Sub Button1_Click(sender As Object, e As EventArgs) '継承元のボタン処理 MyBase.Button1_Click(sender, e) '別の処理にする MsgBox("Form1 からのボタン処理") End Sub End Class
関連する記事
⇒フォームクラス生成時に設定値を同時に渡す方法
⇒フォーム上の複数のコントロール(TextBox)の入力変化を確認する方法について
⇒フォームのマウスカーソルを待機状態する方法について
⇒フォームクラスの継承の方法について
-
通常、長い処理を行うプログラムの場合、処理を行っている間にマウスカーソルを待機状態にして、現在処理中であることをユーザに示します。 これを行うにはフォームの Cursor プロパティを Cursors.WaitCursor に設定します。
また、元に戻す時は Cursor プロパティを Cursors.Default に設定します。フォームのマウスカーソルを待機状態する方法
Public Class frmCursor Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'フォームのカーソルを待機状態にする Me.Cursor = Cursors.WaitCursor '10秒待つ(長い処理の代わりにSleep関数を用いる) System.Threading.Thread.Sleep(10000) 'フォームのカーソルを元に戻す Me.Cursor = Cursors.Default End Sub End Class
上のプログラムで「長い処理の代わり」と書きましたが、実際にはデータベース処理など時間の掛かる処理を書くわけですが、 その中でエラーの対応の為に Try ... Catch ... End でエラー処理を記述すると思います。
このエラー処理の中で適切にカーソルを元に戻してやらないと、カーソルが待機状態のままになってしまいます。
(これは明らかなバグで、フォーム上の処理はできるが、カーソルが矢印に戻ってないので変な感じになります)
これを回避するためにも、カーソル設定処理は Try ... Catch ... End の外側で行うか、 もしくは以下のソースの様に Try の Finnaly の中で行うと良いと思います。
カーソル処理を Finally ブロックで行う方法
Public Class frmCursor Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Try 'フォームのカーソルを待機状態にする Me.Cursor = Cursors.WaitCursor '10秒待つ(ここでは通常の処理においてエラーが発生するかもしれない) System.Threading.Thread.Sleep(10000) Catch ex As Exception 'ここに例外処理を記述する Finally 'フォームのカーソルを元に戻す Me.Cursor = Cursors.Default End Try End Sub End Class
関連する記事
⇒フォームクラス生成時に設定値を同時に渡す方法
⇒フォーム上の複数のコントロール(TextBox)の入力変化を確認する方法について
⇒フォームのマウスカーソルを待機状態する方法について
⇒フォームクラスの継承の方法について