我正在为 Finale 音乐程序编写一个插件,它使用 Rich Edit 控件来显示和编辑格式化文本。其中一种格式是“隐藏”样式,这实际上意味着它是灰色的。 “隐藏”仅在 Finale 打印文本时适用。事实证明
CFM_DISABLED
/CFE_DISABLED
的工作原理完全符合我显示“隐藏”文本部分的需要。它会自动使标记为禁用的文本变灰,但不会影响用户编辑文本的能力。
这是我用来执行此操作的代码:
static CHARFORMAT2W charFormatFromFontInfo(const FCFontInfo *pFont)
{
FCString fontName;
pFont->GetNameString(&fontName);
CHARFORMAT2W cf{};
cf.cbSize = sizeof(cf);
cf.dwMask = CFM_BOLD | CFM_FACE | CFM_ITALIC | CFM_SIZE | CFM_STRIKEOUT | CFM_UNDERLINE | CFM_DISABLED;
lstrcpynW(cf.szFaceName, (LPCWSTR)fontName._GetUnicodeBuffer(), DIM(cf.szFaceName));
cf.szFaceName[DIM(cf.szFaceName) - 1] = 0;
cf.yHeight = 20.0 * pFont->GetSizeFloat(); // points to twps
if (pFont->GetBold())
cf.dwEffects |= CFE_BOLD;
if (pFont->GetItalic())
cf.dwEffects |= CFE_ITALIC;
if (pFont->GetUnderline())
cf.dwEffects |= CFE_UNDERLINE;
if (pFont->GetStrikeOut())
cf.dwEffects |= CFE_STRIKEOUT;
if (pFont->GetHidden())
cf.dwEffects |= CFE_DISABLED;
return cf;
}
当我向控件添加颜色范围时,问题就出现了。当我向一系列文本添加颜色时,如果禁用的段落与我更改颜色的范围重叠,则控件会丢失“禁用”的任何可见表示。这对于我的目的来说没问题,但我希望能够重置颜色并重新将禁用部分显示为灰色。我不知道该怎么做。我试过了,简单地说:
// after setting the selection to the entire text
CHARFORMAT2W cf{};
cf.cbSize = sizeof(cf);
cf.dwMask = CFM_COLOR;
cf.crTextColor = RGB(0, 0, 0);
SendDlgItemMessageW(GetWindowHandle(), GetControlID(), EM_SETCHARFORMAT, SCF_SELECTION | SCF_DEFAULT, (LPARAM)&cf);
这恢复了黑色文本,但也将所有禁用的文本更改为黑色。
ChatGPT 建议将
cf.crTextColor
成员设置为 -1,但那是幻觉。 (没用。)
我的问题归结为,有没有办法取消所有颜色更改并恢复
CFE_DISABLED
文本变灰的默认行为?
答案是
CFE_AUTOCOLOR
标志。微软的文档在这一点上并没有完全明确,但它是解决方案。
// after setting the selection to the entire text
CHARFORMAT2W cf{};
cf.cbSize = sizeof(cf);
cf.dwMask = CFM_COLOR;
cf.dwEffects = CFM_AUTOCOLOR;
cf.crTextColor = RGB(0, 0, 0); // may not strictly be necessary but is clean
SendDlgItemMessageW(GetWindowHandle(), GetControlID(), EM_SETCHARFORMAT, SCF_SELECTION | SCF_DEFAULT, (LPARAM)&cf);
这会导致文本使用系统默认值着色,其中包括使标有
CFM_DISABLED
的文本变灰。