- PR -

FocusしたらLostFocusが走る?

投稿者投稿内容
りんご
ベテラン
会議室デビュー日: 2006/12/21
投稿数: 51
投稿日時: 2006-12-26 12:08
こんにちは。いつもお世話になっております。

開発環境VB2005.NET DB=Firebird WindowsXPです

フォーム上にテキストボックス3つと自作のユーザーコントロールを
貼り付けています。
フォーム上ではEnterキーを押すと次のコントロールへ移動する
処理を行っています。
ですがテキストボックスで↓キーを押されたら自作ユーザーコントロールを
表示させて、このユーザーコントロールにフォーカスを移したいのですが、
いい方法が見つかりません。
なぜか、ユーザーコントロールにFocus()するとそのコントロールの
LostFocusにブレークします。
ActiveControlとして設定しても無理でした。
SelectNextControlはTabIndexの次の順番ですので、
その一つ前のコントロールを設定すると動くのですが、他に方法はないでしょうか・・?
これでは汎用性がないのです。
ちなみにユーザーコントロールにフォーカスが移れば、
その内部ではきちんとEnterキーで移動できます(コントロール内部で制御)
あと、ユーザーコントロールがLostFocusした時点で
取得した値を保存して、Visible=FALSEしていますが、これは制御的には
どうなんでしょうか・・

どうぞよろしくお願いいたします。

Private CC As Control '保存用コントロール

Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
If e.KeyCode = Keys.Enter Then
If Me.ActiveControl.Name = SearchBox2.Name Then
Debug.Print("今SEARCHBOX2がACTIVE")
Else
Me.SelectNextControl(Me.ActiveControl, True, True, True, True)
e.Handled = True
End If
End If
End Sub

Private Sub TextBox2_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox2.KeyDown
Select Case e.KeyCode
Case Keys.Down
Me.SearchBox2.Visible = True
'Me.ActiveControl = SearchBox2
CC = sender
'12/26 以下だとlostFocusされてしまう
'SearchBox2.Focus()
'12/26 以下だとフォーカスがこない
'SearchBox2.Select()
'SearchBox2はTextBox4の次のTabIndexのため、仕方なく・・
         Me.SelectNextControl(TextBox4, True, True, True, True)
e.Handled = True
End Select
End Sub

Private Sub SearchBox2_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles SearchBox2.GotFocus
Debug.Print("SEARCHBOX2のGOTFOCUS!!")
End Sub

Private Sub SearchBox2_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles SearchBox2.LostFocus
Dim mmCODE As Integer
Debug.Print(SearchBox2.wCODE)
Debug.Print(CC.Name)
mmCODE = SearchBox2.wCODE
SearchBox2.Visible = False
If TypeName(CC) = "TextBox" Then
CC.Text = mmCODE
End If
End Sub
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-12-26 12:59
引用:

りんごさんの書き込み (2006-12-26 12:08) より:

フォーム上にテキストボックス3つと自作のユーザーコントロールを貼り付けています。フォーム上ではEnterキーを押すと次のコントロールへ移動する処理を行っています。ですがテキストボックスで↓キーを押されたら自作ユーザーコントロールを表示させて、このユーザーコントロールにフォーカスを移したいのですが、いい方法が見つかりません。
なぜか、ユーザーコントロールにFocus()するとそのコントロールのLostFocusにブレークします。ActiveControlとして設定しても無理でした。


想像が容易でないので、間違ったことを書いているかもしれませんが、

まず、1 点目。
"LostFocus にブレークする" とありますが、LostFocus イベントは、低水準のイベントです。
同様に、GotFocus イベントも低水準なイベントです。

予期せぬ状況 (名前にそぐわない状況) でも発生しうるイベントであり、使用しない方が良いでしょう。

LostFocus イベントの代わりに Leave イベントを使用しましょう。
GotFocus イベントの代わりに Enter イベントを使用しましょう。

2 点目。
UserControl に Focus を設定すると、まず UserControl の Enter イベントが起きます。

そして、そこから先は、UserControl 側の仕事です。
UserControl 内のコントロールの面倒は、直属の親である UserControl が面倒を見ます。

これは、Form 側で SelectNextControl メソッドを実行した場合だろうと、何であろうと同じことです。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
りんご
ベテラン
会議室デビュー日: 2006/12/21
投稿数: 51
投稿日時: 2006-12-26 15:03
じゃんぬねっとさん、ご返信ありがとうございます。

LostFocusをやめてLeaveにし、GotFocusをやめてEnterに
しましたところ、Textボックスで↓キー押下により
ユーザーコントロールの表示となり、そこにフォーカスが移り
あとはユーザーコントロール内部でのEnterキー移動となりました。

ですが、ユーザーコントロール内部で作成した「終了」ボタン
(TabIndex最終)を押しても、フォーム側のユーザーコントロールの
Leaveイベントが発生しません・・
これは、ユーザーコントロールの「終了」Click時に
自分自身をLeaveさせるとかしないといけないのでしょうか?
ユーザーコントロール内部で、データを選択(Enterキー)しても
「終了」ボタンを押しても、ユーザーコントロールの終了ということで
それ自身を消して、フォームの次のコントロールへ移動したいのです。
現在、ユーザーコントロール内部でDisposeさせると、
フォーム側で次に呼び出しをしても表示されません。。

フォーム側の処理としては
・テキスト1でEnter押す→テキスト2
・テキスト1で↓キー押す→ユーザーコントロールの表示でユーザーコントロール
内部の制御
・ユーザーコントロール内部で「終了」→ユーザーコントロールの非表示→
テキスト2へフォーカス
・テキスト2で↓キー押す→ユーザーコントロール内部の制御

が希望です。
ユーザーコントロールからフォーカスを移動することに困難中です。

何かいい案かもしくはヒントでもないでしょうか?

よろしくお願いいたします。


りんご
ベテラン
会議室デビュー日: 2006/12/21
投稿数: 51
投稿日時: 2006-12-26 15:04
すみません。ユーザーコントロールの「終了」処理です。

'閉じるボタン押下でコントロール終了
Private Sub CloseButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CloseButton.Click, CloseButton.Enter
'接続していたら、閉じる
If Me.OdbcConnection1.State = ConnectionState.Open Then
Me.OdbcConnection1.Close()
End If

'返す値は0
wCODE = 0

MessageBox.Show("コントロール終了です。選択された値=" & wCODE)

'コントロール終了のため、データ・表示をクリアしておく
DataGrd.DataSource = Nothing
DataGrd.ClearSelection()
DataGrd.Columns.Clear()

'↓次回検索結果が出ないからダメ
'DataGrd.Dispose()
SearchText.Text = ""
CountLabel.Text = 0
'↓次回使用するとき使えない??・・
Me.Dispose()

'RaiseEvents OnLeave(e New System.EventArgs())

'↓これはアプリ開発者側で設定する
'Me.Visible = False
End Sub
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-12-26 16:14
引用:

りんごさんの書き込み (2006-12-26 15:03) より:

ですが、ユーザーコントロール内部で作成した「終了」ボタン(TabIndex最終)を押しても、フォーム側のユーザーコントロールのLeaveイベントが発生しません・・


結果的に "フォーカスが離れた" ことにはなるのでしょうけど、
その UserControl は Form から見えなくなってしまっているので、
Leave イベント発動条件としては、微妙なところですね。

引用:

これは、ユーザーコントロールの「終了」Click時に自分自身をLeaveさせるとかしないといけないのでしょうか?


とりあえずは、別のコントロールにフォーカスを追い出してしまえば良いと思います。

その前に、UserControl の Leave イベントに拘っている理由がわからないです。
UserControl が見えなくなった時に何かをしたいのであれば、別に手段がありますよね。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
りんご
ベテラン
会議室デビュー日: 2006/12/21
投稿数: 51
投稿日時: 2006-12-26 16:58
じゃんぬねっとさん、いつもご丁寧にありがとうございます。

ユーザーコントロール側で「終了」ボタンを押下したときに
Me.Validate()を追加しました。
フォーム側
Private Sub SearchBox2_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles SearchBox2.Validated
Debug.Print(Me.ActiveControl.Name)
'e.Handled = True
Dim mmCODE As Integer
Debug.Print(SearchBox2.wCODE)
Debug.Print(CC.Name)
mmCODE = SearchBox2.wCODE
SearchBox2.Visible = False
If TypeName(CC) = "TextBox" Then
CC.Text = mmCODE
End If
Me.SelectNextControl(Me.ActiveControl, True, True, True, True)
End Sub

でも、結局はユーザーコントロールの終了後、
別のフォーカスに移さないと、コントロールが非表示になりません。
OnLeaveさせると、なぜかLeaveイベントが永遠に走ってました・・

ユーザーコントロール側の制御が「終了」した場合に
どうすればいいのか・・・

自分自身をDisposeしてしまうと、
フォーム側で別のテキストで↓を押しても(Visible=TRUEしても)
表示されません。

>その前に、UserControl の Leave イベントに拘っている理由がわからないです。
>UserControl が見えなくなった時に何かをしたいのであれば、別に手段がありますよね。

拘ってるつもりはなかったのですが・・・

・テキスト1でEnter押す→テキスト2
・テキスト1で↓キー押す→ユーザーコントロールの表示でユーザーコントロール
内部の制御
・ユーザーコントロール内部で「終了」→ユーザーコントロールの非表示→
テキスト2へフォーカス
・テキスト2で↓キー押す→ユーザーコントロール内部の制御

という制御で、Leaveを使わず、かつ非表示はフォーム側で行うということは
可能なのでしょうか?

というか、「閉じる」処理で値を返したあと、何かイベントを
発生させないといけないのか、Focusをフォーム側に持っていくには?
処理が分からないです。

フォーム側
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
If e.KeyCode = Keys.Enter Then
If Me.ActiveControl.Name = SearchBox2.Name Then
'SearchBox2の内部でEnter制御中
       Debug.Print("今SEARCHBOX2がACTIVE")
Else
Me.SelectNextControl(Me.ActiveControl, True, True, True, True)
e.Handled = True
End If
End If
End Sub

↑この中で、ユーザーコントロールの「閉じる」ボタンが押されたか
どうかを判定できるのでしょうか?

ご教授のほど、よろしくお願いいたします。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-12-26 17:21
引用:

りんごさんの書き込み (2006-12-26 16:58) より:

という制御で、Leaveを使わず、かつ非表示はフォーム側で行うということは可能なのでしょうか?


Leave イベントに頼るのではなく 「UserControl が終了した」 ということを Form 側が関知できるようにしましょう。
UserControl に終了したことを示す独自のイベントを定義して、Raise すれば Form 側で関知できます。

引用:

というか、「閉じる」処理で値を返したあと、何かイベントを
発生させないといけないのか、Focusをフォーム側に持っていくには?
処理が分からないです。


考え方を変えて、値は Form 側が勝手に参照するようにしましょう。

終了のタイミングさえ Form 側が関知できれば、UserControl を非表示にして、
フォーカスを設定したいコントロールを決めることも容易です。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
りんご
ベテラン
会議室デビュー日: 2006/12/21
投稿数: 51
投稿日時: 2006-12-27 09:31
じゃんぬねっとさん、ご返信ありがとうございます。

ご指摘のとおり、ユーザーコントロールにイベントを発生、
フォーム側にそのイベントを記述したら、
上手くいきました!

ユーザーコントロール側
'終了関知 宣言
Public Event SearchEnd(ByVal sender As Object, ByVal e As System.EventArgs)

'12/27追加 終了時にCALL
RaiseEvent SearchEnd(Me, New System.EventArgs())

フォーム側 宣言
'FriendではなくPrivateとします
Private WithEvents SearchBox2 As SearchBox.SearchBox

Private Sub SearchBox2_SearchEnd(ByVal sender As Object, ByVal e As System.EventArgs) Handles SearchBox2.SearchEnd
Dim mmCODE As Integer

Debug.Print("ユーザーコントロールで終了が押されました")
Debug.Print(Me.ActiveControl.Name)
Debug.Print(SearchBox2.wCODE)
Debug.Print(CC.Name)

mmCODE = SearchBox2.wCODE
SearchBox2.Visible = False
If TypeName(CC) = "TextBox" Then
CC.Text = mmCODE
End If

'↓以下ではTabIndexで違うコントロールへフォーカスが移ってしまう
'Me.SelectNextControl(Me.ActiveControl, True, True, True, True)
Me.SelectNextControl(CC, True, True, True, True)
End Sub

終了時の引数をsenderとeにしてますが、いずれ使うかも知れないので、
このままで・・
ユーザーコントロールを初めて作成しましたが、いろいろと勉強になりました。

長々とお付き合いただいて、本当にありがとうございました。

スキルアップ/キャリアアップ(JOB@IT)