Я пытаюсь создать элемент управления редактирования поиска в 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);
}
}
}
На следующем рисунке показана проблема с одной строкой редактирует (изображения были увеличены для лучшего обзора). Желтый фон предназначен только для подсветки, в реальном коде я использую цвет системы . Вы можете видеть, что, когда однострочное редактирование имеет текст и имеет вход, изображение левой стороны окрашено. Это не происходит с многострочным редактированием, где 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» борется с рутиной управления Edit control. Он использует 'CPaintDC' для рисования элемента управления вручную, иногда он вызывает' CEdit :: OnPaint', который, в свою очередь, снова вызывает «CPaintDC», а затем выполняет обработку по умолчанию, которая реплицирует клиентскую область. Это не удастся, если элемент управления Edit будет изменен или неактивен, или когда будет получено какое-либо сообщение с краской. –
'CEdit :: OnPaint()' предназначен только для многострочных изменений, что меня не беспокоит. Я использую только отдельные средства редактирования строк. Я упомянул многострочные изменения, потому что в этом случае установка границ работает правильно. –
Что делать, если вы переопределите 'CWnd :: OnCtlColor()' и вызовите 'ExcludeClipRect()' оттуда? Кажется, здесь хорошо работать с быстрым тестом, но без MFC. Возможно, вам придется снова изменить обрезку в 'OnPaint()', чтобы показать свои собственные вещи. – isanae