Link to home
Start Free TrialLog in
Avatar of perkley
perkley

asked on

Richedit Select Color

I realize that you can not change the color of a Richedit when it has selected text.

What I am trying to do is to create a story book that reads to you.  It highlights a specific sentence as it reads it.  It then highlights the next sentence to read.

I have figured that I could layout a bunch of TLabel's and just turn on and off the transparency when I need it to be colored.

I wonder if anyone else has some nifty idea that would make this section a whole lot easier.

I am working with Delphi 5 Pro.
Avatar of MannSoft
MannSoft

I put a TRichEdit, TEdit and TButton on a form and came up with this code.  Its nasty, but it works :)

Just enter a number into the TEdit, press the TButton, and that line turns Red!

procedure TForm1.Button1Click(Sender: TObject);
var
   I: Integer;
   J: Integer;
   S: String;
begin
     try
        I := StrToInt(Edit1.Text);
     except
           Exit;
     end;
     if (I < 1) or (I > RichEdit1.Lines.Count) then
        Exit;
     if (I = 1) then
        RichEdit1.SelStart := 0
     else
     begin
          S := '';
          for J := 0 to I - 2 do
              S := S + RichEdit1.Lines[J];
          RichEdit1.SelStart := Length(S) + ((I - 1) * 2);
     end;
     RichEdit1.SelLength := Length(RichEdit1.Lines[I - 1]);
     RichEdit1.SelAttributes.Color := clRed;
end;
Avatar of perkley

ASKER

I am not seeing it work.  The highlight color is not red, it is still black.  When I deselect it then the text is red, but I don't want the text to be red, I want the highlight color to be red.  The text will remain black.
If the user is not able to scroll the text in this RichEdit then you may want to compleatly take over drawing all of the text on a paintbox, panel or other component with a Canvas using

DrawText(PaintBox1.Canvas.Handle ,PChar(TextString), -1, Rect1, DT_SINGLELINE or DT_VCENTER or DT_CENTER);

then you can put the Text anywhere, any color, any color Background (red if you want it to look selected), any Font, Bold, large or small. This is more work than just having characters displayed by a RichEdit, but for special Graphical output it may be better than beating and kicking a RichEdit, or hiding and showng labels ect.
listening
hi,
the richedit wont change highlight color ,even using setsyscolors() api all other hilight colors for tedit etc in delphi and for other windows will change but not the richedit.using richedit2 you can change the background color of the text but thats about it.
its a windows thing to make sure no matter what the color of the text in the richedit it will still be readable when highlighted.
Sorry, I don't know it exactly at the moment, but isn't it possible to use
  RichEdit1.SelAttributes.Color := clRed;
very simply? I think something like this should do it.
Regards, Hamilton.
no that just change the color of the text that is currently selected not the actual highlight color,so when text is unselected it will just be red.
I wrote a component awhile ago...it was basically so I could have the look of a console application embedded into a GUI window (so I could write a non-console ANSI editor).  You can change both the foreground and background colour, so you can sort of make it look like a line is being highlighted.  (Write a page of text in regular colour and then rewrite it with the new colour as each line is being read or whatever).  If you are interested I can put the source up on my website.
Hi!
Sorry, I think I have just understood the problem you have. You don't want to change the color of the letters, but the color of the selection rectangle. Am I right?
Regards, Hamilton.
Here's an idea:

Since windows sets the highlight color depending on the
text/font color to make sure the text is visibe,
why don't you try playing with the actual text color
so that you find a color that forces Windows to set
the highlight color to red (or whatever color you want)

rondi.
Avatar of perkley

ASKER

MannSoft, I am interested to see your code.

Hamilton, that is correct, I want to change the highlight color.

Rondi,  I tried your suggestion, but the highlight is always black, only the text changes different colors.  For example:  If I select it and tell it to be green, then the text turns purple with black highlight.  When I deselect then it is green.  Therefore this won't give me what I want.

Slick812, I think your idea would work, but seeing how I have to do an entire story and some lines will be highlighted only partially because of the sentence length, then it seems to me like a lot more work.  I will keep it in mind though if nothing else comes along better.
hello perkley, Here is and app I pieced together from a couple of things I did before. It will show Text you HighLight in a RichEdit with a Red Background. It draws on the Canvas of the RichEdit, so the Red Select is NOT redrawn when the RichEdit is Repainted. You will have to add that if you need it to show after your app loses focus. I only put a few comments, let me know if you need more info. The Red Selection is limited to 2 lines of text in this and Is ReadOnly while the Red Select is shown.
The RichEdit1 is default except WordWrap is False; I did not feel like building the searches for #10 and #13 linebreaks;

Here is the Code
+ + + + + + + + + + + + + + + + + +

unit RichEd1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    RichEdit1: TRichEdit;
    but_ChangeRed: TButton;
    but_Exit: TButton;
    but_Restore: TButton;
    procedure but_ExitClick(Sender: TObject);
    procedure but_ChangeRedClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure but_RestoreClick(Sender: TObject);
    procedure RichEdit1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
    RichCanvas: TCanvas;
    Reds: Boolean;
    Procedure RedSelect;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.but_ExitClick(Sender: TObject);
begin
Close;
end;

procedure TForm1.RedSelect;
{this uses RichCanvas.TextOut to
redraw the selected Text with Red background}
const
EM_EXLINEFROMCHAR = WM_USER + 54;
var
SelString: String;
ClarPos: TPoint;
TH, BW, CharLoca, LineNum, LinePos, i: Integer;
begin
if RichEdit1.SelLength = 0 then Exit;
RichCanvas.Brush.Color := clRed;
RichCanvas.Font := RichEdit1.Font;
SelString := RichEdit1.SelText;
ClarPos := RichEdit1.CaretPos;
{this RichEdit1.CaretPos is not a Pixel Point but a Line Nunber and Charater Point}

{set ReadOnly to true so keboard input will not cause the RedSelect to be lost}
RichEdit1.ReadOnly := True;
{Reds is used to Refresh on MouseDown}
Reds := True;
CharLoca := RichEdit1.SelStart;
LinePos := 0;
TH := RichCanvas.TextHeight('D');
BW := RichEdit1.BorderWidth;
LineNum := SendMessage(RichEdit1.Handle,EM_EXLINEFROMCHAR,0,CharLoca);
for i := 0 to LineNum-1 do
begin
LinePos := LinePos+Length(RichEdit1.Lines[i]);
end;
{LineNum*2 is my Lazy way of dealing with the #10 and #13 lineBreak charaters}
LinePos := CharLoca - LinePos-(LineNum*2);
{I only made this to do a Max of 2 selected lines}
{test to see if the Selection goes more than one line}
if RichEdit1.SelLength > Length(RichEdit1.Lines[LineNum]) - LinePos then
begin
RichCanvas.TextOut(RichCanvas.TextWidth(Copy(RichEdit1.Lines[LineNum], 0, LinePos))+2, ((LineNum) * TH)+BW, Copy(SelString, 0, Length(RichEdit1.Lines[LineNum])- LinePos)+'  '{these 2 spaces cover the LineBreak Charaters});
RichCanvas.TextOut(BW, ((LineNum+1) * TH)+BW, Copy(RichEdit1.Lines[LineNum+1], 0,RichEdit1.SelLength-(Length(RichEdit1.Lines[LineNum])- (LinePos-2))));
end else
RichCanvas.TextOut(RichCanvas.TextWidth(Copy(RichEdit1.Lines[ClarPos.y], 0, ClarPos.x-RichEdit1.SelLength)), (ClarPos.y * TH)+BW, SelString);
end;

procedure TForm1.but_ChangeRedClick(Sender: TObject);
{this button will place the RedSelect where you want it,
 withOUT any text being selected by the user}
begin
Reds := True;
RichEdit1.SelLength := 0;
RichEdit1.Refresh;
{you will have to place the location with TextWidth and TextHeight}
RichCanvas.TextOut(RichCanvas.TextWidth('Rich')+RichEdit1.BorderWidth, ({LineNumber}0 * RichCanvas.TextHeight('D'))+RichEdit1.BorderWidth, 'Edit');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
{you need to get the RichEdit1 HDC to a delphi compatible Canvas}
RichCanvas := TCanvas.Create;
RichCanvas.Handle := GetDC(RichEdit1.Handle);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// Free Canvas
RichCanvas.Free;
end;

procedure TForm1.but_RestoreClick(Sender: TObject);
{this button restores the RichEdit to be Writable again}
begin
RichEdit1.ReadOnly := False;
{Remove all Selections is not really nessary}
RichEdit1.SelLength := 0;
Reds := False;
{Refresh removes any RedSelect}
RichEdit1.Refresh;
RichEdit1.SetFocus;
end;

procedure TForm1.RichEdit1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
if Reds then
RichEdit1.Refresh;
RedSelect;
end;

end.

 - - - - - - - - - - - - - - - - - - - - -

you did not say if the user would be making the selections or if you just wanted to show certain text in the story with a red background for Attention. look at the TForm1.but_ChangeRedClick procedure if all you need is the display in red for attention.
perkley:

I uploaded the 2 files for the component to my homepage (http://www.mannsoft.ca).  The links should be in the topmost news article.  
Ive been meaning to finish it but havent had time lately, so the code is still fairly messy.  But it should (hopefully) do what you want though.  Just let me know if you have any questions
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of perkley

ASKER

Mannsoft I tried out your code, but when I tried to install it in delphi 5 pro, it gave me an error saying that the lines were to long.  I couldn't get it to work.

Slick812, I tried your code and it works pretty cool.  I think you should get the points.

I will wait to see what Mannsoft says though.
Hmm I have used that component in Delphi 4 thru 6 and havent seen that error before.  I guess its possible I changed something recently that broke it in older versions.  The component I was imitating when I wrote it is on www.torry.net can called TConsole.  It was written by a Borland coder who works on Delphi so it's probably better than mine anyway :-)
Avatar of perkley

ASKER

Slick812, thanks for your help.
wow, 5 points, that's a dificult desision. . . LOL