TRichEditでリッチなテキストをプログラムする

TRichEditを使って、メモ帳もどきを作る場合は、編集ボタンなどでモードを切り替えするなどすれば、任意の修飾を行える。
一方、プログラムで文字列を修飾しようとすると気をつける必要がある。

修飾を前提とした場合やってはいけないこと

TRichEdit::Text、TRichEdit::Linesにアクセスして文字列を操作しない。操作するとその時点までの全ての修飾情報は消える。
次のようなコードを書くと、1つ目の修飾(1を上付き文字にする)が消える。

  RichEdit1->Lines->Add( u"012" );
  // 1を上付き文字にする
  RichEdit1->SelStart  = 1;
  RichEdit1->SelLength = 1;
  RichEdit1->SelAttributes->Offset = 4;
  RichEdit1->Text = RichEdit1->Text + u"345"; // ここで修飾情報がリセット
  // 4を下付き文字にする
  RichEdit1->SelStart  = 5; // 改行が1文字としてカウントされている
  RichEdit1->SelLength = 1;
  RichEdit1->SelAttributes->Offset = -3;

TRichEdit::Textは修飾情報を持たないので、今回の目的では使ってはならない。
なお、TRichEdit::Lines::Add、TRichEdit::Lines::Insert、TRichEdit::Lines::Deleteは使っても他の行の修飾情報を消さない。

修飾を行うプログラム

プログラム上では、TRichEdit::SelStart・TRichEdit::SelTextを使って文字列を追加・挿入し、修飾はTRichEdit::SelAttributesプロパティを用いる。
TRichEdit::SelStart・TRichEdit::SelTextを用いると、現在のキャレット位置に文字を挿入してくれ、入力後は入力した文字の直後に移動してくれるので便利だ。

  RichEdit1->SelStart = RichEdit1->GetTextLen(); // 現在のテキストの末尾にキャレットを移動であればこれでも良い
  TTextAttributes* pAttr = RichEdit1->SelAttributes;
  pAttr->Italic = true;
  RichEdit1->SelText = u"k";
  pAttr->Italic = false;
  pAttr->Size   = 7;
  pAttr->Offset = -3;
  RichEdit1->SelText = u"t=";
  RichEdit1->SelText = u"15";
  pAttr->Size   = 10;
  pAttr->Offset = 0;
  RichEdit1->SelText = u" = 2.6×10";
  pAttr->Size   = 7;
  pAttr->Offset = 4;
  RichEdit1->SelText = u"-3";
  pAttr->Size   = 10;
  pAttr->Offset = 0;
  RichEdit1->SelText = u" (cm/sec)\r\n次行";

TRichEdit::SelAttribultesは1つのステートしか保持できないが、追加される文字列の修飾はTRichEdit::SelAttribultesを参照してセットされる。
ここで気づかれると思うが、文字列を細切れでSelTextで追加すると、それぞれに修飾タグがひっつくので、リッチテキストのサイズが大きくなることになる。

注意事項

改行の取り扱い

TRichEdit中での文字の位置は改行コードを含む。
ただし、やっかいなのはTRichEdit::Text系(TRichEdit::GetTextLen()、TRichEdit::Text::Length()など)とTRichEdit::Sel~(TRichEdit::SelStart、TRichEdit::SelLengthなど)では改行コードの取り扱いが異なることだ。
TRichEdit::Text系は改行コードを2文字として計算する。一方TRichEdit::SelStartは改行コードを1文字で計算して指定する。
任意の位置の文字列を選択する場合で、TRichEdit::TextをPosで検索した場合は、上記を考慮して、改行コードをスキャンして改行コード分調整する必要がある。
コード中にも記載したが、単純に末尾にキャレットを移したいのであれば、TRichEdit::GetTextLen()の値をセットするだけで済む。
なお、プログラム中で、文字列に改行コード"\n"のみを埋め込んだ場合でも、自動で"\r\n"に変更される。

TRichEdit::SelAttributes

TRichEdit::SelAttributesはステートデータなので、自動で元には戻らない。
文字列を追加するときにはTRichEdit::SelAttributesを必ず自分の意図する値にセットしておく。