TRichEdit проблемы с цветом

ans:= RichEdit1.Text     
for i:=1 to Length(ans) do
begin
   RichEdit1.SelStart :=  i-1;
   RichEdit1.SelLength:= 1;
   if ans[i] = correct[i] then
      RichEdit1.SelAttributes.Color := clRed
   else
      RichEdit1.SelAttributes.Color := clBlue;  

Если буква в ans совпадает с буквой в той же позиции, что и буква в строке correct, она окрашивается в красный цвет, в противном случае — в синий.

Моя проблема заключается в том, что когда я снова печатаю, весь текст RichEdit1 окрашивается так же, как и первая буква (если первая буква RichEdit1 синяя, то весь текст становится синим).

Кстати, это не настоящий код, я просто упростил его, потому что есть несколько TRichEdits.
TRichEdits доступны только для чтения, и я назначаю буквы чем-то вроде RichEdit1.Text := RichEdit1.Text+Key; (делаю это, потому что это программа с несколькими клавиатурами, и я нужно разделить пользовательский ввод)

Это правильное поведение? Как сделать так, чтобы мои изменения цвета не переопределяли цвет по умолчанию?

update: Решил... неаккуратно (применяя цвет по умолчанию всякий раз, когда кто-то печатает), но я держу это открытым на случай, если кто-то предложит лучшее решение.


person Dian    schedule 22.09.2010    source источник
comment
Во-первых, ваш код даже не компилируется... во-вторых, когда вы вызываете эту подпрограмму? Я сделал небольшой пример на основе вашего кода, добавил исправления и уточнения, и он работает очень хорошо для меня.   -  person jachguate    schedule 22.09.2010
comment
RichEdit1..SelAttributes.Color := clBlue; (вы добавили лишний . между richedit1 и selattributes.color)   -  person Omair Iqbal    schedule 22.09.2010
comment
@jachguate: это не весь код, просто небольшой фрагмент, кстати. Я называю это нажатием клавиши.   -  person Dian    schedule 22.09.2010
comment
@omair: О, просто опечатка. Спасибо, что указали на это. Пойду сейчас поправлю.   -  person Dian    schedule 22.09.2010
comment
Я вызываю это в событии OnChange. Не каждое нажатие клавиши изменяет содержимое редактирования. Как было сказано, он работает с мерцанием, но я уверен, что его можно оптимизировать, чтобы вносить меньше изменений. Я не знаю способа предотвратить перерисовку элемента управления при каждом изменении атрибута, думая о чем-то вроде пары BeginUpdate/EndUpdate.   -  person jachguate    schedule 23.09.2010
comment
@jachguate: я не могу изменить его на OnChange, потому что он не может понять, какая клавиша нажата (это RichEdit только для чтения, причины указаны в вопросе). У меня уже есть временное исправление, но это действительно плохое программирование.   -  person Dian    schedule 23.09.2010
comment
@Dian, ты отредактировал свой вопрос после того, как я его впервые прочитал. Если RichEdit слишком упрощен (без вырезания/вставки, без возврата и т. д.), вы можете просто раскрасить новый символ, а не весь RichEdit. В любом случае ваше описание кажется все еще очень неполным, чтобы сделать хорошее (или умное) предложение.   -  person jachguate    schedule 23.09.2010
comment
@jachguate: Вырезать/вставить нельзя, но есть возврат. Я окрашиваю новый символ цветом по умолчанию (как я указал в вопросе), но я ищу альтернативное решение. Что еще я должен включить в вопрос? Другие детали кажутся несущественными.   -  person Dian    schedule 23.09.2010


Ответы (1)


Как вы уже обнаружили, вам нужно сбросить цвет по умолчанию, когда вы закончите, например:

ans := RichEdit1.Text;
for i := 1 to Length(ans) do 
begin 
  RichEdit1.SelStart := i-1; 
  RichEdit1.SelLength := 1; 
  if ans[i] = correct[i] then 
    RichEdit1.SelAttributes.Color := clRed 
  else 
    RichEdit1.SelAttributes.Color := clBlue;
end;
RichEdit1.SelStart := RichEdit1.GetTextLen;
RichEdit1.SelLength := 0;
RichEdit1.SelAttributes.Color := RichEdit1.Font.Color;

Есть более эффективные способы справиться с этим, чем окрашивание одной буквы за раз, например:

const
  colors: array[Boolean] of TColor = (clRed, clBlue);
var
  ans: string;
  start, len: Integer;
  cur_state: Boolean;

  procedure ColorRange(AStart, ALength: Integer; AColor: TColor);
  begin
    RichEdit1.SelStart := AStart;
    RichEdit1.SelLength := ALength;
    RichEdit1.SelAttributes.Color := AColor;
  end;

begin
  RichEdit1.Lines.BeginUpdate;
  try
    ans := RichEdit1.Text;
    start := 0;
    len := 0;
    cur_start := False;

    for i := 1 to Length(ans) do 
    begin 
      if (ans[i] = correct[i]) = cur_state then
        Inc(len)
      else begin
        if len > 0 then
          ColorRange(start, len, colors[cur_state]);
        start := i-1;
        len := 1;
        cur_state := not cur_state;
      end;
    end;
    if len > 0 then
      ColorRange(start, len, colors[cur_state]);
    ColorRange(RichEdit1.GetTextLen, 0, RichEdit1.Font.Color);
  finally
    RichEdit1.Lines.EndUpdate;
  end;
end;

Кроме того, использование свойства Text для добавления одного символа Char очень неэффективно. Вместо этого используйте свойство SelText, например:

RichEdit1.SelStart := RichEdit1.GetTextLen;
RichEdit1.SelLength := 0;
RichEdit1.SelAttributes.Color := ...; // optional
RichEdit1.SelText := Key;
person Remy Lebeau    schedule 24.09.2010
comment
Ты классный соус. Спасибо! :D - person Dian; 24.09.2010