Sign in to follow this  

Buffering problems with child windows.

This topic is 3117 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, i've been coding an app with basic graphical capabilities (Win32 API) in an attempt to make a networked BlackJack game. However, i've created a child window that is an EditBox to handle chat input. However, when the EditBox is created it doesn't display unless a call to InvalidateRect() is made. This call causes the EditBox to flicker terribly. The EditBox displays fine if I removemy buffering code. So can anyone point me in the direction of some articles that could solve my problem, or have a stab at solving this one themselves? Here's my buffer class;
Buffer.h


#ifndef BUFFER_H_
#define BUFFER_H_

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
class CBuffer
{
	public:
		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
									CBuffer( );
		virtual						~CBuffer( );

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		virtual bool				OnEnter( const HWND& wnd );
		virtual bool				OnPreRender( );
		virtual bool				OnPostRender( );

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		inline HDC					GetHDC( );
		inline HDC					GetMemDC( );

	protected:
		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		HDC							mDC;
		HDC							mMemDC;
		HDC							mBackDC;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		HBITMAP						mFront;
		HBITMAP						mBack;
		HBITMAP						mOldFront;
		HBITMAP						mOldBack;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		HWND						mWndCpy;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		WndRect						mRect;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		virtual void				OnExit( );
};

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
inline HDC CBuffer::GetHDC( )
{
	return mDC;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
inline HDC CBuffer::GetMemDC( )
{
	return mMemDC;
}

#endif
[/code]

[code]
Buffer.cpp


#include "Global.h"
#include "Buffer.h"

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
CBuffer::CBuffer( )
: mDC( NULL )
, mMemDC( NULL )
, mBackDC( NULL )
, mFront( NULL )
, mBack( NULL )
, mOldFront( NULL )
, mOldBack( NULL )
, mWndCpy( NULL )
, mRect( WndRect( 1024, 768, 0, 0 ) )
{
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
CBuffer::~CBuffer( )
{
	OnExit( );
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
bool CBuffer::OnEnter( const HWND& wnd )
{
	mWndCpy = wnd;

	mDC = GetDC( mWndCpy );
	mMemDC = CreateCompatibleDC( mDC );
	mBackDC = CreateCompatibleDC( mDC );

	if( ! mDC || ! mMemDC || ! mBackDC )
	{
		CLogger::GetInstance( )->WriteLog( "Couldn't create DC's" );
		return false;
	}

	RECT rect;

	GetClientRect( mWndCpy, &rect );

	mRect.ConvertToVec4( rect );

	mFront = CreateCompatibleBitmap( mDC, mRect.GetRight( ), mRect.GetBottom( ) );
	mOldFront = ( HBITMAP )SelectObject( mMemDC, mFront );

	mBack = CreateCompatibleBitmap( mBackDC, mRect.GetRight( ), mRect.GetBottom( ) );
	mOldBack = ( HBITMAP )SelectObject( mBackDC, mBack );

	if( ! mFront || ! mBack )
	{
		CLogger::GetInstance( )->WriteLog( "Couldn't create buffer surfaces." );
		return false;
	}

	FillRect( mBackDC, &rect, ( HBRUSH )GetStockObject( WHITE_BRUSH ) );

	return true;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
bool CBuffer::OnPreRender( )
{
	return ( bool )BitBlt( mMemDC, mRect.GetLeft( ), mRect.GetTop( ), mRect.GetRight( ), mRect.GetBottom( ), mBackDC, 0, 0, SRCCOPY );
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
bool CBuffer::OnPostRender( )
{
	return ( bool )BitBlt( mDC, mRect.GetLeft( ), mRect.GetTop( ), mRect.GetRight( ), mRect.GetBottom( ), mMemDC, 0, 0, SRCCOPY );
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
void CBuffer::OnExit( )
{
	if( mDC && mWndCpy )
	{
		ReleaseDC( mWndCpy, mDC );

		mDC = NULL;
		mWndCpy = NULL;
	}

	if( mMemDC && mFront )
	{
		SelectObject( mMemDC, mOldFront );
		DeleteObject( mFront );
		DeleteDC( mMemDC );

		mMemDC = NULL;
		mFront = NULL;
	}

	if( mBackDC && mBack )
	{
		SelectObject( mBackDC, mOldBack );
		DeleteObject( mBack );
		DeleteDC( mBackDC );

		mBackDC = NULL;
		mBack = NULL;
	}
}
[/code]

My EditBox class

[code]
EditBox.h


#ifndef EDITBOX_H_
#define EDITBOX_H_

class CEditBox : public CGameObject
{
	public:
		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
									CEditBox( );
									CEditBox( const WndRect& pos, const HWND& wnd, const HINSTANCE& inst );
		virtual						~CEditBox( );

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		virtual bool				OnEnter( );
		virtual bool				OnUpdate( );
		virtual bool				OnExit( );

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		static LRESULT CALLBACK		EditBoxProc( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );

	protected:
		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		HWND						mEditBox;
		HWND						mWndCopy;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		HINSTANCE					mInstCopy;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		PosVector2D					mDim;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		CString						mClassName;
};

#endif
[/code]

[code]
EditBox.cpp


#include "Global.h"
#include "EditStates.h"
#include "EditBox.h"

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
CEditBox::CEditBox( )
: CGameObject( )
, mWndCopy( NULL )
, mEditBox( NULL )
, mInstCopy( NULL )
, mClassName( "EDIT" )
{
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
CEditBox::CEditBox( const WndRect& pos, const HWND& wnd, const HINSTANCE& inst )
: CGameObject( )
, mWndCopy( wnd )
, mEditBox( NULL )
, mInstCopy( inst )
, mClassName( "EDIT" )
{
	mPosition.SetX( pos.GetX( ) );
	mPosition.SetY( pos.GetY( ) );
	mDim.SetX( pos.GetZ( ) );
	mDim.SetY( pos.GetW( ) );
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
CEditBox::~CEditBox( )
{
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
bool CEditBox::OnEnter( )
{
	CGameObject::OnEnter( );

	mEditBox = CreateWindow( mClassName.GetConstChar( ), NULL, WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL |
									ES_AUTOVSCROLL | ES_LEFT | ES_MULTILINE | ES_NOHIDESEL |
									WS_VSCROLL | WS_HSCROLL | WS_BORDER | ES_WANTRETURN,
									mPosition.GetX( ), mPosition.GetY( ), mDim.GetX( ), mDim.GetY( ), mWndCopy, NULL,
									mInstCopy, NULL );

	ChangeState( CEditIdleState::GetInstance( ) );
	return true;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
bool CEditBox::OnUpdate( )
{
	CGameObject::OnUpdate( );

	RECT redrawRect = { ( long )mPosition.GetX( ), ( long )mPosition.GetY( ), ( long )mDim.GetX( ), ( long )mDim.GetY( ) };
	InvalidateRect( mEditBox, &redrawRect, FALSE );
	return true;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
bool CEditBox::OnExit( )
{
	CGameObject::OnExit( );
	return true;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
LRESULT CEditBox::EditBoxProc( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam )
{
	switch( msg )
	{
		case WM_ERASEBKGND:
			return true;
			break;
	}

	return DefWindowProc( wnd, msg, wparam, lparam );
}
[/code]

Finally, my windows class where it all gets called.

[code]
Win32.h


#ifndef WIN32_H_
#define WIN32_H_

class CWin32
{
	public:
		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
									CWin32( );
		virtual						~CWin32( );

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		virtual bool				OnEnter( );
		virtual bool				OnUpdate( );

	protected:
		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		HWND						mWnd;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		HINSTANCE					mInstance;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		MSG							mMsg;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		CString						mClassName;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		WndRect						mRect;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		CBuffer*					mBuffer;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		IMAGEID						mID;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		CButton*					mButton;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		CEditBox*					mEditBox;

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		enum __ReturnMessages
		{
			IDLE,
			BUSY,
			EXIT
		};

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		int							MessagePump( );

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		bool						CreateAppWindow( );

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		virtual void				OnExit( );

		/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
		static LRESULT CALLBACK		WndProc( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );
};

#endif
[/code]

[code]
Win32.cpp


#include "Global.h"
#include "Win32.h"

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
CWin32::CWin32( )
: mWnd( NULL )
, mInstance( NULL )
, mClassName( "Networked BlackJack v0.15a" )
, mRect( WndRect( 0, 0, 1024, 768 ) )
, mBuffer( NULL )
, mButton( NULL )
, mEditBox( NULL )
{
	memset( &mMsg, 0, sizeof( MSG ) );

	mBuffer = new CBuffer;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
CWin32::~CWin32( )
{
	mButton->OnExit( );

	SAFE_DELETE( mBuffer );
	SAFE_DELETE( mButton );
	SAFE_DELETE( mEditBox );

	OnExit( );
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
bool CWin32::OnEnter( )
{
	WNDCLASSEX wc = { 0 };

	mInstance = GetModuleHandle( NULL );
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.cbSize = sizeof( WNDCLASSEX );
	wc.hbrBackground = NULL;//( HBRUSH )( COLOR_WINDOW + 1 );
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
	wc.hIconSm = LoadIcon( NULL, IDI_WINLOGO );
	wc.hIcon = LoadIcon( NULL, IDI_WINLOGO );
	wc.hInstance = mInstance;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = mClassName.GetConstChar( );
	wc.lpszMenuName = NULL;
	wc.style = NULL;//CS_VREDRAW | CS_HREDRAW;

	if( ! RegisterClassEx( &wc ) )
	{
		CLogger::GetInstance( )->WriteLog( "Couldn't register the windows class." );
		return false;
	}

	if( ! CreateAppWindow( ) )
	{
		CLogger::GetInstance( )->WriteLog( "Couldn't create app window." );
		return false;
	}

	if( ! mBuffer->OnEnter( mWnd ) )
	{
		CLogger::GetInstance( )->WriteLog( "Couldn't setup double buffering." );
		return false;
	}

	mID = CBmpHandler::GetInstance( )->LoadBmp( mBuffer->GetHDC( ), "test.bmp" );

	mButton = new CButton( mBuffer->GetHDC( ), PosVector2D( 200, 200 ), "test.bmp" );
	mButton->OnEnter( );

	mEditBox = new CEditBox( WndRect( 20, 20, 400, 60 ), mWnd, mInstance );
	mEditBox->OnEnter( );

	ShowWindow( mWnd, SW_SHOW );
	UpdateWindow( mWnd );

	return true;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
bool CWin32::OnUpdate( )
{
	while( 1 )
	{
		int msg = MessagePump( );

		switch( msg )
		{
			case EXIT:
				return false;
				break;

			case IDLE:
				CMouseHandler::GetInstance( )->OnUpdate( );

				//Graphics first
				mBuffer->OnPreRender( );

				mButton->OnUpdate( mBuffer->GetMemDC( ) );

				mBuffer->OnPostRender( );

				//Windowing second
				mEditBox->OnUpdate( );
				break;
		}
	}

	return true;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
int CWin32::MessagePump( )
{
	if( PeekMessage( &mMsg, NULL, 0, 0, PM_REMOVE ) )
	{
		if( mMsg.message == WM_QUIT )
		{
			return EXIT;
		}

		TranslateMessage( &mMsg );
		DispatchMessage( &mMsg );

		return BUSY;
	}

	return IDLE;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
bool CWin32::CreateAppWindow( )
{
	mWnd = CreateWindowEx( NULL, mClassName.GetConstChar( ), mClassName.GetConstChar( ), WS_OVERLAPPEDWINDOW, mRect.GetLeft( ), mRect.GetTop( ), mRect.GetRight( ), mRect.GetBottom( ), NULL, NULL, mInstance, NULL );

	if( ! mWnd )
	{
		CLogger::GetInstance( )->WriteLog( "mWnd == NULL" );
		return false;
	}

	return true;
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
void CWin32::OnExit( )
{
	UnregisterClass( mClassName.GetConstChar( ), mInstance );

	if( mWnd )
	{
		DestroyWindow( mWnd );
		mWnd = NULL;
	}
}

/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
LRESULT CWin32::WndProc( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam )
{
	switch( msg )
	{
		case WM_CLOSE:
		case WM_DESTROY:
			PostQuitMessage( 0 );
			break;
	}

	return DefWindowProc( wnd, msg, wparam, lparam );
}

[Edited by - ApochPiQ on June 6, 2009 11:58:50 AM]

Share this post


Link to post
Share on other sites
Since you do drawing on the HDC directly you need to spare the rect of the edit.

Either that, or you could also draw the edit manually (which does bring quite a few input handling issues with it).

Share this post


Link to post
Share on other sites

This topic is 3117 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this