LoginSignup
1
5

More than 5 years have passed since last update.

RichTextBoxのカーソルの行(の背景)に色を付ける。

Posted at

今、ちょっとログブラウザを作っています。

決まったディレクトリにあるログファイルの一覧を作って、そこから選んだらログファイルを閲覧できる。
まあ、それだけなら楽ちんなのですが、「特定のキーワードでは色付けしたい」「今見ている行がすぐわかるようにしたい」「キーボードで今見ている行を移動できるようにしたい」
ということを実現しようとしています。
当初は、Windows FormsでRichTextBoxを使うという方法を考えました。特定のキーワードで色付けはすでに実績があります。
簡単に言うと、

WindowsFormsRTB.cs
void LoadFile(string FileName, string KeyWordRegEx)
{
  richTextBox1.Text = File.ReadAllText(FileName);
  var ms = RegEx.Matches(richTextBox1.Text, KeyWordRegEx).Cast<Match>().Reverse;
  foreach(var m in ms)
  {
    richTextBox1.Select(m.Index, m.Length);
    richTextBox1.SelectionColor = Color.Red;
  }
}

しかし、「今見ている行がすぐわかるようにしたい」の実現がなかなか難しい。
現在のカレット位置に合わせてPictureを動かすというかなり強引な手法で実装してみたのだけど、どうも位置がうまくあわない。

若者よWindowsFormsを捨てよ

いろいろ悩んだ挙げ句に、Windows Formsを捨ててWPF(Windows Presentation Foundation)でちょっと試してみることにしました。
Windows FormsRichTextBoxは上記のように読み込んだテキストファイルをRichTextBox.Textに代入して、そこにRtfを編集するか、RichTextBox上で選択->カラー変更 を繰り返すなんて手法になります。Rtfの編集は早いのですが、かなりハードルは高いです。

WPFRichTextBoxはぜんぜん違います。
簡単に言うと、FlowDocumentというオブジェクトをRichTextBox.Documentに割り付けます。
FlowDocumentオブジェクトの下にBlockオブジェクトを起き、そのBlockオブジェクトの中にさらに下位のオブジェクトを配置するなんていう迂遠なことをやります。なお、それぞれのオブジェクト単位でしか色づけとかはできません。
というわけで、

LoadFile.cs
void LoadFile(FlowDocument fd, string Path)
{
  var Lines = File.ReadLines(Path);
  foreach(var Line in Lines)
  {
    var p = new Paragraph();
    var ms = RegularExpressions.RegEx.Split(Line, Pattern);
    foreach(var m in ms)
    {
      var b = new Run(m);
      if (Pattern.Contains(m))
      b.Foreground = Brushes.Pink;
      p.Inlines.Add(b);
    }
  fd.Blocks.Add(p);
  }
}

なんて形で書きます。ここで重要なのはPatternに書く正規表現です。例えば、「OK」「完了」という文字を色付けしたければ、
"(OK)|(完了)"と書きます。
こうすると、RegEx.Split()で分割する際に分割パターンも配列に入ります。
後は、RichTextBoxSelectionChangedイベントをトリガーにして、fd以下のすべてのBlockオブジェクトのBackcolorを変更します。こんな感じですかね。

CaretMoved.cs
void CaretMoved( object sender, EventArgs e )
{
  var Target = fd.CaretPosition.Paragraph;
  foreach(var b in fd.Blocks.Where(p => p!=Target))
  {
    b.Background = Brushes.White;
  }
  if (Target != null) Target.Backcolor = Brushes.LightSkyBlue; 
}

みたいな感じで書けば、カレットが動くたびにその行の色が反転してくれます。

1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5