none
ScrollView is flickering on resizing RRS feed

  • Question

  • Hi,

    In my dialog I am displaying scrollable bitmap using scrollview. the scrollview dont have any controls.

    On resizing the dialog, view is getting resized that view is flickering.

    how to avoid it.

    This is my scrollview derived class code 

    /////////////////////////////////////////////////////////////////////////////
    // CImageScrollView
    
    #include "stdafx.h"
    #include "ImageScrollView.h"
    #include "MetaBmpUtility\\DIBUtil.h"
    IMPLEMENT_DYNCREATE(CImageScrollView, CScrollView)
    
    CImageScrollView::CImageScrollView()
    {
    	m_bInitialSize = FALSE;
    }
    
    CImageScrollView::~CImageScrollView()
    {
    }
    
    
    BEGIN_MESSAGE_MAP(CImageScrollView, CScrollView)
        //{{AFX_MSG_MAP(CImageScrollView)
    	ON_WM_MOUSEACTIVATE()
    	ON_WM_SIZE()
    	ON_WM_ERASEBKGND()
        //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CImageScrollView drawing
    
    void CImageScrollView::OnDraw(CDC* pDC)
    {
        // TODO: add draw code here
    
    
    	if(m_hImage == NULL)
    		return;
    
    	CDC dcMemory;
    	dcMemory.CreateCompatibleDC( pDC); 
    	
    	CBitmap bitmap;
    	bitmap.CreateCompatibleBitmap(pDC,m_nWd,m_nHt);
    
    	CRect rectBmp;
    	rectBmp.SetRect(0,0,m_nWd,m_nHt);
    
    	CRect rectClient;
    	this->GetClientRect(&rectClient);
    	int nWdClient = rectClient.Width();
    	int nHtClient = rectClient.Height();
    	
    	CBitmap * pOldBitmap = (CBitmap *)dcMemory.SelectObject(&bitmap);
    
    	CEzDIBUtilities dib;
    	dib.PaintDIBforBmpFileCreation(&dcMemory, &rectBmp, (HDIB)m_hImage,&rectBmp);
    
    	/*int nWd = (m_nWd > nWdClient) ? nWdClient : m_nWd;
    	int nHt = (m_nHt > nHtClient) ? nHtClient : m_nHt;*/
    
    	int nWd =  m_nWd;
    	int nHt =  m_nHt;
    	//for high quality resizing
    	SetStretchBltMode(pDC->GetSafeHdc(), HALFTONE );
    	SetBrushOrgEx(pDC->GetSafeHdc(), 0, 0, NULL );
    
    	//pDC->StretchBlt(0, 0, nWd, nHt, &dcMemory, 0, 0, m_nWd, m_nHt, SRCCOPY);
    	pDC->BitBlt(0, 0, nWd, nHt, &dcMemory, 0, 0,  SRCCOPY);
    			
    	dcMemory.SelectObject( pOldBitmap );
    
    	bitmap.DeleteObject();
    	dcMemory.DeleteDC();
       
    }
    
    
    /////////////////////////////////////////////////////////////////////////////
    // CImageScrollView diagnostics
    
    #ifdef _DEBUG
    void CImageScrollView::AssertValid() const
    {
        CScrollView::AssertValid();
    }
    
    void CImageScrollView::Dump(CDumpContext& dc) 
    {
        CScrollView::Dump(dc);
    }
    #endif //_DEBUG
    
    /////////////////////////////////////////////////////////////////////////////
    // CImageScrollView message handlers
    
    void CImageScrollView::OnInitialUpdate() 
    {
    	CScrollView::OnInitialUpdate();
    	CSize sizeTotal;
    	// TODO: calculate the total size of this view
    	sizeTotal.cx = m_nWd;
    	sizeTotal.cy = m_nHt;
    	SetScrollSizes(MM_TEXT, sizeTotal);
    	m_bInitialSize = TRUE;
    }
    
    void CImageScrollView::InitImg(HGLOBAL hImage) 
    { 
    	m_hImage = hImage; 
    
    	m_nWd = m_nHt = 0;
    	if(m_hImage != NULL)
    	{
    		CEzDIBUtilities dib;
    		m_nWd = dib.DibWidth((HDIB)m_hImage);
    		m_nHt = dib.DibHeight((HDIB)m_hImage);
    	}
    
    	Invalidate();
    };
    
    COLORREF CImageScrollView::GetSelectedColor()
    {
    	POINT point;
    	GetCursorPos(&point);
    	ScreenToClient(&point);	
    
    	CDC *pDC = GetDC();
    	return (pDC->GetPixel(point));
    }
    
    int CImageScrollView::OnMouseActivate( CWnd* /*pDesktopWnd*/,UINT /*nHitTest*/,UINT /*message*/ )
    {
      return MA_ACTIVATE;
    }
    
    void CImageScrollView::OnSize(UINT nType, int cx, int cy)
    {
    	CScrollView::OnSize(nType, cx, cy);
    	//////////////////////////////////////////////////////////////////////////
    	// Before we can use OnPrepareDC, we must call SetScrollSize before. So,
    	// this flag is used to check whether we already call SetScrollSize.
    	if (m_bInitialSize == FALSE) 
    	{
    		return;
    	}
    	//////////////////////////////////////////////////////////////////////////
    
    	// TODO: Add your message handler code here
    	Invalidate(0);
    }
    
    BOOL CImageScrollView::OnEraseBkgnd(CDC* /*pDC*/) 
    {
    	return TRUE;
    }
    
    
    BOOL CImageScrollView::PreCreateWindow(CREATESTRUCT& cs)
    {
        
        cs.style |= WS_CLIPCHILDREN;
    
        return CView::PreCreateWindow(cs);
    }


    • Edited by sgrm123 Monday, February 11, 2019 12:28 PM
    Monday, February 11, 2019 12:25 PM

All replies

  • Hello,

    you can use double buffering. One example can be found in the DrawCLI sample of the Visual C++ documentation.

    Regards, Guido

    Monday, February 11, 2019 12:39 PM
  • Hello,

    you can use double buffering. One example can be found in the DrawCLI sample of the Visual C++ documentation.

    Regards, Guido

    In my code I have already doing double buffering only but still flickering
    Monday, February 11, 2019 12:43 PM
  • Hello,

    you could use the MemDC class of Keith Rule:

    (originally the class was named CMemDC, but in VS2015 the class exists already, so I renamed it).

    #if !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)
    #define AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_
    
    #if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    // MemDC.h : header file
    //
    
    //////////////////////////////////////////////////
    // CNewMemDC - memory DC
    //
    // Author: Keith Rule
    // Email:  keithr@europa.com
    // Copyright 1996-1997, Keith Rule
    //
    // You may freely use or modify this code provided this
    // Copyright is included in all derived versions.
    //
    // History - 10/3/97 Fixed scrolling bug.
    //                   Added print support.
    //           25 feb 98 - fixed minor assertion bug
    //
    // This class implements a memory Device Context
    
    class CNewMemDC : public CDC
    {
    public:
    
        // constructor sets up the memory DC
        CNewMemDC(CDC* pDC) : CDC()
        {
            ASSERT(pDC != NULL);
    
            m_pDC = pDC;
            m_pOldBitmap = NULL;
    #ifndef _WIN32_WCE_NO_PRINTING
            m_bMemDC = !pDC->IsPrinting();
    #else
            m_bMemDC = FALSE;
    #endif
    
            if (m_bMemDC)    // Create a Memory DC
            {
                pDC->GetClipBox(&m_rect);
                CreateCompatibleDC(pDC);
                m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
                m_pOldBitmap = SelectObject(&m_bitmap);
    #ifndef _WIN32_WCE
                SetWindowOrg(m_rect.left, m_rect.top);
    #endif
                // EFW - Bug fix - Fill background in case the user has overridden
                // WM_ERASEBKGND.  We end up with garbage otherwise.
                // CJM - moved to fix a bug in the fix.
                FillSolidRect(m_rect, pDC->GetBkColor());
            }
            else        // Make a copy of the relevent parts of the current DC for printing
            {
    #if !defined(_WIN32_WCE) || ((_WIN32_WCE > 201) && !defined(_WIN32_WCE_NO_PRINTING))
                m_bPrinting = pDC->m_bPrinting;
    #endif
                m_hDC       = pDC->m_hDC;
                m_hAttribDC = pDC->m_hAttribDC;
            }
    
        }
    
        // Destructor copies the contents of the mem DC to the original DC
        ~CNewMemDC()
        {
            if (m_bMemDC)
            {
                // Copy the offscreen bitmap onto the screen.
                m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
                              this, m_rect.left, m_rect.top, SRCCOPY);
    
                //Swap back the original bitmap.
                SelectObject(m_pOldBitmap);
            } else {
                // All we need to do is replace the DC with an illegal value,
                // this keeps us from accidently deleting the handles associated with
                // the CDC that was passed to the constructor.
                m_hDC = m_hAttribDC = NULL;
            }
        }
    
        // Allow usage as a pointer
        CNewMemDC* operator->() {return this;}
            
        // Allow usage as a pointer
        operator CNewMemDC*() {return this;}
    
    private:
        CBitmap  m_bitmap;      // Offscreen bitmap
        CBitmap* m_pOldBitmap;  // bitmap originally found in CNewMemDC
        CDC*     m_pDC;         // Saves CDC passed in constructor
        CRect    m_rect;        // Rectangle of drawing area.
        BOOL     m_bMemDC;      // TRUE if CDC really is a Memory DC.
    };
    
    /////////////////////////////////////////////////////////////////////////////
    
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Developer Studio will insert additional declarations immediately before the previous line.
    
    #endif // !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)

    Use it in OnPaint:

    void CMyViewOrDlgClass::OnPaint()
    {
        CPaintDC dc(this);      // device context for painting
    
        if (m_bDoubleBuffer)    // Use a memory DC to remove flicker
        {
            CNewMemDC MemDC(&dc);
            OnDraw(&MemDC);
        }
        else                    // Draw raw - this helps in debugging vis problems.
            OnDraw(&dc);
    }
    Regards, Guido


    Monday, February 11, 2019 1:03 PM
  • Hello,

    you could use the MemDC class of Keith Rule:

    (originally the class was named CMemDC, but in VS2015 the class exists already, so I renamed it).

    #if !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)
    #define AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_
    
    #if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    // MemDC.h : header file
    //
    
    //////////////////////////////////////////////////
    // CNewMemDC - memory DC
    //
    // Author: Keith Rule
    // Email:  keithr@europa.com
    // Copyright 1996-1997, Keith Rule
    //
    // You may freely use or modify this code provided this
    // Copyright is included in all derived versions.
    //
    // History - 10/3/97 Fixed scrolling bug.
    //                   Added print support.
    //           25 feb 98 - fixed minor assertion bug
    //
    // This class implements a memory Device Context
    
    class CNewMemDC : public CDC
    {
    public:
    
        // constructor sets up the memory DC
        CNewMemDC(CDC* pDC) : CDC()
        {
            ASSERT(pDC != NULL);
    
            m_pDC = pDC;
            m_pOldBitmap = NULL;
    #ifndef _WIN32_WCE_NO_PRINTING
            m_bMemDC = !pDC->IsPrinting();
    #else
            m_bMemDC = FALSE;
    #endif
    
            if (m_bMemDC)    // Create a Memory DC
            {
                pDC->GetClipBox(&m_rect);
                CreateCompatibleDC(pDC);
                m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
                m_pOldBitmap = SelectObject(&m_bitmap);
    #ifndef _WIN32_WCE
                SetWindowOrg(m_rect.left, m_rect.top);
    #endif
                // EFW - Bug fix - Fill background in case the user has overridden
                // WM_ERASEBKGND.  We end up with garbage otherwise.
                // CJM - moved to fix a bug in the fix.
                FillSolidRect(m_rect, pDC->GetBkColor());
            }
            else        // Make a copy of the relevent parts of the current DC for printing
            {
    #if !defined(_WIN32_WCE) || ((_WIN32_WCE > 201) && !defined(_WIN32_WCE_NO_PRINTING))
                m_bPrinting = pDC->m_bPrinting;
    #endif
                m_hDC       = pDC->m_hDC;
                m_hAttribDC = pDC->m_hAttribDC;
            }
    
        }
    
        // Destructor copies the contents of the mem DC to the original DC
        ~CNewMemDC()
        {
            if (m_bMemDC)
            {
                // Copy the offscreen bitmap onto the screen.
                m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
                              this, m_rect.left, m_rect.top, SRCCOPY);
    
                //Swap back the original bitmap.
                SelectObject(m_pOldBitmap);
            } else {
                // All we need to do is replace the DC with an illegal value,
                // this keeps us from accidently deleting the handles associated with
                // the CDC that was passed to the constructor.
                m_hDC = m_hAttribDC = NULL;
            }
        }
    
        // Allow usage as a pointer
        CNewMemDC* operator->() {return this;}
            
        // Allow usage as a pointer
        operator CNewMemDC*() {return this;}
    
    private:
        CBitmap  m_bitmap;      // Offscreen bitmap
        CBitmap* m_pOldBitmap;  // bitmap originally found in CNewMemDC
        CDC*     m_pDC;         // Saves CDC passed in constructor
        CRect    m_rect;        // Rectangle of drawing area.
        BOOL     m_bMemDC;      // TRUE if CDC really is a Memory DC.
    };
    
    /////////////////////////////////////////////////////////////////////////////
    
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Developer Studio will insert additional declarations immediately before the previous line.
    
    #endif // !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)

    Use it in OnPaint:

    void CMyViewOrDlgClass::OnPaint()
    {
        CPaintDC dc(this);      // device context for painting
    
        if (m_bDoubleBuffer)    // Use a memory DC to remove flicker
        {
            CNewMemDC MemDC(&dc);
            OnDraw(&MemDC);
        }
        else                    // Draw raw - this helps in debugging vis problems.
            OnDraw(&dc);
    }
    Regards, Guido


    I draw the bitmap using CNewMemDC but still it is flickering.

    This is my OnDraw() code

     
     CNewMemDC memDC(pDC);
    	CDC dcMemory;
    	dcMemory.CreateCompatibleDC( pDC); 
    	CBitmap bitmap;
    	bitmap.CreateCompatibleBitmap(pDC,m_nWd,m_nHt);
    
    	CRect rectBmp;
    	rectBmp.SetRect(0,0,m_nWd,m_nHt);
    	CBitmap * pOldBitmap = (CBitmap *)dcMemory.SelectObject(&bitmap);
    
    	CEzDIBUtilities dib;
    	dib.PaintDIBforBmpFileCreation(&dcMemory, &rectBmp, (HDIB)m_hImage,&rectBmp);
    	int nWd =  m_nWd;
    	int nHt =  m_nHt;
    	memDC.BitBlt(0 ,0, nWd, nHt, &dcMemory, 0, 0,  SRCCOPY);	
    	dcMemory.SelectObject( pOldBitmap );
    
    	bitmap.DeleteObject();
    	dcMemory.DeleteDC();
    

    Monday, February 11, 2019 2:40 PM
  • Hi,

    Thank you for posting here.

    >>ScrollView is flickering on resizing

    You have used double buffering and CNewMemDC but still it is flickering . As far as I am concerned, the flicker problem may not be caused by the drawing, because after the scroll bar appears or is hidden, the entire window will automatically refresh, which will cause the drawing part to be redrawn and flashed.

    I suggest you should select horizontal and vertical scrolling in the dialog properties/styles to display the scroll bar. Unfortunately, if the size of the image is smaller than the size of the client, the scroll bar is automatically hidden. Therefore, you could make the scroll bar display by forcing the scroll bar size.

    Best wishes,

    Jeanine Zhang

    Wednesday, February 13, 2019 7:40 AM
    Moderator