iReso Style > Program > C# Tips > C# Tips - 現在の行や文字の位置を取得
2006年4月5日 23:21
カーソルの位置を表示するのは、カーソルが何らかの形で移動した時なので、この「移動」を知らせるイベントを作成すればよいです。 イベント名は「CursorPositionChanged」とし、このイベントを発生させるメソッドを「OnCursorPositionChanged」とします。 「RichTextBox」には「OnSelectionChanged」メソッドがあり、文字列の選択状態に変更があれば、「SelectionChanged」イベントを発生させます。
「OnSelectionChanged」メソッドは、「0」文字選択した状態、すなわち何も選択していない状態でも、カーソルが移動することにより選択位置が変わったと判断し、イベントを発生させます。 そこで、この「OnSelectionChanged」メソッドを継承し、内部で「OnCursorPositionChanged」メソッドを実行するようにすれば、カーソル移動の検出を知らせるイベントを実現出来ます。
using System; using System.Text; using System.Drawing; using System.Windows.Forms; // namespace (好きな名前でいいです。 // 親コントロールから「using」で呼び出します。) namespace CustomControl { // RichTextBoxを継承した新しいカスタムコントロールを宣言 public class RichTextBoxCustom : System.Windows.Forms.RichTextBox { // カーソル移動の検出を知らせるイベント public event EventHandler CursorPositionChanged; // カーソル移動の検出イベントを発生させるメソッド protected virtual void OnCursorPositionChanged( EventArgs e ) { // イベントが未発生であれば、発生させる if (CursorPositionChanged != null) { CursorPositionChanged(this, e); } } // 既存の「OnSelectionChanged」メソッドをオーバーライドする protected override void OnSelectionChanged( EventArgs e ) { // 「OnCursorPositionChanged」メソッドを実行する OnCursorPositionChanged(e); // 選択範囲が1文字以上あれば、本来の「OnSelectionChanged」メソッドを実行 if (SelectionLength > 0) { base.OnSelectionChanged(e); } }
後は親コントロールで「CursorPositionChanged」イベントを設定すれば、カーソル移動のたびにイベントを受け取る事出来ます。
次に、このカスタムコントロールからカーソルの位置情報を取得するプロパティを設定します。
カーソル位置の行番号を取得するのは簡単です。「RichTextBox」には、指定した文字が何行目にあるかを取得する「GetLineFromCharIndex」メソッドが 実装されていますので、それを使用すればいいでしょう。ちなみにこの「GetLineFromCharIndex」が返す値は「0」から始まる数値ですので、プラス1した数を 返すようにします。指定した文字のインデックスは「SelectionStart」メソッドで取得できます。
現在の行の文字インデックスに関しては、「GetFirstCharIndexOfCurrentLine」メソッドが良いでしょう。これは「.NET Framework version 2.0 」から追加されたメソッドで、 「.NET Framework version 1.1」にはないメソッドです。「GetFirstCharIndexOfCurrentLine」メソッドは、現在カーソルがある行の最初の文字インデックスを返します。 「SelectionStart」で現在の文字カーソル位置の文字インデックスを取得し、この値から「GetFirstCharIndexOfCurrentLine」メソッドで取得した値を減ずる事で、目的の値を取得できます。 サンプルでは、一番左にカーソルがあった場合を「1」としていますので、実際は減じた値にプラス1しています。
また、参考までにv1.1までのバージョンでの方法もコメントアウトで載せておきます。
// 現在のカーソルの行を取得 public int CurrentLine { get { // 「GetLineFromCharIndex」は「0」から始まる数値を返すので、 // 実際はプラス1した値を返す return GetLineFromCharIndex(SelectionStart) + 1; } } // 現在の行におけるカーソルが何文字目かを取得 (v2.0~) public int CurrentColumn { get { // 現在のカーソルの文字インデックスから現在の行の // 最初の文字インデックスを減じ、さらにプラス1した値を返す return SelectionStart - GetFirstCharIndexOfCurrentLine() + 1; } } /* // 現在の行におけるカーソルが何文字目かを取得 (~v1.1) public int CurrentColumn { get { // 現在のカーソルのリッチテキストボックスにおける座標を // ピクセル単位で取得する。 Point p = GetPositionFromCharIndex(SelectionStart); if (p.X == 1) { // 一番左にカーソルがあれば、「1」を返す return 1; } else { // Y座標はそのまま、X座標を一番左にすることで、 // 現在の行の最初の文字インデックスを取得できる。 // 後は同じ。 p.X = 1; return SelectionStart - GetCharIndexFromPosition(p) + 1; } } } */ } }
以上で必要最低限の機能が実装されました。
呼び出し側のフォームに今回作成したリッチテキストボックスを置きます。ファイルの先頭に「using CustomRichTextBox1;」も忘れないように記述します。
// カスタマイズしたリッチテキストボックスの宣言 internal CustomRichTextBox1.CsRichTextBox1 richTextBox1;
// コンストラクタ this.richTextBox1 = new CustomRichTextBox1.CsRichTextBox1();
後は普通に「RichTextBox」と同じです。
サイズなどのプロパティを記述している部分に追加で、以下のイベントを記述します。
// カーソルの移動を検出するイベント this.richTextBox1.CursorPositionChanged += new System.EventHandler(this.richTextBox1_CursorPositionChanged); // 選択範囲の変更を検出するイベント this.richTextBox1.SelectionChanged += new System.EventHandler(this.richTextBox1_SelectionChanged);
さらに、メソッドを記述します。
// カーソルの移動が検出された時の動作 private void richTextBox1_CursorPositionChanged(object sender, System.EventArgs e) { // 現在の行と文字位置を取得 int line = richTextBox1.CurrentLine; int col = richTextBox1.CurrentColumn; // ステータスバーなどに表示すると良いでしょう } // 選択範囲の変更が検出された時の動作 private void richTextBox1_SelectionChanged(object sender, System.EventArgs e) { // 例えば、以下のようにすれば、現在選択されている文字数を取得できます。 int sel = richTextBox1.SelectionLength; // 表示 }