询问者
CListCtrl滚动条显示和隐藏的问题

问题
全部回复
-
你好,
感谢你在这里发帖。
>>1.当我鼠标移动到list区域时候,响应MouseHover显示滚动条
>>2.当我鼠标离开list区域的时候,响应MouseLeave隐藏滚动条
>>我滚动条显示出来之后想用鼠标去拖动它的时候,当我鼠标放在滚动条上的时候响应了MouseLeave而使滚动条隐藏了
你能详细说下你是怎么做的吗?例如你是用MouseMove消息响应来判定鼠标是否在List区域上的吗?鼠标拖动滚动条的时候怎么会去调用MouseLeave的呢?如果照你所说,当离开list区域时会调用MouseLeave,那也就是说你在MouseMove消息响应中判断了鼠标的点在不在list区域,在则调用MouseHover,不在则调用MouseLeave。那你在list区域内拖动滚动条,应该永远也不会调用MouseLeave,因为你的鼠标始终是处在list区域中的。那么你有没有在其他地方调用MouseLeave呢?
我们希望你能给一个可以还原这个问题的demo,或者给出关键部分的代码,这会帮助我们更好地理解你的问题,提出更加有效的解决方案。
Best Regards,
Suarez Zhou
-
关键代码如下
void xmListCtrl::OnMouseMove(UINT nFlags, CPoint point) { if (m_bMouseTrack) //若允许追踪,则。 { TRACKMOUSEEVENT csTME; csTME.cbSize = sizeof(csTME); csTME.dwFlags = TME_LEAVE | TME_HOVER; csTME.hwndTrack = m_hWnd; csTME.dwHoverTime = 1; ::_TrackMouseEvent(&csTME); m_bMouseTrack = FALSE; } CListCtrl::OnMouseMove(nFlags, point); } void xmListCtrl::OnMouseHover(UINT nFlags, CPoint point) { m_bMouseTrack = TRUE; ShowScrollBar(SB_HORZ, TRUE); ShowScrollBar(SB_VERT, TRUE); } void xmListCtrl::OnMouseLeave() { m_bMouseTrack = TRUE; ShowScrollBar(SB_HORZ, FALSE); ShowScrollBar(SB_VERT, FALSE); CListCtrl::OnMouseLeave(); }
所有的MouseLeave和MouseHover都不是我手动调用的,是自己触发的
-
你好,
>>这时候 滚动条隐藏了之后就又会响应MouseHover显示滚动条,看起来就是滚动条一直在闪烁
将csTME.dwHoverTime时间设定的长一些,例如50毫秒,即显示正常。可以修复你所说的问题。
另外一个问题是当鼠标放在滚动条上时响应了MouseLeave,似乎程序认为滚动条并不属于ListCtrl窗口,所以调用了离开窗口的程序。但是当滚动条消失了,程序又认为那部分是属于ListCtrl窗口,又执行了OnMouseHover,所以滚动条又显示了,所以会造成你所说的闪烁的情况。这一点可以通过下图说明,我在OnMouseHover和OnMouseLeave中都加入了输出控制台语句,分别输出1和2,结果可见这两个消息响应函数似乎在一直不停交叉运行。
回到你的问题,如果你想实现当鼠标移动到ListCtrl控件中就会出现滚动条这个想法,可以尝试下我的代码。
//此部分为视图类里的代码 void CtestView::OnMouseMove(UINT nFlags, CPoint point) { CRect rect; CWnd *pWnd = GetDlgItem(1001);//1001为listctrl控件的ID pWnd->GetWindowRect(&rect); ScreenToClient(&rect); if(!((point.x<=rect.right&&point.x>=rect.left)&&(point.y<=rect.bottom &&point.y>=rect.top))) { pWnd->ShowScrollBar(SB_HORZ, FALSE); pWnd->ShowScrollBar(SB_VERT, FALSE); } else { pWnd->ShowScrollBar(SB_HORZ, TRUE); pWnd->ShowScrollBar(SB_VERT, TRUE); } CView::OnMouseMove(nFlags, point); } //此部分为控件类里的代码 void xmListCtrl::OnMouseMove(UINT nFlags, CPoint point) { ShowScrollBar(SB_HORZ, TRUE); ShowScrollBar(SB_VERT, TRUE); CListCtrl::OnMouseMove(nFlags, point); }
如果光添加视图的代码会导致,当你鼠标放到listctrl控件里并点击的时候,程序焦点到了控件上,你的视图不会接收到后续的鼠标移动消息,所以这两者的消息响应都需要去做。
Best Regards,
Suarez Zhou
- 已编辑 Suarez-ZhouMicrosoft contingent staff 2019年9月11日 6:31
- 已建议为答案 Ling_Gao 2019年9月16日 3:19
-
你好,
1,设置时间在我这边是可以修复显示问题的,但并不能解决程序的根本问题,所以并不能算作一种解决方案,可以忽略不考虑。
2,我测试发现我的方法对于你的需求有很大漏洞,如下图所示,想法有时很美好,但现实就是无法触发。尤其是你的是dockpane,就要考虑到如果将dockpane移动出我们的应用程序界面外,我们就无法通过视图类的mousemove等操作来判断是否出了listctrl范围。结合这些情况和你的实际需求,你所言的MouseHover和MouseLeave消息响应来做这个会更好一点。
3,这是MFC默认的滚动条显示隐藏后样式,似乎无法更改。如果你觉得这不满足你的需求,可以尝试自绘滚动条,可以参考以下这个链接进行自绘。
https://www.codeproject.com/Articles/14724/Replace-a-Window-s-Internal-Scrollbar-with-a-custo
Best Regards,
- 已编辑 Suarez-ZhouMicrosoft contingent staff 2019年9月19日 6:54
-
你好,
关于你的问题,给几点参考信息,滚动条也是个窗口,也有自己的句柄,可以通过CWnd::GetScrollBarCtrl获得相应的句柄。这也验证了我们之前的问题,当鼠标移动到滚动条上,不再触发CListCtrl的MouseMove消息,同时也响应了MouseLeave消息,因为滚动条的句柄是通过上面所说的方法获得,它其实是CListCtrl的子窗口。而::_TrackMouseEvent(&csTME);中csTME.hwndTrack = m_hWnd,这个句柄是CListCtrl的句柄,所以触发了MouseLeave消息。另外,滚动条的位置也可以获取。参考的方法如下述链接。
SCROLLBARINFO h; SCROLLBARINFO v; this->GetScrollBarInfo(OBJID_HSCROLL, &h); this->GetScrollBarInfo(OBJID_VSCROLL, &v);
回到我们的问题,想要通过MouseLeave和MouseHover来做这件事,我刚才尝试了几个方法,我发现我都绕不过去一个问题,我们无法设置CListCtrl的滚动条窗口的消息响应函数.当我们鼠标放在滚动条上时,所有CListCtrl和CDockablePane的消息响应函数都无法被响应,这时消息都由滚动条的窗口来接受,我们无法控制放在滚动条上所产生的消息。这就导致了之前的所有问题。我对此的想法就是弃用CListCtrl的滚动条,使用CScrollBar类创建的滚动条来模拟代替原生的滚动条,这样我们就可以对其做消息响应函数,剩下的就是完善消息响应函数,考虑到鼠标离开滚动条时是否移动到了CListCtrl上,是则显示滚动条,否则对滚动条窗口调用ShowWindow(SW_HIDE).
你的第二个问题有关滚动条样式变化的问题和本帖的问题内容并没直接关系,根据论坛的规则,我们需要你重新发帖询问相关问题,这样有益于其他也有相同问题的人更快地找到解决方案。
Best Regards
Suarez Zhou
- 已编辑 Suarez-ZhouMicrosoft contingent staff 2019年9月19日 8:48