none
GotFocusについて RRS feed

  • 質問

  • 初心者ではありますが、2点質問させていただきます。ご教授いただけたら幸いです。

     

    環境はVB2008Pro、Vista上で動いています。

     

    概要ですが、フォームにテキストボックスやコンボボックスを配置し、Enterキー押下で次のコントロールにフォーカスを移動するようにしています。

    以下がコードです。フォームはKeyPreview=Trueに設定しています。

        Private Sub frmLogin_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
            If e.KeyValue = Keys.Enter Then
                Me.ProcessTabKey(Not e.Shift)
            End If
        End Sub

    このコードで問題なく動いていますが、もし他によい方法がありましたら、ご教授ください。

     

     

    さて、このコードで移動されたフォーカスを受けたコントロールのテキストを反転表示(と言うのでしょうか?)したいのですが、コントロールが多数ある場合はどう処理すればよろしいでしょうか?

    数が少なければ、

        Private Sub txtUser_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtUser.GotFocus
            txtUser.SelectionStart = 0
            txtUser.SelectionLength = txtUser.TextLength
        End Sub

    のように書いています。

    また、2~3つのときはHandlesの後ろにカンマで続けて他のコントロールを上記コードのように書いています。

     

    もし、これらを美しく書くとなると、どう処理すればよろしいでしょうか?

     

    たとえば、フォーム上のフォーカスがあるコントロールを見つけてテキストボックスやコンボボックスであった場合に処理するというようなイメージがありますが、どのイベントに、どのように書くべきかわかりません。

    コントロール1つずつに同じようなコードを書いていて他に方法があると思い、質問させていただいた次第です。

     

     

    質問の仕方等に問題があるかも知れませんが、お許しいただきますようお願い致します。

    2008年3月26日 13:57

回答

  • まず、MSDNに明記されていますが、EnterおよびLeaveイベントを使用してください。

    GotFocusとLostFocusはFrameworkの内部的な意味のものに変わりましたので使わないでください。

     

    本題ですが二つの例をあげます。

     

    1.イベントプロシージャを共有する。(Handles以降を書かずにイベントとプロシージャを動的にリンクする)

     

      AddHandlerステートメントを調べてみてください。

      LoadイベントやShownイベントに書くことになります。

     

    2.継承コントロールを作る。

     

      そのような動きをする継承した拡張コントロールを作ってそれをフォームに貼り付けることです。

     

    Code Snippet

    Public Class TextBoxEx

        Inherits TextBox

     

        Protected Overrides Sub OnEnter(ByVal e As EventArgs)

            MyBase.OnEnter(e)

            ' ここに処理を書く

        End Sub

    End Class

     

     

    ビルドするとツールボックスに追加されますので貼り付けることが可能です。

    この場合、上記にその動きをさせるかどうかのプロパティを実装するとさらに良いかも。

    Public Property SelectOnEnter As Boolean

     

    2008年3月26日 15:01
  • yama5525jp さん、こんにちは。

     yama5525jp さんからの引用
    ご教授いただいた内容に質問して申し訳ないですが、上のShownでフォーム内にあるコントロールがテキストボックスやコンボボックスであった場合に設定するということは可能でしょうか?

     

    この手法でいくならば、コンパイル解決できる TypeOf 演算子を使うことをお勧めします。

     

    VB.NET
    For Each cControl As Control In Me.Controls
        If TypeOf cControl Is TextBoxBase Then
            AddHandler ...
        ElseIf TypeOf cControl Is ComboBox Then
            AddHandler...
        End If
    Next

     

    みたいな感じでよろしいかと思います。

     

    # 拡張コントロール案もいいけど、拡張プロバイダ案とかないかなぁw

    2008年3月27日 6:27
  •  yama5525jp さんからの引用

            For Each myCtl As Control In Me.Controls

                If TypeOf myCtl Is TextBox Then

     

    考え方の問題になりますが、貼り付けてあるフォーム自身に記述するので

    つまり、どのコントロールがあるか知っていますので、AddHandlerを並べるという方法もあります。

    上記は探していますので、コントロールの名前が変わってもこのループは変更しなくても良い、という考え方になります。

     

     yama5525jp さんからの引用

    心当たりがあるのは、フォームにグループボックスを貼り、その中にテキストボックスがあります。

    ちなみに、できることなら、このようなグループボックスやパネルがある場合でも意識することなくコードを張れば動くということは不可能でしょうか。

     

    コントロールにはコンテナという概念があります。

    コントロールの内側にコントロールがあるという概念です。

    つまり、グループボックスに配置したものはGroupBox1.Controlsに入っています。

    したがって、試されたControlsをループさせる方法ですとツリー構造をたどる処理方式にする必要があります。

    この場合、「再帰」と呼ばれる処理方式を用います。

    代表的な例は、フォルダの中のフォルダとファイルを列挙する処理ですね。

     

    再帰処理の例を書いておきます。

     

    Code Snippet

    Public Class Form1

        Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown

            AddHandlerToControl(Me)

        End Sub

        Private Sub AddHandlerToControl(ByVal targetControl As Control)

            For Each ctl As Control In targetControl.Controls
                AddHandlerToControl(ctl)  ' これが再帰呼び出し
            Next

            Select Case True
                Case TypeOf targetControl Is TextBox
                    AddHandler targetControl.Enter, AddressOf Me.TextBox_Enter
            End Select

        End Sub

        Private Sub TextBox_Enter(ByVal sender As Object, ByVal e As EventArgs)

        End Sub

    End Class

     

     

     

    2008年3月27日 8:05
  •  yama5525jp さんからの引用

    これでエラーもなく動きます。ただ、反転処理(?)がうまくできていません。

    心当たりがあるのは、フォームにグループボックスを貼り、その中にテキストボックスがあります。

    冒頭から状況説明が不足していたとすれば、大変申し訳ありません。

    ちなみに、できることなら、このようなグループボックスやパネルがある場合でも意識することなくコードを張れば動くということは不可能でしょうか。

     

    可能です。 列挙したコントロールのインスタンスの HasChildren プロパティが True だった場合に再帰するような処理にすれば良いです。 このあたりの処理は http://jeanne.wankuma.com/tips/form/findcontrol.html を参考にすればわかるかと思います。


    そうなると、まどか様からご教授いただいた②の方法がよろしいのでしょうか。

     

    (2) 案は 「ポトペタ」 で対応できるので (1) よりお勧めです。 何らかの仕様変更の対応も非常に容易にできますし、流用もしやすいです。

    2008年3月27日 8:07

すべての返信

  • まず、MSDNに明記されていますが、EnterおよびLeaveイベントを使用してください。

    GotFocusとLostFocusはFrameworkの内部的な意味のものに変わりましたので使わないでください。

     

    本題ですが二つの例をあげます。

     

    1.イベントプロシージャを共有する。(Handles以降を書かずにイベントとプロシージャを動的にリンクする)

     

      AddHandlerステートメントを調べてみてください。

      LoadイベントやShownイベントに書くことになります。

     

    2.継承コントロールを作る。

     

      そのような動きをする継承した拡張コントロールを作ってそれをフォームに貼り付けることです。

     

    Code Snippet

    Public Class TextBoxEx

        Inherits TextBox

     

        Protected Overrides Sub OnEnter(ByVal e As EventArgs)

            MyBase.OnEnter(e)

            ' ここに処理を書く

        End Sub

    End Class

     

     

    ビルドするとツールボックスに追加されますので貼り付けることが可能です。

    この場合、上記にその動きをさせるかどうかのプロパティを実装するとさらに良いかも。

    Public Property SelectOnEnter As Boolean

     

    2008年3月26日 15:01
  • まどか様 ご教授ありがとうございます。

     

    まずは①の方法で進めてみました。以下がコードです。

     

        Private Sub frmLogin_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown

     

            AddHandler txtUser.Enter, AddressOf txtEnter
            AddHandler txtPass.Enter, AddressOf txtEnter
        End Sub

        Private Sub txtEnter(ByVal sender As Object, ByVal e As System.EventArgs)

            With sender
                .SelectionStart = 0
                .SelectionLength = .TextLength
            End With
        End Sub

    これで問題なく動いていますが正しいでしょうか?

    ご教授いただいた内容に質問して申し訳ないですが、上のShownでフォーム内にあるコントロールがテキストボックスやコンボボックスであった場合に設定するということは可能でしょうか?

     

    たとえば、

        Private Sub frmLogin_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown

            For Each myObject In Me.Controls

                If TypeName(myObject) = "TextBox" Then

                    AddHandler myObject.Enter, AddressOf txtEnter
                End If
            Next
        End Sub

    のようなイメージですが、これはmyObjectの部分に下線が出て動きません。

    Select Caseを使うとさまざまなコントロールに設定できるような気がしていますが、このような方法はNGなのでしょうか?

     

    お手数おかけして申し訳ないですが、再度ご教授いただきますよう、お願い致します。

    2008年3月27日 6:20
  • yama5525jp さん、こんにちは。

     yama5525jp さんからの引用
    ご教授いただいた内容に質問して申し訳ないですが、上のShownでフォーム内にあるコントロールがテキストボックスやコンボボックスであった場合に設定するということは可能でしょうか?

     

    この手法でいくならば、コンパイル解決できる TypeOf 演算子を使うことをお勧めします。

     

    VB.NET
    For Each cControl As Control In Me.Controls
        If TypeOf cControl Is TextBoxBase Then
            AddHandler ...
        ElseIf TypeOf cControl Is ComboBox Then
            AddHandler...
        End If
    Next

     

    みたいな感じでよろしいかと思います。

     

    # 拡張コントロール案もいいけど、拡張プロバイダ案とかないかなぁw

    2008年3月27日 6:27
  • じゃんぬねっと様  ご教授ありがとうございます。

     

    素人ながらこのような類のHPをいろいろ見ておりまして、皆様の活躍を拝見しておりました。

    足元にも及ばない遠い存在だと思っていた方々にご教授いただき、なんとお礼を言ったらいいのか・・・。ありがとうございます。

     

    早速、以下のコードにしてみました。

    ちなみに、先ほどの私の質問では、動く・動かないの問題の前に、書き方が違っていました。すみません。

     

        Private Sub frmLogin_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown

            For Each myCtl As Control In Me.Controls

                If TypeOf myCtl Is TextBox Then
                    AddHandler myCtl.Enter, AddressOf txtEnter
                End If
            Next
        End Sub

    これでエラーもなく動きます。ただ、反転処理(?)がうまくできていません。

    心当たりがあるのは、フォームにグループボックスを貼り、その中にテキストボックスがあります。

    冒頭から状況説明が不足していたとすれば、大変申し訳ありません。

    ちなみに、できることなら、このようなグループボックスやパネルがある場合でも意識することなくコードを張れば動くということは不可能でしょうか。

     

    そうなると、まどか様からご教授いただいた②の方法がよろしいのでしょうか。

    じゃんぬねっと様の拡張プロバイダ案もどんな方法か知りたいです。

     

    参考書を片手に基礎の基礎から始めているので、どうか温かくご教授いただけると幸いです。

    お手数おかけして申し訳ありませんが、よろしくお願いいたします。
    2008年3月27日 7:14
  •  yama5525jp さんからの引用

            For Each myCtl As Control In Me.Controls

                If TypeOf myCtl Is TextBox Then

     

    考え方の問題になりますが、貼り付けてあるフォーム自身に記述するので

    つまり、どのコントロールがあるか知っていますので、AddHandlerを並べるという方法もあります。

    上記は探していますので、コントロールの名前が変わってもこのループは変更しなくても良い、という考え方になります。

     

     yama5525jp さんからの引用

    心当たりがあるのは、フォームにグループボックスを貼り、その中にテキストボックスがあります。

    ちなみに、できることなら、このようなグループボックスやパネルがある場合でも意識することなくコードを張れば動くということは不可能でしょうか。

     

    コントロールにはコンテナという概念があります。

    コントロールの内側にコントロールがあるという概念です。

    つまり、グループボックスに配置したものはGroupBox1.Controlsに入っています。

    したがって、試されたControlsをループさせる方法ですとツリー構造をたどる処理方式にする必要があります。

    この場合、「再帰」と呼ばれる処理方式を用います。

    代表的な例は、フォルダの中のフォルダとファイルを列挙する処理ですね。

     

    再帰処理の例を書いておきます。

     

    Code Snippet

    Public Class Form1

        Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown

            AddHandlerToControl(Me)

        End Sub

        Private Sub AddHandlerToControl(ByVal targetControl As Control)

            For Each ctl As Control In targetControl.Controls
                AddHandlerToControl(ctl)  ' これが再帰呼び出し
            Next

            Select Case True
                Case TypeOf targetControl Is TextBox
                    AddHandler targetControl.Enter, AddressOf Me.TextBox_Enter
            End Select

        End Sub

        Private Sub TextBox_Enter(ByVal sender As Object, ByVal e As EventArgs)

        End Sub

    End Class

     

     

     

    2008年3月27日 8:05
  •  yama5525jp さんからの引用

    これでエラーもなく動きます。ただ、反転処理(?)がうまくできていません。

    心当たりがあるのは、フォームにグループボックスを貼り、その中にテキストボックスがあります。

    冒頭から状況説明が不足していたとすれば、大変申し訳ありません。

    ちなみに、できることなら、このようなグループボックスやパネルがある場合でも意識することなくコードを張れば動くということは不可能でしょうか。

     

    可能です。 列挙したコントロールのインスタンスの HasChildren プロパティが True だった場合に再帰するような処理にすれば良いです。 このあたりの処理は http://jeanne.wankuma.com/tips/form/findcontrol.html を参考にすればわかるかと思います。


    そうなると、まどか様からご教授いただいた②の方法がよろしいのでしょうか。

     

    (2) 案は 「ポトペタ」 で対応できるので (1) よりお勧めです。 何らかの仕様変更の対応も非常に容易にできますし、流用もしやすいです。

    2008年3月27日 8:07
  • まどか様 じゃんぬねっと様 ありがとうございます。

     

    これから地道に勉強しながら進めて行きたいと思います。

    今回はまず①の方法でやってみます。

    どちらの方法もご教授いただいたおかげでうまく動かせるようになりました。

     

    進めて行く上で貴重な技術をご教授いただき、ありがとうございました。

    2008年3月28日 13:16
  • こんにちは。フォーラムオペレータの栗原麻里 です。

     

    まどか さん、じゃんぬねっと さん、回答ありがとうございます。

     

    yama5525jp さん、フォーラムのご利用ありがとうございます。

    有用な情報だと思いましたので、

    まどか さん、じゃんぬねっと さんの回答へ回答済みチェックをつけさせていただきました。

     

    回答済みチェックが付くことにより、フォーラムをご利用していただいている皆様が、有用な情報を
    見つけやすくなります。
    ですので、回答された情報が有用だと思われましたら、ぜひ回答済みボタンを押してチェックを付けて
    くださいね!

     

    yama5525jp さんはチェックを解除することもできますので、ご確認ください。

     

    それでは、ぜひまたご活用ください!

     

    2008年4月1日 6:13