[2019/01/16] フォーム上の複数のコントロール(TextBox)の入力変化を確認する方法について (No.74)
[2018/05/28] フォームクラス生成時に設定値を同時に渡す方法 (No.48)
[2018/03/28] 初回のフォームActivatedイベント発生させるフォーム継承について (No.40)
[2018/03/28] 最初のフォームActivatedイベントでの処理(1回のみしか処理しない様にする) (No.39)
[2018/03/28] フォームがKeyDownなどのキーイベントを受取り、ファンクションキー処理をする (No.38)
-
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
-
何かのデータをデータベースから読込み TextBox 等に表示し、それぞれ TextBox のいずれかに入力の変更が在ったかどうかを判断する方法を示します。
以下のソースではフォームロードイベント時に仮のデータを初期値として、フォーム上の5個の TextBox に設定しています。 さらに、TextBox の TextChanged イベントで入力が在ったことを処理するため、内部の変更フラグをONしていますが、 そのイベント処理ハンドラを AddHandler により各 TextBox に関連付けています。
仮に【登録】【終了】ボタンを設置し、【登録】ボタン処理では実際の登録はしないのですが、 登録したものとして、変更フラグをOFFとして再初期化しています。 また、【終了】ボタン処理ではフラグを確認して、確認メッセージを表示する様にしています。フォーム上の複数の TextBox の入力変化を確認する処理
Public Class frmInpCheck 'データに変更が在った証拠のフラグ Private fDirty As Boolean = False '【登録】ボタンクリックイベント処理 Private Sub btnWrite_Click(sender As Object, e As EventArgs) Handles btnWrite.Click MsgBox("登録します。") '登録処理を以下に記述... 'フラグをOFF Me.fDirty = False End Sub '【終了】ボタンクリックイベント処理 Private Sub btnClose_Click(sender As Object, e As EventArgs) Handles btnClose.Click If Me.fDirty = True Then If MsgBox("データが変更されています。終了してもよろしいですか?", _ MsgBoxStyle.Question + MsgBoxStyle.YesNo, "TEST") = MsgBoxResult.No Then 'いいえの場合は処理を取止め Exit Sub End If End If '自分を閉じる Me.Close() End Sub 'フォームロードイベント時処理 Private Sub frmInpCheck_Load(sender As Object, e As EventArgs) Handles Me.Load 'フォームロード時に画面のTextBoxを初期化する '(一般的にはデータベース等からデータを取得し表示する...) Me.TextBox1.Text = "A1234" Me.TextBox2.Text = "BBBB" Me.TextBox3.Text = "C120000" Me.TextBox4.Text = "DDDDDD" Me.TextBox5.Text = "EEE" 'フォームに属するコントロールがTextBoxの場合、TextChangedイベントの処理を関連付ける For Each ctrl As Control In Me.Controls If TypeOf ctrl Is TextBox Then AddHandler CType(ctrl, TextBox).TextChanged, AddressOf event_TextChanged End If Next End Sub 'TextBoxの内容変化イベント処理 Private Sub event_TextChanged(sender As Object, e As EventArgs) 'データの変更フラグON!! Me.fDirty = True End Sub End Class
これを実行すると以下の様な表示になります。
TextBox のデータ4を変更し、【終了】ボタンをクリックすると以下の表示になります。
尚、 AddHandler でイベントを関連付けているところを、 イベント処理の Subプロシージャ で Handlesキーワードの後ろに5個分の TextBox を以下の様に記述しても同じことができます。
TextChangedイベント処理について
'通常の方法でのTextBoxの内容変化イベント処理 '(Handles の後ろに必要なコントロールを全て記述することで AddHandler と同様になる) Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles _ TextBox1.TextChanged, TextBox2.TextChanged, TextBox3.TextChanged, _ TextBox4.TextChanged, TextBox5.TextChanged 'データの変更フラグON!! Me.fDirty = True End Sub
この方法は見た目にも余りかっこよくないですし、仮に TextBox が増えたりした場合には変更が面倒なのでお勧めしません。 ただ、こんな方法もあるということを示しました。
今回は TextBox のみを例にしましたが、実際は日付入力や CheckBox などもありますので それぞれのコントロールで値が変更されたイベントのタイミングでフラグをONしてやればよいと思います。
(CheckBox の場合は、 CheckedChangedイベント)関連する記事
⇒フォームクラス生成時に設定値を同時に渡す方法
⇒フォーム上の複数のコントロール(TextBox)の入力変化を確認する方法について
⇒フォームのマウスカーソルを待機状態する方法について
⇒フォームクラスの継承の方法について
PR -
あるフォームから別のフォームを表示し、その子フォームでの情報を親のフォームからアクセスしたい場合に、 子フォームにプロパティを持ち、それを介してデータのやり取りを行う方法は以下のソースの様になることを以前紹介しました。
プロパティを持つ子フォームのクラス
'''
''' プロパティを持つ子フォーム ''' Public Class frmProperty 'チェック状態退避値 Private mblnChkStatus As Boolean = False '''''' チェック状態プロパティ ''' '''チェック状態の設定値 '''チェック状態を返す Public Property ChkStatus As Boolean Set(value As Boolean) mblnChkStatus = value '退避値に設定 End Set Get Return mblnChkStatus '退避値を返す End Get End Property '''''' ボタンクリックイベント ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'チェックボックスの状態を退避 Me.mblnChkStatus = Me.CheckBox1.Checked '自分を閉じる Me.Close() End Sub '''''' フォームロードイベント ''' Private Sub fomProperty_Load(sender As Object, e As EventArgs) Handles Me.Load 'チェックボックスの初期状態設定 Me.CheckBox1.Checked = Me.mblnChkStatus End Sub End Classこの子フォームを呼出す親フォームの処理が以下の様になります。
子フォームを呼出す親フォームの処理
'''
''' 子フォームを呼出す親フォーム ''' Public Class frmPropMain '''''' ボタンクリックイベント ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'プロパティテストウインドウ生成 Dim frmProp As New frmProperty 'プロパティに自分のチェックボックスの値を設定 frmProp.ChkStatus = Me.CheckBox1.Checked 'ウインドウ表示 frmProp.ShowDialog() 'プロパティ値を自分のチェックボックスの値に設定 Me.CheckBox1.Checked = frmProp.ChkStatus 'プロパティテストウインドウ廃棄 frmProp.Dispose() frmProp = Nothing End Sub End Classこの例では子フォームを生成した後で、子フォームのプロパティを設定しています。二回に分けて処理をしますので少し面倒ですね。
この面倒さを解消するには、子フォームクラスの生成に引数として渡せればできるのです。
実際にどの様にするのかを、上記のソースを土台にして変えていきます。 尚、今回の例ではフォームクラスの名前を frmConstructor と変えています。
ソースは上記の frmProperty を全てコピーしてきて、その後でクラスの先頭辺りで Sub New とキー入力します。 そうすると、以下の様な感じで Sub New() の関数が自動で表示されます。
コンストラクタを明示する子フォームのクラス
'''
''' コンストラクタを明示する子フォーム ''' Public Class frmConstructor Sub New() ' この呼び出しはデザイナーで必要です。 InitializeComponent() ' InitializeComponent() 呼び出しの後で初期化を追加します。 End Sub 'チェック状態退避値 Private mblnChkStatus As Boolean = False '''''' チェック状態プロパティ ''' '''チェック状態の設定値 '''チェック状態を返す Public Property ChkStatus As Boolean Set(value As Boolean) mblnChkStatus = value '退避値に設定 End Set Get Return mblnChkStatus '退避値を返す End Get End Property '''''' ボタンクリックイベント ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'チェックボックスの状態を退避 Me.mblnChkStatus = Me.CheckBox1.Checked '自分を閉じる Me.Close() End Sub '''''' フォームロードイベント ''' Private Sub fomProperty_Load(sender As Object, e As EventArgs) Handles Me.Load 'チェックボックスの初期状態設定 Me.CheckBox1.Checked = Me.mblnChkStatus End Sub End Class
この後で Sub New() に引数を宣言し、フォーム生成時にプロパティが設定できる様に以下の様にソースを変更します。
コンストラクタ(引数設定)を明示する子フォームのクラス
'''
''' コンストラクタを明示する子フォーム ''' Public Class frmConstructor Sub New(ByVal blnChk As Boolean) ' この呼び出しはデザイナーで必要です。 InitializeComponent() ' InitializeComponent() 呼び出しの後で初期化を追加します。 'プロパティを設定する Me.ChkStatus = blnChk End Sub 'チェック状態退避値 Private mblnChkStatus As Boolean = False '''''' チェック状態プロパティ ''' '''チェック状態の設定値 '''チェック状態を返す Public Property ChkStatus As Boolean Set(value As Boolean) mblnChkStatus = value '退避値に設定 End Set Get Return mblnChkStatus '退避値を返す End Get End Property '''''' ボタンクリックイベント ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'チェックボックスの状態を退避 Me.mblnChkStatus = Me.CheckBox1.Checked '自分を閉じる Me.Close() End Sub '''''' フォームロードイベント ''' Private Sub fomProperty_Load(sender As Object, e As EventArgs) Handles Me.Load 'チェックボックスの初期状態設定 Me.CheckBox1.Checked = Me.mblnChkStatus End Sub End Class子フォームの生成時に引数を設定し処理する例として以下のソースに示します。
引数を持って子フォームを呼出す親フォームの処理
'''
''' 引数を持って子フォームを呼出す親フォーム ''' Public Class frmConstructorMain '''''' ボタンクリックイベント ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'プロパティテストウインドウ生成(自分のチェックボックスの値を引数) Dim frmConst As New frmConstructor(Me.CheckBox1.Checked) 'ウインドウ表示 frmConst.ShowDialog() 'プロパティ値を自分のチェックボックスの値に設定 Me.CheckBox1.Checked = frmConst.ChkStatus 'プロパティテストウインドウ廃棄 frmConst.Dispose() frmConst = Nothing End Sub End Classもし、引数在りでも無しでも両方の子フォームのコンストラクタを持ちたい場合には、 以下の様に引数無しの Sub New() をもう1個宣言すればできます。
この方法は オーバーロード と言われるもので、引数や戻り値が異なるが名前が同じの関数を複数定義する方法です。
(この場合は Sub の宣言ですが、 Function の場合でも同じ様にできます。)
コンストラクタ(引数設定)を明示する子フォームのクラス
'''
''' コンストラクタを明示する子フォーム ''' Public Class frmConstructor Sub New(ByVal blnChk As Boolean) ' この呼び出しはデザイナーで必要です。 InitializeComponent() ' InitializeComponent() 呼び出しの後で初期化を追加します。 'プロパティを設定する Me.ChkStatus = blnChk End Sub Sub New() ' この呼び出しはデザイナーで必要です。 InitializeComponent() End Sub '以下のソースは省略..... End Class関連する記事
⇒フォームクラス生成時に設定値を同時に渡す方法
⇒フォーム上の複数のコントロール(TextBox)の入力変化を確認する方法について
⇒フォームのマウスカーソルを待機状態する方法について
⇒フォームクラスの継承の方法について
-
以下のページではフォームクラスにフラグを宣言し、フォームActivatedイベントの処理で最初の呼び出しかどうかを判定していました。
このフラグ処理ですが、全てのフォームに宣言するのも手間が掛かりますので、いっそ継承クラスのフォームにしてはと思い テスト的なフォームのクラスを作成してみました。
先ずはフォーム名をfrmOneActiveBaseとして、 ソース内容は上記の「最初のフォームActivatedイベントでの処理」の内容をそのままコピーしてきます。 但し、テキストボックスの処理は削除してあります。
イベントを1個作成し名前をOneActivatedとして宣言します。 このイベントを、初回のフォームActivatedイベントで発生させる様にします。 ソースは以下の様になります。ベースのフォーム処理
Public Class frmOneActiveBase 'イベント宣言 Public Event OneActivated(ByVal sender As Object, ByVal e As EventArgs) 'アクティブフラグ Private mblnActivated As Boolean = False '''
''' フォームアクティブイベント ''' Private Sub frmOneActiveBase_Activated(sender As Object, e As EventArgs) Handles Me.Activated 'アクティブフラグOFF?? If Me.mblnActivated = False Then 'フラグON Me.mblnActivated = True 'イベント発生 RaiseEvent OneActivated(Me, New EventArgs) End If End Sub '''''' フォームロードイベント ''' Private Sub frmOneActiveBase_Load(sender As Object, e As EventArgs) Handles Me.Load Me.mblnActivated = False End Sub End Classここで一旦ビルド作業を行います。 その後、このfrmOneActiveBaseフォームを継承するフォームを作成してみます。
メインメニューの「プロジェクト」⇒「新しい項目の追加」を選択し、以下の表示になったら 左の「Windows Fomrs」を選択後「継承されたフォーム」を選択し、フォーム名をfrmOneActiveとします。
その後「継承ピッカー」の選択になりますので、先ほどの「frmOneActiveBase」を選択しますと以下の様な表示なります。
frmOneActiveのフォームが以下の様に表示されます。
frmOneActiveのフォームが表示されたら、1個のテキストボックスを貼付け、 複数行許可を画面右のプロパティウインドウから行います。
ここでfrmOneActiveフォームのソースを表示させ、 さらに、「frmOneActive(アクティブ)」から「OneActivated」イベント探して、指定します。そこで、以下の様にソースを記述します。
Public Class frmOneActive Private Sub frmOneActive_OneActivated(sender As Object, e As EventArgs) Handles Me.OneActivated 'テキストボックに時刻表示 Me.TextBox1.Text &= "Activated..." & Now.ToString("hh:mm:ss") & vbCrLf End Sub End Class
これでフォームのActivatedイベントでフラグ処理を行わずとも、このOneActivatedイベントの中で処理が可能となります。関連する記事
⇒フォームの位置設定を行う処理 :[Screen.PrimaryScreen.WorkingArea]
⇒フォームクラスにプロパティ宣言し外からアクセスする方法
⇒親フォームのコントロールを子フォームからアクセスする方法
⇒フォームが閉じるのをキャンセルする方法:[FormClosingEventArgs,Cancel]
⇒フォームの表示をモジュールのMain関数から行う(エントリポイントの変更)
⇒フォームがKeyDownなどのキーイベントを受取り、ファンクションキー処理をする
⇒最初のフォームActivatedイベントでの処理(1回のみしか処理しない様にする)
⇒初回のフォームActivatedイベント発生させるフォーム継承について
-
フォームが表示されて初めてアクティブになった時に行いたい処理が在る場合、 以下のソースの様にActivatedイベント時に処理を記述します。
フォーム上に1個のテキストボックスを貼付け、そのテキストボックスを複数行入力許可とします。
そして、Activatedイベント時に現在の時刻を表示します。 ソースは以下の通りです。フォームのActivatedイベントでの処理
Public Class frmActive '''
''' フォームアクティブイベント ''' Private Sub frmActive_Activated(sender As Object, e As EventArgs) Handles Me.Activated 'テキストボックに時刻表示 Me.TextBox1.Text &= "Activated..." & Now.ToString("hh:mm:ss") & vbCrLf End Sub '''''' フォームロードイベント ''' Private Sub frmActive_Load(sender As Object, e As EventArgs) Handles Me.Load 'テキストボックスを複数行許可 Me.TextBox1.Multiline = True Me.TextBox1.Height = 200 End Sub End Classこれを実行すると以下の様な表示になります。
上手く動いたかに見えますが、このフォームから別のプログラムなどをアクティブにしてから このプログラムを再度アクティブにすることを繰り返すと以下の様な表示になります。 (日付の表示がどんどん増えていきます)
これは問題です。何が悪いのかと言えば、Activatedイベントは自分自身のフォームが非アクティブから アクティブに変わった時に必ず発生するからです。 プログラムが起動し、最初のActivatedイベントかどうかはフラグを使うしかない様です。 そこで、プログラムを以下の様に変更します。フォームのActivatedイベントでの処理その2
Public Class frmActive 'アクティブフラグ Private mblnActivated As Boolean = False '''
''' フォームアクティブイベント ''' Private Sub frmActive_Activated(sender As Object, e As EventArgs) Handles Me.Activated 'アクティブフラグOFF?? If Me.mblnActivated = False Then 'フラグON Me.mblnActivated = True 'テキストボックに時刻表示 Me.TextBox1.Text &= "Activated..." & Now.ToString("hh:mm:ss") & vbCrLf End If End Sub '''''' フォームロードイベント ''' Private Sub frmActive_Load(sender As Object, e As EventArgs) Handles Me.Load 'テキストボックスを複数行許可 Me.TextBox1.Multiline = True Me.TextBox1.Height = 200 'アクティブフラグOFF(くどいですが) Me.mblnActivated = False End Sub End Class
上記のソースではアクティブになったフラグをフォームのローカル変数として宣言し、 Activatedイベント時にそのフラグをみてOFFだったら、フラグをONして二度と時刻表示の処理を しない様にしています。
これで何とかうまくいくようになりました。関連する記事
⇒フォームの位置設定を行う処理 :[Screen.PrimaryScreen.WorkingArea]
⇒フォームクラスにプロパティ宣言し外からアクセスする方法
⇒親フォームのコントロールを子フォームからアクセスする方法
⇒フォームが閉じるのをキャンセルする方法:[FormClosingEventArgs,Cancel]
⇒フォームの表示をモジュールのMain関数から行う(エントリポイントの変更)
⇒フォームがKeyDownなどのキーイベントを受取り、ファンクションキー処理をする
⇒最初のフォームActivatedイベントでの処理(1回のみしか処理しない様にする)
⇒初回のフォームActivatedイベント発生させるフォーム継承について
-
フォーム上のコントロールがアクティブである場合、キー入力があった時にそのコントロールにキーイベントが発生します。 そのコントロールのキーイベントが発生する前に何か処理を行いたい場合、 フォームの KeyPreviewプロパティをTrueに設定すると、フォームのキーイベントが先に発生します。 このイベント処理で、ファンクションキー等の処理が行えます。
例として、ファンクションキー押下でボタンクリックを行う処理を示します。 この処理ですが、ボタンをマウスでクリックする時と同じことをファンクションキー押下で行えます。
良くあるプログラムで、画面の下にボタンを12個並べて、 ボタンキャプションにファンクションキー名を表示しているあれです。 実行画面は以下の様になります。
以下のソースを見て下さい。 フォームのKeyDownイベントで各キーコードの処理を行っています。
ここで注意するのは e.Handled = True の部分です。 この処理でフォームのKeyDownイベント以降に、その他のコントロールにKeyDownイベント発生を抑止しています。
「F10」などではシステムの予約された処理があるので、それを抑止するためです。フォームのKeyDownイベントでのファンクションキー処理
Public Class frmFunc '''
''' フォームロードイベント ''' Private Sub frmFunc_Load(sender As Object, e As EventArgs) Handles MyBase.Load 'フォームが先にキーを受け取る設定 Me.KeyPreview = True End Sub '''''' フォームKeyDownイベント ''' Private Sub frmFunc_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown 'キーコードにより処理する Select Case e.KeyCode Case Keys.F1 '「F1:キー」 If Me.Button1.Enabled = True Then '取りあえずボタン許可チェック Me.Button1.Focus() 'フォーカスセット Me.Button1.PerformClick() 'ボタン1クリック実行 End If e.Handled = True '他にKeyDownイベントを発生させない Case Keys.F2 '「F2:キー」 If Me.Button2.Enabled = True Then '取りあえずボタン許可チェック Me.Button2.Focus() 'フォーカスセット Me.Button2.PerformClick() 'ボタン1クリック実行 End If e.Handled = True Case Keys.F3 '「F3:キー」 e.Handled = True Case Keys.F10 '「F10:キー」 e.Handled = True End Select End Sub '''''' ボタン1クリックイベント ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click MsgBox("Button1_Click", MsgBoxStyle.OkOnly, Me.Text) End Sub '''''' ボタン2クリックイベント ''' Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click MsgBox("Button2_Click", MsgBoxStyle.OkOnly, Me.Text) End Sub End Class
関連する記事
⇒フォームクラスにプロパティ宣言し外からアクセスする方法
⇒最初のフォームActivatedイベントでの処理(1回のみしか処理しない様にする)
⇒初回のフォームActivatedイベント発生させるフォーム継承について
⇒フォームクラス生成時に設定値を同時に渡す方法