WIN32 API 中 WM_MOUSEHOVER 上的弹出窗口 - 如何关闭它?

Posted

技术标签:

【中文标题】WIN32 API 中 WM_MOUSEHOVER 上的弹出窗口 - 如何关闭它?【英文标题】:POPUP Window on WM_MOUSEHOVER in WIN32 API - how to close it? 【发布时间】:2014-12-03 13:27:59 【问题描述】:

我是 WIN32 API 的新手,下面显示的代码有问题,这是来自我的 WinProc 函数:当鼠标光标在我的窗口中停留一段时间时,我使用带有 TME_HOVER 的 TrackMouseEvent 来获取 WM_MOUSEHOVER。如果我在每个 WM_MOUSEMOVE 上调用 TrackMouseEvent,这可行,但如果我只在其他地方调用一次,则不行。为什么? (这是第一个问题)

当我收到 WM_MOUSEHOVER 时,我创建了一个可以看到的 POPUP 窗口,然后再次为 TME_LEAVE 调用 TrackMouseEvent。这有效,当鼠标光标离开我的窗口时我收到 WM_MOUSELEAVE,然后我想隐藏并销毁弹出窗口(我存储在静态变量中的 HWND)但这不起作用,弹出窗口留在那里。为什么? (这是第二个问题)

谁能给我一个示例或链接到一个显示 TrackMouseEvent 和 PopUp 窗口的简单示例?非常感谢。

case WM_MOUSEMOVE:
    
        TRACKMOUSEEVENT tme;
        tme.cbSize = sizeof(TRACKMOUSEEVENT);
        tme.dwFlags = TME_HOVER;
        tme.hwndTrack = hSBox;
        TrackMouseEvent(&tme);
    
    break;

case WM_MOUSEHOVER:
    
        hPop = CreateWindowEx(WS_EX_STATICEDGE, //WS_EX_CLIENTEDGE,
                              TEXT("STATIC"),
                              TEXT("pop-up"),
                              WS_POPUP | WS_BORDER, 
                              100, 100, 100, 100,
                              hWnd, (HMENU)0, hInstance, NULL);
        ShowWindow(hPop, SW_SHOW);

        TRACKMOUSEEVENT tme;
        tme.cbSize = sizeof(TRACKMOUSEEVENT);
        tme.dwFlags = TME_LEAVE;
        tme.hwndTrack = hSBox;
        TrackMouseEvent(&tme);
    
    return 0;

case WM_MOUSELEAVE:
    
       ShowWindow(hPop, SW_HIDE);
       DestroyWindow(hPop);
    
    return 0;

【问题讨论】:

为什么不只创建一次窗口,并在悬停时显示/在离开时隐藏? 有趣的反对意见,我猜这意味着使用 TOOLTIPS_CLASS?尽管如此,使用此处显示的代码,您可能对显示的文本有更多的控制权,并且可以更好地改变它吗?我不知道。 好吧,更好的说法是,你的评论显然是正确的。 【参考方案1】:

对了,我也发现我想做的,用windows TOOLTIPS_CLASS也可以做到。

我为此找到的最值得推荐的链接是:

http://winapi.foosyerdoos.org.uk/info/common_cntrls.php#CreateTooltip

https://github.com/wine-mirror/wine/blob/master/dlls/comctl32/tooltips.c

Unicode tooltips not showing up

【讨论】:

【参考方案2】:

我可以看到两个问题:

TME_HOVER 的问题是因为您没有初始化 dwHoverTime 成员;您应该将其设置为HOVER_DEFAULT。否则,悬停超时将设置为堆栈上的任何随机值。

您的第二个问题是对TrackMouseEvent 的每次调用都会覆盖前一次调用。因为您在每条WM_MOUSEMOVE 消息上都调用TrackMouseEvent,所以TME_LEAVE 调用很快就会被您的下一个TME_HOVER 调用覆盖。

解决方案是在WM_MOUSEMOVE 处理程序中使用某种标志,这样当鼠标第一次进入您的窗口时,您只需调用一次TrackMouseEvent。当您收到 WM_MOUSEHOVERWM_MOUSELEAVE 消息时,跟踪将被取消,因此在这些点您将重置标志,以便下次收到 WM_MOUSEMOVE 时,您可以在必要时重新启动它。

// note: BOOL g_fMouseTracking needs to be declared in the same place
// hPop is

case  WM_MOUSEMOVE:
    if (!g_fMouseTracking && !hPop)
    
        // start tracking if we aren't already
        TRACKMOUSEEVENT tme;
        tme.cbSize = sizeof(TRACKMOUSEEVENT);
        tme.dwFlags = TME_HOVER | TME_LEAVE;
        tme.hwndTrack = hSBox;
        tme.dwHoverTime = HOVER_DEFAULT;
        g_fMouseTracking = TrackMouseEvent(&tme);
    
    break;

case  WM_MOUSEHOVER:
    g_fMouseTracking = FALSE; // tracking now cancelled
    if (!hPop)
    
        hPop = CreateWindowEx(WS_EX_STATICEDGE, //WS_EX_CLIENTEDGE,
                              TEXT("STATIC"),
                              TEXT("pop-up"),
                              WS_POPUP | WS_BORDER, 
                              100, 100, 100, 100,
                              hWnd, (HMENU)0, hInstance, NULL);
        ShowWindow(hPop, SW_SHOW);

        // set up leave tracking
        TRACKMOUSEEVENT tme;
        tme.cbSize = sizeof(TRACKMOUSEEVENT);
        tme.dwFlags = TME_LEAVE;
        tme.hwndTrack = hSBox;
        g_fMouseTracking = TrackMouseEvent(&tme);
    
    return 0;

case  WM_MOUSELEAVE:
    g_fMouseTracking = FALSE; // tracking now cancelled
    if (hPop)
    
        // close popup if it's open
       ShowWindow(hPop, SW_HIDE);
       DestroyWindow(hPop);
       hPop = NULL;
    
    return 0;

【讨论】:

谢谢,您修改后的代码运行良好!不是 HOVER_DEFAULT 是我的问题(我有它,虽然不在我粘贴在这里的代码中)但缺少检查“if (!g_fMouseTracking && !hPop)”是我的问题。 也感谢这个例子说明如何更好地注释源代码

以上是关于WIN32 API 中 WM_MOUSEHOVER 上的弹出窗口 - 如何关闭它?的主要内容,如果未能解决你的问题,请参考以下文章

.net API 与win32API

汇编中的win32 api帮助

当前 Windows 版本中的 Win32 API 是不是仍然“原生”?

win32api:在文本行中合并位图

Win32API 结构中 cbSize 成员的用途是啥

python可以直接调用win32的api吗