Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS General Discussion » CExtScrollBar problem Collapse All
Subject Author Date
Bacsó Gergely Jan 9, 2007 - 9:25 AM

Hi,

I’ve replaced my old scrollbars with CExtScrollBar, and everything works fine, except that I want to use the old scroll position setting mechanism, so that the view set’s the scrollbars’ position, not the scrollbars themselves (I use a custom mechanism).

Currently I set the scroll position in OnHScroll (like for normal scroll bars) ... and then the CExtScrollBar bar sets it back to another position.

Is there any way to avoid this?

Thanks in advance,
Gergely BacsA?

Bacsó Gergely Jan 22, 2007 - 7:56 PM

OK, I made a custom scroll bar for control for myself, derived from CExtScrollBar. I made an ExtSetScrollPos(int nPos) method which sets a member variable to nPos and calls SetScrollPosition as well, and in the overridden _SetScrollPos(int nPos, ...) method I use the given nPos variable if bSendScrollingNotification is true, otherwise I set nPos to the member variable.
And this works fine for me.

Thank You for Your help, nice work further on (I hope I translated it right),
Gergely BacsA?

Bacsó Gergely Jan 19, 2007 - 3:31 PM

I still got an extra WM_HSCROLL message with SB_THUMBPOSITION so I analized the problem and modified the following block (se later) in the OnLButtonDown method, and after that it almost worked right, but my view and my scrollbar began to live different lives.

I don’t call GetScrollPos() when painting the view, I store the actual scroll position as a local variable (it’s a double type, so I can’t let the scroll bar to handle it), so now when I press the right button of the horizontal scroll bar, the view is shifting to the appropriate position, but the scroll bar "ignores" the SetScrollPos() method that I call from OnHScroll(), and sets its thumb position itself to somewhere else.
Typically the thumb position should change for example from 0 to 20 and it changes to 1 instead.

It would be good to have a mode like the scroll bar doesn’t count and set its scroll position, but I have to set it, like for original scroll bars.


The block I modified in OnLButtonDown():

if( bFinalNotify )
{
bool bSendScrollingNotification = true;
switch( m_nSBMHT )
{
case (CExtPaintManager::__ESBMHT_BUTTON_UP):
case (CExtPaintManager::__ESBMHT_BUTTON_DOWN):
case (CExtPaintManager::__ESBMHT_PAGE_UP):
case (CExtPaintManager::__ESBMHT_PAGE_DOWN):
case (CExtPaintManager::__ESBMHT_NOWHERE): /* Added this line */
bSendScrollingNotification = false;
break;
}
_SetScrollPos( nScrollPos, false, true, bSendScrollingNotification );
}


Thank You for the help so far,
BacsA? Gergely

Technical Support Jan 22, 2007 - 12:30 PM

We confirm that there is this difference between the scrollbar common control and the CExtScrollBar window. The latter simply runs a internal message loop for processing timer-based position changing while its part is pressed. The problem is that we cannot intercept invocations of the SetScrollPos() API in this case

Bacsó Gergely Jan 11, 2007 - 3:43 PM

When I press the right button of the horizontal scroll bar, I get a WM_HSCROLL message with first an SB_LINERIGHT, then with an SB_THUMBTRACK and then with an SB_THUMBPOSITION flag.

I uploaded the three call stack images to the following zip file:
http://users.hszk.bme.hu/~bg198/scroll.zip

I also made a simple project that halfly reproduces the problem (without an SB_THUMBTRACK message), I haven’t figured it out yet, why is the difference, maybe it’s becouse of the different visual styles.

Technical Support Jan 19, 2007 - 8:15 AM

Thank you for reporting the problem. Please update the CExtScrollBar::_SetScrollPos() method’s declaration in the ../Prof-UIS/Include/ExtScrollWnd.h file:

    virtual void _SetScrollPos(
        INT nPos,
        bool bTrackPos = false,
        bool bRedraw = true,
        bool bSendScrollingNotification = true
        );
Then please update the source code for the following two methods in the ../Prof-UIS/Include/ExtScrollWnd.cpp file:
void CExtScrollBar::_SetScrollPos(
    INT nPos,
    bool bTrackPos, // = false
    bool bRedraw, // = true
    bool bSendScrollingNotification // = true
    )
{
    ASSERT_VALID( this );
    ASSERT( GetSafeHwnd() != NULL );
    AnimationSite_ClientProgressStop( this );
    AnimationClient_StateGet( false ).Empty();
    AnimationClient_StateGet( true ).Empty();
CExtPaintManager::PAINTSCROLLBARDATA _psbd( this );
SCROLLINFO _scroll_info;
    ::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
    _scroll_info.cbSize = sizeof(SCROLLINFO);
    if( bTrackPos )
    {
        _scroll_info.fMask = SIF_TRACKPOS;
        _scroll_info.nTrackPos = (int)nPos;
    }
    else
    {
        _scroll_info.fMask = SIF_POS;
        _scroll_info.nPos = (int)nPos;
    }
    m_nHelperTrackPos = (int)nPos;
    if( ! CScrollBar::SetScrollInfo(
            &_scroll_info,
            bRedraw ? TRUE : FALSE
            )
        )
        CScrollBar::SetScrollPos( nPos, bRedraw ? TRUE : FALSE );
    else
        bRedraw = false;
    if( bSendScrollingNotification && _psbd.m_bEnabled )
    {
        HWND hWndParent = ::GetParent( m_hWnd );
        if( hWndParent != NULL )
        {
            ::SendMessage(
                hWndParent,
                _psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
                MAKEWPARAM(
                    ( bTrackPos ? SB_THUMBTRACK : SB_THUMBPOSITION ),
                    nPos
                    ),
                LPARAM(m_hWnd)
                );
        }
    }
    if( bRedraw )
    {
        Invalidate();
        if( ::GetCapture() == m_hWnd )
            UpdateWindow();
    }
}
 
void CExtScrollBar::OnLButtonDown(UINT nFlags, CPoint point)
{
    ASSERT_VALID( this );
    if( ! m_bCompleteRepaint )
    {
        CScrollBar::OnLButtonDown( nFlags, point );
        return;
    }
CExtPopupMenuTipWnd * pATTW =
        OnAdvancedPopupMenuTipWndGet();
CExtPaintManager::PAINTSCROLLBARDATA _psbd( this );
    _psbd.AdjustHT( point );
    if(     (! m_bProcessingHover)
        ||  m_bProcessingClick
        ||  (! _psbd.m_bEnabled )
        ||  _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_NOWHERE
        )
    {
        if(     _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_NOWHERE
            ||  (! _psbd.m_bEnabled )
            )
        {
            if( pATTW != NULL )
                pATTW->Hide();
            SendMessage( WM_CANCELMODE );
            Invalidate();
            UpdateWindow();
            return;
        }
    }
    ActivateTopParent();
bool bAnimationLocked = AnimationClient_CacheGeneratorIsLocked();
    if( ! bAnimationLocked )
    {
        AnimationClient_CacheGeneratorLock();
         AnimationClient_CacheNextStateMinInfo(
            false,
            __EAPT_BY_PRESSED_STATE_TURNED_ON
            );
    }
    m_nSBMHT = INT(_psbd.m_eSBMHT);
    m_bProcessingClick = m_bProcessingHover = true;
    m_bProcessingOutClick = false;
    if( ! bAnimationLocked )
    {
         AnimationClient_CacheNextStateMinInfo(
            true,
            __EAPT_BY_PRESSED_STATE_TURNED_ON
            );
        AnimationClient_CacheGeneratorUnlock();
    }
    Invalidate();
    UpdateWindow();
    if( pATTW != NULL )
        OnAdvancedPopupMenuTipWndDisplay( *pATTW, m_nSBMHT, true );
INT nScrollPosStart = _psbd.m_DSI.nPos, nScrollPos = _psbd.m_DSI.nPos;
    m_nHelperTrackPos = _psbd.m_DSI.nPos;
    m_bHelperHaveTrackPos = true;
CRect rcArea = _psbd.GetAreaRectHT();
const UINT nTimerID = 401;
const UINT nTimerEllapse = 100;
HWND hWndOwn = GetSafeHwnd();
    ASSERT( hWndOwn != NULL && ::IsWindow( hWndOwn ) );
HWND hWndParent = ::GetParent( hWndOwn );
bool bVirtualMode = false, bFinalNotify = true;
#if (!defined __EXT_MFC_NO_SCROLLITEMWND)
    if( hWndParent != NULL )
    {
        CWnd * pWndParentPermanent = CWnd::FromHandlePermanent( hWndParent );
        if( pWndParentPermanent != NULL )
        {
            CExtScrollItemWnd * pExtScrollItemWnd =
                DYNAMIC_DOWNCAST(
                    CExtScrollItemWnd,
                    pWndParentPermanent
                    );
            if( pExtScrollItemWnd != NULL )
            {
                DWORD dwScrollType = __ESIW_ST_NONE;
                if( _psbd.m_bHorzBar )
                    dwScrollType = pExtScrollItemWnd->SiwScrollTypeHGet();
                else
                    dwScrollType = pExtScrollItemWnd->SiwScrollTypeVGet();
                if( dwScrollType == __ESIW_ST_VIRTUAL )
                    bVirtualMode = true;
            }
        }
    }
#endif
bool bStopFlag = false;
CPoint ptCursor( point );
INT nStepSize = 0L;
bool bUpStep = false;
    switch( _psbd.m_eSBMHT )
    {
    case CExtPaintManager::__ESBMHT_BUTTON_UP:
        bUpStep = true;
    case CExtPaintManager::__ESBMHT_BUTTON_DOWN:
        nStepSize = 1L;
        break;
    case CExtPaintManager::__ESBMHT_PAGE_UP:
        bUpStep = true;
    case CExtPaintManager::__ESBMHT_PAGE_DOWN:
        nStepSize = (INT)_psbd.m_DSI.nPage;
        if( nStepSize == 0L )
            nStepSize = 1L;
        break;
    case CExtPaintManager::__ESBMHT_THUMB:
        break;
    }
bool bMenuMode = false;
    if( CExtPopupMenuWnd::IsMenuTracking() )
    {
        CExtPopupMenuWnd * pPopup = CExtPopupMenuSite::g_DefPopupMenuSite.GetInstance();
        if( pPopup != NULL )
        {
            CWnd * pWnd = GetParent();
            for( ; pWnd != NULL; pWnd = pWnd->GetParent() )
            {
                if( pWnd == pPopup )
                {
                    bMenuMode = true;
                    break;
                }
            }
        }
    }
INT nMx = INT( _psbd.m_DSI.nMax - _psbd.m_DSI.nPage + 1 );
INT nScrollLimit =
          _psbd.m_DSI.nMax
        - _psbd.m_DSI.nMin
        - _psbd.m_DSI.nPage
        + 1
        ;
    ASSERT( nScrollLimit >= 0 );
    if( nStepSize > nScrollLimit )
        nStepSize = nScrollLimit;
CRect rcScrollable = _psbd.m_rcBar;
    if( _psbd.m_bHorzBar )
    {
        rcScrollable.left = _psbd.m_rcButtonUp.right;
        rcScrollable.right = _psbd.m_rcButtonDown.left;
    }
    else
    {
        rcScrollable.top = _psbd.m_rcButtonUp.bottom;
        rcScrollable.bottom = _psbd.m_rcButtonDown.top;
    }
    ::SetCapture( hWndOwn );
    if( nStepSize != 0L )
        ::SetTimer( hWndOwn, nTimerID, nTimerEllapse, NULL );
    for( MSG msg; ::IsWindow( hWndOwn ) && (!bStopFlag); )
    {
        if( ! PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) )
        {
            if( ! ::IsWindow( hWndOwn ) )
                break;
            ::WaitMessage();
            continue;
        }
        bool bAnalyzeThumb = false;
        switch( msg.message )
        {
        case WM_LBUTTONDBLCLK:
        case WM_LBUTTONUP:
        case WM_RBUTTONDBLCLK:
        case WM_RBUTTONDOWN:
        case WM_RBUTTONUP:
        case WM_MBUTTONDBLCLK:
        case WM_MBUTTONDOWN:
        case WM_MBUTTONUP:
        case WM_CANCELMODE:
        case WM_ACTIVATEAPP:
        case WM_KEYDOWN:
        case WM_KEYUP:
            bStopFlag = true;
        break;
        case WM_CAPTURECHANGED:
            if( (HWND)msg.wParam != hWndOwn )
                bStopFlag = true;
        break;
        case WM_MOUSEMOVE:
            if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_THUMB) )
            {
                if(     ( ! CExtPopupMenuWnd::IsKeyPressed(VK_LBUTTON) )
                    ||  CExtPopupMenuWnd::IsKeyPressed(VK_MBUTTON)
                    ||  CExtPopupMenuWnd::IsKeyPressed(VK_RBUTTON)
                    ||  ( (!bMenuMode) && CExtPopupMenuWnd::IsMenuTracking() )
                    )
                {
                    bStopFlag = true;
                    break;
                }
                PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
                bAnalyzeThumb = true;
                ::GetCursorPos( &ptCursor );
                ::ScreenToClient( hWndOwn, &ptCursor );
                break;
            }
            if( nStepSize == 0 )
                break;
        case WM_TIMER:
            {
                if(     ( ! CExtPopupMenuWnd::IsKeyPressed(VK_LBUTTON) )
                    ||  CExtPopupMenuWnd::IsKeyPressed(VK_MBUTTON)
                    ||  CExtPopupMenuWnd::IsKeyPressed(VK_RBUTTON)
                    ||  ( (!bMenuMode) && CExtPopupMenuWnd::IsMenuTracking() )
                    )
                {
                    bStopFlag = true;
                    break;
                }
                if( msg.message == WM_TIMER )
                {
                    if( msg.wParam != nTimerID )
                        break;
                }
                ASSERT( nStepSize != 0L );
                PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
                ::GetCursorPos( &ptCursor );
                ::ScreenToClient( hWndOwn, &ptCursor );
                if( ! rcArea.PtInRect(ptCursor) )
                {
                    if( ! m_bProcessingOutClick )
                    {
                        m_bProcessingOutClick = true;
                        Invalidate();
                    }
                    if( pATTW != NULL )
                        pATTW->Hide();
                    continue;
                }
                if( bUpStep )
                {
                    nScrollPos -= nStepSize;
                    if( nScrollPos < _psbd.m_DSI.nMin )
                        nScrollPos = _psbd.m_DSI.nMin;
                }
                else
                {
                    nScrollPos += nStepSize;
                    if( nScrollPos > nMx )
                        nScrollPos = nMx;
                }
                if( _GetScrollPos( true ) != nScrollPos )
                {
                    bool bSendScrollingNotification = true;
                    if( hWndParent != NULL )
                    {
                        switch( m_nSBMHT )
                        {
                        case (CExtPaintManager::__ESBMHT_BUTTON_UP):
                            bSendScrollingNotification = false;
                            ::SendMessage(
                                hWndParent,
                                _psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
                                MAKEWPARAM(
                                    ( _psbd.m_bHorzBar ? SB_LINELEFT : SB_LINEUP ),
                                    0
                                    ),
                                LPARAM(m_hWnd)
                                );
                        break;
                        case (CExtPaintManager::__ESBMHT_BUTTON_DOWN):
                            bSendScrollingNotification = false;
                            ::SendMessage(
                                hWndParent,
                                _psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
                                MAKEWPARAM(
                                    ( _psbd.m_bHorzBar ? SB_LINERIGHT : SB_LINEDOWN ),
                                    0
                                    ),
                                LPARAM(m_hWnd)
                                );
                        break;
                        case (CExtPaintManager::__ESBMHT_PAGE_UP):
                            bSendScrollingNotification = false;
                            ::SendMessage(
                                hWndParent,
                                _psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
                                MAKEWPARAM(
                                    ( _psbd.m_bHorzBar ? SB_PAGELEFT : SB_PAGEUP ),
                                    0
                                    ),
                                LPARAM(m_hWnd)
                                );
                        break;
                        case (CExtPaintManager::__ESBMHT_PAGE_DOWN):
                            bSendScrollingNotification = false;
                            ::SendMessage(
                                hWndParent,
                                _psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
                                MAKEWPARAM(
                                    ( _psbd.m_bHorzBar ? SB_PAGERIGHT : SB_PAGEDOWN ),
                                    0
                                    ),
                                LPARAM(m_hWnd)
                                );
                        break;
                        }
                    }
                    if( ! bVirtualMode )
                        _SetScrollPos( nScrollPos, true, true, bSendScrollingNotification );
                    else
                        bFinalNotify = false;
                    if( pATTW != NULL && ( ! bAnalyzeThumb ) )
                        OnAdvancedPopupMenuTipWndDisplay( *pATTW, m_nSBMHT, true );
                }
                _psbd.AdjustHT( ptCursor );
                bool bProcessingOutClick =
                    ( m_nSBMHT == INT(_psbd.m_eSBMHT) )
                        ? false : true;
                rcArea = _psbd.GetAreaRect( CExtPaintManager::e_scroll_bar_mouse_hover_type_t(m_nSBMHT) );
                if( m_bProcessingOutClick != bProcessingOutClick )
                {
                    bool bAnimationLocked = AnimationClient_CacheGeneratorIsLocked();
                    if( ! bAnimationLocked )
                    {
                        AnimationClient_CacheGeneratorLock();
                         AnimationClient_CacheNextStateMinInfo(
                            false,
                            __EAPT_BY_PRESSED_STATE_TURNED_OFF
                            );
                    }
                    m_bProcessingOutClick = bProcessingOutClick;
                    if( ! bAnimationLocked )
                    {
                         AnimationClient_CacheNextStateMinInfo(
                            true,
                            __EAPT_BY_PRESSED_STATE_TURNED_OFF
                            );
                        AnimationClient_CacheGeneratorUnlock();
                    }
                    Invalidate();
                    UpdateWindow();
                }
            }
        break;
        default:
            if(     ( ! CExtPopupMenuWnd::IsKeyPressed(VK_LBUTTON) )
                ||  CExtPopupMenuWnd::IsKeyPressed(VK_MBUTTON)
                ||  CExtPopupMenuWnd::IsKeyPressed(VK_RBUTTON)
                ||  ( (!bMenuMode) && CExtPopupMenuWnd::IsMenuTracking() )
                )
                bStopFlag = true;
        break;
        }
        if( bStopFlag || nScrollLimit == 0L )
            break;
        if( bAnalyzeThumb )
        {
            LONG nPixelOffset = _psbd.m_bHorzBar
                ? (ptCursor.x - point.x)
                : (ptCursor.y - point.y);
            LONG nPixelExtent = _psbd.m_bHorzBar
                ? (rcScrollable.Width() - _psbd.m_rcThumb.Width())
                : (rcScrollable.Height() - _psbd.m_rcThumb.Height());
            if( nPixelExtent <= 0 )
            {
                bStopFlag = true;
                break;
            }
            if( abs(nPixelOffset) > nPixelExtent )
                nPixelOffset =
                    (nPixelOffset < 0)
                        ? (-nPixelExtent)
                        : nPixelExtent;
            INT nShift =
                ( nPixelExtent == 0 || nPixelOffset == 0 )
                    ? 0
                    : ::MulDiv( nScrollLimit, abs(nPixelOffset), nPixelExtent );
            nScrollPos = nScrollPosStart;
            if( nPixelOffset < 0 )
            {
                nScrollPos -= nShift;
                if( nScrollPos < _psbd.m_DSI.nMin )
                    nScrollPos = _psbd.m_DSI.nMin;
            }
            else
            {
                nScrollPos += nShift;
                if( nScrollPos > nMx )
                    nScrollPos = nMx;
            }
            if(! bVirtualMode )
            {
                if( _GetScrollPos( true ) != nScrollPos )
                {
                    _SetScrollPos( nScrollPos, true );
                    if( pATTW != NULL )
                        OnAdvancedPopupMenuTipWndDisplay( *pATTW, m_nSBMHT, true );
                }
                bFinalNotify = true;
            }
            _psbd.AdjustHT( ptCursor );
            rcArea = _psbd.GetAreaRect( CExtPaintManager::__ESBMHT_THUMB );
            continue;
        }
        if( !AfxGetThread()->PumpMessage() )
            break;
    }
    if( ! ::IsWindow( hWndOwn ) )
        return;
    if( nStepSize != 0L )
        ::KillTimer( hWndOwn, nTimerID );
    bAnimationLocked = AnimationClient_CacheGeneratorIsLocked();
    if( ! bAnimationLocked )
    {
        AnimationClient_CacheGeneratorLock();
        if( AnimationClient_StateGet(true).IsEmpty() )
             AnimationClient_CacheNextStateMinInfo(
                false,
                __EAPT_BY_PRESSED_STATE_TURNED_OFF
                );
    }
    if( bFinalNotify )
    {
        bool bSendScrollingNotification = true;
        switch( m_nSBMHT )
        {
        case (CExtPaintManager::__ESBMHT_BUTTON_UP):
        case (CExtPaintManager::__ESBMHT_BUTTON_DOWN):
        case (CExtPaintManager::__ESBMHT_PAGE_UP):
        case (CExtPaintManager::__ESBMHT_PAGE_DOWN):
            bSendScrollingNotification = false;
        break;
        }
        _SetScrollPos( nScrollPos, false, true, bSendScrollingNotification );
    }
    m_nSBMHT = INT(CExtPaintManager::__ESBMHT_NOWHERE);
    m_bProcessingClick
        = m_bProcessingOutClick
        = m_bProcessingHover
        = false;
    if( ! bAnimationLocked )
    {
        ::GetCursorPos( &ptCursor );
        ScreenToClient( &ptCursor );
        _psbd.AdjustHT( ptCursor );
        m_nSBMHT = INT(_psbd.m_eSBMHT);
         AnimationClient_CacheNextStateMinInfo(
            true,
            __EAPT_BY_PRESSED_STATE_TURNED_OFF
            );
        AnimationClient_CacheGeneratorUnlock();
    }
    Invalidate();
    UpdateWindow();
    m_nHelperTrackPos = -1;
    m_bHelperHaveTrackPos = false;
    if( ::GetCapture() == hWndOwn )
        ::ReleaseCapture();
    if( pATTW != NULL )
        OnAdvancedPopupMenuTipWndDisplay( *pATTW, INT(_psbd.m_eSBMHT), false );
}

Sergiy Lavrynenko Jan 11, 2007 - 2:31 AM

Dear Gergely,

Could you show the content of the Visual Studio’s Call Stack window wich contains the following:

TOP OF THE CALL STACK WINDOW

Invocation if the OnHScroll() handler method caused by unwanted scroll position changing inside the CExtScrollBar class code

...

Invocation of the CExtScrollBar class methods.

...

Invocation if the OnHScroll() handler method which is logically correct according to the scrolling implementation in your view window.

...

BOTTOM OF THE CALL STACK WINDOW