2016-08-24 36 views
2

Visual Studio 2015を使用し、MFCの複数ドキュメントアプリケーション(リボンスタイル)を使用します。 CViewにpngイメージを追加し、WM_TIMERを使用してスライドショーを作成しようとしています。 最初に同じ目的でダイアログベースのアプリケーションを作ったが、それは完全に機能する。これらのアプリケーションの違いは、ImageControl(CStatic)のダイアログウィンドウで最初のアプリケーションに画像が描画され、ツールボックスで追加されることです。そして、2番目のアプリでは、CViewのCStaticに同じように画像を追加しようとしています。しかし、CViewでは正しく再描画されません。ウィンドウのサイズを変更する(ストレッチ、最大化する)ときのみ、pngイメージが変更されますが、ウィンドウのサイズ変更を停止するとイメージが再びフリーズします。Visual C++ CPaintDC、CDCを使用してCViewでイメージを再描画する方法

CStaticコントロールの作成。

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); 
} 

タイマーと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::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を使用して、3つのメタモデルすべてで動作します。ほぼ完璧に、1つのことを実行:点滅。多くの場合、3つの方法すべてで画像の変化が点滅する。ダイアログベースでは、画像が点滅しません。 CPaintDC dc(&m_ctrlImage)を使用します。そしてCPaintDC dc(これ)でそれはそこで働いていません... –

+1

それはサイズ変更中にちらつく可能性があります。それはあなたが意味することですか?または、 'dc.FillSolidRect(rect、RGB(255,255,255))'を削除し、それが原因かどうかを確認してください。'Invalidate(TRUE)'を 'Invalidate(FALSE)'に変更する –

+0

私はCPictureHolderでメソッドを選択するので、今はFillSolidRectを使用しません。無効化(FALSE)が機能しました。ありがとう! –

関連する問題