テキストボックス(またはリッチテキストボックス)内で現在カレットのある行と列を取得する方法を紹介します。
行を理論的に数えるとは、改行文字までを一行として数える方法です。テキストボックスのWordWrapプロパティがTrueの場合は、長い行は右側で折り返されますが、改行文字で折り返されるのでない限り、一行として数えます。
行を論理的に数える場合は、次のようにラインフィードを数えることで計算できます。ここでは、テキストボックス"TextBox1"の現在のカレット位置を計算しています。
補足:リッチテキストボックスでは改行文字がラインフィードのみとなりますので、キャリッジリターンを数える方法ではできません。
'文字列 Dim str As String = TextBox1.Text 'カレットの位置を取得 Dim selectPos As Integer = TextBox1.SelectionStart 'カレットの位置までの行を数える Dim row As Integer = 1 Dim startPos As Integer = 0 Dim endPos As Integer While (True) endPos = str.IndexOf(vbLf, startPos) If (endPos < 0 Or endPos >= selectPos) Then Exit While End If startPos = endPos + 1 row += 1 End While '列の計算 Dim col As Integer = selectPos - startPos + 1 '結果を表示 Console.WriteLine("行:{0} 列:{1}", row, col)
//文字列 string str = TextBox1.Text; //カレットの位置を取得 int selectPos = TextBox1.SelectionStart; //カレットの位置までの行を数える int row = 1, startPos = 0; for (int endPos = 0; (endPos = str.IndexOf('\n', startPos)) < selectPos && endPos > -1; row++) { startPos = endPos + 1; } //列の計算 int col = selectPos - startPos + 1; //結果を表示 Console.WriteLine("行:{0} 列:{1}", row, col);
行を物理的に数える場合は、テキストボックスのWordWrapプロパティがTrueで、右側で折り返されている場合でも、2行として数えます。
行を物理的に数える場合は、SendMessage関数を使用して取得します。
次の例では、Button1をクリックすることにより、物理的な現在のカレットの位置を表示しています。
<System.Runtime.InteropServices.DllImport("User32.Dll")> _ Private Shared Function SendMessage( _ ByVal hWnd As IntPtr, _ ByVal Msg As Integer, _ ByVal wParam As Integer, _ ByVal lParam As Integer) As Integer End Function Private Const EM_LINEINDEX As Integer = &HBB Private Const EM_LINEFROMCHAR As Integer = &HC9 'Button1のクリックイベントハンドラ Private Sub Button1_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Button1.Click '現在の行を取得する Dim row As Integer = SendMessage( _ TextBox1.Handle, EM_LINEFROMCHAR, -1, 0) + 1 '現在の列を取得する Dim lineIndex As Integer = SendMessage( _ TextBox1.Handle, EM_LINEINDEX, -1, 0) Dim col As Integer = TextBox1.SelectionStart - lineIndex + 1 Console.WriteLine("行:{0} 列:{1}", row, col) End Sub
[System.Runtime.InteropServices.DllImport("User32.Dll")] private static extern int SendMessage( IntPtr hWnd,int Msg,int wParam,int lParam); private const int EM_LINEINDEX = 0xBB; private const int EM_LINEFROMCHAR=0xC9; //Button1のクリックイベントハンドラ private void Button1_Click(object sender, System.EventArgs e) { //現在の行を取得する int row = SendMessage( TextBox1.Handle, EM_LINEFROMCHAR, -1, 0) + 1; //現在の列を取得する int lineIndex = SendMessage( TextBox1.Handle, EM_LINEINDEX, -1, 0); int col = TextBox1.SelectionStart - lineIndex + 1; Console.WriteLine("行:{0} 列:{1}", row, col); }
RichTextBoxの物理的な行は、GetLineFromCharIndexメソッドで取得できます。GetLineFromCharIndexメソッドは、.NET Framework 2.0からは、TextBox(TextBoxBase)クラスにも追加されました。
GetLineFromCharIndexメソッドは、1行目を「0」とします。
'RichTextBox1の現在の物理行を表示する
Console.WriteLine(
RichTextBox1.GetLineFromCharIndex(RichTextBox1.SelectionStart))
//RichTextBox1の現在の物理行を表示する
Console.WriteLine(
RichTextBox1.GetLineFromCharIndex(RichTextBox1.SelectionStart));
しかしこの方法では、自動的に折り返されている行の一番最後にカレットがあるときは、次の行の番号を返してしまいます。
(この記事は、「.NETプログラミング研究 第51号」で紹介したものを基にしています。)