2016-08-24 16 views
2

MFC 다중 문서 응용 프로그램 (리본 스타일)으로 작업하는 Visual Studio 2015를 사용합니다. CView에 png 이미지를 추가하고 WM_TIMER를 사용하여 슬라이드 쇼를 만들려고합니다. 처음에는 같은 목적으로 대화 상자 기반 응용 프로그램을 만들었지 만 완벽하게 작동합니다. 이러한 응용 프로그램의 차이점은 도구 상자를 추가하여 PictureControl (CStatic)의 대화 상자 창에서 이미지가 첫 번째 응용 프로그램에 그려지는 것입니다. 그리고 두 번째 응용 프로그램에서 똑같은 방식으로 CView의 CStatic에 이미지를 추가하려고합니다. 그러나 CView를 사용하면 올바르게 다시 그려지지 않습니다. 창 크기를 변경 (늘림, 최대화) 할 때만 png 이미지가 변경되지만 크기 조정 창을 멈 추면 이미지가 다시 고정됩니다.Visual C++ CPaintDC, CDC로 CView에서 이미지를 다시 그리는 방법

CStatic 컨트롤 만들기. 타이머 OnSize()

void CCardioAppView::OnTimer(UINT_PTR nIDEvent) 
{ 
    if (ShowImageTimer == nIDEvent) 
    { 
     auto bmp_iter = theApp.FullBmpMap.begin(); 
     int sz = theApp.FullBmpMap.size(); 
     CRect ImageRect; 
     GetClientRect(&ImageRect); 

     if (m_iCurrentImage < sz) 
     { 
      m_iCurrentImage++; 
      InvalidateRect(ImageRect, false); 
     } 
     else 
     { 
      m_iCurrentImage = 1; 
     } 
    } 

    CView::OnTimer(nIDEvent); 
} 

void CCardioAppView::OnSize(UINT nType, int cx, int cy) 
{ 
    CView::OnSize(nType, cx, cy); 

    CRect rect; 
    if (m_ctrlImage.GetSafeHwnd()) 
    { 
     GetClientRect(rect); 
     m_ctrlImage.DestroyWindow(); 
     BOOL b = m_ctrlImage.Create(_T(""), WS_CHILD | WS_VISIBLE, rect, this, 2); 
     m_ctrlImage.ModifyStyle(0, SS_BITMAP); 
    } 
} 

OnPaint를 다시 그리기()에 의해

void CCardioAppView::OnInitialUpdate() 
{ 
    CView::OnInitialUpdate(); 

    CRect rect; 
    GetClientRect(rect); 
    BOOL b = m_ctrlImage.Create(_T(""), WS_CHILD | WS_VISIBLE, rect,this,2); 
    m_ctrlImage.ModifyStyle(0, SS_BITMAP, SWP_NOSIZE); 
} 

다시 그리기는

void CCardioAppView::OnPaint() 
{ 
    CPaintDC view_dc(this); // device context for painting 

    CBitmap bmp; 
    CRect rect, scaleRect; 
    BITMAP b; 
    auto bmp_iter = theApp.FullBmpMap.find(m_iCurrentImage); 

    GetClientRect(&rect); 

    if (bmp_iter == theApp.FullBmpMap.end()) return; 
    bmp.Attach((*bmp_iter).second); 

    bmp.GetObject(sizeof(BITMAP), &b); 

    CPaintDC dc(&m_ctrlImage); 
    CDC memdc; 
    memdc.CreateCompatibleDC(&dc); 
    memdc.SelectObject(&bmp); 

    if (rect.Height() <= b.bmHeight) //scaling image 
    { 
     scaleRect = rect; 
     scaleRect.right = rect.left + ((b.bmWidth*rect.Height())/ b.bmHeight); 
    } 
    dc.FillSolidRect(rect, RGB(255, 255, 255)); 
    dc.StretchBlt(0, 0, scaleRect.Width(), scaleRect.Height(), &memdc, 
     0, 0, b.bmWidth, b.bmHeight, SRCCOPY); 
    //dc.MoveTo(0, 0); 

    (*bmp_iter).second.Detach(); 
    (*bmp_iter).second.Attach(bmp); 
    bmp.Detach(); 
} 

OnPaint를 올바르게 타이머에 의해 호출된다. 기본 창 크기를 조정했을 때만 이미지가 표시되는 이유는 무엇입니까?

+0

'ON_WM_ERASEBKGND()'와 핸들러'OnEraseBkgnd (CDC * pDC) '로 몇 가지 시도해 보시기 바랍니다. 디폴트의 ​​친 클래스 구현과 반대의 값을 돌려주는 것이 있습니다. – sergiol

+0

덧붙여서, 왜 모든 크기 변경시'm_ctrlImage'를 파괴하고 다시 만드나요? 단순히 크기를 조정하지 않는 것이 좋습니다 ([CWnd :: SetWindowPos] (https://msdn.microsoft.com/en-us/library/a1yzfz6d.aspx))? – IInspectable

답변

2
void CCardioAppView::OnPaint() 
{ 
    CPaintDC view_dc(this); 
    ... 
    CPaintDC dc(&m_ctrlImage); //<== wrong place 
    ... 
} 

CPaintDCWM_PAINT는 메시지에 대한 응답 BeginPaint/EndPaint 대한 래퍼이다. 다른 창에서 장치 컨텍스트를 가져 오는 데 사용할 수 없습니다.

정적 컨트롤에 그리려면 소유자 컨트롤을 그려야합니다. 하지만 여기에서는 그럴 필요가 없습니다. 당신은 그림 컨트롤을 사용하여 간단하게

void CCardioAppView::OnTimer(UINT_PTR nIDEvent) 
{ 
    CView::OnTimer(nIDEvent); 
    if (ShowImageTimer == nIDEvent) 
    { 
     m_iCurrentImage++; 
     if (m_iCurrentImage >= theApp.FullBmpMap.size()) 
      m_iCurrentImage = 0; 

     //get HBITMAP: ??? 
     auto bmp_iter = theApp.FullBmpMap.find(m_iCurrentImage); 
     HBITAMP hbitmap = bmp_iter->second; //??? 
     m_ctrlImage.SetBitmap(hbitmap); 
    } 
} 

CStatic::SetBitmap이 방법으로 OnPaint()OnSize()을 무시하지 마십시오 호출 할 수 있습니다.


두 번째 옵션 : CStatic는 비트 맵을 스트레칭하지 않습니다. CPictureHolder을 사용하여 비트 맵을 늘릴 수 있습니다.

void OnPaint() 
{ 
    CPaintDC dc(this); 

    auto bmp_iter = theApp.FullBmpMap.find(m_iCurrentImage); 
    HBITAMP hbitmap = bmp_iter->second; //??? 

    CPictureHolder pic; 
    pic.CreateFromBitmap(hbitmap); 

    CRect rect; 
    GetClientRect(&rect); 
    pic.Render(&dc, rect, rect); 
} 

void CCardioAppView::OnTimer(UINT_PTR nIDEvent) 
{ 
    CView::OnTimer(nIDEvent); 
    if (nIDEvent == ShowImageTimer) 
    { 
     m_iCurrentImage++; 
     if (m_iCurrentImage >= theApp.FullBmpMap.size()) 
      m_iCurrentImage = 0; 
     Invalidate(TRUE); 
    } 
} 

세 번째 옵션 (모든 m_ctrlImage/CStatic 컨트롤을 생성하지 않음) 아래의 예를 사용 를 당신이 당신의 자신의 그림을 수행 할 경우, 윈도우의 자신의 DC를 사용합니다. 예 :

void CCardioAppView::OnPaint() 
{ 
    CPaintDC dc(this); 
    CRect rect; 
    GetClientRect(&rect); 

    auto bmp_iter = theApp.FullBmpMap.find(m_iCurrentImage); 
    HBITAMP hbitmap = bmp_iter->second; //??? 

    CBitmap bmp; 
    bmp.Attach(hbitmap); 
    CDC memdc; 
    memdc.CreateCompatibleDC(&dc); 
    memdc.SelectObject(&bmp); 

    BITMAP b; 
    bmp.GetObject(sizeof(BITMAP), &b); 

    CRect scaleRect = rect; 
    if (rect.Height() <= b.bmHeight) 
    { 
     scaleRect = rect; 
     scaleRect.right = rect.left + ((b.bmWidth*rect.Height())/b.bmHeight); 
    } 

    dc.FillSolidRect(rect, RGB(255, 255, 255)); 
    dc.StretchBlt(0, 0, scaleRect.Width(), scaleRect.Height(), &memdc, 
     0, 0, b.bmWidth, b.bmHeight, SRCCOPY); 

    bmp.Detach(); 
} 
+0

라이브로 배우십시오! 정말 고마워! SetBitmap, CPaintDC dc (this) 및 CPictureHolder를 사용하여 세 가지 metods와 모두 작동합니다. 거의 완벽하게, exept 한 가지 : 깜박입니다. 종종 이미지 변경은 3 가지 방법 모두에서 깜박임을 동반합니다. 대화 상자 기반에서는 이미지가 깜박 거리지 않습니다. CPaintDC dc (& m_ctrlImage)를 사용합니다. 그리고 CPaintDC dc (this)와 함께 작동하지 않습니다 ... –

+1

크기를 조정하는 동안 깜박일 수 있습니다. 이게 네가 말하는거야? 또는'dc.FillSolidRect (rect, RGB (255, 255, 255))'를 제거하여 그것이 원인인지 확인하십시오.'Invalidate (TRUE)'를'Invalidate (FALSE)'로 변경하십시오. –

+0

CPictureHolder로 메소드를 선택할 때 필자는 FillSolidRect를 사용하지 않습니다. 무효화 (FALSE)되었습니다. 감사! –