Codejock Forums Homepage
Forum Home Forum Home > Codejock Products > Visual C++ MFC > General Discussion
  New Posts New Posts RSS Feed - Backstage display issue
  FAQ FAQ  Forum Search   Events   Register Register  Login Login

Backstage display issue

 Post Reply Post Reply
Author
Message
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 605
Post Options Post Options   Thanks (1) Thanks(1)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Topic: Backstage display issue
    Posted: 25 July 2018 at 12:21pm
We build a backstage and when we transition to it, users (some) are complaining that they see rectangles "flashing". What they are seeing is that during the painting operation, parts of the window displayed before transitioning to the backstage show up where buttons and other controls sit.

So I built the CJ RibbonSample. I size the window so that the "CodeJock" technology (testimonial) page fills the frame client area. Then I set a breakpoint in CXTPRibbonBackstageView::RecalcLayout and CXTPRibbonBackstageView::OnCtlColor. Then I click the "File" object to go to the backstage.

RecalcLayout is called twice. On the second call after GetActiveControlPane is called and then SetWindowPos is called. OnCtlColor is called then and the white brush is returned. Then as the calls unwind, the app window updates with parts of the window painted with the background but lots of areas (rectangles) are not painted. This is what the user is seeing, which when running our app is much more noticable to the user.

Is there a way to force the entire background to update so the user doesn't briefly see this?


Back to Top
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 605
Post Options Post Options   Thanks (0) Thanks(0)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Posted: 25 July 2018 at 2:31pm
I added this to fix the problem (minimal testing so mileage may vary):

BOOL CXTPRibbonBackstageView::OnEraseBkgnd(CDC* pDC)
{
    CRect rectClient;
    GetClientRect(rectClient);
    pDC->FillSolidRect(rectClient, m_clrBack);
    return TRUE;
}

Is this something that can be added to the toolkit source?
Back to Top
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 605
Post Options Post Options   Thanks (0) Thanks(0)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Posted: 25 July 2018 at 3:26pm
Should have mentioned this too. When exiting the BS, the call in SetTrackingMode to DestroyWindow causes another "flashing" display in our app. I duplicate it (essentially) in the ribbon sample. What I did to avoid that is to not call DestroyWindow. Instead I copied the code from OnDestroy and execute it except for the call to CWnd::OnDestroy.

Then I modified ShowbackstageView like this:

    if( 0 == m_hWnd )
    {
        CWnd::Create(AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)), 0, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CRect(0, 0, 0, 0), pParentWnd, 0);
    }

The result is that the window is created only one time and the user doesn't see the display that occurs when DestroyWindow is called. For our app, the entire area of the app under the ribbon bar fills with a gray background (not sure if it is the button face color or the background color of our MDI child window but I think it is the latter).

Here is what calling DestroyWindow does to the sample app. You can see rectangles for items of the app client area that will be transitioned to displayed blue at the bottom left as well as the outline of the "Styles" docking pane list. The change I made avoids all that.



Again, code changes is minimally tested. Factoring OnDestroy to create a new method that is called  from OnDestroy and SetTrackingMode with a flag to indicate it really is a destroy call so CWnd::OnDestroy can be called would be desirable to avoid the flashing we are seeing. That way I don't have to modify the toolkit code or override methods and copy the current code.
Back to Top
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 605
Post Options Post Options   Thanks (0) Thanks(0)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Posted: 25 July 2018 at 3:31pm
Rats. I forgot one detail when exiting the BS. Besides not calling CWnd::OnDestroy, I added a call to Sho9wWindow(SW_HIDE) AFTER removing hooks and showing windows etc., etc. Here is the code snippet where I made the change. The static just let me experiment in case I thought the change caused some unintended side-effect (none of which I have observed).

    if (!bMode)
    {
        static int s_NoD = 1;
        if( !s_NoD )
        {
            DestroyWindow();
        }
        else
        {
            m_bTracking = FALSE;

            CWnd* pParentWnd = GetCommandBars()->GetSite();

            XTPHookManager()->RemoveHook(pParentWnd->GetSafeHwnd(), this);

            for (int i = 0; i < m_arrChildWindows.GetSize(); i++)
            {
                HWND hWndChild = m_arrChildWindows;
                ::ShowWindow(hWndChild, SW_SHOWNOACTIVATE);
            }

            SetActiveTab(NULL);

            if (m_pSystemButton)
            {
                m_pSystemButton->OnSetPopup(FALSE);
                if (m_pSystemButton->GetParent())
                {
                    m_pSystemButton->GetParent()->Redraw(0, FALSE);
                }

                GetCommandBars()->RecalcFrameLayout();
            }

            GetCommandBars()->GetKeyboardManager()->UnhookKeyboard(this);

            m_pSystemButton = NULL;

            if (m_themeCurrent == xtpThemeOffice2016)
            {
                //CXTPRibbonBar* pRibbonBar = DYNAMIC_DOWNCAST(CXTPRibbonBar, GetCommandBars()->GetMenuBar());
                ASSERT(pRibbonBar);
                if (m_bRestoreQuickAccess)
                    pRibbonBar->ShowQuickAccess(TRUE);
                m_pCommandBars->GetPaintManager()->m_bBackstageMode = FALSE;
                m_pCommandBars->GetPaintManager()->m_nFrameCaptionTextShift = 0;
            }

            // Show here as when I did this where destroy was called, the background still painted on some window giving the big gray area "flash" I am trying
            // to prevent.
            ShowWindow( SW_HIDE );
        }

Back to Top
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 605
Post Options Post Options   Thanks (0) Thanks(0)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Posted: 25 July 2018 at 5:31pm
Since I had to modify our copy of the CJ source, I figured I post my changes to XTPRibbonBackstageView.cpp. The version I have modified is 18.2

void CXTPRibbonBackstageView::OnDestroy()
{
    CleanupForTrackingOrDestroy(true);
}

void  CXTPRibbonBackstageView::CleanupForTrackingOrDestroy( bool bDestroy )
{
    m_bTracking = FALSE;

    CWnd* pParentWnd = GetCommandBars()->GetSite();

    XTPHookManager()->RemoveHook(pParentWnd->GetSafeHwnd(), this);

    for (int i = 0; i < m_arrChildWindows.GetSize(); i++)
    {
        HWND hWndChild = m_arrChildWindows;
        ::ShowWindow(hWndChild, SW_SHOWNOACTIVATE);
    }

    SetActiveTab(NULL);

    if (m_pSystemButton)
    {
        m_pSystemButton->OnSetPopup(FALSE);
        if (m_pSystemButton->GetParent())
        {
            m_pSystemButton->GetParent()->Redraw(0, FALSE);
        }

        GetCommandBars()->RecalcFrameLayout();
    }

    GetCommandBars()->GetKeyboardManager()->UnhookKeyboard(this);

    m_pSystemButton = NULL;

    if( bDestroy )
    {
        CWnd::OnDestroy();
    }

    if (m_themeCurrent == xtpThemeOffice2016)
    {
        CXTPRibbonBar* pRibbonBar = DYNAMIC_DOWNCAST(CXTPRibbonBar, GetCommandBars()->GetMenuBar());
        ASSERT(pRibbonBar);
        if (m_bRestoreQuickAccess)
            pRibbonBar->ShowQuickAccess(TRUE);
        m_pCommandBars->GetPaintManager()->m_bBackstageMode = FALSE;
        m_pCommandBars->GetPaintManager()->m_nFrameCaptionTextShift = 0;
    }

    if( !bDestroy )
    {
        // Show here as when I did this where destroy was called, the background still painted on some window giving the big gray area "flash" I am trying
        // to prevent.
        ShowWindow( SW_HIDE );
    }
}
BOOL CXTPRibbonBackstageView::SetTrackingMode(int bMode, BOOL /*bSelectFirst = TRUE*/, BOOL /*bKeyboard = FALSE*/)
{
    if (m_bTracking == bMode)
        return FALSE;

    m_bTracking = bMode;

    CXTPRibbonBar* pRibbonBar = DYNAMIC_DOWNCAST(CXTPRibbonBar, GetCommandBars()->GetMenuBar());
    ASSERT (pRibbonBar);

    for (int i = 0; i < pRibbonBar->GetControlCount(); i++)
    {
        pRibbonBar->GetControl(i)->OnEnabledChanged();
    }

    if (!m_hWnd)
        return FALSE;

    CWnd* pWnd = GetSite();
    CXTPCommandBars* pCommandBars = GetCommandBars();

    if (!bMode)
    {
        CleanupForTrackingOrDestroy(false);

        if (pWnd && ::IsWindow(pWnd->m_hWnd)) pWnd->SendMessage(WM_XTP_UNINITCOMMANDSPOPUP, 0, (LPARAM)this);
    }
    else
    {

    }

    if (pCommandBars)
    {
        pCommandBars->OnTrackingModeChanged(this, bMode);
    }
    return TRUE;
}

void CXTPRibbonBackstageView::ShowBackstageView()
{
    CWnd* pParentWnd = GetCommandBars()->GetSite();

    if( 0 == m_hWnd )
    {
        CWnd::Create(AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)), 0, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CRect(0, 0, 0, 0), pParentWnd, 0);
    }
   

    XTPHookManager()->SetHook(pParentWnd->GetSafeHwnd(), this);

    GetCommandBars()->GetKeyboardManager()->HookKeyboard(this);


    RecalcLayout();


    m_arrChildWindows.RemoveAll();

    for (HWND hWndChild = ::GetWindow(pParentWnd->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))
    {
        if (::GetDlgCtrlID(hWndChild) == AFX_IDW_DOCKBAR_TOP || hWndChild == m_hWnd)
            continue;

        DWORD dwStyle = ::GetWindowLong(hWndChild, GWL_STYLE);
        if ((dwStyle & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE)
        {
            ::ShowWindow(hWndChild, SW_HIDE);
            m_arrChildWindows.Add(hWndChild);
        }
    }

    ::SetFocus(m_hWnd);

    for (int i = 0; i < GetControlCount(); i++)
    {
        if (GetControl(i)->IsItemDefault())
        {
            SetFocusedControl(GetControl(i));
            break;
        }
    }
}

Back to Top
rdhd View Drop Down
Senior Member
Senior Member
Avatar

Joined: 13 August 2007
Location: United States
Status: Offline
Points: 605
Post Options Post Options   Thanks (0) Thanks(0)   Quote rdhd Quote  Post ReplyReply Direct Link To This Post Posted: 26 July 2018 at 2:42pm
I have yet another change. When SetTrackingMode(false) is called, I still had a few areas of our app frame that draw the eye attracting grey background - the docking pane auto hide pane areas, status bar etc. To avoid that I first examined the auto hide panel class code and found it does not implement OnEraseBkgnd. Instead the background is drawn in OnDraw. Fortunately we already subclass from the CJ auto hide panel so I copied the CJ code to draw the background to an OnEraseBkgnd method I implemented. But that didn't quite work. The code is called and the background is drawn but as I transition out of the backstage, something still drew the grey background on it. However, I still needed that code for when our MDI application switches active documents and we load docking pane layouts - the user sees that same color drawn briefly on the auto hide panels and the implementation fixes that.

So here is what I did to handle exiting the backstage that seems to work pretty well and clears up almost all the display issues. In the new CleanupForTrackingOnDestroy, where I was calling ShowWindow( SW_HIDE ) if bDestroy is false, I post a user message to the backstage view. I also do not call SetActiveTab(NULL) unless bDestroy is true. Then in the message handler I just do this:

#define WM_SETACTIVETABANDHIDE WM_USER+100
BEGIN_MESSAGE_MAP(CXTPRibbonBackstageView, CWnd)
    ON_WM_PAINT()
    ON_WM_KEYDOWN()
    ON_COMMAND(IDCANCEL, OnCancel)
    ON_WM_MOUSEMOVE()
    ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave)
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_GETDLGCODE()
    ON_WM_DESTROY()
    ON_MESSAGE(WM_SETACTIVETABANDHIDE,ClearnActiveTabAndHide)

END_MESSAGE_MAP()

...

void  CXTPRibbonBackstageView::CleanupForTrackingOrDestroy( bool bDestroy )
{
    m_bTracking = FALSE;

    CWnd* pParentWnd = GetCommandBars()->GetSite();

    XTPHookManager()->RemoveHook(pParentWnd->GetSafeHwnd(), this);

    for (int i = 0; i < m_arrChildWindows.GetSize(); i++)
    {
        HWND hWndChild = m_arrChildWindows;
        ::ShowWindow(hWndChild, SW_SHOWNOACTIVATE);
    }

    if( bDestroy )
    {
        SetActiveTab(NULL);
    }

    if (m_pSystemButton)
    {
        m_pSystemButton->OnSetPopup(FALSE);
        if (m_pSystemButton->GetParent())
        {
            m_pSystemButton->GetParent()->Redraw(0, FALSE);
        }

        GetCommandBars()->RecalcFrameLayout();
    }

    GetCommandBars()->GetKeyboardManager()->UnhookKeyboard(this);

    m_pSystemButton = NULL;

    if( bDestroy )
    {
        CWnd::OnDestroy();
    }

    if (m_themeCurrent == xtpThemeOffice2016)
    {
        CXTPRibbonBar* pRibbonBar = DYNAMIC_DOWNCAST(CXTPRibbonBar, GetCommandBars()->GetMenuBar());
        ASSERT(pRibbonBar);
        if (m_bRestoreQuickAccess)
            pRibbonBar->ShowQuickAccess(TRUE);
        m_pCommandBars->GetPaintManager()->m_bBackstageMode = FALSE;
        m_pCommandBars->GetPaintManager()->m_nFrameCaptionTextShift = 0;
    }

    if( !bDestroy )
    {
        // Show here as when I did this where destroy was called, the background still painted on some window giving the big gray area "flash" I am trying
        // to prevent.
        PostMessage(WM_SETACTIVETABANDHIDE, 0, 0 );
    }
}

LRESULT CXTPRibbonBackstageView::ClearnActiveTabAndHide(WPARAM,  LPARAM)
{
    SetActiveTab(NULL);
    ShowWindow( SW_HIDE );
    return 1;
}

Now I have the cleanest entry and exit yet as far as display events are concerned. Again, minimal testing over the last day and a half but so far so good.
Back to Top
 Post Reply Post Reply
  Share Topic   

Forum Jump Forum Permissions View Drop Down



This page was generated in 0.109 seconds.