Question

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;  

If the letter in ans matches the letter in the same position as the letter in correct string, it is colored red otherwise, it is blue.

My problem is when I type again the whole RichEdit1 text is colored as the same as the first letter (if the first letter of RichEdit1 is blue then the whole text becomes blue).

By the way, this is not the the actual code I just simplified it because there are mutiple TRichEdits.
The TRichEdits are read-only and I assign the letters by something like RichEdit1.Text := RichEdit1.Text+Key; (doing this because it's a multiple keyboard program and I need to separate user inputs)

Is this the correct behavior? How can I stop my color changes from overriding the default color?

update: Solved it... in a sloppy way (applying the default color whenever someone types), but I'm keeping this open in case someone comes up with a better solution.

Was it helpful?

Solution

As you already discovered, you have to reset the default color when you are done, eg:

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;

There are more efficient ways to handle this than coloring one letter at a time, eg:

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;

Also, using the Text property to append a single Char is very inefficient. Use the SelText property instead, eg:

RichEdit1.SelStart := RichEdit1.GetTextLen;
RichEdit1.SelLength := 0;
RichEdit1.SelAttributes.Color := ...; // optional
RichEdit1.SelText := Key;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top