テキストボックス(またはリッチテキストボックス)内で現在カレットのある行と列を取得する方法を紹介します。
行を理論的に数えるとは、改行文字までを一行として数える方法です。テキストボックスの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号」で紹介したものを基にしています。)