Page 1 of 1

Scrollbar Popup Menu

Posted: Thu Jul 18, 2024 10:04 pm
by standay
Sergey,

Would you have any idea on how to get a popupmenu to show when the rve vertical scrollbar is right clicked? I've looked all over and tried things and nothing works. Just wondered if you had any ideas.

Thanks

Stan

Re: Scrollbar Popup Menu

Posted: Fri Jul 19, 2024 10:28 am
by Sergey Tkachenko
AFAIK, it can be implemented by handling WM_NCRBUTTONDOWN message in rve. But TRichView does not process this message, so it can be done only in an inherited component.
Or you can hide a scrollbar (VScrollVisible = False) and use your own external scrollbar instead.

Re: Scrollbar Popup Menu

Posted: Fri Jul 19, 2024 3:15 pm
by standay
Hi Sergey,

Yes, WM_NCRBUTTONDOWN (along with a HitTest check) works. My app already lets me choose between using a native scrollbar or an external one. Adding a popup to the external one is easy, but I was stumped with how to add it to the native scrollbar.

Here's what I did in case someone else wants to try it. I just subclassed the rve so I didn't have to make a new component:

Code: Select all

type
  TRichViewEdit = class( RVEdit.TRichViewEdit )
  private
    procedure WMNCRButtonDown(var Msg : TWMNCRButtonDown); message WM_NCRBUTTONDOWN;
  end;
...
//http://www.delphicorner.f9.co.uk/articles/forms3.htm
procedure TRichViewEdit.WMNCRButtonDown(var Msg : TWMNCRButtonDown);
begin
  if Form1.rve.VScrollVisible then
  if (Msg.HitTest = HTVSCROLL) then
  begin
    Form1.PopupMenu1.Popup( Mouse.CursorPos.X,Mouse.CursorPos.Y );
  end;
  if Form1.rve.HScrollVisible then
  if (Msg.HitTest = HTHSCROLL) then
  begin
    Form1.PopupMenu1.Popup( Mouse.CursorPos.X,Mouse.CursorPos.Y );
  end;
end;
Works great and is just what I was after. Thanks again.

Stan

Re: Scrollbar Popup Menu

Posted: Fri Jul 26, 2024 12:15 pm
by standay
Hi Sergey,

Probably no one cares about this but I thought I'd post a follow up. While subclassing the TRichViewEdit let me show a popupmenu when right-clicking the rve scrollbar, it was causing some unintended problems elsewhere in my app. It would work OK in a simple project, but my project is not a simple one.

So I did this instead. Since the rve sends the WM_NCRBUTTONDOWN out when its scrollbar is clicked, I handled that message in an appication events message event instead of the rve itself.

Code: Select all

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  Pt: TPoint;
  r: TRect;
begin

  //Processing WM_NCRBUTTONDOWN this way let me put a popupmenu on the native OS scrollbar.
  //Panel7 is the rve parent component
  Pt := Panel7.ScreenToClient( Mouse.CursorPos );
  r := Panel7.ClientRect;
  if Msg.message = WM_NCRBUTTONDOWN then
  begin
    r := Panel7.ClientRect;
    //Restrict this to just the vertical scrollbar:
    r.Left := r.Right - GetSystemMetrics( SM_CYVSCROLL );
    if PtInRect( r, Pt ) then
    begin
      //ReleaseCapture; //So far, not needed...
      //Only show the scroll popup if the native OS scrollbar is visible:
      if Form1.rve.VScrollVisible then
      begin
        //Use if VScrollMax > 0 here if you only want to show the popup
        //if it is active.
        ScrollPopup.Popup( Mouse.CursorPos.X,Mouse.CursorPos.Y );
      end;
      //The key to making this work: Shut off this message:
      Handled := true;
    end;
  end;
This now works without subclassing or making a new component. Maybe it will help someone else wanting to do this.

Stan