简体   繁体   English

从 CDC 创建 CBitmap?

[英]Create CBitmap from CDC?

Using C++/MFC and GDI (not GDI+), the overall goal is to create an patterned HBRUSH , which will be used in OnCtlColor to outline an edit control in red, with the ability to turn the outline on and off.使用 C++/MFC 和 GDI(不是 GDI+),总体目标是创建一个带图案的HBRUSH ,它将在OnCtlColor中用于以红色勾勒编辑控件,并能够打开和关闭轮廓。 To do this, you attach a bitmap to an HBRUSH using CreatePatternBrush .为此,您使用CreatePatternBrush将 bitmap 附加到HBRUSH Here is the code for doing that, using a stored bitmap resource:这是执行此操作的代码,使用存储的 bitmap 资源:

CDialog::OnInitDialog();
BOOL ok = redBoxBitmap.LoadBitmap(MAKEINTRESOURCE(IDB_mespe_EditBox_Red));
ok = redBoxBrush.CreatePatternBrush(&redBoxBitmap);

and in OnCtlColor并在OnCtlColor

HBRUSH CModelEditorSpecies::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr;
    int ctrlID=pWnd->GetDlgCtrlID();
    if(ctrlID==IDC_MyEditControl)
        hbr=(HBRUSH) redBoxBrush;
    else
        hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

    return hbr;
}

The above code all works as desired.上面的代码都可以按需要工作。 However, it depends on the bitmap being sized to the edit control.但是,这取决于 bitmap 的大小是否适合编辑控件。 What I need now is the ability to create the bitmap within the C++ program, sized to the client area of the control, which depends on both the design size of the control (in the dialog editor), and the user's setting of text size in Windows 10 settings.我现在需要的是在 C++ 程序中创建 bitmap 的能力,其大小取决于控件的客户区域,这取决于控件的设计大小(在对话框编辑器中)和用户在Windows 10 个设置。

I cannot find a straightforward way of either constructing a bitmap, or, better, creating an empty one of the proper size (can do), selecting it into a CDC (can do), drawing the red box into it (can do), then extracting the update bitmap from the CDC (how to do?).我找不到一种直接的方法来构建 bitmap,或者,更好的是,创建一个适当大小的空的(可以做),将其选择到CDC (可以做),将红色框拉入其中(可以做),然后从CDC提取更新 bitmap(怎么做?)。

Can anyone suggest either how to create the bitmap programmatically, or suggest a better method of getting an edit control boxed in red when the program calls for that?任何人都可以建议如何以编程方式创建 bitmap,或者建议一种更好的方法,以便在程序需要时将编辑控件框为红色?

Added in response to @Constantine Georgiou's answer of 3/9:为响应@Constantine Georgiou 3/9 的回答而添加:

New code:新代码:

CBitmap redBoxBitmap; // member variables of class CModelEditorSpecies
CBrush redBoxBrush;

BOOL CModelEditorSpecies::OnInitDialog()
{
    CDialog::OnInitDialog();
    BOOL ok;
    CRect r; defaultSpecies1Ctrl.GetClientRect(&r);
    xx(r.Width(), r.Height()/*, redBoxBrush*/);
    ok = redBoxBrush.CreatePatternBrush(&redBoxBitmap);
    //...
}

void CModelEditorSpecies::xx(const int w, const int h)
{
    CDC *pDC=GetDC();
    redBoxBitmap.CreateCompatibleBitmap(pDC, w, h);
    
    // Create a red pen
    CPen redPen;
    redPen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
    
    // Draw the bitmap - red pen & default background brush
    CBitmap *pOldBitmap=pDC->SelectObject(&redBoxBitmap);
    pDC->SelectObject(&redPen);
    CBrush editBoxBrush;
    editBoxBrush.CreateSysColorBrush(COLOR_WINDOW);
    pDC->SelectObject(&editBoxBrush);
    pDC->Rectangle(0, 0, w, h);
        
    pDC->SelectObject(pOldBitmap);
    
    // Create the edit-control custom brush
    redBoxBrush.CreatePatternBrush(&redBoxBitmap);
    return;
}

This code produces an all-black edit control, as if the bitmap being used were monochrome.此代码生成一个全黑的编辑控件,就好像正在使用的 bitmap 是单色的。 That would be expected if drawing in the dc does not affect the bitmap, or, if drawing in a dc-compatible bitmap does not use the colors in redPen and editBoxBrush , as suggested by @IInspectable.如果在 dc 中绘图不会影响 bitmap,或者,如果在与 dc 兼容的 bitmap 中绘图不使用redPen和 editBox 中的editBoxBrush ,这是可以预期的。

Here's how to create the brush - used the Win32 functions instead of their MFC wrappers, but you can figure it out.这是创建画笔的方法 - 使用 Win32 函数而不是它们的 MFC 包装器,但您可以弄清楚。

BOOL CModelEditorSpecies::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // Get edit-control's size
    RECT rc;
    GetDlgItem(IDC_MyEditControl)->GetClientRect(&rc);

    // Create the bitmap and a memory-DC
    HDC hDC = ::GetDC(HWND_DESKTOP);
    HDC mDC = CreateCompatibleDC(hDC);
    HBITMAP hBmp = CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
    ::ReleaseDC(HWND_DESKTOP, hDC);

    // Create a red pen
    HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

    // Draw the bitmap - red pen & default background brush
    HBITMAP hOldBmp = (HBITMAP) SelectObject(mDC, hBmp);
    HPEN hOldPen = (HPEN) SelectObject(mDC, hPen);
    HBRUSH hOldBr = (HBRUSH) SelectObject(mDC, GetSysColorBrush(COLOR_WINDOW));
    Rectangle(mDC, rc.left, rc.top, rc.right, rc.bottom);
    SelectObject(mDC, hOldBr);
    SelectObject(mDC, hOldPen);
    SelectObject(mDC, hOldBmp);

    // Create the edit-control custom brush
    redBoxBrush = CreatePatternBrush(hBmp);

    // Clean-up - the SysColorBrush doesn't need to be deleted
    DeleteObject(hPen);
    DeleteObject(hBmp);
    DeleteDC(mDC);

    return TRUE;
}

HBRUSH CModelEditorSpecies::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    return (nCtlColor == CTLCOLOR_EDIT && pWnd->GetDlgCtrlID() == IDC_MyEditControl) ?
        redBoxBrush : CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
}

Also check the alternatives I suggested in the comments.还要检查我在评论中建议的替代方案。 This one will be drawing into the edit-control's client area.这个将绘制到编辑控件的客户区。


EDIT:编辑:

The code I posted above does work, and after it runs all left is the HBRUSH handle (pattern-brush for your edit box).我在上面发布的代码确实有效,在它运行完之后就是HBRUSH句柄(编辑框的模式画笔)。 I can't see why you insist using the MFC wrappers instead.我不明白您为什么坚持使用 MFC 包装器。 They are "higher-level" thin wrappers, so... "thin" actually, that you still have to perform almost exactly the same operations (create, select into a DC, perfrom some drawing operation, select out of the DC) as the GDI ones.它们是“更高级别”的薄包装器,所以......实际上“薄”,您仍然必须执行几乎完全相同的操作(创建 select 到 DC,执行一些绘图操作,select 出 DC) GDI 的那些。 The only operation you don't need to perform is delete the resource (the object's destructor will call DeleteObject() for you).您不需要执行的唯一操作是删除资源(对象的析构函数将为您调用DeleteObject() )。

Anyways, if you prefer MFC over GDI, let's see what's wrong with your code.无论如何,如果您更喜欢 MFC 而不是 GDI,让我们看看您的代码有什么问题。 It has quite a few issues:它有很多问题:

  • First and foremost, you need a memory DC to draw on a bitmap, the window DC you get by calling GetDC() draws on a window's surface.首先,您需要一个memory DC来在 bitmap 上绘图,window DC 您通过调用GetDC()在窗口表面上绘制。
  • The DC you get by calling GetDC() must be returned to the system ( ReleaseDC() ), because pDC is just a pointer, and the compiler won't call the destructor.调用GetDC()得到的 DC 必须返回给系统( ReleaseDC() ),因为pDC只是一个指针,编译器不会调用析构函数。
  • The objects you select into a DC must be selected out before it is destroyed, otherwise memory-leaks may be occurring.您 select 进入 DC 的对象必须在销毁之前选择出来,否则可能会发生内存泄漏。

So your code should be changed as shown below:所以你的代码应该如下所示进行更改:

void CModelEditorSpecies::xx()
{
    CRect r;
    GetDlgItem(IDC_MyEditControl)->GetClientRect(&r);
    
    // Create the bitmap and a memory-DC
    CBitmap redBoxBitmap;
    CDC mDC, *pDC = GetDC();
    redBoxBitmap.CreateCompatibleBitmap(pDC, r.Width(), r.Height());
    mDC.CreateCompatibleDC(pDC);
    ReleaseDC(pDC);

    // Create a red pen and get the default background brush
    CPen redPen;
    redPen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
    CBrush editBoxBrush;
    editBoxBrush.CreateSysColorBrush(COLOR_WINDOW);

    // Draw the bitmap - red pen & default background brush
    CBitmap *pOldBitmap = mDC.SelectObject(&redBoxBitmap);
    CPen *pOldPen = mDC.SelectObject(&redPen);
    CBrush *pOldBrush =mDC.SelectObject(&editBoxBrush);
    mDC.Rectangle(r);
    mDC.SelectObject(pOldBrush);
    mDC.SelectObject(pOldPen);
    mDC.SelectObject(pOldBitmap);

    // Create the edit-control custom brush
    redBoxBrush.CreatePatternBrush(&redBoxBitmap);
}

It's basically the same as the GDI version.它与 GDI 版本基本相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM