[2018/05/28] フォームクラス生成時に設定値を同時に渡す方法 (No.48)
[2018/03/28] 初回のフォームActivatedイベント発生させるフォーム継承について (No.40)
[2018/03/28] 最初のフォームActivatedイベントでの処理(1回のみしか処理しない様にする) (No.39)
[2018/03/28] フォームがKeyDownなどのキーイベントを受取り、ファンクションキー処理をする (No.38)
-
何かのデータをデータベースから読込み TextBox 等に表示し、それぞれ TextBox のいずれかに入力の変更が在ったかどうかを判断する方法を示します。
以下のソースではフォームロードイベント時に仮のデータを初期値として、フォーム上の5個の TextBox に設定しています。 さらに、TextBox の TextChanged イベントで入力が在ったことを処理するため、内部の変更フラグをONしていますが、 そのイベント処理ハンドラを AddHandler により各 TextBox に関連付けています。
仮に【登録】【終了】ボタンを設置し、【登録】ボタン処理では実際の登録はしないのですが、 登録したものとして、変更フラグをOFFとして再初期化しています。 また、【終了】ボタン処理ではフラグを確認して、確認メッセージを表示する様にしています。フォーム上の複数の TextBox の入力変化を確認する処理
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253Public
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イベント処理について
12345678'通常の方法での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 -
あるフォームから別のフォームを表示し、その子フォームでの情報を親のフォームからアクセスしたい場合に、 子フォームにプロパティを持ち、それを介してデータのやり取りを行う方法は以下のソースの様になることを以前紹介しました。
プロパティを持つ子フォームのクラス
1234567891011121314151617181920212223242526272829303132333435363738394041''' <summary>
''' プロパティを持つ子フォーム
''' </summary>
Public
Class
frmProperty
'チェック状態退避値
Private
mblnChkStatus
As
Boolean
=
False
''' <summary>
''' チェック状態プロパティ
''' </summary>
''' <value>チェック状態の設定値</value>
''' <returns>チェック状態を返す</returns>
Public
Property
ChkStatus
As
Boolean
Set
(value
As
Boolean
)
mblnChkStatus = value
'退避値に設定
End
Set
Get
Return
mblnChkStatus
'退避値を返す
End
Get
End
Property
''' <summary>
''' ボタンクリックイベント
''' </summary>
Private
Sub
Button1_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button1.Click
'チェックボックスの状態を退避
Me
.mblnChkStatus =
Me
.CheckBox1.Checked
'自分を閉じる
Me
.Close()
End
Sub
''' <summary>
''' フォームロードイベント
''' </summary>
Private
Sub
fomProperty_Load(sender
As
Object
, e
As
EventArgs)
Handles
Me
.Load
'チェックボックスの初期状態設定
Me
.CheckBox1.Checked =
Me
.mblnChkStatus
End
Sub
End
Class
この子フォームを呼出す親フォームの処理が以下の様になります。
子フォームを呼出す親フォームの処理
1234567891011121314151617181920212223''' <summary>
''' 子フォームを呼出す親フォーム
''' </summary>
Public
Class
frmPropMain
''' <summary>
''' ボタンクリックイベント
''' </summary>
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() の関数が自動で表示されます。
コンストラクタを明示する子フォームのクラス
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950''' <summary>
''' コンストラクタを明示する子フォーム
''' </summary>
Public
Class
frmConstructor
Sub
New
()
' この呼び出しはデザイナーで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
End
Sub
'チェック状態退避値
Private
mblnChkStatus
As
Boolean
=
False
''' <summary>
''' チェック状態プロパティ
''' </summary>
''' <value>チェック状態の設定値</value>
''' <returns>チェック状態を返す</returns>
Public
Property
ChkStatus
As
Boolean
Set
(value
As
Boolean
)
mblnChkStatus = value
'退避値に設定
End
Set
Get
Return
mblnChkStatus
'退避値を返す
End
Get
End
Property
''' <summary>
''' ボタンクリックイベント
''' </summary>
Private
Sub
Button1_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button1.Click
'チェックボックスの状態を退避
Me
.mblnChkStatus =
Me
.CheckBox1.Checked
'自分を閉じる
Me
.Close()
End
Sub
''' <summary>
''' フォームロードイベント
''' </summary>
Private
Sub
fomProperty_Load(sender
As
Object
, e
As
EventArgs)
Handles
Me
.Load
'チェックボックスの初期状態設定
Me
.CheckBox1.Checked =
Me
.mblnChkStatus
End
Sub
End
Class
この後で Sub New() に引数を宣言し、フォーム生成時にプロパティが設定できる様に以下の様にソースを変更します。
コンストラクタ(引数設定)を明示する子フォームのクラス
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152''' <summary>
''' コンストラクタを明示する子フォーム
''' </summary>
Public
Class
frmConstructor
Sub
New
(
ByVal
blnChk
As
Boolean
)
' この呼び出しはデザイナーで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
'プロパティを設定する
Me
.ChkStatus = blnChk
End
Sub
'チェック状態退避値
Private
mblnChkStatus
As
Boolean
=
False
''' <summary>
''' チェック状態プロパティ
''' </summary>
''' <value>チェック状態の設定値</value>
''' <returns>チェック状態を返す</returns>
Public
Property
ChkStatus
As
Boolean
Set
(value
As
Boolean
)
mblnChkStatus = value
'退避値に設定
End
Set
Get
Return
mblnChkStatus
'退避値を返す
End
Get
End
Property
''' <summary>
''' ボタンクリックイベント
''' </summary>
Private
Sub
Button1_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button1.Click
'チェックボックスの状態を退避
Me
.mblnChkStatus =
Me
.CheckBox1.Checked
'自分を閉じる
Me
.Close()
End
Sub
''' <summary>
''' フォームロードイベント
''' </summary>
Private
Sub
fomProperty_Load(sender
As
Object
, e
As
EventArgs)
Handles
Me
.Load
'チェックボックスの初期状態設定
Me
.CheckBox1.Checked =
Me
.mblnChkStatus
End
Sub
End
Class
子フォームの生成時に引数を設定し処理する例として以下のソースに示します。
引数を持って子フォームを呼出す親フォームの処理
123456789101112131415161718192021''' <summary>
''' 引数を持って子フォームを呼出す親フォーム
''' </summary>
Public
Class
frmConstructorMain
''' <summary>
''' ボタンクリックイベント
''' </summary>
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 の場合でも同じ様にできます。)
コンストラクタ(引数設定)を明示する子フォームのクラス
1234567891011121314151617181920212223242526''' <summary>
''' コンストラクタを明示する子フォーム
''' </summary>
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イベントで発生させる様にします。 ソースは以下の様になります。ベースのフォーム処理
1234567891011121314151617181920212223242526272829Public
Class
frmOneActiveBase
'イベント宣言
Public
Event
OneActivated(
ByVal
sender
As
Object
,
ByVal
e
As
EventArgs)
'アクティブフラグ
Private
mblnActivated
As
Boolean
=
False
''' <summary>
''' フォームアクティブイベント
''' </summary>
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
''' <summary>
''' フォームロードイベント
''' </summary>
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」イベント探して、指定します。そこで、以下の様にソースを記述します。
12345678Public
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イベントでの処理
1234567891011121314151617181920Public
Class
frmActive
''' <summary>
''' フォームアクティブイベント
''' </summary>
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
''' <summary>
''' フォームロードイベント
''' </summary>
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
123456789101112131415161718192021222324252627282930Public
Class
frmActive
'アクティブフラグ
Private
mblnActivated
As
Boolean
=
False
''' <summary>
''' フォームアクティブイベント
''' </summary>
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
''' <summary>
''' フォームロードイベント
''' </summary>
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イベントでのファンクションキー処理
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253Public
Class
frmFunc
''' <summary>
''' フォームロードイベント
''' </summary>
Private
Sub
frmFunc_Load(sender
As
Object
, e
As
EventArgs)
Handles
MyBase
.Load
'フォームが先にキーを受け取る設定
Me
.KeyPreview =
True
End
Sub
''' <summary>
''' フォームKeyDownイベント
''' </summary>
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
''' <summary>
''' ボタン1クリックイベント
''' </summary>
Private
Sub
Button1_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button1.Click
MsgBox(
"Button1_Click"
, MsgBoxStyle.OkOnly,
Me
.Text)
End
Sub
''' <summary>
''' ボタン2クリックイベント
''' </summary>
Private
Sub
Button2_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button2.Click
MsgBox(
"Button2_Click"
, MsgBoxStyle.OkOnly,
Me
.Text)
End
Sub
End
Class
Windowsのデスクトップアプリケーションを作成しながら少しずつ言語仕様や組み方を理解していきます。 プログラミングがはじめての人にも理解できる様に構成されています。
関連する記事
⇒フォームクラスにプロパティ宣言し外からアクセスする方法
⇒最初のフォームActivatedイベントでの処理(1回のみしか処理しない様にする)
⇒初回のフォームActivatedイベント発生させるフォーム継承について
⇒フォームクラス生成時に設定値を同時に渡す方法
おすすめ本