Original Post
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; [Edited by - ApochPiQ on June 6, 2009 11:58:50 AM]
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; } #endifBuffer.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, ▭ ); 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, ▭, ( 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; } }My EditBox classEditBox.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; }; #endifEditBox.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 ); }Finally, my windows class where it all gets called.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 ); }; #endifWin32.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 ); }