【问题标题】:Translating WM_MOUSEWHEEL Delphi code to C++ Builder将 WM_MOUSEWHEEL Delphi 代码转换为 C++ Builder
【发布时间】:2013-07-08 15:38:48
【问题描述】:

我有这些代码链接:

WMMouseWheel not working in Delphi

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

将其翻译成 C++ Builder 但它不起作用:

更新:在缩小问题范围后,WM_MOUSEWHEEL 消息似乎不适用于未聚焦的TVirtualStringTree 控件,它们适用于其他控件。当焦点在例如TMemo 控制,其他TMemo 控制在滚轮上滚动,但不是TVirtualStringTree 控制。当焦点位于TVirtualStringTree 时,它会滚动TVirtualStringTree,但不会滚动其他控件。所以问题现在只针对TVirtualStringTree

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
            }
        }
    }
}

不同版本的类似代码,同样不行:

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;
        }
    }

它应该工作,但它没有。也尝试了其他代码。无效 - 鼠标滚轮不会在未聚焦的控件上运行。如您所见,我检查了所有 3 种滚轮消息变体,它在鼠标下得到了正确的控制,它显示了该控件名称但该控件没有收到滚轮消息。

任何想法我缺少哪一块拼图才能让它发挥作用?

【问题讨论】:

  • 目标控件是什么?它收到消息后会做什么?
  • VirtualTreeView 是目标控件。它什么也不做,滚动条不会在鼠标滚轮上移动。在 Delphi 中也可以使用相同的代码。
  • ApplicationEventsMessage 附属于什么?
  • 它被放到一个主窗体(TForm1)上。
  • 我相信我确实缩小了范围。在表单上放置了 2 个 TMemo 和 1 个 TListView 和 1 个 TVirtualStringTree 控件。当焦点位于TMemo 时,滚轮会滚动除TVirtualStringTree 之外的所有内容。当焦点位于 TVirtualStringTree 时,滚轮仅滚动 TVirtualStringTree,而不是其他未获得焦点的控件。

标签: c++ delphi c++builder virtualtreeview


【解决方案1】:

由于没有人提供任何适当的解决方案,我发布了自己的解决方案。该解决方案并不完美,但至少它完成了它需要做的事情——鼠标滚轮滚动它下面的所有控件,包括VirtualTreeView 控件。解决方案中的代码是C++,但Delphi版本非常相似(只需要翻译)。

我当前的解决方案是获取WM_MOUSEWHEEL 事件并将它们转换为WM_VSCROLLWM_HSCROLLVirtualTreeView 对此作出反应并滚动内容。此外,它需要考虑高精度鼠标滚轮,其值可能小于 WHEEL_DELTA(设置为 120)。最后,它需要考虑用户对滚动行数的设置(在 Windows 的控制面板中设置)。所以这里是:

TApplicationEvents 放入表单并在OnMessage 事件中执行以下操作:

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;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    相关资源
    最近更新 更多