• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 250
  • Last Modified:

"Color-coding" the characters in an edit box?

Hi, I'm trying to do a color-coding kind of thing where the user types characters in an Edit box and depending on the character he types in, it turns a certain color. For example if he typed in a alphabetic (a-Z) character it would be black... if he typed in a '#' or a "?" character, it would turn green. Also, I'd like to be able to allow the user to "toggle" those green characters to red just by double-clicking (or right-clicking) on the character position. Can this be done?

Thanks!
    Shawn

P.S: I use Delphi 7.
0
shawn857
Asked:
shawn857
  • 6
  • 5
1 Solution
 
Sinisa VukCommented:
There are few components on Torry net ready to use or as just like examples. (SynEdit, LMD SyntaxEdit, ColorMemo, ...)
All components override Paint method for own needs and there - depending on contents of Text do draw.
0
 
jimyXCommented:
Or simplest to do is use adjusted RichEdit (turn off WordWrap...etc) and use KeyDown and MouseUp:

procedure TForm1.RichEdit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  Clr: TColor;
begin
  Clr:= RichEdit1.SelAttributes.Color; //Default Color

  if key in [ord('A')..ord('Z'), ord('a')..ord('z')] then
    Clr:= ClBlack;

  if key = 51 then    {#}
    Clr:= clGreen;

  if key = 191 then    {?}
    Clr:= clGreen;

  //if key in [ord('A')..ord('Z'), ord('a')..ord('z'), 51, 191] then
  RichEdit1.SelAttributes.Color:= Clr;
end;

procedure TForm1.RichEdit1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  Clr: TColor;
begin
  //To allow selecting text
  if RichEdit1.SelLength >= 1 then Exit;

  RichEdit1.SelLength:= 1;
  Clr:= RichEdit1.SelAttributes.Color;

  case RichEdit1.SelAttributes.Color of
    clGreen:  Clr:= clRed;
    clRed  :  Clr:= clGreen;
  end;
  RichEdit1.SelAttributes.Color:= Clr;
  RichEdit1.SelLength:= 0;
end;

Open in new window

0
 
shawn857Author Commented:
Thanks Guys. Sinisa, I will look through some of these components. Jimy, your suggestion looks good, but if I enter a tring like this:

hyskasdf#?sdwe

... all is good when I enter them - they appear in the correct colors. But when I try to double-click on just the # character to change its color, it also automatically selects the adjacent "?" character. Is there someway to make it just select the one character I double-click on?

Thanks!
    Shawn
0
What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

 
jimyXCommented:
Right now one click before the "#" or "?" toggles their color.

Double Click can not behave other way than what you experienced. Double click is designed to select some predefined text ranges.
For instance, string of "a".."z" are selected when double clicking at, until meeting one special character and same way with special chars until meeting "a".."z", or space.

e.g.:
.,-abc#?defg

Double click on "b" will highlight "abc", double click on "f" will highlight "defg".
Same happens with special characters, double click on "," will highlight ".,-", and you saw what happens when double clicking "#".

Double click does a highlight based on characters grouping, not sure if that can be overridden.

But if Right Click is acceptable, you can use the following code, but right click does not move the cursor position so one Left click to move the cursor and right click to toggle the color:
procedure TForm1.RichEdit1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  Clr: TColor;
begin
  //To allow selecting text
  if RichEdit1.SelLength >= 1 then Exit;

  if Button <> mbRight then Exit;   //To toggle colors when right clicking only

  RichEdit1.SelLength:= 1;
  Clr:= RichEdit1.SelAttributes.Color;

  case RichEdit1.SelAttributes.Color of
    clGreen:  Clr:= clRed;
    clRed  :  Clr:= clGreen;
  end;
  RichEdit1.SelAttributes.Color:= Clr;
  RichEdit1.SelLength:= 0;
end;

Open in new window


What do you prefer?
0
 
shawn857Author Commented:
Thanks JimyX, I think your right-click solution is what I need. But I'm having a problem - I have 6 specific characters that I want to paint Green as soon as they're typed, but the "key" parameter in the KeyDown event doesn't seem to be returning the proper ascii code:

 
 if key in [ord('g'), ord('#'), ord('%'), ord('='), ord('~'), ord('!')] then
     Clr:= clGreen
  else
     Clr:= ClBlack;

Open in new window


... as I step through this in debug, for example when I press character 'g', I see the value in "Key" is equal to 71. Why wouldn't it be equal to 103... which is the ascii code for lower-case 'g'?
   In your original code for the KeyDown event, you have:

  if key = 51 then    {#}
    Clr:= clGreen;

  if key = 191 then    {?}
    Clr:= clGreen;

Open in new window


Shouldn't the '#' character be 35 and the "?" be 63?? I don't know where you get 51 and 191 from.


Thanks!
   Shawn
0
 
jimyXCommented:
Hi Shawn,
>   "I don't know where you get 51 and 191 from."
I just read the key at OnKeyDown to put in the condition.

That's the conflict of using KeyDown/KeyUp/KeyPress.

Here is a nice article to read, will clear so many questions about the differences between Key Down/Up/Press.

OnKeyPress
OnKeyPress returns a different ASCII character for 'g' and 'G,' but OnKeyDown and OnKeyUp do not make a distinction between uppercase and lowercase alpha keys.

So in your case you better of using the OnKeyPress:
procedure TForm1.RichEdit1KeyPress(Sender: TObject; var Key: Char);
begin
...
 if key in ['g', '#', '%', '=', '~', '!'] then
     Clr:= clGreen
  else
     Clr:= ClBlack;
...
end;

Open in new window

0
 
shawn857Author Commented:
That is great Jimy, that works fine now. This raises one other thought Jimy - if I paste some text into my TRichEdit... let's say:

DHU#%=TRU

it doesn't show the #%= characters as red, they're black. This is understandable as this text was pasted in and therefore the KeyPress event was not invoked. But is there a way to have pasted text also be subject to my same color-coding rules?

Thanks!
    Shawn
0
 
jimyXCommented:
>   "But is there a way to have pasted text also be subject to my same color-coding rules?"
Yes sure.

//global variables
var
  curPos, TxtLen: Integer;    //to reposition the Caret after Copy-Paste in the RichEdit

Procedure ApplyClrCoding(RE:TRichEdit);
var
  i,
  LineLen: Integer;
  LineStr: String;
  Clr: TColor;
begin
  RE.Lines.BeginUpdate;
  try
    LineLen:= Length(RE.Lines[0]);
    LineStr:= RE.Lines[0];
    for i:= 1 to LineLen do
      begin
        if LineStr[i] in ['g', '#', '%', '=', '~', '!'] then
          begin
            Clr:= clGreen;

            //If there are previously applied colors, such as toggled colors, you can avoid recoloring them here
            RE.SelStart:= i-1;
            RE.SelLength:= 1;
            if RE.SelAttributes.Color = clred then  //list the colors you want to keep unchanged
              begin
                Clr:= RE.SelAttributes.Color;         // it's a previously set color
              end;

          end
        else
          Clr:= ClBlack;

        RE.SelStart:= i-1;
        RE.SelLength:= 1;
        RE.SelAttributes.Color:= Clr;
      end;
  finally
    RE.SelLength:= 0;
    RE.SelStart:= (LineLen-TxtLen)+curPos;
    RE.Lines.EndUpdate;
  end;
end;

procedure TForm1.RichEdit1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  Clr: TColor;
begin
  //To allow selecting text
  if RichEdit1.SelLength >= 1 then Exit;

  if Button <> mbRight then Exit;   //To toggle colors when right clicking only

  RichEdit1.SelLength:= 1;
  Clr:= RichEdit1.SelAttributes.Color;

  case RichEdit1.SelAttributes.Color of
    clGreen:  Clr:= clRed;
    clRed  :  Clr:= clGreen;
  end;
  RichEdit1.SelAttributes.Color:= Clr;
  RichEdit1.SelLength:= 0;
end;

procedure TForm1.RichEdit1KeyPress(Sender: TObject; var Key: Char);
var
  Clr: TColor;
begin
  if (key = '') then  //Ctrl+V / paste
    begin
      ApplyClrCoding(RichEdit1);
      Exit;
    end;


  if key in ['g', '#', '%', '=', '~', '!'] then
    Clr:= clGreen
  else
    Clr:= ClBlack;

  RichEdit1.SelAttributes.Color:= Clr;
end;

procedure TForm1.RichEdit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  curPos:= RichEdit1.SelStart;
  TxtLen:= Length(RichEdit1.Lines[0])-RichEdit1.SelLength;   //  if pasting over selected text, subtract the selection
end;

Open in new window

0
 
shawn857Author Commented:
Thanks Jimy, that is excellent. Something I just noticed now is that if I highlight some of the text in the RichEdit box and hit CTRL-C , that the color of the red or green characters gets lost and everything turns to black. Is there a way to prevent that?

Thanks
    Shawn
0
 
jimyXCommented:
That happens due to the fact that you set the color for any Key Pressed which is not among ['g', '#', '%', '=', '~', '!'] to clBlack, Ctrl+C is a key press and highlighted text gets formatted to clBlack.
Either skip the text format if it's a Ctrl+C or add condition to sanitize the keys pressed that are capable of invoking SelAttributes:

procedure TForm1.RichEdit1KeyPress(Sender: TObject; var Key: Char);
var
  Clr: TColor;
begin
  if key = '' then exit; //Ctrl-C / Copy

  if (key = '') then  //Ctrl+V / paste
    begin
      ApplyClrCoding(RichEdit1);
      Exit;
    end;

  if key in ['g', '#', '%', '=', '~', '!'] then
    Clr:= clGreen
  else
    Clr:= ClBlack;

  //Also you could add condition here, such as:
  //if key in ['A'..'Z', 'a'..'z', ...etc] then // "...etc" where you list all possible chars that need to make color changes
  RichEdit1.SelAttributes.Color:= Clr;
end;

Open in new window

0
 
shawn857Author Commented:
I see, thanks Jimy. OK, well how could I disable/ignore ALL keypresses that have CTRL in them?

Thanks
   Shawn
0
 
jimyXCommented:
You can detect when the Ctrl button is pressed on KeyDown and turn on a flag and test that flag before applying selAttributes at KeyPress. In code:
var
  curPos, TxtLen: Integer;
  CtrlBtn: Boolean=False;

Procedure ApplyClrCoding(RE:TRichEdit);
begin
  //Remains the same
  ...
end;

procedure TForm1.RichEdit1KeyPress(Sender: TObject; var Key: Char);
var
  Clr: TColor;
begin
  //if key = '' then exit; //Ctrl-C / Copy // no need since we already covered any combination with Ctrl

  if (key = '') then  //Ctrl+V / paste
    begin
      ApplyClrCoding(RichEdit1);
      Exit;
    end;

  if key in ['g', '#', '%', '=', '~', '!'] then
    Clr:= clGreen
  else
    Clr:= ClBlack;

  if not CtrlBtn then // if not Ctrl button is pressed
    RichEdit1.SelAttributes.Color:= Clr;
end;

procedure TForm1.RichEdit1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  //Remains the same
  ...
end;

procedure TForm1.RichEdit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  CtrlBtn:= ssCtrl in Shift; //<< Ctrl is pressed

  curPos:= RichEdit1.SelStart;
  TxtLen:= Length(RichEdit1.Lines[0])-RichEdit1.SelLength;
end;

Open in new window


For visitors:
Ctrl+C & Ctrl+V keys appear empty in the code blocks here but when copied to Delphi they show up.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

  • 6
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now