More about scrolling RichEdit...

Sirs,
still several nuts to crack!
I'm working on with a terminal program and the window for the received text.
Normally, the text scrolls with the incoming carriage return, line feed and word wraps.
Sometimes I need to roll back the received text, selecting some words and copy them with the mouse click to the other part of the app.
In the meantime when working with the received text -  incoming text may not affect the text I'm inspecting. Rolling accepted only if I want to scroll text with the mouse wheel, etc.. I will say, when the window is focused, it must be "freezed".
Have the following code, but it allows the selection hike up to the first visible line in the Line Feed will be added the the end of the text (in the invisible part)!
On the Window I have some usually actions as OnEnter, OnExit, OnScroll, etc.
The code below is simplified with some test function.

procedure TfrmDigiTerm.DoAddProc;
var
  P: TPoint;
  SelectStart, SelectLen, ScrollPosVert , ScrollPosHoriz :Integer;
begin
  RxWindow1.Lines.BeginUpdate;
 if not LetScroll then  
 begin 
 {Scrolling NOT allowed when Window focused! This function still allow moving the CaretPos to 1st visible row when LF or CR comes in}
  P := RxWindow1.CaretPos;
  SelectLen := RxWindow1.SelLength;
  SelectStart := RxWindow1.SelStart;
  ScrollPosVert :=GetScrollPos(RxWindow1.Handle, SB_VERT);
  ScrollPosHoriz :=GetScrollPos(RxWindow1.Handle, SB_HORZ);
  RxWindow1.Lines.Add(TimeToStr(Now));
  RxWindow1.CaretPos := P;
  RxWindow1.SelStart := SelectStart;
  RxWindow1.SelLength:=SelectLen;
  SetScrollPos(RxWindow1.Handle, SB_VERT,ScrollPosVert,True);
  SetScrollPos(RxWindow1.Handle, SB_HORZ,ScrollPosHoriz,True);
end
 else
begin 
   { Scrolling allowed - Window not focused }
    RxWindow1.Lines.Add(TimeToStr(Now);  
    RxWindow1.selstart  := length(RxWindow1.text);
    RxWindow1.Perform(EM_SCROLL,SB_BOTTOM,0);
end;
end;
  RxWindow1.Lines.EndUpdate;
end;

Open in new window

ejla51Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ejla51Author Commented:
I think I at last have solved the problem, but some text flickering are still visible.
Any comments?
procedure TfrmDigiTerm.DoAddProc;
var
  P: TPoint;
  SelectStart, SelectLen, ScrollPosVert , ScrollPosHoriz :Integer;
  TextPosition: LResult;
  LineNumber: Integer;

begin
 if cbxLetScroll.Checked then
  begin
   RxWindow1.Lines.Add(TimeToStr(Now));
   RxWindow1.selstart  := length(RxWindow1.text);
   RxWindow1.Perform(EM_SCROLL,SB_BOTTOM,0);
  end
   else
 begin
   //get the actually text view
   LineNumber := GetFirstVisibleLine(RxWindow1);
   TextPosition := SendMessage(RxWindow1.Handle, EM_LINEINDEX, LineNumber, 0);
   P := RxWindow1.CaretPos;
   SelectStart := RxWindow1.SelStart;
   SelectLen := RxWindow1.SelLength;
   ScrollPosVert  := GetScrollPos(RxWindow1.Handle, SB_VERT);
   ScrollPosHoriz := GetScrollPos(RxWindow1.Handle, SB_HORZ);
   RxWindow1.Lines.BeginUpdate;
   RxWindow1.Lines.Add(TimeToStr(Now));
   //Reset first visible line to old position
   SendMessage(RxWindow1.Handle, EM_SETSEL, TextPosition, TextPosition);
   // Reset old caret position and possible selection
   RxWindow1.CaretPos := P;
   RxWindow1.SelStart := SelectStart;
   RxWindow1.SelLength:=SelectLen;
   SetScrollPos(RxWindow1.Handle, SB_VERT,ScrollPosVert,True);
   SetScrollPos(RxWindow1.Handle, SB_HORZ,ScrollPosHoriz,True);
   RxWindow1.Lines.EndUpdate;
end;
end;
// -----------------------------------------------------------------------------
function TfrmDigiTerm.GetLastVisibleLine(Window:TJvRichEdit) : Integer;
Begin
 Result := GetFirstVisibleLine(Window) + LinesVisible(RxWindow1);
end;
// -----------------------------------------------------------------------------
function TfrmDigiTerm.GetFirstVisibleLine(Window: TJvRichEdit): Integer;
begin
 Result := Window.Perform(EM_GETFIRSTVISIBLELINE, 0, 0 );
end;
// -----------------------------------------------------------------------------
 function TfrmDigiTerm.LinesVisible(Window: TJvRichEdit): integer;
    Var
      OldFont : HFont;
      Hand : THandle;
      TM : TTextMetric;
      Rect  : TRect;
      tempint : integer;
    begin
      Hand := GetDC(Window.Handle);
      try
        OldFont := SelectObject(Hand, Window.Font.Handle);
        try
          GetTextMetrics(Hand, TM);
          Window.Perform(EM_GETRECT, 0, longint(@Rect));
          tempint := (Rect.Bottom - Rect.Top) div (TM.tmHeight + TM.tmExternalLeading);
        finally
          SelectObject(Hand, OldFont);
        end;
      finally
        ReleaseDC(Window.Handle, Hand);
      end;
      Result := tempint;
    end;
// -----------------------------------------------------------------------------

Open in new window

jimyXCommented:
You can use:
  RichEdit1.Perform(WM_SETREDRAW, 0, 0);
  RichEdit1.Perform(WM_SETREDRAW, 1, 0);

Or:
  LockWindowUpdate(handle);
ejla51Author Commented:
jimyX,

> You can use:
>  RichEdit1.Perform(WM_SETREDRAW, 0, 0);
>  RichEdit1.Perform(WM_SETREDRAW, 1, 0);

>Or:
>  LockWindowUpdate(handle);

aah... sorry, instead what?
Can you please complete my code and remove all unnecessary code!?
OWASP: Avoiding Hacker Tricks

Learn to build secure applications from the mindset of the hacker and avoid being exploited.

jimyXCommented:
Here you are I updated

 
procedure TfrmDigiTerm.DoAddProc;
var
  P: TPoint;
  SelectStart, SelectLen, ScrollPosVert , ScrollPosHoriz :Integer;
  TextPosition: LResult;
  LineNumber: Integer;

begin
 if cbxLetScroll.Checked then
  begin
   RxWindow1.Lines.Add(TimeToStr(Now));
   RxWindow1.selstart  := length(RxWindow1.text);
   RxWindow1.Perform(EM_SCROLL,SB_BOTTOM,0);
  end
   else
 begin
   //get the actually text view
   LineNumber := GetFirstVisibleLine(RxWindow1);
   TextPosition := SendMessage(RxWindow1.Handle, EM_LINEINDEX, LineNumber, 0);
   P := RxWindow1.CaretPos;
   SelectStart := RxWindow1.SelStart;
   SelectLen := RxWindow1.SelLength;
   ScrollPosVert  := GetScrollPos(RxWindow1.Handle, SB_VERT);
   ScrollPosHoriz := GetScrollPos(RxWindow1.Handle, SB_HORZ);
   RxWindow1.Lines.BeginUpdate;
   RxWindow1.Perform(WM_SETREDRAW, 0, 0);
   RxWindow1.Lines.Add(TimeToStr(Now));
   //Reset first visible line to old position
   SendMessage(RxWindow1.Handle, EM_SETSEL, TextPosition, TextPosition);
   // Reset old caret position and possible selection
   RxWindow1.CaretPos := P;
   RxWindow1.SelStart := SelectStart;
   RxWindow1.SelLength:=SelectLen;
   SetScrollPos(RxWindow1.Handle, SB_VERT,ScrollPosVert,True);
   SetScrollPos(RxWindow1.Handle, SB_HORZ,ScrollPosHoriz,True);
   RxWindow1.Perform(WM_SETREDRAW, 1, 0);
   RxWindow1.Lines.EndUpdate;
end;
end;

Open in new window

jimyXCommented:
You call BeginUpdate and EndUpdate to enclose the code and you may add Perform(WM_SETREDRAW, 0, 0) right after BeginUpdate and Perform(WM_SETREDRAW, 1, 0) before EndUpdate if it flickers:

 
procedure TfrmDigiTerm.DoAddProc;
var
  P: TPoint;
  SelectStart, SelectLen, ScrollPosVert , ScrollPosHoriz :Integer;
  TextPosition: LResult;
  LineNumber: Integer;
begin
 RxWindow1.Lines.BeginUpdate;
 //RxWindow1.Perform(WM_SETREDRAW, 0, 0); //enable this if it still flickers
 if cbxLetScroll.Checked then
  begin
   RxWindow1.Lines.Add(TimeToStr(Now));
   RxWindow1.selstart  := length(RxWindow1.text);
   RxWindow1.Perform(EM_SCROLL,SB_BOTTOM,0);
  end
   else
 begin
   //get the actually text view
   LineNumber := GetFirstVisibleLine(RxWindow1);
   TextPosition := SendMessage(RxWindow1.Handle, EM_LINEINDEX, LineNumber, 0);
   P := RxWindow1.CaretPos;
   SelectStart := RxWindow1.SelStart;
   SelectLen := RxWindow1.SelLength;
   ScrollPosVert  := GetScrollPos(RxWindow1.Handle, SB_VERT);
   ScrollPosHoriz := GetScrollPos(RxWindow1.Handle, SB_HORZ);
   RxWindow1.Lines.Add(TimeToStr(Now));
   //Reset first visible line to old position
   SendMessage(RxWindow1.Handle, EM_SETSEL, TextPosition, TextPosition);
   // Reset old caret position and possible selection
   RxWindow1.CaretPos := P;
   RxWindow1.SelStart := SelectStart;
   RxWindow1.SelLength:=SelectLen;
   SetScrollPos(RxWindow1.Handle, SB_VERT,ScrollPosVert,True);
   SetScrollPos(RxWindow1.Handle, SB_HORZ,ScrollPosHoriz,True);
   //RxWindow1.Perform(WM_SETREDRAW, 1, 0); //enable this if it still flickers
   RxWindow1.Lines.EndUpdate;
end;
end;

Open in new window


All the update is done on the procedure DoAddProc only, you may replace it in your code.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ejla51Author Commented:
Thanks for the tips - think I have to accept this solution - although the flickering problem is not resolved ...
The problem is bigger on slower computers - but I suspect that all the symptoms originated from the ActiveX module (ocx file) used to decoding signals from the sound card.

Perhaps flickering is not directly related to the writing process?

I'll wait a bit if it would be more tips how to go around this problem.

Happy New Year to all the freaks!
senadCommented:
On which OS are you trying to run this ?
ejla51Author Commented:
I'm using Windows XP-32 with Delphi 7.
I think the problem is close related to the Thread Syncronization (write to terminal window).
Have tested in the "flat" write process (not threaded) and seems to work better...

Functionality:

process received character:

rx.Chr := '';
Rx.Chr := Char( ComOCX.OnRxChar);  // Rx = Received, Tx = Transmitted
if not  printable(Rx.chr) then Exit else WriteChrToScreenWin(Rx.Chr);

The speed (baudrate) may vary between 10 - 300 baud

Ephraim WangoyaCommented:
The begin and end updates do not match here
procedure TfrmDigiTerm.DoAddProc;
var
  P: TPoint;
  SelectStart, SelectLen, ScrollPosVert , ScrollPosHoriz :Integer;
  TextPosition: LResult;
  LineNumber: Integer;
begin
 
 if cbxLetScroll.Checked then
 begin
   RxWindow1.Lines.BeginUpdate;
   RxWindow1.Lines.Add(TimeToStr(Now));
   RxWindow1.selstart  := length(RxWindow1.text);
   RxWindow1.Perform(EM_SCROLL,SB_BOTTOM,0);
   RxWindow1.Lines.EndUpdate;
 end
 else
 begin
   RxWindow1.Lines.BeginUpdate;
   //get the actually text view
   LineNumber := GetFirstVisibleLine(RxWindow1);
   TextPosition := SendMessage(RxWindow1.Handle, EM_LINEINDEX, LineNumber, 0);
   P := RxWindow1.CaretPos;
   SelectStart := RxWindow1.SelStart;
   SelectLen := RxWindow1.SelLength;
   ScrollPosVert  := GetScrollPos(RxWindow1.Handle, SB_VERT);
   ScrollPosHoriz := GetScrollPos(RxWindow1.Handle, SB_HORZ);
   RxWindow1.Lines.Add(TimeToStr(Now));
   //Reset first visible line to old position
   SendMessage(RxWindow1.Handle, EM_SETSEL, TextPosition, TextPosition);
   // Reset old caret position and possible selection
   RxWindow1.CaretPos := P;
   RxWindow1.SelStart := SelectStart;
   RxWindow1.SelLength:=SelectLen;
   SetScrollPos(RxWindow1.Handle, SB_VERT,ScrollPosVert,True);
   SetScrollPos(RxWindow1.Handle, SB_HORZ,ScrollPosHoriz,True);
   RxWindow1.Lines.EndUpdate;
end;

Open in new window

ejla51Author Commented:
Well... I can at last accept that my problem is not related in this function!
I have to accept jimyX helpful advices! Thanks
ejla51Author Commented:
ewangoya: yes... have made several experiments and BeginUpdate was needed here to redraw RichEdit! Thanks!
jimyXCommented:
Thanks
ejla51Author Commented:
More questions are coming soon :)
Ephraim WangoyaCommented:
We are always here to help anytime
ejla51Author Commented:
a little additional  notice to the above ...
In practice - any selection should of course be saved even if the last line IS visible ...
... and very important point - scrolling with the mouse wheel in TApplicationEvents.OnIdle works well - otherwise lot of madness.
 
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Editors IDEs

From novice to tech pro — start learning today.