Win32:测试鼠标是否停留了一秒钟
Win32: Test if mouse has hovered for a second
我试图使一个函数,只有当鼠标停留在同一地方的时间增加而不停止程序时才运行(所以没有Sleep(1000)
函数)。我试图做的是让回调在鼠标移动时运行paint中的一个函数。在这个函数中,会有一个while循环来确保鼠标在最后一帧之后没有移动,如果点击或移动就会中断。
在回调中:
case WM_MOUSEMOVE:
POINT pt;
GetCursorPos(&pt);
ScreenToClient(hWnd, &pt);
iPosX = pt.x;
iPosY = pt.y;
if (!mouseMoved) {
mouseMoved = true;
period = 0;
InvalidateRect(hWnd, 0, FALSE);
}
break;
In the Paint:
if (mouseMoved && !MouseClicked) {
test.newBit(1, 100, 0, hdc); //Draws a picture as a test
oldx = iPosX;
oldy = iPosY;
period = 0;
while (period <= 1000000 && !MouseClicked) {
oldx = iPosX;
oldy = iPosY;
POINT pt;
GetCursorPos(&pt);
ScreenToClient(hWnd, &pt);
iPosX = pt.x;
iPosY = pt.y;
if (iPosX != oldx || iPosY != oldy) {
mouseMoved = false;
period = 0;
break;
}
period++;
}
if (period <= 1000000) {
period = 0;
test.newBit(0, 0, 0, hdc); //Draws a picture as a test
mouseMoved = false;
}
}
当您移动鼠标并单击时,会产生随机闪烁。如果你能指出我做错了什么,我将不胜感激。
系统已经为您实现了这个功能。你只需要通过调用TrackMouseEvent:
来请求鼠标悬停消息TRACKMOUSEEVENT tme = { sizeof( tme ) };
tme.dwFlags = TME_HOVER;
tme.hwndTrack = hWnd;
tme.dwHoverTime = 1000;
::TrackMouseEvent( &tme );
应用程序接收到一个WM_MOUSEHOVER消息,当光标悬停在窗口的客户端区域上一段在调用TrackMouseEvent
中指定的时间。悬停跟踪停止,一旦WM_MOUSEHOVER
消息产生。为了接收更多的WM_MOUSEHOVER
消息,应用程序需要重新请求悬停跟踪(使用与上面相同的代码)。
应用程序可以调用SystemParametersInfo并使用SPI_GETMOUSEHOVERTIME
来检索默认的悬停超时
注意,这考虑了悬停矩形(SPI_GETMOUSEHOVERWIDTH
和SPI_GETMOUSEHOVERHEIGHT
)。这是一个鼠标光标周围的区域,允许鼠标移动到其中,而不需要重置悬停超时。
如果您需要一个解决方案,只报告鼠标没有移动时的悬停,您将不得不自己实现它。基于计时器的解决方案是一个干净的解决方案。
每当鼠标移动时,我们需要重置计时器。如果鼠标之前在窗口的客户端区域之外,我们还必须重新请求WM_MOUSELEAVE
消息。这是必要的,以便在鼠标离开客户端区域时取消计时器:
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) {
enum TimerId { TimerId_MouseHover = 1 };
static const UINT HoverTimeoutInMs = 1000;
static int PrevX = INT_MIN;
static int PrevY = INT_MIN;
static bool IsMouseOutside = true;
static bool IsMouseHovered = false;
switch ( message ) {
case WM_MOUSEMOVE: {
// If mouse was previously outside, re-request WM_MOUSELEAVE messages
if ( IsMouseOutside ) {
TRACKMOUSEEVENT tme = { sizeof( tme ) };
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hWnd;
::TrackMouseEvent( &tme );
IsMouseOutside = false;
}
int CurrX = GET_X_LPARAM( lParam );
int CurrY = GET_Y_LPARAM( lParam );
if ( ( CurrX != PrevX ) || ( CurrY != PrevY ) ) {
// Mouse moved -> reset timer
::SetTimer( hWnd, TimerId_MouseHover, HoverTimeoutInMs, nullptr );
PrevX = CurrX;
PrevY = CurrY;
IsMouseHovered = false;
// For testing only:
::InvalidateRect( hWnd, nullptr, FALSE );
}
return 0;
}
每当鼠标离开客户端区域时,我们需要取消计时器。如果我们不取消计时器,它将过期,即使当鼠标移动到窗口的客户端区域之外:
case WM_MOUSELEAVE:
::KillTimer( hWnd, TimerId_MouseHover );
IsMouseOutside = true;
PrevX = INT_MIN;
PrevY = INT_MIN;
return 0;
如果我们的计时器到期,我们有一个悬停事件:
case WM_TIMER:
if ( wParam == TimerId_MouseHover ) {
// The mouse hasn't been moved for the specified timeout:
// This is a hover event
IsMouseHovered = true;
// For testing only:
::InvalidateRect( hWnd, nullptr, FALSE );
return 0;
}
else {
return ::DefWindowProc( hWnd, message, wParam, lParam );
}
作为测试,让我们用黑色笔刷填充客户端区域,每当悬停超时:
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint( hWnd, &ps );
::FillRect( hdc, &ps.rcPaint, GetStockBrush( IsMouseHovered ? BLACK_BRUSH :
WHITE_BRUSH ) );
EndPaint( hWnd, &ps );
return 0;
}
- 使用strcpy将char数组的元素复制到另一个数组
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 在 c++ 中拥有一组结构的正确方法是什么?
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何将三维尺寸不固定的三维阵列展平为一维阵列
- nlohmann-json将一个数组插入到另一个数组中
- redis_client::get 需要一秒钟以上的时间来回复
- 执行/在循环中停留一段时间,例如 1 分钟
- 在不到一分钟的情况下,在一秒钟内显示计时器
- 使用结构显示军事时间,并将一秒钟的时间添加到用户输入(C )中
- 每隔几秒钟移动一次对象
- 一秒钟后,OpenCV窗口消失了
- 随着时间的推移,每几秒钟喷一次精灵SFML C++
- WinSock closesocket() 调用在某些计算机上需要一秒钟
- Win32控制台在一秒钟后消失
- 输出屏幕停留一秒钟
- 一秒钟计时器
- 一秒钟有多少个滴答声
- Win32:测试鼠标是否停留了一秒钟