有人可以解释如何在内存中的位图上绘制文本吗? 我有以下代码,但我无法弄清楚如何做到这一点。
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HDC buffDC = CreateCompatibleDC(hdc);
SelectObject(buffDC, hFnt);
SetTextColor(buffDC, RGB(1, 1, 1));
SetBkColor(buffDC, RGB(0, 255, 0));
RECT rc;
GetClientRect(hWnd, &rc);
HBITMAP buffBitmap = CreateCompatibleBitmap(buffDC, rc.right, rc.bottom);
int savedDC = SaveDC(buffDC);
HBRUSH hBrush = CreateSolidBrush(RGB(0, 255, 0));
FillRect(buffDC, &rc, hBrush);
DeleteObject(hBrush);
//This is the part where i would like to draw to the bitmap
TextOutA(buffDC, 0, 0, "Hello", 6);
SelectObject(buffDC, buffBitmap);
BitBlt(hdc, 0, 0, rc.right, rc.bottom, buffDC, 0, 0, SRCCOPY);
RestoreDC(buffDC, savedDC);
DeleteObject(buffBitmap);
DeleteDC(buffDC);
EndPaint(hWnd, &ps);
break;
}
我见过许多不同的解决方案,主要是使用MFC,但是如果可能的话我想避免这种方法。
编辑:我已经检查了其他已经问过的问题,但是如果没有MFC,我找不到一个会覆盖这个问题。我最初的问题是我正在使用计时器调用RedrawWindow并更新文本的位置并制作一种从右向左移动的滚动文本。
当我在测试过程中时,我注意到在某些机器上,应用程序以高达25%的CPU使用率运行,而在其他一些机器上,它使用< 1%。我已经使用运行Windows 7的完全相同的规格对应用程序测试了两台机器,并且应用程序运行了一个~10%,另一个运行0%。
(顺便说一句,我的计时器每33毫秒调用一次,RedrawWindow使用RDW_UPDATENOW,我也没有处理WM_ERASEBKGND消息:P 由于WM_TIMER(据我所知)是一个低优先级的消息,我不关心定时器导致CPU使用问题。)
我认为也许我应该使用位图和BitBlt它到屏幕而不是简单地绘制到dc并每次重新绘制屏幕时更新x坐标。
由于
答案 0 :(得分:2)
在绘制位图之前,必须将其选择到内存设备上下文中。
在第一次调用绘图函数之前移动SelectObject(buffDC, buffBitmap);
,但通常在创建位图后尽快。
在您的示例代码中,似乎适合在SaveDC()
调用后插入它,以便稍后在您致电RestoreDC()
时恢复原始位图:
int savedDC = SaveDC(buffDC);
SelectObject(buffDC, buffBitmap);
评论者指出,CreateCompatibleBitmap(buffDC, rc.right, rc.bottom)
应更改为CreateCompatibleBitmap(hdc, rc.right, rc.bottom)
。
来自CreateCompatibleBitmap()
的参考:
创建内存设备上下文时,它最初为1 x 1 选择单色位图。如果这个内存设备上下文是 在CreateCompatibleBitmap中使用,创建的位图是 单色位图。要创建颜色位图,请使用所使用的HDC 创建内存设备上下文
最后一个建议:如果您只需要一个临时位图(如示例代码中所示),则自Windows Vista以来可以使用更高效的API。它被称为缓冲绘制API 。 MSDN似乎没有提供良好的概述,这里是tutorial和reference(所有在其名称中都有“BufferedPaint”的函数)。
答案 1 :(得分:0)
以下是适用于我的Window程序,它基于zett42的答案。 这段代码仅用于测试目的,因为我无法发布因工作而正在处理的应用程序的原始源代码。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int xPos;
const bool bIsBufferedPaint = true;
switch (message)
{
case WM_CREATE:
{
BufferedPaintInit();
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
if(bIsBufferedPaint)
{
HDC newDC;
RECT rc;
RECT dstrc;
GetClientRect(hWnd, &rc);
dstrc = rc;
dstrc.left = rc.right + xPos;
HPAINTBUFFER hBufferedPaint = BeginBufferedPaint(hdc, &rc, BPBF_COMPATIBLEBITMAP, NULL, &newDC);
if(hBufferedPaint)
{
BufferedPaintClear(hBufferedPaint, NULL);
SetTextColor(newDC, RGB(0, 0, 0));
DrawText(newDC, L"Using buffered paint", -1, &dstrc, DT_SINGLELINE | DT_VCENTER | DT_LEFT);
Sleep(2);
EndBufferedPaint(hBufferedPaint, TRUE);
}
else
{
// buffer paint did not work.
}
}
else
{
HDC buffDC = CreateCompatibleDC(hdc);
SetTextColor(buffDC, RGB(0, 0, 0));
SetBkColor(buffDC, RGB(255, 255, 255));
RECT rc;
GetClientRect(hWnd, &rc);
HBITMAP buffBitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
int savedDC = SaveDC(buffDC);
SelectObject(buffDC, buffBitmap);
HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
FillRect(buffDC, &rc, hBrush);
DeleteObject(hBrush);
std::string testText = "Not using the buffered paint API";
TextOutA(buffDC, xPos, 0, testText.c_str(), testText.size());
BitBlt(hdc, 0, 0, rc.right, rc.bottom, buffDC, 0, 0, SRCCOPY);
RestoreDC(buffDC, savedDC);
DeleteObject(buffBitmap);
DeleteDC(buffDC);
}
EndPaint(hWnd, &ps);
}
break;
case WM_ERASEBKGND:
return 1;
case WM_TIMER:
{
switch(wParam)
{
case TIMER1:
{
xPos--;
RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ERASE);
if(bIsBufferedPaint)
{
if(xPos <= -500)
xPos = 0;
}
else
{
if(xPos <= -50)
xPos = 1000;
}
}
break;
}
}
break;
case WM_NCDESTROY:
{
BufferedPaintUnInit();
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}