2

私はこれらのコードとのリンクを持っています:

WMMouseWheel が Delphi で動作しない

マウスが VirtualTreeView (TVirtualStringTree) 上にない場合に MouseWheel を無効にする方法

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 つのバリアントすべてをチェックしました。マウスの下で正しいコントロールが得られ、コントロール名が表示されますが、コントロールはホイール メッセージを受信しません。

それを機能させるために欠けているパズルのピースはありますか?

4

1 に答える 1

1

誰も適切な解決策を提供しなかったので、私は自分自身を投稿しています。解決策は完璧ではありませんが、少なくとも必要なことは実行します。マウス ホイールは、コントロールを含め、その下にあるすべてのコントロールをスクロールしVirtualTreeViewます。ソリューションのコードは C++ ですが、Delphi のバージョンは非常に似ています (翻訳する必要があるだけです)。

私の現在の解決策は、イベントを取得し、WM_MOUSEWHEELそれらを変換して、コンテンツに反応してスクロールすることです。さらに、WHEEL_DELTA (120 に設定) よりも小さい値を持つことができる高精度のマウス ホイールを考慮する必要があります。最後に、スクロールする行数のユーザー設定 (Windows のコントロール パネルで設定) を考慮する必要があります。だからここに行きます:WM_VSCROLLWM_HSCROLLVirtualTreeView

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;
        }
    }
}
于 2013-07-12T18:38:39.487 に答える