[C#] RichTextBoxで行番号を表示する方法

C#のRichTextBoxで行番号を表示するには、通常、カスタム描画を行う必要があります。

RichTextBox自体には行番号を表示する機能がないため、以下のような手法を用います。

まず、RichTextBoxの左側にPanelを配置し、そのPanelに行番号を描画します。

RichTextBoxのTextChangedイベントやVScrollイベントを利用して、テキストの変更やスクロールに応じて行番号を更新します。

行番号の描画は、Graphicsオブジェクトを使用してPanelのPaintイベント内で行います。

これにより、テキストの行数に応じた行番号が常に表示されるようになります。

この記事でわかること
  • RichTextBoxに行番号を表示する方法
  • 行番号の描画に必要な手順
  • 行番号のスタイルをカスタマイズする方法
  • スクロール時の行番号の更新方法
  • 行番号表示の最適化手法

目次から探す

RichTextBoxに行番号を表示する手順

必要なUIコンポーネントの準備

まず、Visual Studioで新しいWindowsフォームアプリケーションを作成します。

次に、以下のUIコンポーネントをフォームに追加します。

スクロールできます
コンポーネント名プロパティ設定
PanelDock: Left
RichTextBoxDock: Fill

これにより、行番号を表示するためのPanelと、テキストを表示するRichTextBoxが配置されます。

Panelの配置と設定

Panelは行番号を表示するための領域です。

以下の手順でPanelを設定します。

  1. Panelのサイズを設定します。

幅は行番号の表示に必要なサイズに調整します。

  1. Panelの背景色を設定します。

例えば、Color.LightGrayなどにすると、行番号が見やすくなります。

partial class MyForm : Form
{
    private Panel lineNumberPanel;
    public MyForm()
    {
        InitializeComponent();
        InitializeLineNumberPanel();
    }
    private void InitializeLineNumberPanel()
    {
        lineNumberPanel = new Panel();
        lineNumberPanel.Dock = DockStyle.Left;
        lineNumberPanel.Width = 50; // 行番号の幅を設定
        lineNumberPanel.BackColor = Color.LightGray; // 背景色を設定
        this.Controls.Add(lineNumberPanel);
    }
}

RichTextBoxのイベントハンドリング

RichTextBoxの内容が変更されたときやスクロールされたときに行番号を更新するために、イベントハンドラを設定します。

TextChangedイベントの利用

RichTextBoxの内容が変更されたときに行番号を更新するために、TextChangedイベントを利用します。

private void InitializeRichTextBox()
{
    RichTextBox richTextBox = new RichTextBox();
    richTextBox.Dock = DockStyle.Fill;
    richTextBox.WordWrap = false; // 折り返しを無効に設定
    richTextBox.TextChanged += RichTextBox_TextChanged; // イベントハンドラを追加
    this.Controls.Add(richTextBox);
}
private void RichTextBox_TextChanged(object sender, EventArgs e)
{
    // 行番号を更新する処理をここに記述
}

VScrollイベントの利用

RichTextBoxがスクロールされたときに行番号を更新するために、VScrollイベントを利用します。

private void InitializeRichTextBox()
{
    RichTextBox richTextBox = new RichTextBox();
    richTextBox.Dock = DockStyle.Fill;
    richTextBox.VScroll += RichTextBox_VScroll; // スクロールイベントを追加
    this.Controls.Add(richTextBox);
}
private void RichTextBox_VScroll(object sender, EventArgs e)
{
    // 行番号を更新する処理をここに記述
}

これで、RichTextBoxに行番号を表示するための基本的な準備が整いました。

次のステップでは、実際に行番号を描画する方法について説明します。

行番号の描画方法

Graphicsオブジェクトの使用

行番号を描画するためには、Graphicsオブジェクトを使用します。

このオブジェクトは、描画操作を行うためのメソッドを提供します。

PanelのPaintイベントでこのオブジェクトを利用して、行番号を描画します。

private void lineNumberPanel_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics; // Graphicsオブジェクトを取得
    // 行番号を描画する処理をここに記述
}

Paintイベントでの描画

PanelのPaintイベントを利用して、行番号を描画します。

このイベントは、Panelが再描画されるたびに呼び出されます。

以下のように、行番号を描画する処理を実装します。

private void lineNumberPanel_Paint(object sender, PaintEventArgs e)
{
	Graphics g = e.Graphics;
	if (richTextBox != null)
	{
		// スクロール位置を取得
		int firstLine = richTextBox.GetLineFromCharIndex(richTextBox.GetCharIndexFromPosition(new Point(0, 0)));
		int firstLineY = richTextBox.GetPositionFromCharIndex(richTextBox.GetFirstCharIndexFromLine(firstLine)).Y;

		// 表示されている最後の行を取得
		int lastVisibleCharIndex = richTextBox.GetCharIndexFromPosition(new Point(0, richTextBox.ClientSize.Height));
		int lastLine = richTextBox.GetLineFromCharIndex(lastVisibleCharIndex);

		for (int i = firstLine; i <= lastLine; i++)
		{
			string lineNumber = (i + 1).ToString(); // 行番号を取得

			// 行のY座標を計算
			int y = richTextBox.GetPositionFromCharIndex(richTextBox.GetFirstCharIndexFromLine(i)).Y - firstLineY;

			g.DrawString(lineNumber, lineNumberFont, lineNumberBrush, new PointF(0, y));
		}
	}
}

行番号のフォーマットとスタイル

行番号のフォーマットやスタイルをカスタマイズすることも可能です。

フォントや色を変更することで、行番号をより見やすくすることができます。

private void lineNumberPanel_Paint(object sender, PaintEventArgs e)
{
	Graphics g = e.Graphics;
	if (richTextBox != null)
	{
		// スクロール位置を取得
		int firstLine = richTextBox.GetLineFromCharIndex(richTextBox.GetCharIndexFromPosition(new Point(0, 0)));
		int firstLineY = richTextBox.GetPositionFromCharIndex(richTextBox.GetFirstCharIndexFromLine(firstLine)).Y;

		// 表示されている最後の行を取得
		int lastVisibleCharIndex = richTextBox.GetCharIndexFromPosition(new Point(0, richTextBox.ClientSize.Height));
		int lastLine = richTextBox.GetLineFromCharIndex(lastVisibleCharIndex);

		for (int i = firstLine; i <= lastLine; i++)
		{
			string lineNumber = (i + 1).ToString(); // 行番号を取得
			Font lineNumberFont = new Font("Arial", 10, FontStyle.Regular);
			Brush lineNumberBrush = Brushes.Blue; // 行番号の色を青に設定

			// 行のY座標を計算
			int y = richTextBox.GetPositionFromCharIndex(richTextBox.GetFirstCharIndexFromLine(i)).Y - firstLineY;

			g.DrawString(lineNumber, lineNumberFont, lineNumberBrush, new PointF(0, y));
		}
	}
}

このようにして、行番号を描画する際にフォーマットやスタイルを調整することで、ユーザーにとってより使いやすいインターフェースを提供できます。

次のステップでは、行番号表示の最適化について説明します。

完成したプログラム

以下に、RichTextBoxに行番号を表示するための完成したプログラムの全体コードを示します。

このプログラムでは、RichTextBoxの内容が変更されたときやスクロールされたときに、行番号が自動的に更新されるようになっています。

using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public partial class MyForm : Form
{
	private Panel lineNumberPanel;
	private RichTextBox richTextBox;
	public MyForm()
	{
		InitializeComponent();
		InitializeRichTextBox();
		InitializeLineNumberPanel();
	}
	private void InitializeLineNumberPanel()
	{
		lineNumberPanel = new Panel();
		lineNumberPanel.Dock = DockStyle.Left;
		lineNumberPanel.Width = 50; // 行番号の幅を設定
		lineNumberPanel.BackColor = Color.LightGray; // 背景色を設定
		lineNumberPanel.Paint += lineNumberPanel_Paint; // Paintイベントを追加
		this.Controls.Add(lineNumberPanel);
	}
	private void InitializeRichTextBox()
	{
		richTextBox = new RichTextBox();
		richTextBox.Dock = DockStyle.Fill;
		richTextBox.WordWrap = false; // 折り返しを無効に設定
		richTextBox.TextChanged += RichTextBox_TextChanged; // TextChangedイベントを追加
		richTextBox.VScroll += RichTextBox_VScroll; // VScrollイベントを追加
		this.Controls.Add(richTextBox);
	}
	private void RichTextBox_TextChanged(object sender, EventArgs e)
	{
		lineNumberPanel.Invalidate(); // Panelを再描画
	}
	private void RichTextBox_VScroll(object sender, EventArgs e)
	{
		lineNumberPanel.Invalidate(); // Panelを再描画
	}
	private void lineNumberPanel_Paint(object sender, PaintEventArgs e)
	{
		Graphics g = e.Graphics;
		if (richTextBox != null)
		{
			// スクロール位置を取得
			int firstLine = richTextBox.GetLineFromCharIndex(richTextBox.GetCharIndexFromPosition(new Point(0, 0)));
			int firstLineY = richTextBox.GetPositionFromCharIndex(richTextBox.GetFirstCharIndexFromLine(firstLine)).Y;

			// 表示されている最後の行を取得
			int lastVisibleCharIndex = richTextBox.GetCharIndexFromPosition(new Point(0, richTextBox.ClientSize.Height));
			int lastLine = richTextBox.GetLineFromCharIndex(lastVisibleCharIndex);

			for (int i = firstLine; i <= lastLine; i++)
			{
				string lineNumber = (i + 1).ToString(); // 行番号を取得
				Font lineNumberFont = new Font("Arial", 10, FontStyle.Regular);
				Brush lineNumberBrush = Brushes.Blue; // 行番号の色を青に設定

				// 行のY座標を計算
				int y = richTextBox.GetPositionFromCharIndex(richTextBox.GetFirstCharIndexFromLine(i)).Y - firstLineY;

				g.DrawString(lineNumber, lineNumberFont, lineNumberBrush, new PointF(0, y));
			}
		}
	}
}

プログラムの解説

  • UIコンポーネントの初期化: InitializeLineNumberPanelメソッドで行番号を表示するPanelを、InitializeRichTextBoxメソッドでRichTextBoxを初期化しています。
  • イベントハンドリング: TextChangedおよびVScrollイベントでPanelを再描画するためにInvalidateメソッドを呼び出しています。
  • 行番号の描画: lineNumberPanel_Paintメソッドで、Graphicsオブジェクトを使用して行番号を描画しています。

行番号のフォントや色も設定可能です。

スクロールも正しく処理される

このプログラムを実行すると、RichTextBoxに入力したテキストに応じて、左側に行番号が表示されるアプリケーションが完成します。

次のステップでは、行番号表示の最適化について説明します。

行番号表示の最適化

パフォーマンスの考慮

行番号を表示する際のパフォーマンスは、特に大量のテキストを扱う場合に重要です。

以下の点を考慮することで、描画処理のパフォーマンスを向上させることができます。

  • 再描画の最小化: Invalidateメソッドを呼び出す際には、必要な部分だけを再描画するようにします。

例えば、行番号が変更された場合のみ再描画するように条件を設定します。

スクロール時のスムーズな更新

RichTextBoxがスクロールされる際に行番号をスムーズに更新するためには、以下の方法を検討します。

  • スクロール位置の取得: VScrollイベントでスクロール位置を取得し、行番号の描画を最適化します。

これにより、必要な行番号のみを描画することができます。

  • 非同期処理の利用: スクロール時に行番号の更新を非同期で行うことで、UIの応答性を向上させることができます。

これにより、ユーザーがスクロールしている間もアプリケーションがスムーズに動作します。

大量のテキストに対する対応

大量のテキストを扱う場合、行番号の描画処理がボトルネックになることがあります。

以下の対策を講じることで、パフォーマンスを向上させることができます。

  • 行番号のキャッシュ: 行番号を一度計算したら、次回以降はキャッシュを利用して再描画を行うことで、計算コストを削減します。
  • 描画範囲の制限: 現在表示されている行番号のみを描画するようにし、表示されていない行番号は描画しないようにします。

これにより、描画処理の負荷を軽減できます。

private void lineNumberPanel_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;
    int firstLine = richTextBox.GetLineFromCharIndex(richTextBox.GetCharIndexFromPosition(new Point(0, 0)));
    int lastLine = richTextBox.GetLineFromCharIndex(richTextBox.TextLength);
    
    // 現在表示されている行番号のみを描画
    for (int i = firstLine; i <= lastLine; i++)
    {
        // 行番号の描画処理
    }
}

これらの最適化手法を実装することで、RichTextBoxに行番号を表示するアプリケーションのパフォーマンスを向上させ、ユーザーに快適な操作体験を提供することができます。

次のステップでは、応用例について説明します。

応用例

カスタム行番号のスタイル設定

行番号のスタイルをカスタマイズすることで、アプリケーションの見た目を向上させることができます。

以下の方法で、行番号のフォントや色を変更することができます。

private void lineNumberPanel_Paint(object sender, PaintEventArgs e)
{
	Graphics g = e.Graphics;
	if (richTextBox != null)
	{
		// ...省略

		for (int i = firstLine; i <= lastLine; i++)
		{
			string lineNumber = (i + 1).ToString(); // 行番号を取得
			Font lineNumberFont = new Font("Arial", 10, FontStyle.Regular);
			Brush lineNumberBrush = Brushes.Blue; // 行番号の色を青に設定
            // ...省略
		}
	}
}

このコードでは、行番号のフォントを Courier New に変更し、色をダークグリーンに設定しています。

これにより、行番号がより目立つようになります。

行番号のクリックイベントの実装

行番号をクリックした際に特定のアクションを実行するために、行番号のクリックイベントを実装することができます。

以下のように、PanelのMouseClickイベントを利用して、クリックされた行番号を取得します。

private void lineNumberPanel_MouseClick(object sender, MouseEventArgs e)
{
    // スクロール位置を取得
    int firstLine = richTextBox.GetLineFromCharIndex(richTextBox.GetCharIndexFromPosition(new Point(0, 0)));
    int firstLineY = richTextBox.GetPositionFromCharIndex(richTextBox.GetFirstCharIndexFromLine(firstLine)).Y;

    // クリックされた位置のY座標から行番号を計算
    int clickedY = e.Y + firstLineY;
    int clickedLine = richTextBox.GetLineFromCharIndex(richTextBox.GetCharIndexFromPosition(new Point(0, clickedY)));

    if (clickedLine >= 0 && clickedLine < richTextBox.Lines.Length)
    {
        // クリックされた行のテキストを取得
        string clickedLineText = richTextBox.Lines[clickedLine];
        MessageBox.Show($"クリックされた行: {clickedLine + 1}\n内容: {clickedLineText}");
    }
}

このコードでは、行番号をクリックすると、その行の内容をメッセージボックスで表示します。

これにより、ユーザーは特定の行に関連する情報を簡単に取得できます。

行番号とテキストの同期

行番号とRichTextBoxのテキストを同期させることで、ユーザーがテキストを編集した際に行番号が正しく更新されるようにします。

TextChangedイベントで行番号を再描画する処理を行います。

private void RichTextBox_TextChanged(object sender, EventArgs e)
{
    lineNumberPanel.Invalidate(); // 行番号を再描画
    lineNumberPanel.Refresh(); // Panelを強制的に再描画
}

また、行番号の表示を更新する際に、行の追加や削除に応じて行番号を正しく計算することが重要です。

これにより、ユーザーがテキストを変更した際に、行番号が常に正確に表示されるようになります。

これらの応用例を実装することで、RichTextBoxに行番号を表示するアプリケーションの機能を拡張し、ユーザーにとってより便利で使いやすいインターフェースを提供することができます。

次のステップでは、よくある質問について説明します。

よくある質問

RichTextBoxで行番号を表示する際の注意点は?

RichTextBoxで行番号を表示する際には、以下の点に注意が必要です。

  • フォントサイズの変更: RichTextBoxのフォントサイズを変更すると、行番号の位置も変わるため、行番号の描画処理を見直す必要があります。

行の高さを正確に計算することが重要です。

  • 行の折り返し: テキストが折り返される場合、行番号の計算が複雑になります。

行のインデックスを正確に取得するために、GetLineFromCharIndexメソッドを適切に使用する必要があります。

  • パフォーマンス: 大量のテキストを扱う場合、描画処理が重くなることがあります。

パフォーマンスを考慮し、必要な部分だけを再描画するように最適化することが重要です。

他のUIコンポーネントで行番号を表示する方法は?

行番号を表示する方法は、RichTextBox以外のUIコンポーネントでも実装可能です。

例えば、以下のようなコンポーネントで行番号を表示できます。

  • ListBox: ListBoxに行番号を表示する場合、アイテムのインデックスを利用して行番号を表示することができます。

DrawItemイベントを利用してカスタム描画を行います。

  • DataGridView: DataGridViewでは、行番号を表示するためにカスタム列を追加することができます。

行のインデックスを表示する列を作成し、データをバインドすることで行番号を表示できます。

  • TextBox: TextBoxでも行番号を表示することができますが、RichTextBoxのように行のインデックスを取得するメソッドがないため、独自に行番号を計算する必要があります。

行番号の表示がずれる場合の対処法は?

行番号の表示がずれる場合、以下の対処法を試みることができます。

  • 行の高さの確認: 行番号の描画時に使用している行の高さが正しいか確認します。

RichTextBoxのフォントサイズやスタイルが変更された場合、行の高さも変わるため、再計算が必要です。

  • 再描画のタイミング: TextChangedVScrollイベントで行番号を再描画する際、適切なタイミングでInvalidateメソッドを呼び出しているか確認します。

必要に応じて、Refreshメソッドを使用して強制的に再描画することも検討します。

  • 行番号の計算ロジックの見直し: 行番号を計算するロジックに誤りがないか確認します。

特に、行のインデックスを取得する際に使用するメソッドが正しいかどうかを再確認します。

これらの対策を講じることで、行番号の表示がずれる問題を解決し、正確な行番号を表示することができるようになります。

まとめ

この記事では、C#のRichTextBoxに行番号を表示する方法について詳しく解説しました。

行番号の描画手法やイベントハンドリング、さらには行番号のスタイル設定やクリックイベントの実装など、実用的なテクニックを紹介しました。

これらの知識を活用することで、ユーザーにとって使いやすいテキストエディタを作成することが可能になります。

ぜひ、実際にコードを試してみて、独自の機能を追加してみてください。

当サイトはリンクフリーです。出典元を明記していただければ、ご自由に引用していただいて構いません。

関連カテゴリーから探す

  • URLをコピーしました!
目次から探す