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 » The bug of MDI switching is not fixed in 2.84 - it's even worse... Collapse All
Subject Author Date
Offer Har Dec 22, 2008 - 5:09 PM

Dear Support


What happen now that my views receive some resize events and all their center is moved when I switching view from the MDI tab for example.


Is there any chance to get this working like it did in 2.82? We are currently releasing products with 2.82 and this bug is not there.


This is for us a major problem and we don’t know how to use the library like this.


Please help us solve this issue ASAP. We were planning on moving to 2.84 early January, because of some bug fixes and new feature, but with this bug we cannot do it.


Thanks,


Ron.

Technical Support Dec 24, 2008 - 7:59 AM

The WM_SIZE message during MDI child frame activation is generated by Windows not by Prof-UIS. The only thing we can do is to hide flicker during MDI child frame activation. Prof-UIS 2.84 hides this flicker in all the cases excepting one case which even happen not in all the applications: the MDI tabs based MDI child frame selection. To fix this issue please update the source code of the CExtTMWI::OnTabWndSelectionChange() method:

      virtual bool OnTabWndSelectionChange(
            LONG nOldItemIndex,
            LONG nNewItemIndex,
            bool bPreSelectionTest
            )
      {
#if (!defined __EXT_MFC_NO_CUSTOMIZE)
            CExtCustomizeSite * pSite =
                  CExtCustomizeSite::GetCustomizeSite( m_hWnd );
            if(         pSite != NULL
                  &&    pSite->IsCustomizeMode()
                  )
                  return false;
#endif // (!defined __EXT_MFC_NO_CUSTOMIZE)
            bool bRetVal =
                  _BT::OnTabWndSelectionChange( nOldItemIndex, nNewItemIndex, bPreSelectionTest );
            if( (!m_bInSyncLayout) && (!bPreSelectionTest) && (!m_bDragging))
            {
                  ASSERT( bRetVal );
                  HWND hWnd = (HWND)ItemLParamGet( nNewItemIndex );
                  if( hWnd != NULL && ::IsWindow(hWnd) )
                  {
                        // FrameFeatures does not use CMDIFrameWnd
                        HWND hWndMdiArea = _GetHwndMdiArea();
                        if( hWndMdiArea != NULL )
                        {
                              ::SendMessage( hWndMdiArea, WM_SETREDRAW, 0, 0 );
                              HWND hWndAlreadyActive = (HWND)
                                    ::SendMessage( hWndMdiArea, WM_MDIGETACTIVE, 0, 0 );
                              if( hWndAlreadyActive != hWnd )
                                    ::SendMessage( hWndMdiArea, WM_MDIACTIVATE, (WPARAM)hWnd, 0 );
                              ::SendMessage( hWndMdiArea, WM_SETREDRAW, 1, 0 );
                              ::SetWindowPos(
                                    hWndMdiArea, NULL, 0, 0, 0, 0,
                                    SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER
                                          |SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_FRAMECHANGED
                                    );
                        } // if( hWndMdiArea != NULL )
                  } // if( hWnd != NULL && ::IsWindow(hWnd) )
            } // if( (!m_bInSyncLayout) && (!bPreSelectionTest) )
            else
            {
                  HWND hWndMdiArea = _GetHwndMdiArea();
                  if( hWndMdiArea != NULL )
                        ::SetWindowPos(
                              hWndMdiArea, NULL, 0, 0, 0, 0,
                              SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER
                                    |SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_FRAMECHANGED
                              );
            } // else from if( (!m_bInSyncLayout) && (!bPreSelectionTest) )
            return bRetVal;
      }

Offer Har Dec 24, 2008 - 1:34 PM

Thanks - that solved the flicker problem.


Is there anyway to add an hourglash when swithcing view or to have some globar variable that will tell me that we’re in the of views switching so that I will stop doing the hard-work in these useless WM_SIZE messages? My problem now is that views switching still takes up noticeable time, and it fells that the system hangs...

Technical Support Dec 26, 2008 - 2:47 AM

The MDI child frame activation is performed via sending WM_MDIACTIVATE message to the MDI client area:

http://msdn.microsoft.com/en-us/library/ms644911(VS.85).aspx

Then the MDI client area window switches the active child frame window and sends this message to child frames. So, you need to subclass the window procedure of the MDI client area window to catch the WM_MDIACTIVATE message. This procedure is already subclassed by the CExtMenuControlBar class (and derived from it classes like CExtRibbonPage and CExtRibbonBar ). The CExtMenuControlBar is derived from the CExtHookSink class and implements the CExtHookSink::OnHookWndMsg() virtual method. You should override this method in your CExtMenuControlBar-derived class and show the waiting cursor on the WM_MDIACTIVATE message. You will also need to implement the CExtHookSink::OnPostHookWndMsg() virtual method for restoring cursor.

class CYourMenuBar : public CExtMenuControlBar
{
protected:
            CWaitCursor * m_pWaitCursor;
public:
            CYourMenuBar ()
                        : m_pWaitCursor( NULL )
            {
            }
            ~CYourMenuBar()
            {
                        if( m_pWaitCursor != NULL )
                                    delete m_pWaitCursor;
            }
protected:
            virtual bool OnHookWndMsg( LRESULT & lResult, HWND hWndHooked, UINT nMessage, WPARAM & wParam, LPARAM & lParam )
            {
                        if( hWndHooked == _GetHwndMdiArea() && nMessage == WM_MDIACTIVATE )
                                    m_pWaitCursor = new CWaitCursor;
                        return CExtMenuControlBar::OnHookWndMsg( lResult, hWndHooked, nMessage, wParam, lParam );
            }
            virtual void OnPostHookWndMsg( LRESULT lResult, HWND hWndHooked, UINT nMessage, WPARAM wParam, LPARAM lParam )
            {
                        if( m_pWaitCursor != NULL && hWndHooked == _GetHwndMdiArea() && nMessage == WM_MDIACTIVATE )
                        {
                                    delete m_pWaitCursor;
                                    m_pWaitCursor = NULL;
                        }
                        CExtMenuControlBar::OnPostHookWndMsg( lResult, hWndHooked, nMessage, wParam, lParam );
            }
};

Please note, the method above will show the show the waiting cursor when your application activates the MDI child frame window by its handle. This happens when you clicking tab item on the MDI tab control or selecting menu item from Window button of menu bar. The MDI frames can also be switched using MDI window sequence. This happen when you pressing Ctrt+Tab, Ctrt+Shift+Tab and Ctrt+F6 key combinations. The improved menu bar which you see above will not show the waiting cursor on cyclic MDI frame activation. If you need the waiting cursor during cyclic MDI child frame activation, then the class above should be improved and it should catch the WM_MDINEXT message:
class CYourMenuBar : public CExtMenuControlBar
{
protected:
            CWaitCursor * m_pWaitCursor;
public:
            CYourMenuBar ()
                        : m_pWaitCursor( NULL )
            {
            }
            ~CYourMenuBar()
            {
                        if( m_pWaitCursor != NULL )
                                    delete m_pWaitCursor;
            }
protected:
            virtual bool OnHookWndMsg( LRESULT & lResult, HWND hWndHooked, UINT nMessage, WPARAM & wParam, LPARAM & lParam )
            {
                        if(                     ( nMessage == WM_MDIACTIVATE || nMessage == WM_MDINEXT )
                                    &&        hWndHooked == _GetHwndMdiArea()
                                    )
                                    m_pWaitCursor = new CWaitCursor;
                        return CExtMenuControlBar::OnHookWndMsg( lResult, hWndHooked, nMessage, wParam, lParam );
            }
            virtual void OnPostHookWndMsg( LRESULT lResult, HWND hWndHooked, UINT nMessage, WPARAM wParam, LPARAM lParam )
            {
                        if(                     m_pWaitCursor != NULL
                                    &&        ( nMessage == WM_MDIACTIVATE || nMessage == WM_MDINEXT )
                                    &&        hWndHooked == _GetHwndMdiArea()
                                    )
                        {
                                    delete m_pWaitCursor;
                                    m_pWaitCursor = NULL;
                        }
                        CExtMenuControlBar::OnPostHookWndMsg( lResult, hWndHooked, nMessage, wParam, lParam );
            }
};

We think the last one works better and displays the waiting cursor in all the often occurred cases but not in all the 100% cases. The MDI child frames sometimes become created and destroyed. If you are closing the MDI child frame window, then the next MDI child frame under it will become active and this will take the same time as active frame selection or cyclic switching. The same is related for newly created frame. Besides, the newly created time may require some additional time for initialization in your real application. So, we should improve the second version of menu bar once more:
class CYourMenuBar : public CExtMenuControlBar
{
protected:
            CWaitCursor * m_pWaitCursor;
public:
            CYourMenuBar ()
                        : m_pWaitCursor( NULL )
            {
            }
            ~CYourMenuBar()
            {
                        if( m_pWaitCursor != NULL )
                                    delete m_pWaitCursor;
            }
protected:
            virtual bool OnHookWndMsg( LRESULT & lResult, HWND hWndHooked, UINT nMessage, WPARAM & wParam, LPARAM & lParam )
            {
                        if(                     ( nMessage == WM_MDIACTIVATE || nMessage == WM_MDINEXT || nMessage == WM_MDICREATE || nMessage == WM_MDIDESTROY )
                                    &&        hWndHooked == _GetHwndMdiArea()
                                    )
                                    m_pWaitCursor = new CWaitCursor;
                        return CExtMenuControlBar::OnHookWndMsg( lResult, hWndHooked, nMessage, wParam, lParam );
            }
            virtual void OnPostHookWndMsg( LRESULT lResult, HWND hWndHooked, UINT nMessage, WPARAM wParam, LPARAM lParam )
            {
                        if(                     m_pWaitCursor != NULL
                                    &&        ( nMessage == WM_MDIACTIVATE || nMessage == WM_MDINEXT || nMessage == WM_MDICREATE || nMessage == WM_MDIDESTROY )
                                    &&        hWndHooked == _GetHwndMdiArea()
                                    )
                        {
                                    delete m_pWaitCursor;
                                    m_pWaitCursor = NULL;
                        }
                        CExtMenuControlBar::OnPostHookWndMsg( lResult, hWndHooked, nMessage, wParam, lParam );
            }
};

Offer Har Dec 22, 2008 - 9:01 PM

The bug is that WM_SIZE is called when this views switch is done - this is not supposed to be called, because it is passed with the restore size values, so I do some computations that changes the center of the view according to this wrong size.


In any case, the call to WM_SIZE also slows down the views switching, because I do a lot of computations in this function, and there is no need to it to be called, because the size did not really change.