跳转至主内容

 none
CListCtrl滚动条显示和隐藏的问题 RRS feed

  • 问题

  • 我现在的list滚动条 我想控制他的显示和隐藏的方法如下

    1.当我鼠标移动到list区域时候,响应MouseHover显示滚动条

    2.当我鼠标离开list区域的时候,响应MouseLeave隐藏滚动条

    这两步是没有问题的

    但是 我滚动条显示出来之后想用鼠标去拖动它的时候,当我鼠标放在滚动条上的时候响应了MouseLeave而使滚动条隐藏了

    这时候 滚动条隐藏了之后就又会响应MouseHover显示滚动条,看起来就是滚动条一直在闪烁

    并且这个时候滚动条就变的无法使用

    请问这个问题该怎么解决或者规避

    2019年9月10日 2:59

全部回复

  • 你好,

    感谢你在这里发帖。

    >>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

    2019年9月10日 7:38
  • 关键代码如下

    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都不是我手动调用的,是自己触发的

    2019年9月10日 8:30
  • 你好,

    >>这时候 滚动条隐藏了之后就又会响应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






    2019年9月11日 6:20
  • 你好,

    如果你的问题得到解决,请标记有价值的回复为答案,这会帮助到其他有相同问题的社区成员更快地找到解决方案。如果没有,欢迎你随时回来提问。

    Best Regards,

    Suarez Zhou

    2019年9月16日 1:05
  • 抱歉这么晚才回复

    1.滚动条闪烁就是因为MouseLeave和OnMouseHover触发的,和修改csTME.dwHoverTime时间没任何关系吧

    我试了也不行的

    2.我的listCtrl是放在dockpane上的  是完全盖住dockpane的  我在dockpane里面加了mousemove消息,

    这个消息是没有响应到的


    2019年9月19日 2:21
  • 我观察了其他界面库的处理方式是给list和滚动条中间留一个间隔

    对于水平滚动条来说,

    会在滚动条底部和list底部留一个两三个像素的间隔

    在list响应MouseLeave 判断鼠标是不是在滚动条上,

    是的话滚动条不隐藏,然后鼠标继续往下会再次触发一次MouseHover和MouseLeave

    在第二次响应MouseLeave 鼠标不在滚动条上,然后滚动条消失

    2019年9月19日 2:25
  • 你好

    这样做是不是增大了程序的复杂程度,最后做的事其实和MouseMove消息判断鼠标是否在ListCtrl控件上所得到的效果是一样的,但是通过你所说的这种方法似乎需要的工作量变大了很多。你是还有其他需求的功能吗?

    Best Regards

    Suarez Zhou

    2019年9月19日 3:20
  • 1.滚动条闪烁就是因为MouseLeave和OnMouseHover触发的,和修改csTME.dwHoverTime时间没任何关系吧

    我试了也不行的

    2.我的listCtrl是放在dockpane上的  是完全盖住dockpane的  我在dockpane里面加了mousemove消息,

    这个消息是没有响应到的

    你好  这个问题还没有解决呀

    你说的解决方案  因为上述原因根本没有解决

    2019年9月19日 5:38
  • 你好

    目前要解决的事情是滚动条自动隐藏的功能

    不过在我操作的过程中,发现了个问题

    

    这2个都是dockpane上铺满了listctrl,在首次调用

    ShowScrollBar(SB_HORZ, TRUE); ShowScrollBar(SB_VERT, TRUE);


    的时候   显示出来的滚动条入右边的样式,点击滚动条就变成了左边的样式

    后面再次显示出来  会一直是左边的样式

    这个是什么原因导致的,有办法解决吗?  工具VS2017  系统win10

    2019年9月19日 6:03
  • 你好,

    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 Zhou


    2019年9月19日 6:54
  • 1. 我现在是用的是MouseHover和MouseLeave,但是碰到的问题 是正是我刚开始提问的问题

    这种情况我也没有好的办法去处理

    2.自绘滚动条我也试过了,结果还是2个滚动条在变化,只不过把图上的左边的滚动条替换成我自绘的滚动条了,但还是存在2个样式

    2019年9月19日 7:08
  • 你好,

    关于你的问题,给几点参考信息,滚动条也是个窗口,也有自己的句柄,可以通过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);

    GetScrollBarInfo

    SCROLLBARINFO

    回到我们的问题,想要通过MouseLeave和MouseHover来做这件事,我刚才尝试了几个方法,我发现我都绕不过去一个问题,我们无法设置CListCtrl的滚动条窗口的消息响应函数.当我们鼠标放在滚动条上时,所有CListCtrl和CDockablePane的消息响应函数都无法被响应,这时消息都由滚动条的窗口来接受,我们无法控制放在滚动条上所产生的消息。这就导致了之前的所有问题。我对此的想法就是弃用CListCtrl的滚动条,使用CScrollBar类创建的滚动条来模拟代替原生的滚动条,这样我们就可以对其做消息响应函数,剩下的就是完善消息响应函数,考虑到鼠标离开滚动条时是否移动到了CListCtrl上,是则显示滚动条,否则对滚动条窗口调用ShowWindow(SW_HIDE).

    你的第二个问题有关滚动条样式变化的问题和本帖的问题内容并没直接关系,根据论坛的规则,我们需要你重新发帖询问相关问题,这样有益于其他也有相同问题的人更快地找到解决方案。

    Best Regards

    Suarez Zhou


    2019年9月19日 8:47