2016-10-31 2 views
5

문제가 있습니다 - 두 개의 png 파일을 하나씩 그릴 필요가 있습니다. 내가 보통의 방법으로 할 때, "깜박 거리는"효과가 있습니다 (첫 번째 이미지는 작은 시간 동안 두 번째 이미지를 오버 드로합니다). 나는 GDI + 라이브러리를 사용하여 내 WM_PAINT 처리는 다음과 같습니다오프 스크린 드로잉 GDI +

case WM_PAINT: 
{ 
    PAINTSTRUCT ps; 
    HDC hdc = BeginPaint(hwnd, & ps); 
    displayImage(firstImage, hwnd); 
    displayImage(secondImage, hwnd); 
    EndPaint(hwnd, & ps); 
    break; 
} 

displayImage 기능 : 변수

void displayImage(HBITMAP mBmp, HWND mHwnd) 
{ 
    RECT myRect; 
    BITMAP bm; 
    HDC screenDC, memDC; 
    HBITMAP oldBmp; 
    BLENDFUNCTION bf; 

    GetObject(mBmp, sizeof(bm), &bm); 

    bf.BlendOp = AC_SRC_OVER; 
    bf.BlendFlags = 0; 
    bf.SourceConstantAlpha = 0xff; 

    bf.AlphaFormat = AC_SRC_ALPHA; 

    screenDC = GetDC(mHwnd); 
    GetClientRect(mHwnd, &myRect); 

    if (mBmp == NULL) 
     FillRect(screenDC, &myRect, WHITE_BRUSH); 

    else 
    { 
     memDC = CreateCompatibleDC(screenDC); 
     oldBmp = (HBITMAP)SelectObject(memDC, mBmp); 
     AlphaBlend (screenDC, 0, 0, myRect.right,myRect.bottom, memDC, 0, 0, bm.bmWidth,bm.bmHeight, bf); 
     SelectObject(memDC, oldBmp); 
     DeleteDC(memDC); 
     ReleaseDC(mHwnd, screenDC); 
    } 
} 

로드 파일 :

HBITMAP mLoadImg(WCHAR *szFilename) 
{ 
    HBITMAP result=NULL; 

    Gdiplus::Bitmap* bitmap = new Gdiplus::Bitmap(szFilename,false); 
    bitmap->GetHBITMAP(NULL, &result); 
    delete bitmap; 
    return result; 
} 


firstImage = mLoadImg(L"data\\img\\screen.png"); 
secondImage = mLoadImg(L"data\\img\\screen2.png"); 

나는이 작업을 수행해야한다고 들었어요 오프 스크린 드로잉. 어떻게 생겼어?

+0

메모리 dc를 만들고 비트 맵을로드 한 다음 dc 창을 열고 memorydc를 매개 변수로 사용하여 bitblt를 호출하십시오. – jhbh

+0

ReleaseDC는 'else' 절 외부에 있어야합니다. –

+0

@jhbh :이 질문에 대해서는 언급하지 않습니다. 알파 블렌딩 두 개의 이미지를 요구합니다. – IInspectable

답변

6

당신은 그 모든 필요하지 않습니다.

static Gdiplus::Image *firstImage; 
static Gdiplus::Image *secondImage; 

case WM_CREATE: // or WM_INITDIALOG if it's dialog 
{ 
    firstImage = new Gdiplus::Image(L"data\\img\\screen.png"); 
    secondImage = new Gdiplus::Image(L"data\\img\\screen2.png"); 
    return 0; 
} 

case WM_PAINT: 
{ 
    PAINTSTRUCT ps = { 0 }; 
    HDC hdc = BeginPaint(hwnd, &ps); 

    Gdiplus::Graphics gr(hdc); 
    gr.DrawImage(firstImage, 0, 0); 
    gr.DrawImage(secondImage, 0, 0);//<== this will draw transparently 

    EndPaint(hwnd, &ps); 

    return 0; 
} 

그러나이 코드는 여전히 원래 코드와 같이 깜박임이 가능한 2 개의 이미지를 연속해서 그립니다. WM_PAINT에서 더블 버퍼링을 사용하면 BltBlt 하나만 수행됩니다. 간단하게 변경합니다 : 원래의 코드에 관해서는

if (msg == WM_PAINT) 
{ 
    PAINTSTRUCT ps = { 0 }; 
    HDC hdc = BeginPaint(hwnd, &ps); 

    RECT rc; 
    GetClientRect(hwnd, &rc); 
    HDC memdc = CreateCompatibleDC(hdc); 
    HBITMAP hbitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom); 
    HGDIOBJ oldbmp = SelectObject(memdc, hbitmap); 

    FillRect(memdc, &rc, WHITE_BRUSH); 
    Gdiplus::Graphics gr(memdc); 
    gr.DrawImage(firstImage, 0, 0); 
    gr.DrawImage(secondImage, 0, 0); 

    BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY); 

    SelectObject(memdc, oldbmp); 
    DeleteObject(hbitmap); 
    DeleteDC(memdc); 

    EndPaint(hwnd, &ps); 

    return 0; 
} 

:

void displayImage(HBITMAP mBmp, HWND mHwnd) 
{ 
HDC hdc = GetDC(mHwnd); 
... 
} 

그런 다음에 WM_PAINT

+0

답해 주셔서 감사합니다. 당신의 솔루션도 잘 작동합니다. –

0

"WM_ERASEBKGND"메시지를 직접 처리하십시오.

실제로 두 번째 이미지를로드하기 전에 두 가지 일이 발생합니다.

  1. WM_ERASEBKGND는 현재 Windows 배경색이 무엇이든 처음으로 이미지 영역을 채우기 위해 트리거됩니다.
  2. WM_PAINT 동작을 렌더링합니다.

설명서에는 깜박임/Flickr을 피하기 위해 "WM_ERASEBKGND"에 대한 기본 처리기가 제공됩니다.

아래 링크는 "깜박 거림없는 컨트롤"로 이동하십시오. 당신도 예제가 있습니다.

https://msdn.microsoft.com/en-us/library/ms969905.aspx

+0

깜박임을 유발하는 원인과이를 방지하는 방법을 이해하지 못했던 것 같습니다. 이 질문의 깜박임은 두 이미지를 연속적으로 렌더링하여 발생하므로 제안 된 솔루션이 적용되지 않습니다. 나는 당신이 충분히 신경 쓰지 않기 때문에, 나는 당신에게 나의 명성을 낭비해야한다는 것에 약간의 불안감을 느낍니다. 나는 너에게서 단 하나의 도움이되는 대답을 보지 못했다. 다음 질문에 대답하기 전에 당신이 그것을 완전히 이해했는지 그리고 ** 답을 알고 있는지 ** 확인하십시오. – IInspectable

+0

보스 나는 한 달에 983 그 명성을 얻었습니다. 네가 나를 이해하는데 어려움이 있다고 생각한다. 그리고 당신은 여기 주위에 보스가되지 않습니다. – Naidu

+0

첫 달에 이미 [Peer Pressure] (http://stackoverflow.com/help/badges/38/peer-pressure?userid=6866309) 배지를 가지고 있음을보고 , 아마도 당신의 공헌이 의심 스럽다고 생각하는 것은 아닙니다. (이 제안 된 답변은 확실히 완전히 문제를 해결하는 데 실패합니다.) – IInspectable

3

첫째, 변화 displayImage에서 직접 hdc을 통과 할 수 void displayImage(HBITMAP mBmp, HWND mHwnd, HDC hdc)에 함수 선언을 변경해야합니다 HDC와 RECT를 HWND 대신 발신자에게서 가져옵니다.

void displayImage(HBITMAP mBmp, HDC hdc, const RECT &myRect) 
{ 
    if (mBmp == NULL) 
     FillRect(screenDC, &myRect, WHITE_BRUSH); 
    else 
    { 
     BITMAP bm; 
     GetObject(mBmp, sizeof(bm), &bm); 

     HDC memDC = CreateCompatibleDC(screenDC); 
     HBITMAP oldBmp = (HBITMAP)SelectObject(memDC, mBmp); 

     BLENDFUNCTION bf; 
     bf.BlendOp = AC_SRC_OVER; 
     bf.BlendFlags = 0; 
     bf.SourceConstantAlpha = 0xff; 
     bf.AlphaFormat = AC_SRC_ALPHA; 

     AlphaBlend(hdc, 0, 0, myRect.right, myRect.bottom, memDC, 0, 0, bm.bmWidth, bm.bmHeight, bf); 

     SelectObject(memDC, oldBmp); 
     DeleteDC(memDC); 
    } 
} 

그런 다음 호출자가 호환되는 DC 및 비트 맵을 만듭니다. 이것들은 합성을하기위한 오프 스크린 공간입니다. 이 새로운 DC로 displayImage를 호출합니다. 이것은 화면 밖에서 PNG를 구성합니다. 마지막으로, 한 번에 실제 창 DC에 구성된 결과를 blit하십시오.

case WM_PAINT: 
{ 
    PAINTSTRUCT ps; 
    HDC hdc = BeginPaint(hwnd, &ps); 
    RECT myRect; 
    GetClientRect(hwnd, &myRect); 

    // Create an off-screen DC for composing the images. 
    HDC hdcMem = CreateCompatibleDC(hdc); 
    HBITMAP hbmpMem = CreateCompatibleBitmap(hdc, myRect.right, myRect.bottom); 
    HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcMem, hbmpMem); 

    // Compose the images to the offscreen bitmap. 
    displayImage(firstImage, hdcMem, myRect); 
    displayImage(secondImage, hdcMem, myRect); 

    // Blit the resulting composition to the window DC. 
    BitBlt(hdc, 0, 0, myRect.right, myRect.bottom, 
      hdcMem, 0, 0, SRCCOPY); 

    // Clean up the offscreen stuff. 
    SelectObject(hdcMem, hbmpOld); 
    DeleteObject(hbmpMem); 
    DeleteDC(hdcMem); 

    EndPaint(hwnd, &ps); 
    break; 
} 

마지막으로 배경색이 계속 깜박이면 Pavan Chandaka의 답변을 참조하십시오.

+0

좋아요! 그것은 작동합니다. 참고 : BitBlt 함수에는'SRC_COPY'와 함께'SRCCOPY'가 있어야합니다. –

+0

Re'SRCCOPY' : 그게 내가 기억에서 타이핑 할 때 얻는 것입니다. 수정할 수정 된 답변 자주 페인트를 칠하는 경우 효율성을 높이기 위해 여분의 메모리 DC와 비트 맵을 캐시 할 수도 있습니다. –

관련 문제