我的对话框来自CDialog,我希望一旦用户将鼠标光标移离它就关闭它。为此,我添加了OnMouseLeave处理程序,它调用OnCancel()。据我了解,要及时发送WM_MOUSELEAVE事件,必须在OnMouseMove例程内调用TrackMouseEvent。所以整个代码如下:
void CDlgMain::OnMouseLeave()
{
CDialog::OnMouseLeave();
// Close dialog when cursor is going out of it
OnCancel();
}
void CDlgMain::OnMouseMove(UINT nFlags, CPoint point)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
CDialog::OnMouseMove(nFlags, point);
}
它运行正常,但是当用户悬停一些子控件(比如他想点击的按钮:)时,对话框会关闭。这是因为子控件不会将WM_MOUSEMOVE发送到父对话框。
我发现从子控件“传播”WM_MOUSEMOVE消息的唯一函数是SetCapture()。它完成了这项工作,但1)用户之后无法点击任何按钮,2)鼠标图标更改为沙漏。所以这不是一个选择。
有什么建议吗?
更新我将TrackMouseEvent调用放置到PreTranslateMessage例程中,该例程在任何鼠标移动事件上都被正确调用(甚至将鼠标控件悬停)。奇怪的是当用户徘徊儿童控制时仍然会生成WM_MOUSELEAVE!看起来像TrackMouseEvent知道现在悬停的控件。任何想法如何解决这个问题?
答案 0 :(得分:1)
如果这是一个模态对话框,我会尝试CDialog::PreTranslateMessage()
。如果仍无法检测到孩子内部的鼠标移动,则唯一的选项是SetWindowsHookEx
+ WH_MOUSE
。
答案 1 :(得分:0)
当2对话框获得事件时,则强制上升子对话框的WM_MOUSELEAVE事件。 见下面的代码
void CDlgParent::OnMouseMove(UINT nFlags, CPoint point)
{
CWnd* cwnd = this->GetDlgItem(IDC_CHILDRENNAME);
::SendMessage(cwnd->m_hWnd, WM_MouseLeave());
CDialog::OnMouseMove(nFlags, point);
}
void CDlgMain::OnMouseMove(UINT nFlags, CPoint point)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
::SetFocus(this->mhWnd);
CDialog::OnMouseMove(nFlags, point);
}
你觉得怎么样?
答案 2 :(得分:0)
我想我现在明白了这个问题。这确实有点棘手。我认为您需要一个计时器来保证后续的WM_MOUSEMOVE
消息得到处理(您必须对此进行测试)。
BOOL CTestDgDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_MOUSEMOVE)
{
TCHAR buffer[255];
::GetWindowText(pMsg->hwnd, buffer, 255);
TRACE(_T("WM_MOUSEMOVE: %s\n"), buffer);
}
return CDialogEx::PreTranslateInput(pMsg);
}
处理WM_MOUSELEAVE
,等待WM_MOUSEMOVE
。它到了吗?不 - >解雇对话。是的 - >重新启动。
答案 3 :(得分:0)
感谢您的帮助,伙计们。我无法正确制作TrackMouseEvent,所以我最终用计时器实现了解决方案。在每个刻度线上,我检查鼠标光标的位置是否在我的对话区域内,并确保它仍然是前景。这对我来说很完美,虽然它有点黑客。
void CALLBACK EXPORT TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
// This is a little hack, but suggested solution with TrackMouseEvent is quite
// unreliable to generate WM_MOUSELEAVE events
POINT pt;
RECT rect;
GetCursorPos(&pt);
GetWindowRect(hWnd, &rect);
HWND hFGW = GetForegroundWindow();
// Send leave message if cursor moves out of window rect or window
// stops being foreground
if (!PtInRect(&rect, pt) || hFGW != hWnd)
{
PostMessage(hWnd, WM_MOUSELEAVE, 0, 0);
}
}