Solved

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

Posted on 2015-02-04
12
204 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 5
12 Comments
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 40590684
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
ID: 40590801
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
ID: 40592971
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
Get 15 Days FREE Full-Featured Trial

Benefit from a mission critical IT monitoring with Monitis Premium or get it FREE for your entry level monitoring needs.
-Over 200,000 users
-More than 300,000 websites monitored
-Used in 197 countries
-Recommended by 98% of users

 
LVL 24

Expert Comment

by:jimyX
ID: 40593886
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
ID: 40596510
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
ID: 40596543
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
 

Author Comment

by:shawn857
ID: 40597366
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
ID: 40597660
>   "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
ID: 40597701
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
ID: 40597795
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
ID: 40599961
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
ID: 40600172
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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
There is an easy way, in .NET, to centralize the treatment of all unexpected errors. First of all, instead of launching the application directly in a Form, you need first to write a Sub called Main, in a module. Then, set the Startup Object to th…
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

724 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