Solved

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

Posted on 2015-02-04
12
194 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 26

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
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
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

Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

Question has a verified solution.

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

Suggested Solutions

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…
Windows Script Host (WSH) has been part of Windows since Windows NT4. Windows Script Host provides architecture for building dynamic scripts that consist of a core object model, scripting hosts, and scripting engines. The key components of Window…
This tutorial will introduce the viewer to VisualVM for the Java platform application. This video explains an example program and covers the Overview, Monitor, and Heap Dump 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.

777 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