我试图用Windows API在透明背景的窗口上绘制animation。 问题是我不能从窗口中删除以前的图纸。
我设置了以下参数:
InvalidateRect(m_hWnd, &sClientRect, TRUE); // we set the bErase parameter as TRUE paintParams.dwFlags = BPPF_ERASE; // erase window content while copying backbuffer paintParams.pBlendFunction = &m_sBlendfunc; // copy source image to backbuffer
但它仍然不起作用。 你可以看到附加图像的结果。 我想要的animation是在屏幕上移动圆圈。 我所得到的(如附图中所示)是它们运动的伪像,因为在每次绘制之前窗口没有被清除。
看到我的完整代码如下:
#include "DrawTest.h" DrawTest* m_sDrawTest; DrawTest::DrawTest() { m_pAnimation = NULL; m_sDrawTest = NULL; m_nFrameindex = 0; } DrawTest::~DrawTest(void) { if(m_pAnimation) delete m_pAnimation; m_pAnimation = NULL; if(m_sDrawTest) delete m_sDrawTest; m_sDrawTest = NULL; } int DrawTest::Init(AnimationManager* pAnimationManager,HINSTANCE hInstance,int nCmdShow) { //listener m_sDrawTest = this; //get anemation (sequence of frames containing location and png's); m_pAnimation = pAnimationManager->GetAnimation(2); //set window class information WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndDrawTestProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(HOLLOW_BRUSH);//configures the window to use transparrent brush wcex.lpszMenuName = NULL; wcex.lpszClassName = sWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL); return 1; } m_hInst = hInstance; // Store instance handle in our global variable m_hWnd = CreateWindow( sWindowClass, sTitle, WS_POPUP, 200, 200, 1024, 600, NULL, NULL, hInstance, NULL ); if (!m_hWnd) { MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL); return 1; } SetWindowPos(m_hWnd, // handle to window HWND_TOPMOST, // top z 0, // ignored 0, // ignored 0, // ignored 0, // ignored SWP_NOSIZE | SWP_NOMOVE); // The parameters to ShowWindow explained: // hWnd: the value returned from CreateWindow // nCmdShow: the fourth parameter from WinMain ShowWindow(m_hWnd, nCmdShow); UpdateWindow(m_hWnd); return 1; } // Called by an external timer. This is the application "Next Step" proc. void DrawTest::TimeStep(){ PostMessage(m_hWnd, WM_PAINT, 0, 0); } // WndDrawTestProc replaces the default DefWindowProc // // FUNCTION: WndDrawTestProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // // LRESULT CALLBACK WndDrawTestProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_ERASEBKGND: return DefWindowProc(hWnd, message, wParam, lParam); case WM_PAINT: // call onNextFrame to draw current frame. m_sDrawTest->OnNextFrame(hWnd); // ensures that the window is in top most position SetWindowPos(hWnd, // handle to window HWND_TOPMOST, // top z 0, // ignored 0, // ignored 0, // ignored 0, // ignored SWP_NOSIZE | SWP_NOMOVE); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; } /* DrawTest::OnNextFrame Called by WndDrawTestProc when receving WM_PAINT message Configures the drawing canvas and calles DrawTest::Draw(HDC hBBDC) to do the actual drawing */ void DrawTest::OnNextFrame(HWND hUILoopWnd) { if(m_nFrameindex > m_pAnimation->GetNumOfFrames() - 1) return; // defines paint area RECT sClientRect; GetClientRect(hUILoopWnd, &sClientRect); InvalidateRect(m_hWnd, &sClientRect, TRUE); // we set the bErase parameter as TRUE //blending structure m_sBlendfunc.BlendOp= AC_SRC_OVER; m_sBlendfunc.BlendFlags = 0; m_sBlendfunc.SourceConstantAlpha = 255; m_sBlendfunc.AlphaFormat = AC_SRC_ALPHA; HDC hdc; PAINTSTRUCT ps; hdc = BeginPaint(hUILoopWnd, &ps); GetClientRect(hUILoopWnd, &sClientRect); BP_PAINTPARAMS paintParams = { sizeof(BP_PAINTPARAMS) }; paintParams.dwFlags = BPPF_ERASE; // erase window content while copying backbuffer paintParams.pBlendFunction = &m_sBlendfunc; // how to copy source image to backbuffer HDC hBBDC; HPAINTBUFFER hPBuffer; paintParams.cbSize = sizeof(paintParams); hPBuffer = BeginBufferedPaint(hdc, &sClientRect, BPBF_COMPATIBLEBITMAP, &paintParams, &hBBDC); //draw animation Draw(hBBDC); m_nFrameindex ++; EndBufferedPaint(hPBuffer, TRUE); EndPaint(hUILoopWnd, &ps); } /* Draw Paint the animation frame on the backbuffer */ void DrawTest::Draw(HDC hBBDC) { HDC hdcScreen = GetDC(NULL); HDC hdcMem = CreateCompatibleDC(hdcScreen); bool test = false; HGDIOBJ hbmpOld = SelectObject(hdcMem, m_pAnimation->m_pFramesArray[m_nFrameindex]->hBmp); HBITMAP ptemp = CreateCompatibleBitmap(hdcMem,m_pAnimation->m_pFramesArray[m_nFrameindex]->nWidth, m_pAnimation->m_pFramesArray[m_nFrameindex]->nHeight); DeleteObject(ptemp); test = AlphaBlend(hBBDC,m_pAnimation->m_pFramesArray[m_nFrameindex]->nPtX,m_pAnimation->m_pFramesArray[m_nFrameindex]->nPtY ,m_pAnimation->m_pFramesArray[m_nFrameindex]->nWidth, m_pAnimation->m_pFramesArray[m_nFrameindex]->nHeight, hdcMem,0,0,m_pAnimation->m_pFramesArray[m_nFrameindex]->nWidth,m_pAnimation->m_pFramesArray[m_nFrameindex]->nHeight,m_sBlendfunc); DWORD test10 = GetLastError(); SelectObject(hdcMem, hbmpOld); //placing the old object back test = DeleteDC(hdcMem); // after CreateCompatibleDC test = ReleaseDC(NULL, hdcScreen); // after GetDC }
这是5帧后的结果:
// Called by an external timer. This is the application "Next Step" proc. void DrawTest::TimeStep(){ PostMessage(m_hWnd, WM_PAINT, 0, 0); }
不,这并不能完成整个油漆周期。 哪些需要包含WM_ERASEBKGND来解决你的问题。 改用InvalidateRect()。 您现在也可以像在WM_PAINT处理程序中一样调用BeginPaint()。