Question

I have these links with code:

WMMouseWheel not working in Delphi

How to disable MouseWheel if mouse is not over VirtualTreeView (TVirtualStringTree)

Translated it to C++ Builder but it doesn't work:

UPDATE: After narrowing the problem down it appears that WM_MOUSEWHEEL messages don't work over unfocused TVirtualStringTree control only, they work over other controls. When focus is on e.g. TMemo control, other TMemo control scrolls on wheel but not TVirtualStringTree control. When focus is on TVirtualStringTree it scrolls TVirtualStringTree but not other controls. So the problem is now specific to TVirtualStringTree only.

void __fastcall TForm1::ApplicationEventsMessage(tagMSG &Msg, bool &Handled)
{
TPoint Pt;
HWND   Wnd;

if (Msg.message == WM_MOUSEWHEEL ||
    Msg.message == WM_VSCROLL    ||
    Msg.message == WM_HSCROLL)
    {
    if (GetCursorPos(&Pt))
        {
        Wnd = WindowFromPoint(Pt);
        // It must be a VCL control otherwise we could get access violations
        if (IsWindowEnabled(Wnd) && FindControl(Wnd) != NULL)
            {
            Msg.hwnd = Wnd; // change the message receiver to the control under the cursor
            }
        }
    }
}

Different version of the similar code, also doesn't work:

TPoint       pnt;
TWinControl *ctrl;

if ((Msg.message == WM_MOUSEWHEEL ||
     Msg.message == WM_VSCROLL    ||
     Msg.message == WM_HSCROLL) &&
    GetCursorPos(&pnt))
    {
    ctrl = FindVCLWindow(pnt);
    if (ctrl != NULL)
        {
        SendMessage(ctrl->Handle, Msg.message, Msg.wParam, Msg.lParam); // No effect
//      SendMessage(ctrl->Handle, WM_VSCROLL, 1, 0); // This is the only thing that actually moves scrollbars but this is not exactly the same message like above

//      Msg.hwnd = ctrl->Handle; // No effect
        this->Caption=ctrl->Name; // This shows correct control name so the message IS GETTING THROUGH!
        Handled = true;
        }
    }

It should work but it doesn't. Tried other code as well. No effect - mouse wheel does not operate on unfocused control. As you can see, I checked for all 3 variants of wheel messages, it gets correct control under the mouse, it shows that control name but the control doesn't receive wheel messages.

Any ideas what piece of the puzzle am I missing to get it to work?

Was it helpful?

Solution

As nobody offered any proper solution, I am posting my own. The solution is not perfect but at least it does what it needs to do - mouse wheel scrolls all controls under it, including the VirtualTreeView controls. The code in solution is in C++ but Delphi version is very similar (it only needs to be translated).

My current solution is to grab WM_MOUSEWHEEL events and translate them into WM_VSCROLL or WM_HSCROLL to which VirtualTreeView reacts and scrolls the content. Additionally, it needs to take into account high-precision mouse wheels which can have smaller value than WHEEL_DELTA (which is set to 120). Finally, it needs to take into account user setting for number of lines to scroll (set in Control Panel in Windows). So here goes:

Put a TApplicationEvents to a form and in the OnMessage event do this:

void __fastcall TFormMain::ApplicationEventsMessage(tagMSG &Msg, bool &Handled)
{
// Check these 3 messages because some mouse drivers may use VSCROLL instead of MOUSESWHEEL message
if (Msg.message == WM_MOUSEWHEEL || Msg.message == WM_VSCROLL || Msg.message == WM_HSCROLL)
    {
    TPoint       pnt;
    TWinControl *ctrl;

    if (!GetCursorPos(&pnt)) return;

    ctrl = FindVCLWindow(pnt);

    if (ctrl != NULL)
        {
// ToDo: implement if user needs wheel-click - then we also need KEYSTATE but for this example it is not needed
//      int fwKeys = GET_KEYSTATE_WPARAM(Msg.wParam);
        int      zDelta  = GET_WHEEL_DELTA_WPARAM(Msg.wParam),
                 pvParam = 3;                                                   // Windows default value
        unsigned MyMsg   = WM_VSCROLL;


// ToDo: extract SystemParametersInfo somewhere else so it is not extracted for each WM_MOUSEWHEEL message which may not be needed
        switch (Msg.message)
            {
            // This will translate WM_MOUSEWHEEL into WM_VSCROLL
                    case WM_MOUSEWHEEL:
            case WM_VSCROLL:
    // Windows setting which determines how many lines to scroll - we'll send that many WM_VSCROLL or WM_HSCROLL messages
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &pvParam, 0);
                                MyMsg = WM_VSCROLL;
                                break;
            case WM_HSCROLL:    
      // Same as above but for WM_HSCROLL (horizontal wheel)
      SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &pvParam, 0);
                                MyMsg = WM_HSCROLL;
                                break;
            }

        // This calculation takes into account high-precision wheels with delta smaller than 120
        // Possible TODO: Round up values smaller than 1 (e.g. 0.75 * pvParam) if pvParam is 1
        int ScrollBy = ((double)zDelta / (double)WHEEL_DELTA) * pvParam;

        // Send multiple messages based on how much the zDelta value was
        if (zDelta > 0)
            {
            do
                {
                SendMessage(ctrl->Handle, MyMsg, SB_LINEUP, 0);
                }
            while (--ScrollBy > 0);
            }
        else
            {
            do
                {
                SendMessage(ctrl->Handle, MyMsg, SB_LINEDOWN, 0);
                }
            while (++ScrollBy < 0);
            }

        Handled = true;
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top