问题描述
使用 C++/MFC 和 GDI(而不是 GDI+),总体目标是创建一个带图案的 HBrush
,它将在 OnCtlColor
中用红色勾勒出一个编辑控件,并能够打开和关闭轮廓。为此,您可以使用 HBrush
将位图附加到 CreatePatternBrush
。这是使用存储的位图资源执行此操作的代码:
CDialog::OnInitDialog();
BOOL ok = redBoxBitmap.LoadBitmap(MAKEINTRESOURCE(IDB_mespe_EditBox_Red));
ok = redBoxBrush.CreatePatternBrush(&redBoxBitmap);
并在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;
}
以上代码都可以正常工作。但是,这取决于为编辑控件调整大小的位图。我现在需要的是能够在 C++ 程序中创建位图,其大小与控件的客户区一致,这取决于控件的设计大小(在对话框编辑器中)和用户对文本大小的设置Windows 10 设置。
我找不到一种直接的方法来构建位图,或者更好的是,创建一个适当大小的空位图(可以),将其选入 CDC
(可以),绘制红色框进入它(可以做),然后从 CDC
中提取更新位图(怎么做?)。
任何人都可以建议如何以编程方式创建位图,或者建议一种更好的方法来在程序调用时将编辑控件框为红色?
为回应@Constantine GeorgIoU 3/9 的回答而添加:
新代码:
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));
// 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,h);
pDC->SelectObject(pOldBitmap);
// Create the edit-control custom brush
redBoxBrush.CreatePatternBrush(&redBoxBitmap);
return;
}
此代码生成一个全黑的编辑控件,就好像所使用的位图是单色的一样。如果在 dc 中绘制不影响位图,或者如果在 dc 兼容位图中绘制不使用 redPen
和 editBoxBrush
中的颜色,如@IInspectable 所建议的那样,这将是预期的。
解决方法
这是创建画笔的方法 - 使用了 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));
// 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.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);
}
还要检查我在评论中建议的替代方案。这将绘制到编辑控件的客户区。
编辑:
我上面发布的代码确实有效,在它运行后,剩下的就是 HBRUSH
句柄(编辑框的模式画笔)。我不明白你为什么坚持使用 MFC 包装器。它们是“更高级别”的瘦包装器,所以......实际上是“瘦”的,您仍然必须执行几乎完全相同的操作(创建、选择到 DC、执行某些绘图操作、从 DC 中选择) GDI的。您唯一不需要执行的操作是删除资源(对象的析构函数会为您调用 DeleteObject()
)。
无论如何,如果您更喜欢 MFC 而不是 GDI,让我们看看您的代码有什么问题。它有很多问题:
- 首先,您需要一个 memory DC 在位图上绘制,您通过调用
GetDC()
获得的窗口 DC 绘制在窗口的表面上。 - 调用
GetDC()
得到的DC必须返回给系统(ReleaseDC()
),因为pDC
只是一个指针,编译器不会调用析构函数。 - 您选择到 DC 中的对象必须在销毁之前被选中,否则可能会发生内存泄漏。
所以你的代码应该修改如下:
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,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);
}
与GDI版本基本一致。