Avatar of microwhat
microwhat
 asked on

Trying to create Flicker free CStatic with Bitmap background

I have a transparent background CStatic text class(CStatic subclass). The CStatic txt is located in a dialog with a bitmap for a background. I'm trying to implement flicker free with this. Currently the code below is flickering less, but it's not flicker free. Also, i can't seem to get it to display the background as transparent with this flicker free code, this is something it did with no issue without the flicker free code. Any input is welcome. I've read/searched a lot and i'm just about stuck at this point.
BOOL CTransparentStatic::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
void CTransparentStatic::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	CDC      memDC;
	CBitmap  memBM;
	CBrush   hbrBkGnd;

	// Where to draw text
	CRect client_rect;
	GetClientRect(client_rect);

	// Get the caption
	CString szText;
	GetWindowText(szText);

	// Get the font
	CFont *pFont, *pOldFont;
	pFont = GetFont();


	
		// Create a compatible DC.
		memDC.CreateCompatibleDC(&dc);

		// Create a bitmap big enough for our client rectangle.
		memBM.CreateCompatibleBitmap(&dc,
										client_rect.right-client_rect.left,
										client_rect.bottom-client_rect.top);

		// Select the bitmap into the off-screen memory DC.
		CBitmap *hbmOld = memDC.SelectObject(&memBM);

		// Erase the background.
		hbrBkGnd.CreateSolidBrush(GetSysColor(COLOR_WINDOW));
		memDC.FillRect( &client_rect, &hbrBkGnd);
		hbrBkGnd.DeleteObject();

		// Select the font.
		if(pFont){
			pOldFont = memDC.SelectObject(pFont);
		}

		// Render the image into the offscreen DC.
		memDC.SetBkMode(TRANSPARENT);
		//memDC.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
		memDC.SetTextColor ( RGB(54,54,112) );
		memDC.DrawText(szText, client_rect, DT_LEFT);

		if(pOldFont){
			memDC.SelectObject(pOldFont);
		}

		// Blt the changes to the screen DC.
		dc.BitBlt(client_rect.left, client_rect.top,
			   client_rect.right-client_rect.left,
			   client_rect.bottom-client_rect.top,
			   &memDC,
			   0, 0,
			   SRCCOPY);

		// Done with off-screen bitmap and DC, clean up.
		memDC.SelectObject(hbmOld);
		memBM.DeleteObject();
		memDC.DeleteDC();
}

Open in new window

System ProgrammingC++Visual C++.NET

Avatar of undefined
Last Comment
Zoppo

8/22/2022 - Mon
pgnatyuk

"Remove" everything and leave only one BitBlt.

You GetWindowText to retrieve a text. Probably, you set this text in another place of your program. At this moment you can prepare a memory DC with the selected bitmap and draw text on it.

Or, in this OnPaint method, make all that only once and  save the memory DC with the selected bitmap in a member-variable. When you change the text, just delete this member-variable.
Something like that:
 
void MyDialog::OnPaint()
{
   CPaintDC dc(this);
   if ( m_MemDC == NULL)
      CreateThePicture(&dc);
   dc.BitBlt(...);
 }

Zoppo

Hi microwhat,

IMO the flickering you describe isn't caused by that function since all drawing is made in the memory DC which is once drawn to the control's DC.

I think you have to handle WM_ERASEBKGND message too for your control (and most probably for the dialog where you use this control too) and return a none-zero value there to avoid the system itself erases the control's/dialog's background in case of a needed redrawing action ...

ZOPPO
AndyAinscow

Your code looks OK as a simple flicker free attempt.  Handling the ERASEBKGND message as you do is correct (failure to do so is the usual cause of lickering).

>>Also, i can't seem to get it to display the background as transparent with this flicker free code

Erm, what should be transparent?  The dialog or the control?  What are you doing to try to make things transparent - that might be conflicting with what you are doing to remove flickering.
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
microwhat

ASKER
pgnatyuk:
"Remove" everything and leave only one BitBlt.

Im not sure what you mean. I can't removed most of the code or BitBlt will have nothing as a source.

You GetWindowText to retrieve a text. Probably, you set this text in another place of your program. At this moment you can prepare a memory DC with the selected bitmap and draw text on it.

Yes it is already set as this is a subclass of CStatic. The memory Dc you are referring to, Is that not what im already doing?

Or, in this OnPaint method, make all that only once and  save the memory DC with the selected bitmap in a member-variable. When you change the text, just delete this member-variable.
Something like that:
 
void MyDialog::OnPaint()
{
   CPaintDC dc(this);
   if ( m_MemDC == NULL)
      CreateThePicture(&dc);
   dc.BitBlt(...);
 }
Sorry i dont not follow what you are suggesting here

See underlined text.


Hi microwhat,

IMO the flickering you describe isn't caused by that function since all drawing is made in the memory DC which is once drawn to the control's DC.

I think you have to handle WM_ERASEBKGND message too for your control (and most probably for the dialog where you use this control too) and return a none-zero value there to avoid the system itself erases the control's/dialog's background in case of a needed redrawing action ...

ZOPPO

Its flickering less with this code. Without this code the flicker is very obvious(Due to bad painting implementation in MFC).
 I am currently handling the erasebckgrnd for this subclass control and i had to also return TRUE for the dialogs erasebckgrnd call to get the flicker to a minimum.


AndyAinscow:
Your code looks OK as a simple flicker free attempt.  Handling the ERASEBKGND message as you do is correct (failure to do so is the usual cause of lickering).

By just returning TRUE from ERASEBKGND, will that cause a memory leak of any kind?

>>Also, i can't seem to get it to display the background as transparent with this flicker free code

Erm, what should be transparent?  The dialog or the control?  What are you doing to try to make things transparent - that might be conflicting with what you are doing to remove flickering.

The class CTransparentStatic is a subclass of CStatic, which is just a text control. The text control is located in a dialog which uses a bitmap for the entire background. Without the flicker free code, the text control has a transparent background so there is no ugly box around the text, only the background bitmap of the dialog.


Also one of the other methods that i tried which works flawlessly in its test application is a CPaintDC replacement. It does not work perfect for me though when i implement it in my application. The only need changes are replacing CPaintDC dc(this); with CBufferDC dc(this); and returning true for erasebckgrnd like all other flicker free implementations. It flickers slightly and has a black background for the text control. Here is the code for it.

CBufferDC::CBufferDC(CWnd* pWnd) : CPaintDC(pWnd)
{
	if (pWnd != NULL && CPaintDC::m_hDC != NULL)
	{
		m_hOutputDC    = CPaintDC::m_hDC;
		m_hAttributeDC = CPaintDC::m_hAttribDC;

		pWnd->GetClientRect(&m_ClientRect);

		m_hMemoryDC = ::CreateCompatibleDC(m_hOutputDC);

		m_hPaintBitmap =
			::CreateCompatibleBitmap(
					m_hOutputDC,
					m_ClientRect.right  - m_ClientRect.left,
					m_ClientRect.bottom - m_ClientRect.top);

		m_hOldBitmap = (HBITMAP)::SelectObject(m_hMemoryDC, m_hPaintBitmap);

		CPaintDC::m_hDC       = m_hMemoryDC;
		CPaintDC::m_hAttribDC = m_hMemoryDC;
	}

	m_bBoundsUpdated = FALSE;
}

CBufferDC::~CBufferDC(void)
{
	Flush();

	::SelectObject(m_hMemoryDC, m_hOldBitmap);
	::DeleteObject(m_hPaintBitmap);

	CPaintDC::m_hDC		  = m_hOutputDC;
	CPaintDC::m_hAttribDC = m_hAttributeDC;

	::DeleteDC(m_hMemoryDC);
}

void CBufferDC::Flush()
{
	::BitBlt(
		m_hOutputDC,
		m_ClientRect.left, m_ClientRect.top,
		m_ClientRect.right  - m_ClientRect.left, 
		m_ClientRect.bottom - m_ClientRect.top,
		m_hMemoryDC,
		0, 0,
		SRCCOPY);
}

Open in new window


I've found that if i use my old transparent background code and return true from both the CStatic subclass onpaint() and the dialog onpaint(), the flickering is greatly reduced and the transparent background works like it should. So the only real change im making then is disabling the erase background in both classes. Is this a safe thing to do? IE. Blocking erase background will not cause a memory leak or any sort?
ASKER CERTIFIED SOLUTION
Zoppo

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
SOLUTION
Log in to continue reading
Log In
Sign up - Free for 7 days
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
microwhat

ASKER
Accepted myself also as Zoppo verified code i wrote.
Zoppo

You're welcome - I'm glad I could help ...

> Is that something you came up with, or did you read about that from a book/tutorial?
I know about this since at least 10 years but cannot really remember where I saw it first, but I guess I found it at www.codeguru.com, there I found a lot of helpful hints.

Best regards,

ZOPPO
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.