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 » Repainting label text after changing document title Collapse All
Subject Author Date
Rolf Boerkoel Nov 2, 2009 - 8:52 AM

Dear support,


I have an MDI application with tabs to manage the childframes (CExtTabMdiWnd and friends). ProfUIS 2.87 latest snapshot.


If I change the title of some CDocument, the new document name is not repainted automatically in the tab labels. Only after forcing an invalidation of the tab control area (by moving the mouse over, by minimizing/maximizing etc.) the new name gets repainted.



You can see this same behaviour in e.g. the form-editor sample application. Start the application, select File / Save As..., enter some new name and notice that the label text in the tab control remains the same.


I can of course get by this problem by doing something like :


AfxGetMainWnd()->PostMessage(WM_APP_INVALIDATEMDITABS)

...

void CMainFrame::OnInvalidateMdiTabs()

{

    m_mdiTabWindow.Invalidate();

}


on every occasion a document title might be changed. In fact I am doing this right now. But this feels a bit like a clumsy workaround. 


Is there a possibility that you can invalidate MDI tab controls automatically from somewhere within the Prof-UIS library?


 


Kind Regards,


Marco

Rolf Boerkoel Nov 4, 2009 - 2:14 AM

No, actually I meant CExtTMWI<CExtTabWnd>::_SyncAllItems(). I’ll send you a minimal sample application by email.



In this sample I can close the documents without any problems, strangely enough. However it DOES go wrong if I switch to another doc/view by clicking on the tabs. Exact the same assertion is raised as in our application; the stack trace looks very similar.



Here’s a piece of this stack trace:


(...)

__crtMessageBoxA(const char * 0x0012b6a4, const char * 0x102579a0 `string’, unsigned int 73746) line 65

CrtMessageWindow(int 2, const char * 0x00c833a0 THIS_FILE, const char * 0x0012c7d8, const char * 0x00000000, const char * 0x0012e7fc) line 520 + 22 bytes

_CrtDbgReport(int 2, const char * 0x00c833a0 THIS_FILE, int 948, const char * 0x00000000, const char * 0x00000000) line 419 + 76 bytes

AfxAssertFailedLine(const char * 0x00c833a0 THIS_FILE, int 948) line 39 + 20 bytes

CExtTabWnd::AssertValid() line 948 + 47 bytes

CExtTabMdiWnd::AssertValid() line 6478

AfxAssertValidObject(const CObject * 0x018cf574 {CExtTabMdiWnd}, const char * 0x00c833a0 THIS_FILE, int 4943) line 108

CExtTabWnd::OnTabWndRemoveItem(long 2, long 1, unsigned char 0) line 4947

CExtTMWI<CExtTabWnd>::OnTabWndRemoveItem(long 2, long 1, unsigned char 0) line 1988

CExtTabWnd::ItemRemove(long 2, long 1, unsigned char 0) line 1709 + 26 bytes

CExtTMWI<CExtTabWnd>::_SyncAllItems() line 1330

CExtTMWI<CExtTabWnd>::WindowProc(unsigned int 275, unsigned int 3, long 0) line 2144 + 16 bytes

AfxCallWndProc(CWnd * 0x018cf574 {CExtTabMdiWnd hWnd=???}, HWND__ * 0x00140502, unsigned int 275, unsigned int 3, long 0) line 215 + 26 bytes

AfxWndProc(HWND__ * 0x00140502, unsigned int 275, unsigned int 3, long 0) line 368

AfxWndProcBase(HWND__ * 0x00140502, unsigned int 275, unsigned int 3, long 0) line 220 + 21 bytes

(...)


 CExtTabWnd::AssertValid() is triggered because m_nVisibleItemCount (=3) becomes bigger than nItemCount (=2).


As I mentioned before, the problem is not present if the update is delayed by posting a WM_TIMER message.

I also noticed that if I leave out the CExtNCB from the CMdiFrameWnd the problem also does not occur.



Marco

Technical Support Nov 9, 2009 - 1:23 PM

Dear Marco,

Thank you for providing us with the test project. To fix the MDI tabs assertion issue please update the source code for the CExtTMWI::_SyncAllItems() method:

   virtual bool _SyncAllItems()
            {
                        if( m_nSyncCounter < m_nSyncWaitCount )
                        {
                                    m_nSyncCounter++;
                                    return false;
                        }
                        if( m_bInSyncLayout || _IsDND() )
                                    return true;
                        m_bInSyncLayout = true;
                        CWnd * pWndActiveMdiChild = NULL;
                        HWND hWndMainFrame = _GetHwndMainFrame();
                        HWND hWndMdiArea = _GetHwndMdiArea();
                        if(                     hWndMainFrame == NULL
                                    ||           hWndMdiArea == NULL
                                    )
                        {
                                    m_bInSyncLayout = false;
                                    return true;
                        }
                        CMDIFrameWnd * pMdiFrame =
                                    DYNAMIC_DOWNCAST(
                                                CMDIFrameWnd,
                                                CWnd::FromHandlePermanent(hWndMainFrame)
                                                );
                        if( pMdiFrame != NULL )
                        {
                                    pWndActiveMdiChild = pMdiFrame->MDIGetActive(NULL);
                        } // if( pMdiFrame != NULL )
                        else
                        {
                                    HWND hWnd = (HWND)
                                                ::SendMessage(
                                                            hWndMdiArea,
                                                            WM_MDIGETACTIVE,
                                                            0,
                                                            0
                                                            );
                                    if( hWnd == NULL )
                                    {
                                                m_bInSyncLayout = false;
                                                return true;
                                    }
                                    pWndActiveMdiChild = CWnd::FromHandle( hWnd );
                        } // else from if( pMdiFrame != NULL )
                        if( pWndActiveMdiChild == NULL )
                        {
                                    m_bInSyncLayout = false;
                                    return true;
                        }
                        bool bCloseEnabled = false;
                        HWND hWndMdiChild = NULL;
                        if( pWndActiveMdiChild != NULL )
                        {
                                    hWndMdiChild =
                                                pWndActiveMdiChild->
                                                            GetWindow( GW_HWNDFIRST )->
                                                                        GetSafeHwnd();
                                    CMenu * pSysMenu = pWndActiveMdiChild->GetSystemMenu( FALSE );
                                    if( pSysMenu != NULL )
                                    {
                                                MENUITEMINFO mii;
                                                ::memset(&mii,0,sizeof(MENUITEMINFO));
                                                mii.cbSize = sizeof(MENUITEMINFO);
                                                mii.fMask = MIIM_STATE;
                                                if( pSysMenu->GetMenuItemInfo(
                                                                        SC_CLOSE,
                                                                        &mii,
                                                                        FALSE
                                                                        )
                                                            )
                                                {
                                                            if( ( mii.fState & (MFS_DISABLED|MFS_GRAYED) ) == 0 )
                                                                        bCloseEnabled = true;
                                                }
                                    }
                        }
                        ModifyTabWndStyle(
                                    bCloseEnabled ? 0 : __ETWS_ENABLED_BTN_CLOSE,
                                    bCloseEnabled ? __ETWS_ENABLED_BTN_CLOSE : 0,
                                    false
                                    );
                        for( ; hWndMdiChild != NULL; hWndMdiChild = ::GetWindow( hWndMdiChild, GW_HWNDNEXT ) )
                        {
                                    LONG nIndexExist = ItemFindByHWND( hWndMdiChild, -1, true, true );
                                    if( nIndexExist >= 0 )
                                    {
                                                if( hWndMdiChild == pWndActiveMdiChild->GetSafeHwnd() )
                                                            SelectionSet( nIndexExist, true, false );
                                                continue;
                                    }
                                    ItemInsert(
                                                NULL,
                                                NULL, false,
                                                0,
                                                -1,
                                                LPARAM( hWndMdiChild ),
                                                false
                                                );
                                    if( hWndMdiChild == pWndActiveMdiChild->GetSafeHwnd() )
                                                SelectionSet( ItemGetCount()-1, true, false );
                        } // for( ; hWndMdiChild != NULL; hWndMdiChild = ::GetWindow( hWndMdiChild, GW_HWNDNEXT ) )
                        m_nVisibleItemCount = 0L;

                        for( INT nIndex = 0; nIndex < ItemGetCount(); )
                        {
                                    TAB_ITEM_INFO * pTii = ItemGet( nIndex );
                                    ASSERT_VALID( pTii );
                                    HWND hWnd = (HWND)pTii->LParamGet();
                                    ASSERT( hWnd );
                                    if( ::IsWindow( hWnd ) )
                                    {
                                                if(                     hWnd == pWndActiveMdiChild->m_hWnd 
                                                            &&        (!bCloseEnabled)
                                                            )
                                                            pTii->ModifyItemStyleEx( 0, __ETWI_EX_NO_CLOSE_ON_TAB );

                                                bool bVisible = ::IsWindowVisible( hWnd ) ? true : false;
                                                pTii->VisibleSet( bVisible );
                                                nIndex++;
                                    }
                                    else
                                                ItemRemove( nIndex );
                        }
                        m_bInSyncLayout = false;
                        bool bLayoutUpdated = _RecalcFrameLayout();
                        Invalidate();
                        return bLayoutUpdated;
            }

Rolf Boerkoel Nov 10, 2009 - 2:36 AM

It looks like the problem is solved with this fix. Thanks.

Technical Support Nov 2, 2009 - 11:14 AM

The MDI tab window hooks the standard MDI interface and updates tab items automatically when catching any messages affecting to captions of MDI child frame windows. But the document title is just a text property of MFC document that is not HWND-based component and does not receive any messages. That’s why manual updating of the MDI tab window is required. You should invoke the UpdateTabWnd() method of MDI tabs control after changing document’s title.


Rolf Boerkoel Nov 3, 2009 - 2:46 AM

Ok, got it.


In the meantime I changed the redraw mechanism by overriding CMDIFrameWnd::OnUpdateFrameTitle which seems to work fine.




void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
    CMDIFrameWnd::OnUpdateFrameTitle(bAddToTitle);
    m_myExtMdiTabWindow.UpdateTabWnd();
}


After a google search I found that this question has been asked before on this forum. It might be illustrative for other ProfUIS users if you include a similar solution in the sample applications, because these samples also do not redraw their tabs when a document title changes.


 

Rolf Boerkoel Nov 3, 2009 - 4:35 AM

Perhaps calling UpdateTabWnd directly from OnUpdateFrameTitle is not a good idea, it makes my application crash somewhere in CExtTabMdiWnd::_SyncAllItems() when a document is closed when two or more documents are active.



A delayed update however always works fine:


void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
    CMDIFrameWnd::OnUpdateFrameTitle(bAddToTitle);
    m_myExtMdiTabWindow.PostMessage(WM_TIMER, __EXTTAB_MDI_UPDATE_TIMER_ID, 0);
}

(using the same trick as you do).

Technical Support Nov 3, 2009 - 1:00 PM

We guess you meant the CExtPopupMenuWnd::_SyncItems() method. Could you please provide us with a call stack listing at the crash time and exact crash location in the source code of the _SyncItems() method?