MFC CScrollView鼠标拖拽移动滚动条出现回滚问题

    xiaoxiao2023-10-02  159

    MFC CScrollView鼠标拖拽移动滚动条出现回滚问题

    问题分析:逻辑视图较大的时候(10w),使用鼠标拖拽移动滚动条时(单击不会回滚),会在32000左右回滚到0。看到熟悉的32000,应该是在获取滚动条位置时,出现了短字节数据转换到长字节数据时出现的精度丢失问题,通过debug单步调试,发现函数调用层次如下:滚动条位置nPos数据,通过函数一层层的转换和计算后传递到SetScrollPos正式更新滚动条位置。

    OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) (垂直方向移动滚动条时调用)

           OnScroll(MAKEWORD(nSBCode, 0xff), nPos);

                  OnScrollBy(CSize(x - xOrig, y - yOrig), bDoScroll);

                           SetScrollPos(SB_HORZ, x);(此处更新滚动条位置)

    通过打印nPos,当x为0后(回滚后),nPos是一个很大的数0xff280012,所以很有可能是OnHScroll上一层函数将nPos传递到OnHScroll出现问题。查找调用OnHScroll的函数,在wincore.cpp以下函数调用OnHScroll

    case AfxSig_SCROLL_REFLECT: { // special case for WM_VSCROLL and WM_HSCROLL ASSERT(message == WM_VSCROLL || message == WM_HSCROLL || message == WM_VSCROLL+WM_REFLECT_BASE || message == WM_HSCROLL+WM_REFLECT_BASE); int nScrollCode = (short)LOWORD(wParam); int nPos = (short)HIWORD(wParam); // nPos是short转换的,即不能大于32768 if (lpEntry->nSig == AfxSig_SCROLL) (this->*mmf.pfn_v_u_u_W)(nScrollCode, nPos, CWnd::FromHandle(reinterpret_cast<HWND>(lParam))); else (this->*mmf.pfn_v_u_u)(nScrollCode, nPos); } break;

    可以看到,其中nPos,是short到int转换成的;因为某种原因,short溢出了,变成了负数,传输到OnHScroll后,再次转换成UINT,所以出现了一个很大的数0xff280012。

    解决方式:抛开在wincore.cpp调用OnHScroll函数,直接获取滚动条的位置进行更新;在OnHScroll使用GetScrollInfo();函数直接获取滚动条位置,传递下去。

    void MyScrollView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: 在此添加消息处理程序代码和/或调用默认值 SCROLLINFO si; GetScrollInfo(SB_HORZ,&si); CScrollView::OnHScroll(nSBCode, si.nTrackPos, pScrollBar); }

     

     

    最新回复(0)