gpt4 book ai didi

c++ - Windows 7 中的 GDI 加速/绘制到内存位图

转载 作者:太空狗 更新时间:2023-10-29 21:26:39 25 4
gpt4 key购买 nike

我的 GDI 程序在 Windows XP 上运行良好,但在 Windows Vista 和 7 上,由于缺少 GDI 硬件加速,它看起来很糟糕。记得几年前读过一篇文章,说 Windows 7 为一些 GDI 函数添加了硬件加速,包括 BitBlt() 函数。据推测,如果您绘制到内存位图,然后使用 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 的黑框,但没有成功。我可能做的每件事都错得离谱,所以如果有人能告诉我如何正确地做这件事,我将不胜感激。

感谢您提供的任何建议。

最佳答案

据我所知,您在所有版本的 Windows 上都获得了 GDI 功能的硬件加速(如果有人可以更详细地解释它,我很乐意对此进行更正)。但无论哪种方式,双缓冲(这就是您所说的)相对于直接在屏幕上绘图提供了巨大的性能提升(更重要的是没有闪烁)是正确的。

我已经做了很多这方面的工作,并提出了一种方法,允许您在绘图函数中同时使用 GDI 和 GDI+,但在绘图到屏幕时受益于 BitBlt 的硬件加速。 GDI+ 不是硬件加速 AFAIK,但在许多更复杂的绘图技术中可能非常有用,因此选择它可能会很有用。

因此,我的基本 View 类将包含以下成员:

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 的方式。开始可能需要一些努力,但绝对值得。

关于c++ - Windows 7 中的 GDI 加速/绘制到内存位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10840464/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com