TRichEditで書式が部分的に変更できない場合の対処法

TRichEditの書式設定がうまくいかない場合、フォームの生成時にRichEditのデュアルフォントモードを無効にしたほうがうまくいくっぽい。

void __fastcall TForm1::FormCreate(TObject *Sender)
{
  // デュアルフォントモードを無効にする
  DWORD dwLangOptions = SendMessage(RichEdit1->Handle, EM_GETLANGOPTIONS, 0, 0);
  dwLangOptions &= ~IMF_DUALFONT;
  SendMessage(RichEdit1->Handle, EM_SETLANGOPTIONS, 0, (LPARAM)dwLangOptions);
}

う〜ん、この辺の挙動は本当によくわからない。

RichEditのデフォルトの書式は、DefAttributesプロパティで設定する。
また、FontプロパティのCharSetプロパティの値をSHIFTJIS_CHARSETにしておないと、全角文字を追加した場合に行間が変わるので注意。

文字列を追加する場合は、SelStartとSelLengthでRichEditの選択部分を一番後ろにして、SelTextを変更すれば書式が無くならずに文字列が追加できる。

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  if (Edit1->Text.IsEmpty()) return;

  UnicodeString us = Edit1->Text;
  int l = us.Length();

  // 文字列を追加
  int s = RichEdit1->Text.Length();
  RichEdit1->SelStart = s;
  RichEdit1->SelLength = 0;
  RichEdit1->SelText = us;
  //RichEdit1->Text = RichEdit1->Text + us; //←は前までの書式が無くなってしまうので駄目

  // 背景色を設定
  //s = RichEdit1->Text.Length(); //←改行があると位置がずれる
  s = RichEdit1->Text.Length() - RichEdit1->Lines->Count + 1;  // CR/LFを考慮する
  RichEdit1->SelStart = s - l;
  RichEdit1->SelLength = l;

  CHARFORMAT2 cf;
  ZeroMemory(&cf, sizeof(cf));
  cf.cbSize = sizeof(CHARFORMAT2);
  cf.dwMask = CFM_BACKCOLOR;
  cf.crBackColor = ColorToRGB(ColorBox1->Selected);
  SendMessage(RichEdit1->Handle, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
}

JVCLのTJvRichEditを使えば、EM_SETCHARFORMATを呼び出す代わりにSelAttributes->BackColorプロパティで選択部分の背景文字列が設定可能。

  RichEdit1->SelAttributes->BackColor = ColorBox1->Selected;