У меня есть эти ссылки с кодом:
WMMouseWheel не работает в Delphi
Как отключить MouseWheel, если мышь не находится над 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
управления. Код в решении написан на C ++, но версия Delphi очень похожа (ее нужно только перевести).
Мое текущее решение состоит в том, чтобы захватить WM_MOUSEWHEEL
события и перевести их в WM_VSCROLL
или же WM_HSCROLL
которому VirtualTreeView
реагирует и прокручивает содержимое. Кроме того, необходимо учитывать колеса мыши высокой точности, которые могут иметь меньшее значение, чем 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;
}
}
}
Других решений пока нет …