Solved

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

Posted on 2015-02-04
12
189 Views
Last Modified: 2015-02-10
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
Comment
Question by:shawn857
  • 6
  • 5
12 Comments
 
LVL 25

Expert Comment

by:Sinisa Vuk
Comment Utility
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
 
LVL 24

Accepted Solution

by:
jimyX earned 500 total points
Comment Utility
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
 

Author Comment

by:shawn857
Comment Utility
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
 
LVL 24

Expert Comment

by:jimyX
Comment Utility
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
 

Author Comment

by:shawn857
Comment Utility
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
 
LVL 24

Expert Comment

by:jimyX
Comment Utility
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
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:shawn857
Comment Utility
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
 
LVL 24

Expert Comment

by:jimyX
Comment Utility
>   "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
 

Author Comment

by:shawn857
Comment Utility
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
 
LVL 24

Expert Comment

by:jimyX
Comment Utility
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
 

Author Comment

by:shawn857
Comment Utility
I see, thanks Jimy. OK, well how could I disable/ignore ALL keypresses that have CTRL in them?

Thanks
   Shawn
0
 
LVL 24

Expert Comment

by:jimyX
Comment Utility
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

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Having just graduated from college and entered the workforce, I don’t find myself always using the tools and programs I grew accustomed to over the past four years. However, there is one program I continually find myself reverting back to…R.   So …
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now