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 » avoiding unneeded RecalcLayout calls Collapse All
Subject Author Date
Mark Walsen Apr 21, 2006 - 6:44 PM

My application was calling CMDIFrameWnd::RecalcLayout multiple times in a transaction, when only one final call was really needed. I suspect that I had this problem before I initroduced Prof-UIS into the application. But the extra calls to RecalcLayout noticeably slowed down the application when Prof-UIS was introduced. Also, the control bars would shuffle around, creating a distraction for the user.

I think I found a way to work around this problem. It might be even better than a work-around. It might actually be a good solution. I’d be interested in Prof-UIS Support’s opinion of this:

1. Add a BOOL m_bPendingPostMessage member to the CMainFrame.

2. In the CMainFrame, override CMDIFrameWnd::RecalcLayout:

void CMainFrame::RecalcLayout(BOOL bNotify)
{
    if (!m_bPostMessageRecalcLayoutPending)
    {
        m_bPostMessageRecalcLayoutPending = TRUE;
        PostMessage(WM_USER_PENDING_RECALC_LAYOUT, bNotify);
    }
}

3. Handle the WM_USER_PENDING_RECALC_LAYOUT message as follows:

LONG CMainFrame::OnPendingRecalcLayout(UINT wParam, LONG)
{
    CMDIFrameWnd::RecalcLayout((BOOL)wParam /* bNotify */);
    m_bPostMessageRecalcLayoutPending = FALSE;
    return 0;
}


The control bars have really "calmed down" once I did this. It was such a easy solution, compared to hunting down all of the cases where there were redundant calls to RecalcLayout. I believe this solution does more than what the MFC CFrameWnd::m_bInRecalcLayout does, which is apparently to just avoid recursive calls, perhaps infinitely recursive calls.

Please let me know if you see any flaws in this.

Cheers
-- Mark

Technical Support Apr 22, 2006 - 7:08 AM

In most cases, when the main thread often becomes busy, using CFrameWnd::DelayRecalcLayout()is enough to make the frame layout re-computed and updated. This method simply modifies the CFrameWnd::m_nIdleFlags public property by adding the CFrameWnd::idleLayout flag. If your application periodically reaches the idle state, then the frame layout will be recomputed.

If the main UI thread is constantly busy like in the GLViews sample when animation is on, then you should do one of the following ways:

1) Let the message queue live. Invoke periodically the CExtPopupMenuWnd::PassMsgLoop() static method. It should be invoked after each long and heavy operation in the main UI thread. The GLViews sample application generates scene images in the second helper thread and passes the image surface to the main thread. The main thread invokes the CExtPopupMenuWnd::PassMsgLoop() static method after receiving an updated scene image from the second thread. This makes frame layout updated and allows you to perform mouse/keyboard input which is needed to see working toolbar buttons and menu items. If you do not need the mouse/keyboard input, you can use the CExtPaintManager::stat_PassPaintMessages() static method instead of CExtPopupMenuWnd::PassMsgLoop(). The CExtPaintManager::stat_PassPaintMessages() static method will process only painting messages pending in the message queue of the main UI thread. This will make all the windows updated.

2) You can use the timer in the main frame window which will check the ( ( ( CFrameWnd::m_nIdleFlags & CFrameWnd::idleLayout ) != 0 ) ? true : false ) condition. If it is true, then you should the CFrameWnd::DelayRecalcLayout() method. You can also check this condition without using the timer if you have any other kind periodically invoked code where this condition can be checked.