【发布时间】:2016-12-17 21:31:33
【问题描述】:
我正在尝试在 MFC 中创建一个搜索编辑控件,该控件始终在控件窗口中显示一个图标(无论控件的状态和文本)。很多年前我写过这样的东西并且工作得很好,但是代码不再适用于 Windows 7 和更高版本(甚至可能是 Vista,但没有尝试过)。发生的情况是控件中显示的图像与输入区域重叠(见下图)。
代码背后的想法:
- 有一个派生自
CEdit的类(在 OnPaint 中处理绘画) - 图标显示在右侧,编辑区域根据图标大小缩小
- 单行和多行编辑的大小调整方式不同。对于单行我调用SetMargins,对于多行编辑我调用SetRect。
- 此编辑调整大小应用于
PreSubclassWindow()、OnSize()和OnSetFont()
这是应用编辑输入大小的方式:
void CSymbolEdit::RecalcLayout()
{
int width = GetSystemMetrics( SM_CXSMICON );
if(m_hSymbolIcon)
{
if (GetStyle() & ES_MULTILINE)
{
CRect editRect;
GetRect(&editRect);
editRect.right -= (width + 6);
SetRect(&editRect);
}
else
{
DWORD dwMargins = GetMargins();
SetMargins(LOWORD(dwMargins), width + 6);
}
}
}
下图显示了单行编辑的问题(图像已放大以获得更好的视图)。黄色背景仅用于突出显示,在实际代码中我使用COLOR_WINDOW 系统颜色。您可以看到,当单行编辑有文本并且有输入时,左侧图像被绘制。这不会发生在SetRect 正确设置格式矩形的多行编辑中。
我已尝试使用ExcludeClipRect 删除显示图像的编辑区域。
CRect rc;
GetClientRect(rc);
CPaintDC dc(this);
ExcludeClipRect(dc.m_hDC, rc.right - width - 6, rc.top, rc.right, rc.bottom);
DWORD dwMargins = GetMargins();
SetMargins(LOWORD(dwMargins), width + 6);
这似乎对结果没有任何影响。
供参考,这是多年前写的画法,曾经在Windows XP上运行良好,但不再更正。
void CSymbolEdit::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect( &rect );
// Clearing the background
dc.FillSolidRect( rect, GetSysColor(COLOR_WINDOW) );
DWORD dwMargins = GetMargins();
if( m_hSymbolIcon )
{
// Drawing the icon
int width = GetSystemMetrics( SM_CXSMICON );
int height = GetSystemMetrics( SM_CYSMICON );
::DrawIconEx(
dc.m_hDC,
rect.right - width - 1,
1,
m_hSymbolIcon,
width,
height,
0,
NULL,
DI_NORMAL);
rect.left += LOWORD(dwMargins) + 1;
rect.right -= (width + 7);
}
else
{
rect.left += (LOWORD(dwMargins) + 1);
rect.right -= (HIWORD(dwMargins) + 1);
}
CString text;
GetWindowText(text);
CFont* oldFont = NULL;
rect.top += 1;
if(text.GetLength() == 0)
{
if(this != GetFocus() && m_strPromptText.GetLength() > 0)
{
oldFont = dc.SelectObject(&m_fontPrompt);
COLORREF color = dc.GetTextColor();
dc.SetTextColor(m_colorPromptText);
dc.DrawText(m_strPromptText, rect, DT_LEFT|DT_SINGLELINE|DT_EDITCONTROL);
dc.SetTextColor(color);
dc.SelectObject(oldFont);
}
}
else
{
if(GetStyle() & ES_MULTILINE)
CEdit::OnPaint();
else
{
oldFont = dc.SelectObject(GetFont());
dc.DrawText(text, rect, DT_SINGLELINE | DT_INTERNAL | DT_EDITCONTROL);
dc.SelectObject(oldFont);
}
}
}
我查看了类似编辑控件的其他实现,现在它们都有相同的错误。
显然,问题是如何从控件的输入区域中排除图像区域?
【问题讨论】:
-
您的
OnPaint覆盖正在与编辑控件的绘制例程作斗争。它使用CPaintDC手动绘制控件,有时它调用CEdit::OnPaint,然后又调用CPaintDC,然后是重新绘制客户区的默认处理。当编辑控件进入和失去焦点时,或者收到任何绘制消息时,这将失败。 -
CEdit::OnPaint()仅用于多行编辑,这不是我关心的问题。我只使用单行编辑控件。我提到了多行编辑,因为在这种情况下设置边界可以正常工作。 -
如果覆盖
CWnd::OnCtlColor()并从那里调用ExcludeClipRect()会怎样?通过快速测试似乎可以正常工作,但没有 MFC。您可能需要再次更改OnPaint()中的剪辑以显示您自己的内容。 -
我的回答有帮助吗?你收到了一个“提请注意”的悬赏通知,但从那以后你什么也没说。
-
我很抱歉忽略了这一点,它最近完全不在我的关注范围内。我会检查你发布的内容,如果它有效,我会给你奖励积分(必须创建一个新的,希望有效)。
标签: c++ visual-c++ mfc paint editcontrol