3

私のGDIプログラムはWindowsXPで正常に動作しますが、Windows Vistaおよび7では、GDIハードウェアアクセラレーションがないため、かなりひどいように見えます。数年前に、Windows 7がBitBlt()関数を含む一部のGDI関数にハードウェアアクセラレーションを追加したという記事を読んだことを思い出します。おそらく、メモリビットマップに描画してからBitBlt()を使用して画像をメインウィンドウにコピーすると、XPとほぼ同じ速度で実行されます。本当?

それが本当なら、どうやってそれをしますか?私はプログラミングがひどくて、少し問題があります。私はそれを機能させるために以下のクラスを作成しました:

class CMemBmpTest
{
private: 
    CDC         m_dcDeviceContext;
    CBitmap     m_bmpDrawSurface;

public:
    CMemBmpTest();
    ~CMemBmpTest();
    void Init();
    void Draw();
};

CMemBmpTest::CMemBmpTest()
{
}

CMemBmpTest::~CMemBmpTest()
{
    m_bmpDrawSurface.DeleteObject();
    m_dcDeviceContext.DeleteDC();
}

void CMemBmpTest::Init()
{  
    m_dcDeviceContext.CreateCompatibleDC(NULL);
    m_bmpDrawSurface.CreateCompatibleBitmap(&m_dcDeviceContext, 100, 100);
}

void CMemBmpTest::Draw()
{  
    m_dcDeviceContext.SelectObject(I.m_brshRedBrush);
    m_dcDeviceContext.PatBlt(0, 0, 100, 100, BLACKNESS);
}

ウィンドウのOnPaint()関数に、次の行を追加しました。

pDC->BitBlt(2, 2, 100, 100, &m_MemBmp, 0, 0, SRCCOPY);

ウィンドウの隅に100x100のブラックボックスが表示されることを期待していましたが、機能しませんでした。私は恐ろしくすべてを間違ってやっているので、誰かがこれを正しく行う方法について私にアドバイスしてくれたらありがたいです。

あなたが提供できるアドバイスをありがとう。

4

2 に答える 2

3

私の知る限り、すべてのバージョンの Windows で GDI 関数のハードウェア アクセラレーションが得られます (誰かが詳しく説明してくれれば、喜んで訂正します)。しかし、いずれにせよ、ダブル バッファリング (これはあなたが話していることです) は、画面に直接描画する場合と比較して、パフォーマンスを大幅に向上させます (さらに重要なことに、ちらつきはありません)。

私はかなり多くのことを行い、描画関数で GDI と GDI+ を同時に使用できる方法を考え出しましたが、画面への描画では BitBlt のハードウェア アクセラレーションの恩恵を受けます。GDI+ は、知る限りハードウェア アクセラレーションではありませんが、より多くの複雑な描画手法で非常に役立つ可能性があるため、オプションがあると便利です。

したがって、私の基本的なビュー クラスには次のメンバーが含まれます。

Graphics *m_gr;
CDC *m_pMemDC;
CBitmap *m_pbmpMemBitmap;

次に、クラス自体に次のようなコードが含まれます

    /*======================================================================================*/
    CBaseControlPanel::CBaseControlPanel()
    /*======================================================================================*/
    { 
        m_pMemDC = NULL;
        m_gr = NULL;
        m_pbmpMemBitmap = NULL;
    }

    /*======================================================================================*/
    CBaseControlPanel::~CBaseControlPanel()
    /*======================================================================================*/
    {
        // Clean up all the GDI and GDI+ objects we've used
        if(m_pMemDC)
        { delete m_pMemDC; m_pMemDC = NULL; }
        if(m_pbmpMemBitmap)
        { delete m_pbmpMemBitmap; m_pbmpMemBitmap = NULL; }
        if(m_gr)
        { delete m_gr; m_gr = NULL; }
    }   

/*======================================================================================*/
void CBaseControlPanel::OnPaint()
/*======================================================================================*/
{
    pDC->BitBlt(rcUpdate.left, rcUpdate.top, rcUpdate.Width(), rcUpdate.Height(),
                        m_pMemDC, rcUpdate.left, rcUpdate.top, SRCCOPY);
}

/*======================================================================================*/
void CBaseControlPanel::vCreateScreenBuffer(const CSize szPanel, CDC *pDesktopDC)
// In : 
//      szPanel = The size that we want the double buffer bitmap to be
// Out : None
/*======================================================================================*/
{
    // Delete anything we're already using first
    if(m_pMemDC)
    {
        delete m_gr;
        m_gr = NULL;
        delete m_pMemDC;
        m_pMemDC = NULL;
        delete m_pbmpMemBitmap;
        m_pbmpMemBitmap = NULL;
    }
    // Make a compatible DC
    m_pMemDC = new CDC;
    m_pMemDC->CreateCompatibleDC(pDesktopDC);           
    // Create a new bitmap
    m_pbmpMemBitmap = new CBitmap;
    // Create the new bitmap
    m_pbmpMemBitmap->CreateCompatibleBitmap(pDesktopDC, szPanel.cx, szPanel.cy);
    m_pbmpMemBitmap->SetBitmapDimension(szPanel.cx, szPanel.cy);
    // Select the new bitmap into the memory DC
    m_pMemDC->SelectObject(m_pbmpMemBitmap);
    // Then create a GDI+ Graphics object
    m_gr = Graphics::FromHDC(m_pMemDC->m_hDC);
    // And update the bitmap
    rcUpdateBitmap(rcNewSize, true);
}

/*======================================================================================*/
CRect CBaseControlPanel::rcUpdateBitmap(const CRect &rcInvalid, const bool bInvalidate, const bool bDrawBackground /*=true*/)
// Redraws an area of the double buffered bitmap
// In : 
//      rcInvalid - The rect to redraw
//      bInvalidate - Whether to refresh to the screen when we're done
//      bDrawBackground - Whether to draw the background first (can give speed benefits if we don't need to)
// Out : None
/*======================================================================================*/
{
   // The memory bitmap is actually updated here

   // Then make the screen update
   if(bInvalidate)
   { InvalidateRect(rcInvalid); }
}

したがって、メモリ DC に直接描画して InvalidateRect() を呼び出すか、すべての描画コードを rcUpdateBitmap() に入れることができます。これは、私が使用していた方法にとってより便利でした。OnSize() で vCreateScreenBuffer() を呼び出す必要があります。

とにかく、それがあなたにいくつかのアイデアを与えることを願っています。ダブル バッファリングは、速度とちらつきのない UI を実現するための確実な方法です。始めるには少し手間がかかるかもしれませんが、それだけの価値があることは間違いありません。

于 2012-05-31T21:18:59.633 に答える