Applying Richedit text style in Delphi

Asked

Viewed 1,958 times

1

I need black a few words within a Richedit in Delphi, it works normally when there is no line break. But when I insert a line break I cannot correctly select the word to apply the style.

All the examples I found are with the same problem.

inserir a descrição da imagem aqui

In this example it stores the words that will be bold and the color they will have and when typing it will apply the formatting. But it only works until you insert a line break.

procedure TfrmRichEdit.RichEdit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
const
   LetrasValidas = ['a'..'z', 'A'..'Z', '0'..'9', '<', '>', '!', '='];

var
   iPosIni: Integer;
   iPosFim: Integer;
   iSelStart: Integer;
   iSelLength: Integer;
   iLoopFor: Integer;
   sText: string;
begin
   LockWindowUpdate(RichEdit1.Handle);

   // Guardaremos a posição inicial
   iSelStart := RichEdit1.SelStart;
   iSelLength := RichEdit1.SelLength;

   sText := RichEdit1.Text;

   // Acharemos o inicio da palavra
   iPosIni := iSelStart;
   if sText[iPosIni] in LetrasValidas then
   begin
      for iLoopFor := iSelStart - 1 downto 0 do
      begin
         if sText[iLoopFor] in LetrasValidas then
            iPosIni := iLoopFor
         else
            Break;
      end;
   end;

   // Acharemos o final da palavra
   iPosFim := iSelStart;
   for iLoopFor := iSelStart + 1 to Length(RichEdit1.Text) do
   begin
      if RichEdit1.Text[iLoopFor] in LetrasValidas then
         iPosFim := iLoopFor
      else
         Break;
   end;

   // Selecionaremos a palavra
   RichEdit1.SelStart := iPosIni - 1;
   RichEdit1.SelLength := (iPosFim) - RichEdit1.SelStart;

   // setaremos a cor original e estilo original
   RichEdit1.SelAttributes.Color := clBlack;
   RichEdit1.SelAttributes.Style := [];

   // Atribuiremos a nova cor e estilo caso encontre a palavra
   for iLoopFor := 0 to High(APalavras) do
   begin
      if UpperCase(APalavras[iLoopFor].DS_PALAVRA) = UpperCase(RichEdit1.SelText) then
      begin
         RichEdit1.SelAttributes.Color := APalavras[iLoopFor].VR_COR;
         RichEdit1.SelAttributes.Style := APalavras[iLoopFor].ESTILO;
         Break;
      end;
   end;

   // Posicionaremos o cursor na posição original
   RichEdit1.SelStart := iSelStart;
   RichEdit1.SelLength := iSelLength;

   LockWindowUpdate(0);
end;

1 answer

1


From what I could identify when debugging the code you have put, the problem is that each line break adds an invisible special character (the character CR or #13#10).

With each new line break the count is losing more and more. The solution is to count how many line breaks there are from the beginning of the text to the current cursor position and then subtract that number of line breaks from the value of RichEdit1.SelStart.

To make this count I created a method (created fast, so I know I could improve kkk) and use it inside the OnKeyUp.

METHOD THAT COUNTS LINE BREAKS:

function TfrmRichEdit.GetCrCount(const pText: string; const pPosition: Integer): Integer;
var
  lPos: Integer;
begin
  Result := 0;

  lPos := 1;
  while lPos < pPosition do
  begin
    lPos := Pos(#13#10, pText, lPos);
    if (lPos = 0) or (lPos >= pPosition) then
    begin
      Break;
    end
    else
    begin
      inc(Result);
      inc(lPos);
    end;
  end;
end;

Now that we have the method that counts line breaks, we will apply its use in OnKeyUp that you posted:

ATTENTION: The changes I made are indicated with these markers:

<<<<< PONTO 1 >>>>> <<<<< PONTO 2 >>>>> <<<<< PONTO 3 >>>>>

YOUR METHOD ONKEYUP() WITH MY AMENDMENTS

procedure TfrmRichEdit.RichEdit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
const
  LetrasValidas = ['a'..'z', 'A'..'Z', '0'..'9', '<', '>', '!', '='];

var
  iPosIni: Integer;
  iPosFim: Integer;
  iSelStart: Integer;
  iSelLength: Integer;
  iLoopFor: Integer;
  lCountCr: Integer;
  sText: string;
begin
  LockWindowUpdate(RichEdit1.Handle);

  // Guardaremos a posição inicial
  iSelStart := RichEdit1.SelStart;
  iSelLength := RichEdit1.SelLength;

  sText := RichEdit1.Text;

  // Acharemos o inicio da palavra
  iPosIni := iSelStart;
  if sText[iPosIni] in LetrasValidas then
  begin
    for iLoopFor := iSelStart - 1 downto 0 do
    begin
      if sText[iLoopFor] in LetrasValidas then
        iPosIni := iLoopFor
      else
        Break;
    end;
  end;

  // Acharemos o final da palavra
  iPosFim := iSelStart;
  for iLoopFor := iSelStart + 1 to Length(RichEdit1.Text) do
  begin
    if RichEdit1.Text[iLoopFor] in LetrasValidas then
      iPosFim := iLoopFor
    else
      Break;
  end;

  // <<<<< PONTO 1 >>>>>
  // ***( OBTENHO A CONTAGEM DE QUEBRAS DE LINHA )***
  lCountCr := GetCrCount(sText, iSelStart);
  // ************************************************

  // Selecionaremos a palavra
  // <<<<< PONTO 2 >>>>>
  // ***( SUBTRAIO O NÚMERO DE QUEBRAS DE LINHA )***
  //RichEdit1.SelStart := iPosIni - 1;
  //RichEdit1.SelLength := (iPosFim) - RichEdit1.SelStart;
  RichEdit1.SelStart := iPosIni - 1 - lCountCr;
  RichEdit1.SelLength := (iPosFim) - RichEdit1.SelStart - lCountCr;
  // ***********************************************

  // setaremos a cor original e estilo original
  RichEdit1.SelAttributes.Color := clBlack;
  RichEdit1.SelAttributes.Style := [];

  // Atribuiremos a nova cor e estilo caso encontre a palavra
  for iLoopFor := 0 to High(APalavras) do
  begin
    // <<<<< PONTO 3 >>>>>
    // ***( REMOVO OS ESPAÇOS ANTES E DEPOIS PARA OTIMIZAR A COMPARAÇÃO )***
    //if UpperCase(APalavras[iLoopFor].DS_PALAVRA) = UpperCase(RichEdit1.SelText) then
    if Trim(UpperCase(APalavras[iLoopFor].DS_PALAVRA)) = Trim(UpperCase(RichEdit1.SelText)) then
    // *********************************************************************
    begin
      RichEdit1.SelAttributes.Color := APalavras[iLoopFor].VR_COR;
      RichEdit1.SelAttributes.Style := APalavras[iLoopFor].ESTILO;
      Break;
    end;
  end;

  // Posicionaremos o cursor na posição original
  RichEdit1.SelStart := iSelStart;
  RichEdit1.SelLength := iSelLength;

  LockWindowUpdate(0);
end;
  • The code got interesting. But there are some situations where it doesn’t apply the style correctly. For example: if I type a word that is in the list, it applies the style, so I break a line type the same word, it applies the style, so if I break a line and type some word that is not in the list no longer works after it. I haven’t been able to identify the problem yet.

  • I hit point two, take a look there.

  • It’s getting round. rs But still have some problems to apply the style. For example: after typing a few lines it starts to apply a style when I start typing and sometimes when I finish typing the word it does not apply the corresponding style, and if I delete the word it keeps the style. Another situation is when I have a few words typed, so if I delete one at the beginning it loses the style of everything.

  • But man, you want me to do the whole software for you? I’m not developing the app, I open Delphi, I test, I find the problem, I answer and I close without saving. Your problem was the line break, it’s already solved. I think I’ve shown you the way to the rocks and now you touch the boat, that’s how you’ll have to do it.

  • No time I asked you to develop everything. Similarly I’m doing tests here and trying to correct you did and managed to correct. This is just one part of the solution I am in need of. I really appreciate the help. I will mark as solved here.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.