[英]Translating WM_MOUSEWHEEL Delphi code to C++ Builder
I have these links with code: 我有这些代码链接:
WMMouseWheel not working in Delphi WMMouseWheel在Delphi中不起作用
How to disable MouseWheel if mouse is not over VirtualTreeView (TVirtualStringTree) 如果鼠标不在VirtualTreeView(TVirtualStringTree)上,如何禁用MouseWheel
Translated it to C++ Builder but it doesn't work: 将其翻译为C ++ Builder,但不起作用:
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. 更新:缩小问题范围后,似乎WM_MOUSEWHEEL消息仅对未聚焦的
TVirtualStringTree
控件起作用,而对其他控件起作用。 When focus is on eg TMemo
control, other TMemo
control scrolls on wheel but not TVirtualStringTree
control. 当焦点集中在
TMemo
控件上时,其他TMemo
控件在滚轮上滚动而不是TVirtualStringTree
控件。 When focus is on TVirtualStringTree
it scrolls TVirtualStringTree
but not other controls. 当焦点在
TVirtualStringTree
它将滚动TVirtualStringTree
但不滚动其他控件。 So the problem is now specific to TVirtualStringTree
only. 因此,该问题现在仅特定于
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
}
}
}
}
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.
如您所见,我检查了Wheel消息的所有3个变体,它在鼠标下获得了正确的控件,它显示了控件名称,但控件未接收到Wheel消息。
Any ideas what piece of the puzzle am I missing to get it to work? 有什么主意我想让它起作用的难题是哪一个?
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. 该解决方案并不完美,但至少可以完成所需的工作-鼠标滚轮滚动其下的所有控件,包括
VirtualTreeView
控件。 The code in solution is in C++ but Delphi version is very similar (it only needs to be translated). 解决方案中的代码是C ++,但是Delphi版本非常相似(只需要翻译)。
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. 我当前的解决方案是获取
WM_MOUSEWHEEL
事件并将其转换为VirtualTreeView
对其进行VirtualTreeView
并滚动内容的WM_VSCROLL
或WM_HSCROLL
。 Additionally, it needs to take into account high-precision mouse wheels which can have smaller value than WHEEL_DELTA (which is set to 120). 此外,它需要考虑高精度鼠标滚轮,该滚轮的值可能小于WHEEL_DELTA(设置为120)。 Finally, it needs to take into account user setting for number of lines to scroll (set in Control Panel in Windows).
最后,它需要考虑用户设置的滚动行数(在Windows的“控制面板”中设置)。 So here goes:
因此,这里去:
Put a TApplicationEvents
to a form and in the OnMessage
event do this: 将
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;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.