如何在内存中的位图上绘制文本[无MFC]

bwntbbo3  于 2023-03-17  发布在  其他
关注(0)|答案(2)|浏览(184)

有人能解释一下如何在内存中的位图上绘制文本吗?我有下面的代码,但是我不知道怎么做。

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%.
(By我的计时器每33 ms调用一次,RedrawWindow使用RDW_UPDATENOW,我也没有处理WM_ERASEBKGND消息:P由于WM_TIMER(据我所知)是低优先级消息,我不担心计时器会导致CPU使用率问题。)
我开始想,也许我应该使用位图和BitBlt它到屏幕上,而不仅仅是简单地绘制到dc和更新x坐标,每次我重新绘制屏幕。
谢谢

tv6aics1

tv6aics11#

在位图上绘图之前,必须将其选择到内存设备上下文中。
在第一次调用绘图函数之前移动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乘1的单色位图被选中。如果这个内存设备上下文在CreateCompatibleBitmap中使用,则创建的位图是单色位图。要创建彩色位图,请使用用于创建内存设备上下文的HDC
最后一个建议:如果你只需要一个 * 临时 * 位图(就像你的示例代码中那样),有一个自Windows Vista以来更有效的API可用。它被称为bufferedpaint API。MSDN似乎没有提供一个很好的概述,这里有一个tutorialreference(所有函数的名称中都有“BufferedPaint”)。

klsxnrf1

klsxnrf12#

这是为我工作的窗口过程,它基于zett42的答案。这段代码只是为了测试purposes,因为我不能发布我正在工作的应用程序的原始源代码。

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

相关问题