TextBox

タグの編集
投稿者 がもー  (学生) 投稿日時 2009/8/19 13:00:33
はじめまして。VB.NETを使用しています。

TextBoxかRichTextBoxでは、未確定状態の下線が引かれた文字列でも
TextChangedのようなイベントを発生させる事は可能なのでしょうか。

もし可能であれば、ご教授宜しくお願い致します。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/8/19 14:15:19
これでどうでしょう。

Public Class Form1
    Private win As Window

    Private Sub Form1_Load(ByVal sender As ObjectByVal e As EventArgs) Handles Me.Load
        win = New Window()
        win.AssignHandle(TextBox1.Handle)
    End Sub

    Private Class Window
        Inherits NativeWindow

        Private Declare Function ImmGetContext Lib "imm32" (ByVal hWnd As IntPtr) As IntPtr
        Private Declare Auto Function ImmGetCompositionString Lib "imm32" _
            (ByVal hIMC As IntPtr, _
             ByVal dwIndex As Integer, _
             ByVal lpBuf As System.Text.StringBuilder, _
             ByVal dwBufLen As IntegerAs Integer
        Private Declare Function ImmReleaseContext Lib "imm32.dll" _
            (ByVal hWnd As IntPtr, ByVal hIMC As IntPtr) As Integer

        Protected Overrides Sub WndProc(ByRef m As Message)
            'Console.WriteLine(m.ToString()) 

            Const WM_IME_COMPOSITION As Integer = &H10F
            Const GCS_COMPSTR As Integer = 8

            If m.Msg = WM_IME_COMPOSITION Then
                If (m.LParam.ToInt32() And GCS_COMPSTR) <> 0 Then
                    Dim imc As IntPtr = ImmGetContext(Handle)
                    Dim length As Integer = ImmGetCompositionString(imc, GCS_COMPSTR, Nothing, 0)
                    Dim buf As New System.Text.StringBuilder(length)
                    Dim l As Integer = ImmGetCompositionString(imc, GCS_COMPSTR, buf, length)
                    ImmReleaseContext(Handle, imc)
                    Console.WriteLine(buf.ToString(0, l \ 2))
                End If
            End If

            MyBase.WndProc(m)
        End Sub
    End Class
End Class
投稿者 がもー  (学生) 投稿日時 2009/8/20 07:33:10
魔界の仮面弁士さん、早速の丁寧なご返答ありがとうございます。

ImmGetCompositionString APIについて知識が不足している点が多く、現在調べを進めています。
また私は、開発中のメールソフトにおける予測変換機能を現在制作しています。
具体的には、TextBoxに文字を入力すると前方一致検索を行い、
あらかじめメモ帳に登録した語句がListBoxに一覧表示されるようにしました。
コードの一部は以下のようになっています。

Dim yosoku As List(Of String)
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged

        If yosoku Is Nothing Then
            ReadFile()
        End If

        Dim yosoku_No As String = TextBox1.Text

        ListBox1.Items.Clear()

        For i As Integer = 0 To yosoku.Count - 1
            If yosoku_No = yosoku(i).Substring(0, Math.Min(yosoku_No.Length, yosoku(i).Length)) Then
                ListBox1.Items.Add(yosoku(i).Substring(yosoku(i).IndexOf(",") + 1))
            End If
        Next

    End Sub

このような機能でのTextboxで、未確定の文字列でもtextchangeのようなイベントを発生させたいと考えています。
この場合、魔界の仮面弁士さんに教えていただいたコードにはどのように組み合わせていけばいいのでしょうか。
初歩的な質問で申し訳ございません。ご指導宜しくお願い致します。




投稿者 魔界の仮面弁士  (社会人) 投稿日時 2009/8/20 08:43:29
>  投稿日時 2009/08/19 4:00:33 
>  投稿日時 2009/08/19 22:33:10
凄…。


> ImmGetCompositionString APIについて知識が不足している点が多く、現在調べを進めています。
他にも、変換中の部分確定された状態に対して、入力文字列内のカーソル位置や文節情報などを
取得する機能などがあります。

> 未確定の文字列でもtextchangeのようなイベントを発生させたいと考えています。
イベント制御込みだと、たとえばこんな感じでしょうか。

ここでは、NativeWindow を用いて TextBox のメッセージを捕まえていますが、
TextBox その物を継承する事でもメッセージを捕まえることができます。

Public Class Form1
    Private WithEvents win As Window

    Private Sub Form1_Load(ByVal sender As ObjectByVal e As EventArgs) Handles Me.Load
        win = New Window()
        win.AssignHandle(TextBox1.Handle)
    End Sub

    Private Sub TextBox1_TextChanged(ByVal sender As ObjectByVal e As EventArgs) Handles TextBox1.TextChanged
        Label1.Text = TextBox1.Text
    End Sub

    Private Sub win_Typing(ByVal text As StringHandles win.Typing
        Label2.Text = text
    End Sub

    Private Class Window
        Inherits NativeWindow

        Public Event Typing(ByVal text As String)

        Private Declare Function ImmGetContext Lib "imm32" (ByVal hWnd As IntPtr) As IntPtr
        Private Declare Auto Function ImmGetCompositionString Lib "imm32" _
            (ByVal hIMC As IntPtr, _
             ByVal dwIndex As Integer, _
             ByVal lpBuf As System.Text.StringBuilder, _
             ByVal dwBufLen As IntegerAs Integer
        Private Declare Function ImmReleaseContext Lib "imm32.dll" _
            (ByVal hWnd As IntPtr, ByVal hIMC As IntPtr) As Integer

        Protected Overrides Sub WndProc(ByRef m As Message)
            Const WM_IME_COMPOSITION As Integer = &H10F
            Const GCS_COMPSTR As Integer = 8
            If m.Msg = WM_IME_COMPOSITION Then
                If (m.LParam.ToInt32() And GCS_COMPSTR) <> 0 Then
                    Dim imc As IntPtr = ImmGetContext(Handle)
                    Dim length As Integer = ImmGetCompositionString(imc, GCS_COMPSTR, Nothing, 0)
                    Dim buf As New System.Text.StringBuilder(length)
                    Dim l As Integer = ImmGetCompositionString(imc, GCS_COMPSTR, buf, length)
                    ImmReleaseContext(Handle, imc)
                    RaiseEvent Typing(buf.ToString(0, l \ 2))
                End If
            End If
            MyBase.WndProc(m)
        End Sub
    End Class
End Class
投稿者 がもー  (学生) 投稿日時 2009/8/20 15:08:45
返事が遅れてしまい大変申し訳ございません。

魔界の仮面弁士さんに教えていただいたコードに予測変換のコードを書き込み、
まだ多少修正しなければならない部分はあるのですが、未確定状態の文字列でも予測変換の候補を表示させることができました。

> 他にも、変換中の部分確定された状態に対して、入力文字列内のカーソル位置や文節情報などを
取得する機能などがあります。
そんな便利な機能もあるのですね。今後もImmGetCompositionString APIの知識を深め、より使いやすく充実した予測変換機能を制作したいと思います。
また機会がありましたらご指導を宜しくお願い致します。ありがとうございました!