将 EDIT 控件子类化对我来说效果很好 - 需要在编辑对象属性时向用户显示一些格式信息(并且某些属性可能是多行)。重要的是,就像 Adrian 在他的回答中所说的那样,在您自己的绘图之前调用 EDIT 控件的过程。之后调用它或发出您自己的 BeginPaint/EndPaint(返回 0 或 DefWindowProc)给我带来了问题,从根本不显示文本到仅在调整大小时显示但在编辑后不显示,再到留下剩余插入符号的屏幕垃圾。这样,无论 EDIT 控件的其他重绘时间如何,我都没有遇到任何问题。
一些设置:
SetWindowSubclass(attributeValuesEdit, &AttributeValueEditProcedure, 0, reinterpret_cast<DWORD_PTR>(this));
// Not only do multiline edit controls fail to display the cue banner text,
// but they also ignore the Edit_SetCueBannerText call, meaning we can't
// just call GetCueBannerText in the subclassed function. So store it as
// a window property instead.
SetProp(attributeValuesEdit, L"CueBannerText", L"<attribute value>");
回调:
LRESULT CALLBACK AttributeValueEditProcedure(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
UINT_PTR subclassId,
DWORD_PTR data
)
{
...
case WM_PRINTCLIENT:
case WM_PAINT:
{
auto textLength = GetWindowTextLength(hwnd);
if (textLength == 0 && GetFocus() != hwnd)
{
// Get the needed DC with DCX_INTERSECTUPDATE before the EDIT
// control's WM_PAINT handler calls BeginPaint/EndPaint, which
// validates the update rect and would otherwise lead to drawing
// nothing later because the region is empty. Also, grab it from
// the cache so we don't mess with the EDIT's DC.
HDC hdc = (message == WM_PRINTCLIENT)
? reinterpret_cast<HDC>(wParam)
: GetDCEx(hwnd, nullptr, DCX_INTERSECTUPDATE|DCX_CACHE|DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
// Call the EDIT control so that the caret is properly handled,
// no caret litter left on the screen after tabbing away.
auto result = DefSubclassProc(hwnd, message, wParam, lParam);
// Get the font and margin so the cue banner text has a
// consistent appearance and placement with existing text.
HFONT font = GetWindowFont(hwnd);
RECT editRect;
Edit_GetRect(hwnd, OUT &editRect);
// Ideally we would call Edit_GetCueBannerText, but since that message
// returns nothing when ES_MULTILINE, use a window property instead.
auto* cueBannerText = reinterpret_cast<wchar_t*>(GetProp(hwnd, L"CueBannerText"));
HFONT previousFont = SelectFont(hdc, font);
SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
SetBkMode(hdc, TRANSPARENT);
DrawText(hdc, cueBannerText, int(wcslen(cueBannerText)), &editRect, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_NOCLIP);
SelectFont(hdc, previousFont);
ReleaseDC(hwnd, hdc);
// Return the EDIT's result (could probably safely just return zero here,
// but seems safer to relay whatever value came from the edit).
return result;
}
}
break;
编写自己的 EDIT 控件(实际上我已经不止一次完成了,与内置控件相比,它的完整性程度不高)如果你只做最低限度的工作(也许只有英语和基本的插入符号支持),但如果您想要在具有可变大小的集群的复杂脚本上进行插入符号导航、范围内的选择、IME 支持、带有复制和粘贴的上下文菜单、高对比度模式以及文本到语音等可访问性功能,则需要做很多工作才能做到正确。因此,与许多其他答案不同,我建议不要仅仅为提示横幅文本实现您自己的 EDIT 控件。