Solved

Access ScrollBars in TRichEdit

Posted on 2011-03-04
14
794 Views
Last Modified: 2012-05-11
I need to move something as I scroll in a RichEdit. I don't seem to have access to the scrollbars (height, position, etc). How can I tell where the ScrollBar is in relation to my text?
0
Comment
Question by:TracerXXX
  • 5
  • 4
  • 4
  • +1
14 Comments
 
LVL 32

Expert Comment

by:ewangoya
ID: 35039094
use the ScrollBars property to show scrollbars or in code you can write

TForm1.FormCreate(Sender: TObject);
begin
  RichEdit1.ScrollBars := ssBoth
end;
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 35039114
From Object Inspector - Properties
RichEditScrollBars.PNG
0
 
LVL 3

Expert Comment

by:pasolo
ID: 35039180
I am afraid you need to go through the Windows API to find the position.
GetScrollInfo

For example:

var
info : TSCROLLBARINFO;
n : integer;
begin
info.cbSize := SizeOf(TSCROLLBARINFO);

GetScrollBarInfo( RichEdit.Handle, OBJID_VSCROLL, info);
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
LVL 24

Expert Comment

by:jimyX
ID: 35042043
To get the ScrollBar height or position:
procedure TForm1.Button1Click(Sender: TObject);
var
  ScrlBrPos : integer;
begin
  ScrlBrPos := GetScrollPos(RichEdit1.Handle, SB_VERT);
  Showmessage(IntToStr(ScrlBrPos));
end;

Open in new window

0
 
LVL 24

Expert Comment

by:jimyX
ID: 35042067
If you want to scroll the RichEdit according to the text:
procedure Find_a_Text(TheText: string);
var FoundPos: integer;
begin
// Perfom the search action, foundpos is the starting point of the found text
FoundPos := RichEdit1.FindText(TheText, 0, Length(RichEdit1.Text), []);
if not (FoundPos < 0)
   then begin

// These show found text as selected
        RichEdit1.SelStart := FoundPos;
        RichEdit1.SelLength := Length(TheText);

// If the found text is outside the displayed portion of the text
// this instruction performs an automatic scroll.
        RichEdit1.Perform(EM_SCROLLCARET, 0, 0);

// Make sure the control is redrawn
        RichEdit1.Invalidate;
        end;
end;

Open in new window

http://www.delphi3000.com/articles/article_2410.asp?SK=
0
 

Author Comment

by:TracerXXX
ID: 35056661
Some Detail: My RichEdit has a TPanel next to it (along the left side) that will hold TImages. The Panel needs to move with the vert scrollbar of the RichEdit. The images are blue balls to indicate breakpoints in the RichEdit Text (see below):

 RichEdit and Panel
I created a new TRichEdit so I could surface the scroll meesages and create OnScroll Events. In the OnVertScroll event I get the scroll position (thanks jimyX) and change Panel.Top so it moves with the RichEdit. The problem is the Panel only moves on the MouseUp, not dynamically during the scrolling.

The event is firing when it should (I can increment a counter and watch it change), it just seems that the value of GetScrollPos() doesn't change until MouseUp. Any ideas?
0
 
LVL 24

Expert Comment

by:jimyX
ID: 35056780
Since the event is firing try to Refresh or Update the Panel or the view thier. Or you can try "Application.ProcessMessages;"
0
 

Author Comment

by:TracerXXX
ID: 35056823
I previously had tried both. I can update a counter and write it to my form caption and it updates as I scroll, but if I do the same thing with GetScrollPos, it only updates on mouse up. So it doesn't seem to be a refresh problem. The issue seems to be with the GetScrollPos.

I'd send some code but I left it at another location.
0
 
LVL 24

Expert Comment

by:jimyX
ID: 35057084
I can't test code at the moment neither, but I would try "invalidate" as well at "OnVertScroll" I am not sure though if it works.

Have you considered another approaches?
Such as using "OnMouseMove" of the Form while the mouse is pressed. So you set a flag in "OnVertScroll" to true and when the mouse moves while the flag is true set the Panel.Top value at "OnMouseMove".

Or use Canvas Draw "Canvas.Ellipse(x,y,x+30,y+30);" after setting the desired color and everything else, instead of using the Panel, so whenever you Scroll you are going to draw on the canvas at the location you set.

Once I have Delphi in hand will try those scenarios.
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 35066911
Sorry I did not initially understand your question.

To get scroll bar events, you have to trap the messages being sent to the component. Create a new windowproc method, Try this
TForm3 = class(TForm)
    RichEdit1: TRichEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FOldRichEditProc: TWndMethod;
    procedure RichEditProc(var Message: TMessage);
  public
    { Public declarations }
  end;

implementation

procedure TForm3.FormCreate(Sender: TObject);
begin
  FOldRichEditProc := RichEdit1.WindowProc;
  RichEdit1.WindowProc := RichEditProc;
end;

procedure TForm3.FormDestroy(Sender: TObject);
begin
  RichEdit1.WindowProc := FOldRichEditProc;
end;

procedure TForm3.RichEditProc(var Message: TMessage);
var
  Position: Integer;
begin
  if (csDestroying in ComponentState) then
    Exit;

  FOldRichEditProc(Message);  //make sure message is handled properly

  //here you need to trap your messages, it may not only be scroll message
  // you can find the message in Windows
  //example
  //if Message.Msg = WM_VSCROLL then
  //begin
    //Here its your choice, you can look for specific scrollbar messages
    {case Message.wParamLo of
      SB_LINEDOWN, SB_LINEUP, SB_PAGEDOWN, SB_PAGEUP:
      begin
        Position := GetScrollPos(RichEdit1.Handle, SB_VERT);
        Caption := IntToStr(Position);
      end;
    end;}   
  //end;

  Position := GetScrollPos(RichEdit1.Handle, SB_VERT); //there maybe a better way here
  //Add your code to move the Panel in relation to scroll position
  Caption := IntToStr(Position);
end;

Open in new window

0
 

Author Comment

by:TracerXXX
ID: 35073991
ewanqoya,

I tried your method in place of my method and the results are the same. GetScrollPos only updates (Caption incremented) on MouseUp. Your comment in your code "there may be a better way here" says it all. GetScrollPos does not work as expected and I need a better way.

I appreciate the help you and jimyX are giving me.
0
 
LVL 32

Accepted Solution

by:
ewangoya earned 500 total points
ID: 35078296

Ok, seems GetScrollPos really does not return if the thumbtrack is pressed.
For that  I've overriden the WMVScroll method

This will detect the position when the ThumbTrack is dragged.
You have to use them in combination with the previous code.
Here is the code a simple program, it just outputs the scrollbar position in a memo, you will replace that with your code to synchronize the Panel
unit Unit3;

interface

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

type
  TScrollEvent = procedure(Sender: TObject; AScrollCode, APos: Integer) of Object;

  TRichEdit = class(ComCtrls.TRichEdit)
  private
    FScrollEvent: TScrollEvent;
    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
  end;

  TForm3 = class(TForm)
    RichEdit1: TRichEdit;
    Memo1: TMemo;
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    FOldRichEditProc: TWndMethod;
    procedure DoScroll(Sender: TObject; AScrollCode, APos: Integer);
    procedure RichEditProc(var Message: TMessage);
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.DoScroll(Sender: TObject; AScrollCode, APos: Integer);
begin
  Memo1.Lines.Add(IntToStr(APos));
end;

procedure TForm3.FormDestroy(Sender: TObject);
begin
  RichEdit1.WindowProc := FOldRichEditProc;
end;

procedure TForm3.FormShow(Sender: TObject);
begin
  FOldRichEditProc := RichEdit1.WindowProc;
  RichEdit1.WindowProc := RichEditProc;
  RichEdit1.FScrollEvent := DoScroll;
end;

procedure TForm3.RichEditProc(var Message: TMessage);
var
  Position: Integer;
begin
  if (csDestroying in ComponentState) then
    Exit;

  FOldRichEditProc(Message);  //make sure message is handled properly

  if Message.Msg = WM_VSCROLL then
    case Message.wParamLo of
      SB_LINEUP,
      SB_LINEDOWN,
      SB_PAGEUP,
      SB_PAGEDOWN,
      SB_TOP,
      SB_BOTTOM,
      SB_ENDSCROLL:
      begin
        Position := GetScrollPos(RichEdit1.Handle, SB_VERT);
        DoScroll(RichEdit1, Message.wParamLo, Position);
      end;
    end;
end;

{ TRichEdit }

procedure TRichEdit.WMVScroll(var Message: TWMVScroll);
begin
  inherited;
  if (Message.ScrollCode in [SB_THUMBTRACK, SB_THUMBPOSITION]) then
    FScrollEvent(Self, Message.ScrollCode, Message.Pos);
end;

end.

Open in new window

Unit3.dfm
Unit3.pas
0
 

Author Comment

by:TracerXXX
ID: 35084600
ewanqoya,

I rolled in your code and I'm very close. my panel moves with the Scroll properly now. The only issue I have is an "invalid handle" exception (code: 1400) on exit of the application. Since I don't fully understand your code I'm not sure where the error is occuring. I've attached the code if you wouldn't mind taking a look.

 NewRichEdit.pas Unit3.pas Unit3.dfm
unit Unit3;

interface

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

type
  TForm3 = class(TForm)
    NewRichEdit1: TNewRichEdit;
    pnlBreak: TPanel;
    Image1: TImage;
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
    FOldRichEditProc: TWndMethod;
    procedure DoScroll(Sender: TObject; AScrollCode, APos: Integer);
    procedure RichEditProc(var Msg: TMessage);
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

{----------------------------------------------------------------------}
procedure TForm3.FormShow(Sender: TObject);
begin
  SetScrollPos(NewRichEdit1.Handle, SB_VERT, 0, True);
  FOldRichEditProc := NewRichEdit1.WindowProc;
  NewRichEdit1.WindowProc := RichEditProc;
  NewRichEdit1.OnScrollEvent := DoScroll;
end;

{----------------------------------------------------------------------}
procedure TForm3.DoScroll(Sender: TObject; AScrollCode, APos: Integer);
begin
   pnlBreak.Top:=(APos * -1) + NewRichEdit1.Top;
end;

{----------------------------------------------------------------------}
procedure TForm3.RichEditProc(var Msg: TMessage);
var
  Position: Integer;
begin
  if (csDestroying in ComponentState) then
    Exit;

  FOldRichEditProc(Msg);  //make sure message is handled properly

  if Msg.Msg = WM_VSCROLL then
    case Msg.wParamLo of
      SB_LINEUP,
      SB_LINEDOWN,
      SB_PAGEUP,
      SB_PAGEDOWN,
      SB_TOP,
      SB_BOTTOM,
      SB_ENDSCROLL:
      begin
        Position := GetScrollPos(NewRichEdit1.Handle, SB_VERT);
        DoScroll(NewRichEdit1, Msg.wParamLo, Position);
      end;
    end;
end;

end.

Open in new window

0
 
LVL 32

Expert Comment

by:ewangoya
ID: 35084704

on FormDestroy, you need to reassign the old window proc

procedure TForm3.FormDestroy(Sender: TObject);
begin
  NewRichEdit1.WindowProc := FOldRichEditProc;
end;
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say 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

Suggested Solutions

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…

856 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