Search code examples
delphidelphi-xe4

How to defocus a child TButton for TScrollbox to scroll with mousewheel


Requirements

  1. Dynamically created buttons (a lot of).
  2. Wordwrap essential since caption length not known beforehand (TSpeedButton no good).

Code to scroll the TScrollBox by mouse wheel is given below and resides in the Form's OnMouseWheel event. When the cursor stays static over a button, it gets the orange (XP) rectangle and doesn't scroll the TScrollBox. Seems like all other mouse movement events are there except for this particular case.

If WindowFromPoint( mouse.Cursorpos ) = scrlbx1.Handle Then Begin
  Handled := true;
  If ssShift In Shift Then
    msg := WM_HSCROLL
  Else
    msg := WM_VSCROLL;

  If WheelDelta > 0 Then
    code := SB_LINEUP
  Else
    code := SB_LINEDOWN;

  n:= Mouse.WheelScrollLines;
  For i:= 1 to n Do
    scrlbx1.Perform( msg, code, 0 );
  scrlbx1.Perform( msg, SB_ENDSCROLL, 0 );
End;

Any workaround will be appreciated.


Solution

  • Your problem is not that of buttons have focus, it is that your code does not account for the case when mouse pointer is on a button.

    If WindowFromPoint( mouse.Cursorpos ) = scrlbx1.Handle Then Begin
    

    The condition in the above statement will not be true when the mouse is on a button. WindowFromPoint will return the button handle, hence the rest of the code will not execute.

    You have to correct your code to account for mouse can be on another control. BTW, the event handler already passes the mouse position, use that instead of retrieving the position again - potentially even a different position. An example can be:

    GetWindowRect(scrlbx1.Handle, Rect);
    if PtInRect(Rect, MousePos) then begin
      ..
    


    Focus is not a problem, VCL propagates the wheel message in the parent chain until it is handled.