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 Tech Support » Two questions about tabbing through a property grid Collapse All
Subject Author Date
Rolf Boerkoel Nov 13, 2009 - 2:05 AM

Dear support,


I have a property grid on a CExtResizableDialog dialog. This dialog is a child of another dialog. Navigating through the several property items with the tab key does not work as it normally does, unless I manually set


m_bAllowLongFocusJumpFix = false


in the child dialog.


1) Is it correct and/or safe to set this m_bAllowLongFocusJumpFix member to false to allow tabbing through the items?


2) I see that this m_bAllowLongFocusJumpFix is only explicitly initialized in the CExtResizableDialog’s default constructor, not in the two other constructors, could this be a small bug?


 


Regards,


Marco

Technical Support Nov 18, 2009 - 6:50 AM

You can set the g_bAllowLongFocusJumpFix flag to false and use this temporarily solution. But it should work OK when it’s set to true. We need to repeat this problem in any of Prof-UIS sample applications or in some test project. Could you please provide us with a test project or with exact window layout description which reproduces the tab navigation problem?

Rolf Boerkoel Nov 18, 2009 - 9:26 AM

I sent you a test project by email.

Rolf Boerkoel Nov 16, 2009 - 2:33 AM

Then it is a bug.My child dialog is created with the second CExtResizableDialog constructor. As m_bAllowLongFocusJumpFix is initialized with a random value when using the 2nd or 3rd constructor, tabbing sometimes works and sometimes it doesn’t:


CExtResizableDialog::CExtResizableDialog()
    : m_bEnabledControlBarUpdate( false )
    , m_bInConrolBarUpdate( false )
    , m_bAllowLongFocusJumpFix( g_bAllowLongFocusJumpFix )
    , m_hWndFocus( NULL )
    , m_bHelperSizingMoving( false )
{
    m_bShowResizingGripper = true;
}

CExtResizableDialog::CExtResizableDialog(
    UINT nIDTemplate,
    CWnd * pParentWnd
    )
    : CExtWA < CExtWS < __BASEOF_CExtResizableDialog__ > > ( nIDTemplate, pParentWnd )
    , m_bEnabledControlBarUpdate( false )
    , m_bInConrolBarUpdate( false )
    , m_hWndFocus( NULL )
    , m_bHelperSizingMoving( false )
{
    m_bShowResizingGripper = true;
}

CExtResizableDialog::CExtResizableDialog(
    __EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
    CWnd * pParentWnd
    )
    : CExtWA < CExtWS < __BASEOF_CExtResizableDialog__ > > ( lpszTemplateName, pParentWnd )
    , m_bEnabledControlBarUpdate( false )
    , m_bInConrolBarUpdate( false )
    , m_hWndFocus( NULL )
    , m_bHelperSizingMoving( false )
{
    m_bShowResizingGripper = true;
}

Technical Support Nov 18, 2009 - 2:07 PM

We received your e-mail and replied it.

Rolf Boerkoel Nov 19, 2009 - 3:05 AM

Seems to work fine now, thank you. I have one (slightly off topic) remaining question/problem:



Our property grid is set up in two stages. First it is initialized with default values. Later on the actual values are put into the grid (well, actually in the property store, of course). To make these new values become visible, we call the PropertyStoreSynchronize() method. The new values indeed become visible.


So we’re doing something like this (simplified):


void InitPropertyGrid()
{
	CreateCategories();
	CreatePropertyValues();
	propertyGrid.PropertyStoreSet(&propertyStore);
}

void UpdatePropertyGrid()
{
	UpdatePropertyValues();
	propertyGrid.PropertyStoreSynchronize();
}

 


However by calling PropertyStoreSynchronize() the grid seems to loose its focus. In some situations it even means the dialog gets locked up. Even pressing the tab key doesn’t help. Only by using the mouse (or by pressing up or down arrow key) one can get it to work again. After some investigation I discovered that calling PropertyStoreSet instead of PropertyStoreSynchronize makes this problem disappear. I’m completely happy with calling PropertyStoreSet method, but what do you think? I thought PropertyStoreSynchronize was the recommended way of updating the grid? Is the PropertyStoreSynchronize method still useful in some situations?

Technical Support Nov 19, 2009 - 1:51 PM

We agree, the focus should not be lost in the property grid after synchronization. Please update the source code for the following method:

void CExtPropertyGridCtrl::PropertyStoreSynchronize()
{
            ASSERT_VALID( this );
            _EnsureInitialized();
CExtPropertyGridWnd * pActivePGW = NULL;
CExtPropertyStore * pCurrentPS = PropertyStoreGet();
CExtPropertyItem * pRestoreFocusPI = NULL;
            if( pCurrentPS != NULL )
            {
                        ASSERT_VALID( pCurrentPS );
                        pActivePGW = GetActiveGrid();
                        if( pActivePGW->GetSafeHwnd() != NULL )
                        {
                                    ASSERT_VALID( pActivePGW );
                                    HTREEITEM htiFocus = pActivePGW->ItemFocusGet();
                                    if( htiFocus != NULL )
                                                pRestoreFocusPI = pActivePGW->PropertyItemFromTreeItem( htiFocus );
                        }
            }
CTypedPtrArray < CPtrArray, CExtPropertyGridWnd * > arrGrids;
            OnPgcQueryGrids( arrGrids );
INT nGridIdx = 0;
            for( ; nGridIdx < arrGrids.GetSize(); nGridIdx ++ )
            {
                        CExtPropertyGridWnd * pGrid = arrGrids[ nGridIdx ];
                        ASSERT_VALID( pGrid );
                        pGrid->PropertyStoreSynchronizeAll();
            } // for( ; nGridIdx < arrGrids.GetSize(); nGridIdx ++ )
            if( pRestoreFocusPI != NULL )
            {
                        ASSERT_VALID( pActivePGW );
                        ASSERT( pActivePGW->GetSafeHwnd() != NULL );
                        HTREEITEM htiSetFocus = pActivePGW->PropertyItemToTreeItem( pRestoreFocusPI );
                        if( htiSetFocus != NULL )
                                    pActivePGW->ItemFocusSet( htiSetFocus );
            }
}


Rolf Boerkoel Nov 20, 2009 - 2:16 AM

This solves the focus problem, thanks. But I keep on nagging (sorry)...



The tabbing works ok when the property grid is on a dialog which is a child of another dialog. But the tabbing doesn’t seem to work anymore in the more common case of having a property grid as a direct child of a dialog. Again when setting the m_bAllowLongFocusJumpFix to false it works ok.



I sent you another test project (sample11) which illustrates this case.

Technical Support Nov 16, 2009 - 1:32 PM

Thank you very much for reporting this issue. The m_bAllowLongFocusJumpFix must be initialized in all the CExtResizableDialog class constructors:

CExtResizableDialog::CExtResizableDialog()
            : m_bEnabledControlBarUpdate( false )
            , m_bInConrolBarUpdate( false )
            , m_hWndFocus( NULL )
            , m_bHelperSizingMoving( false )
            , m_bAllowLongFocusJumpFix( g_bAllowLongFocusJumpFix )
{
            m_bShowResizingGripper = true;
}

CExtResizableDialog::CExtResizableDialog(
            UINT nIDTemplate,
            CWnd * pParentWnd
            )
            : CExtWA < CExtWS < __BASEOF_CExtResizableDialog__ > > ( nIDTemplate, pParentWnd )
            , m_bEnabledControlBarUpdate( false )
            , m_bInConrolBarUpdate( false )
            , m_hWndFocus( NULL )
            , m_bHelperSizingMoving( false )
            , m_bAllowLongFocusJumpFix( g_bAllowLongFocusJumpFix )
{
            m_bShowResizingGripper = true;
}

CExtResizableDialog::CExtResizableDialog(
            __EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
            CWnd * pParentWnd
            )
            : CExtWA < CExtWS < __BASEOF_CExtResizableDialog__ > > ( lpszTemplateName, pParentWnd )
            , m_bEnabledControlBarUpdate( false )
            , m_bInConrolBarUpdate( false )
            , m_hWndFocus( NULL )
            , m_bHelperSizingMoving( false )
            , m_bAllowLongFocusJumpFix( g_bAllowLongFocusJumpFix )
{
            m_bShowResizingGripper = true;
}

Technical Support Nov 20, 2009 - 2:40 PM

Thank you for all your test projects. Please update the source code for the following two methods:

LRESULT CExtPropertyGridWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
            if(                     message == WM_PRINT
                        ||           message == WM_PRINTCLIENT
                        )
            {
                        CDC * pDC = CDC::FromHandle( (HDC) wParam );
                        
                        CRect rcWnd, rcClient;
                        GetWindowRect( &rcWnd );
                        GetClientRect( &rcClient );
                        ClientToScreen( rcClient );
                        rcClient.OffsetRect( -rcWnd.TopLeft() );
                        rcWnd.OffsetRect( -rcWnd.TopLeft() );

                        if( (lParam&PRF_NONCLIENT) != 0 )
                        {
                                    CExtMemoryDC dc(
                                                pDC,
                                                &rcWnd
                                                );
                                    dc.ExcludeClipRect(rcClient);
                                    PmBridge_GetPM()->PaintResizableBarChildNcAreaRect(
                                                dc,
                                                rcWnd,
                                                this
                                                );
                                    dc.SelectClipRgn( NULL );
                        }
            
                        if( (lParam&(PRF_CLIENT|PRF_ERASEBKGND)) != 0 )
                        {
                                    CExtMemoryDC dc(
                                                pDC,
                                                &rcClient
                                                );
                                    CPoint ptVpOffset( 0, 0 );
                                    if( (lParam&PRF_NONCLIENT) != 0 )
                                    {
                                                ptVpOffset.x = rcWnd.left - rcClient.left;
                                                ptVpOffset.y = rcWnd.top - rcClient.top;
                                    }
                                    if(                     ptVpOffset.x != 0
                                                ||           ptVpOffset.y != 0
                                                )
                                                dc.OffsetViewportOrg(
                                                            -ptVpOffset.x,
                                                            -ptVpOffset.y
                                                            );
                                    OnSwPaint( dc );
                                    if(                     ptVpOffset.x != 0
                                                ||           ptVpOffset.y != 0
                                                )
                                                dc.OffsetViewportOrg(
                                                            ptVpOffset.x,
                                                            ptVpOffset.y
                                                            );
                        } // if( (lParam&(PRF_CLIENT|PRF_ERASEBKGND)) != 0 )
                        
                        if( (lParam&PRF_CHILDREN) != 0 )
                                    CExtPaintManager::stat_PrintChildren(
                                                m_hWnd,
                                                message,
                                                pDC->GetSafeHdc(),
                                                lParam,
                                                false
                                                );
                        return (!0);
            }
LRESULT lResult = CWnd::WindowProc( message, wParam, lParam );
            if( message == WM_GETDLGCODE )
                        lResult |= DLGC_WANTTAB;
            return lResult;
}

BOOL CExtResizableDialog::PreTranslateMessage(MSG* pMsg) 
{
            if(                     WM_KEYFIRST <= pMsg->message
                        &&        pMsg->message <= WM_KEYLAST
                        &&        GetSafeHwnd() != NULL
                        &&        ( pMsg->hwnd == m_hWnd || ::IsChild( m_hWnd, pMsg->hwnd ) )
                        &&        (GetStyle()&(WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE
                        )
            { // pre translating keyboard input (if enabled/visible dialog)
                        if( pMsg->wParam == VK_TAB )
                        {
                                    if( m_bAllowLongFocusJumpFix )
                                    {
                                                if( pMsg->message == WM_KEYDOWN )
                                                {
                                                            HWND hWnd = ::GetFocus();
                                                            if( hWnd != NULL )
                                                            {
                                                                        bool bWantsTab = ( ( ::SendMessage( hWnd, WM_GETDLGCODE, VK_TAB, 0 ) & DLGC_WANTTAB ) != 0 ) ? true : false;
                                                                        if( bWantsTab )
                                                                        {
                                                                                    CWnd * pWnd = CWnd::FromHandlePermanent( hWnd );
                                                                                    if(                     pWnd != NULL
                                                                                                &&        (           pWnd->IsKindOf( RUNTIME_CLASS(CDialog) )
#if (!defined __EXT_MFC_NO_TAB_PAGECONTAINER_CTRL)
                                                                                                            ||           pWnd->IsKindOf( RUNTIME_CLASS(CExtTabPageContainerWnd) )
#endif // (!defined __EXT_MFC_NO_TAB_PAGECONTAINER_CTRL)
                                                                                                            )
                                                                                                )
                                                                                                bWantsTab = false;
                                                                        } // if( bWantsTab )
                                                                        if( ! bWantsTab )
                                                                        {
                                                                                    HWND hWndMain = m_hWnd;
                                                                                    if( ( __EXT_MFC_GetWindowLong( hWndMain, GWL_STYLE ) & WS_CHILD ) != 0 )
                                                                                                hWndMain = ::GetParent( m_hWnd );
                                                                                    for( ; ( __EXT_MFC_GetWindowLong( hWndMain, GWL_STYLE ) & WS_CHILD ) != 0 ; )
                                                                                                hWndMain = ::GetParent( hWndMain );
                                                                                    if( hWndMain != NULL )
                                                                                    {
                                                                                                BOOL bPrevious = CExtPopupMenuWnd::IsKeyPressed( VK_SHIFT );
                                                                                                hWnd = stat_GetNextItemZ( hWndMain, m_hWnd, hWnd, bPrevious );
                                                                                                //hWnd = ::GetNextDlgTabItem( m_hWnd, hWnd, CExtPopupMenuWnd::IsKeyPressed( VK_SHIFT ) );
                                                                                                if( hWnd != NULL )
                                                                                                {
                                                                                                            //CWnd * pWnd = CWnd::FromHandlePermanent( hWnd );
                                                                                                            g_bProcessingLongFocusJump = true;
                                                                                                            g_bProcessingLongFocusJumpToPrevDir = bPrevious ? true : false;
                                                                                                            ::SetFocus( hWnd );
                                                                                                            if( ::SendMessage( hWnd, WM_GETDLGCODE, WPARAM(VK_TAB), LPARAM(pMsg) ) )
                                                                                                                        ::SendMessage( hWnd, EM_SETSEL, WPARAM(0L), LPARAM(-1L) );
                                                                                                            g_bProcessingLongFocusJump = false;
                                                                                                            //pWnd;
                                                                                                }
                                                                                    }
                                                                        } // if( ! bWantsTab )
                                                                        else
                                                                                    return FALSE;
                                                            } // if( hWnd != NULL )
                                                } // if( pMsg->message == WM_KEYDOWN )
                                                return TRUE;
                                    } // if( m_bAllowLongFocusJumpFix )
                        } // if( pMsg->wParam == VK_TAB )
                        else
                        {
                                    if( (GetStyle()&(WS_VISIBLE|WS_CHILD)) == (WS_VISIBLE|WS_CHILD) )
                                    { // if child/visible dialog
                                                HWND hWndParent = ::GetParent( m_hWnd );
                                                CWnd * pWndParentPermanent = CWnd::FromHandlePermanent( hWndParent );
                                                if(                     pWndParentPermanent != NULL
                                                            &&        (           pWndParentPermanent->IsKindOf( RUNTIME_CLASS(CExtControlBar) )
#if (!defined __EXT_MFC_NO_TAB_CONTROLBARS)
                                                                        ||           pWndParentPermanent->IsKindOf( RUNTIME_CLASS(CExtDynAutoHideSlider) )
#endif // (!defined __EXT_MFC_NO_TAB_CONTROLBARS)
                                                                        )
                                                            &&        pWndParentPermanent->PreTranslateMessage(pMsg)
                                                            )
                                                            return TRUE;
                                    } // if child/visible dialog
                        } // else from if( pMsg->wParam == VK_TAB )

                        HWND hWndFocus = ::GetFocus();
                        if(                     hWndFocus != NULL
                                    &&        ::GetParent( hWndFocus ) == m_hWnd
                                    //&&      ( ::SendMessage( hWndFocus, WM_GETDLGCODE, 0L, 0L ) & (DLGC_WANTCHARS|DLGC_WANTALLKEYS) == 0 )
                                    )
                        {
                                    bool bProcessKey = false;
                                    BOOL bAlt = HIWORD(pMsg->lParam) & KF_ALTDOWN;
                                    LRESULT lRDC = ::SendMessage( hWndFocus, WM_GETDLGCODE, pMsg->wParam, 0L );
                                    if(                     ( lRDC & DLGC_WANTALLKEYS ) == 0
                                                &&        (           ( lRDC & DLGC_WANTCHARS ) == 0
                                                            ||           bAlt
                                                            )
                                                )
                                    {
                                                bProcessKey = true;
                                    }
                                    if( bProcessKey )
                                    {
                                                //BOOL bKeyUp = ( pMsg->message == WM_KEYUP || pMsg->message == WM_SYSKEYUP) ? TRUE : FALSE;
                                                BOOL bCtrl = GetKeyState(VK_CONTROL) & 0x80000000;
                                                BOOL bShift = GetKeyState(VK_SHIFT) & 0x80000000;
                                                if( ! ( bCtrl || bShift ) )
                                                {
                                                            TCHAR vkTCHAR = (TCHAR)pMsg->wParam;
                                                            BYTE lpKeyState[256];
                                                            ::GetKeyboardState( lpKeyState );
                                                            UINT wScanCode = ::MapVirtualKey( vkTCHAR, 0 );
                                                            HKL hKeyboardLayout =
                                                                        ::GetKeyboardLayout(
                                                                                    ( ::AfxGetThread() ) -> m_nThreadID
                                                                                    );
#if (defined _UNICODE)
                                                            TCHAR szChar[2] = { _T(’\0’), _T(’\0’) };
                                                            ::ToUnicodeEx(
                                                                        vkTCHAR,
                                                                        wScanCode,
                                                                        lpKeyState,
                                                                        szChar, 1,
                                                                        1,
                                                                        hKeyboardLayout
                                                                        );
#else
                                                            WORD nMapped = 0;
                                                            ::ToAsciiEx(
                                                                        vkTCHAR,
                                                                        wScanCode,
                                                                        lpKeyState,
                                                                        &nMapped,
                                                                        1,
                                                                        hKeyboardLayout
                                                                        );
                                                            TCHAR szChar[2] = { (TCHAR)nMapped, _T(’\0’) };
#endif
                                                            ::CharUpper( szChar );
                                                            if( szChar[0] != 0 )
                                                            {
                                                                        HWND hWnd = ::GetWindow( m_hWnd, GW_CHILD );
                                                                        for( ; hWnd != NULL; hWnd = ::GetWindow( hWnd, GW_HWNDNEXT ) )
                                                                        {
                                                                                    CWnd * pWnd = CWnd::FromHandlePermanent( hWnd );
                                                                                    if( pWnd == NULL )
                                                                                                continue;
                                                                                    if( (pWnd->GetStyle()&(WS_VISIBLE|WS_DISABLED)) != WS_VISIBLE )
                                                                                                continue;
                                                                                    CExtButton * pExtButton = DYNAMIC_DOWNCAST( CExtButton, pWnd );
                                                                                    if( pExtButton == NULL )
                                                                                                continue;
                                                                                    if(                     pExtButton->m_bQuickActivationEnabled
                                                                                                &&        pExtButton->_QuickActivationCheck( DWORD(vkTCHAR) )
                                                                                                )
                                                                                    {
                                                                                                if(                     pMsg->message == WM_KEYDOWN
                                                                                                            ||           pMsg->message == WM_SYSKEYDOWN
                                                                                                            )
                                                                                                {
                                                                                                            if( hWndFocus != pExtButton->m_hWnd )
                                                                                                                        pExtButton->SetFocus();
                                                                                                }
                                                                                                if(                     pMsg->message == WM_KEYUP
                                                                                                            ||           pMsg->message == WM_SYSKEYUP
                                                                                                            )
                                                                                                {
                                                                                                            if( pExtButton->PreTranslateMessage( pMsg ) )
                                                                                                                        return TRUE;
                                                                                                }
                                                                                                //break;
                                                                                                return TRUE;
                                                                                    }
                                                                        }
                                                            }
                                                } // if( ! ( bCtrl || bShift ) )
                                    } // if( bProcessKey )
                        } // if( hWndFocus != NULL && ::GetParent( hWndFocus ) == m_hWnd ...
            } // pre translating keyboard input (if enabled/visible dialog)

            if(                     ( GetStyle() & WS_VISIBLE ) != 0
                        &&        CExtControlBar::DoCustomModePreTranslateMessage( this, pMsg )
                        )
                        return TRUE;

            if( pMsg->message == WM_LBUTTONDOWN )
                        return FALSE;

            return CExtWA < CExtWS < __BASEOF_CExtResizableDialog__ > >::PreTranslateMessage(pMsg);
}







Rolf Boerkoel Nov 17, 2009 - 2:32 AM

You are now initializing them with the value of g_bAllowLongFocusJumpFix, which is true by default. Therefore this will not solve the tabbing problem as it requires the m_bAllowLongFocusJumpFix to be false instead of true.


So what is the recommended way to get this to work? Should I set the global  g_bAllowLongFocusJumpFix to false myself, or should I set m_bAllowLongFocusJumpFix in every child dialog? Something else?

Technical Support Nov 13, 2009 - 1:54 PM

Your child dialog that is inside other dialog should have the WS_EX_CONTROLPARENT extended window style. Nothing else is needed.
Additionally, the property grid control in Prof-UIS 2.87 supports the tab key navigation through it.