Get / Set color from characters

  • I need to loop through all the text of a document and change font color depending on a certain condition.

    I tried a lot of different alternatives, some worked, some didn't.

    Tha alternatives that worked use CPAtt which I understand is deprecated. None of the alternatives that use GetCharAttr worked.

    Now my interest is to know how to use an alternative that doesn’t need a deprecated method, CPAttr.

    How and when can I use?:

    - TextCursor.CurrentCharAttr.AGet
    - TextCursor.CurrentCharAttr.ASetColor
    - CurrentCharAttr.GetColor / GetColorNR
    - CurrentCharAttr.SetColor / SetColorNR
    - CurrentCharAttr.SetBGColor

    How can I evaluate and get the font color of a certain char, using TextCursor.CurrentCharAttr or CurrentCharAttr?

    When do I have to use TextCursor.CurrentCharAttr and when just CurrentCharAttr ?

    I would like to know why the code I wrote that doesn’t work, doesn’t work?

    The alternatives I used are:

    Code
    var  par   : TParagraph;  i     : integer;  a     : TWPCharAttr;  props : TWPRTFProps;  col   : integer;  bgCol : Integer;begin // Change colors   // Works   with WPRichText do begin     CPPosition := 0;     col        := CurrAttr.ColorToNr(clBlack, false);     bgCol      := 0;     BeginUpdate;     repeat       if ( CPAttr.Color <> col ) then begin          CPAttr.Color := col;          CPAttr.IncludeStyle(afsBold);       end; // if ...       if ( CPAttr.BGColor <> bgCol ) then begin          CPAttr.BGColor := bgCol;          CPAttr.IncludeStyle(afsBold);          CPAttr.IncludeStyle(afsUnderline);          // CPAttr.Style   := CPAttr.Style + [afsBold] + [afsUnderline]; // Working alternative          // CurrAttr.AddStyle([afsBold, afsUnderline]); // Working alternative       end; // if ...     until not ( CPMoveNext );     EndUpdate;   end; // with ...      // Works, but is slower than the last method   with WPRichText do begin     CPPosition := 0;     col        := CurrAttr.ColorToNr(clBlack, false);     repeat       if ( TextCursor.CPAttr.Color <> col ) then begin          TextCursor.CPAttr.Color := col;          TextCursor.CPAttr.IncludeStyle(afsBold);          // TextCursor.CPAttr.Style := TextCursor.CPAttr.Style + [afsBold]; // Working alternative       end; // if ...     until not ( CPMoveNext );   end; // with ...   // Works   col                   := WPRichText.CurrAttr.ColorToNr(clBlack, false);   WPRichText.CPPosition := 0;   par                   := WPRichText.FirstPar;   props                 := WPRichText.ActiveText.RTFProps;   WPRichText.BeginUpdate;   while ( par <> nil ) do begin     for i := 0 to par.CharCount-1 do begin       if ( WPRichText.CPAttr.Color <> col ) then begin          props.Attributes.GetCharAttr(par.CharAttr[i], a);          props.AttrInterface.SetColor(a, clRed);          props.AttrInterface.IncludeStyle(a, afsBold);          props.Attributes.SetCharAttr(par.CharAttr[i], a);       end; // if ...        WPRichText.CPMoveNext;     end; // for ...     par := par.next;     WPRichText.CPMoveNext;   end; // while ...   WPRichText.EndUpdate;   WPRichText.Refresh;   // Doesn’t work   col   := WPRichText.CurrAttr.ColorToNr(clBlack, false);   par   := WPRichText.FirstPar;   props := WPRichText.ActiveText.RTFProps;   WPRichText.BeginUpdate;   while ( par <> nil ) do begin     for i := 0 to par.CharCount-1 do begin       props.Attributes.GetCharAttr(par.CharAttr[i], a);       // if not ( props.AttrInterface.GetColor(a, col) ) then begin // Doesn’t compile       if not ( props.AttrInterface.GetColorNR(a, col) ) then begin          props.Attributes.GetCharAttr(par.CharAttr[i], a);          props.AttrInterface.SetColor(a, clRed);          props.AttrInterface.IncludeStyle(a, afsBold);          props.Attributes.SetCharAttr(par.CharAttr[i], a);       end;     end;     par := par.next;   end;   WPRichText.EndUpdate;   WPRichText.Refresh;   // Doesn’t work   with WPRichText do begin     CPPosition := 0;     col        := CurrAttr.ColorToNr(clBlack, false);     BeginUpdate;     repeat       if not ( TextCursor.CurrentCharAttr.AGet(WPAT_CharColor, col) ) then begin       // if not ( TextCursor.CurrentCharAttr.AGet(WPAT_CharColor, clBlack) ) then begin // Doesn’t compile          TextCursor.CurrentCharAttr.ASetColor(WPAT_CharColor, col);          TextCursor.CurrentCharAttr.ASetAdd(WPAT_CharStyleON, WPSTY_BOLD);       end; // if ...     until not ( CPMoveNext );     EndUpdate;   end; // with ...      // Doesn’t work   with WPRichText do begin     col        := CurrAttr.ColorToNr(clBlack, false);     CPPosition := 0;     repeat       // if not ( CurrentCharAttr.GetColor(clBlack) ) then begin // Doesn’t compile       // if not ( CurrentCharAttr.GetColorNr(clBlack) ) then begin // Doesn’t compile       // if not ( CurrentCharAttr.GetColor(col) ) then begin // Doesn’t compile       if not ( CurrentCharAttr.GetColorNR(col) ) then begin          CurrentCharAttr.BeginUpdate;          CurrentCharAttr.SetColor(clBlack);          CurrentCharAttr.IncludeStyles([afsBold]);          CurrentCharAttr.EndUpdate;       end; // if ...     until not ( CPMoveNext );   end; // if ...   // Doesn’t work   with WPRichText do begin     CPPosition := 0;     col        := CurrAttr.ColorToNr(clBlack, false);     BeginUpdate;     repeat       if ( CurrAttr.GetColorEx(WPAT_CharColor) <> col ) then begin          CPAttr.Color := col;          CPAttr.IncludeStyle(afsBold);       end; // if ...     until not ( CPMoveNext );     EndUpdate;   end; // with ...   // Doesn’t work   with WPRichText do begin     CPPosition := 0;     col        := CurrAttr.ColorToNr(clBlack, false);     bgCol      := 0;     BeginUpdate;     repeat       if ( CurrAttr.Color <> col ) then begin          CurrAttr.Color := col;          CurrAttr.AddStyle([afsBold]);       end; // if ...       if ( CurrAttr.BKColor <> bgCol ) then begin          CurrAttr.BKColor := bgCol;          CurrAttr.AddStyle([afsBold, afsUnderline]);       end; // if ...     until not ( CPMoveNext );     EndUpdate;   end; // with ...   // Doesn’t work   with WPRichText do begin     CPPosition := 0;     col        := CurrAttr.ColorToNr(clBlack, false);     bgCol      := 0;     BeginUpdate;     repeat       if ( CPAttr.Color <> col ) then begin          CurrAttr.Color := col;          CurrAttr.AddStyle([afsBold]);       end; // if ...       if ( CPAttr.BGColor <> bgCol ) then begin          CurrAttr.BKColor := bgCol;          CurrAttr.AddStyle([afsBold, afsUnderline]);       end; // if ...     until not ( CPMoveNext );     EndUpdate;   end; // with ...   // Strange results, doesn’t work   with WPRichText do begin     CPPosition := 0;     col        := CurrAttr.ColorToNr(clBlack, false);     bgCol      := 0;     BeginUpdate;     repeat      if ( CurrAttr.Color <> col ) then begin       // if ( CurrAttr.Color <> clBlack ) then begin // This alternative compiles          CPAttr.Color := col;          CPAttr.IncludeStyle(afsBold);       end; // if ...       if ( CurrAttr.BKColor <> bgCol ) then begin          CPAttr.BGColor := bgCol;          CPAttr.IncludeStyle(afsBold);          CPAttr.IncludeStyle(afsUnderline);       end; // if ...     until not ( CPMoveNext );     EndUpdate;   end; // with ...end; // Change colors

    I also used:

    Code
    for i := 0 to WPRichText.TextColorCount - 1 do
      WPRichText.TextColors[i] := clBlack;

    This code led me to paragraphs unreadable, with black background.

    I understand I can also use styles, but as I am exporting the text to an RTF file that can be read by Microsoft Word, I didn't use styles.

    Kind regards,

    Carlos Borrero

    • Offizieller Beitrag

    Moving the cursor is usually not a good idea.

    That code looks best:

    Code
    col                   := WPRichText.CurrAttr.ColorToNr(clBlack, false);    WPRichText.CPPosition := 0;    par                   := WPRichText.FirstPar;    props                 := WPRichText.ActiveText.RTFProps;    WPRichText.BeginUpdate;    while ( par <> nil ) do begin      for i := 0 to par.CharCount-1 do begin        if ( WPRichText.CPAttr.Color <> col ) then begin           props.Attributes.GetCharAttr(par.CharAttr[i], a);           props.AttrInterface.SetColor(a, clRed);           props.AttrInterface.IncludeStyle(a, afsBold);           props.Attributes.SetCharAttr(par.CharAttr[i], a);        end; // if ...        WPRichText.CPMoveNext;      end; // for ...      par := par.next;      WPRichText.CPMoveNext;    end; // while ...    WPRichText.EndUpdate;    WPRichText.Refresh;

    But You can do it without moving the cursor. The following code will make all red text blue:

    Code
    procedure TForm1.Button2Click(Sender: TObject);var par : TParagraph;    i,IsRed,c : Integer;begin    par := WPRichText1.RTFData.FirstPar;    IsRed := WPRichText1.CurrAttr.ColorToNr(clRed, false);    while par<>nil do    begin      for i:=0 to par.CharCount-1 do      begin        WPRichText1.AttrHelper.CharAttr := par.CharAttr[i];        if WPRichText1.AttrHelper.GetColorNr( c ) and (c=IsRed) then        begin           WPRichText1.AttrHelper.SetColor( clBlue );           par.CharAttr[i] := WPRichText1.AttrHelper.CharAttr;        end;      end;      par := par.globalnext;    end;    WPRichText1.ReformatAll(false, true);end;

    Please note, that black is usually not assigned. This means text text is black if GetColorNr returns false. So you can make all black text blue using this code: