假设您刚刚在启用拼写检查的富编辑控件中设置了一些文本,并且该文本有一些拼写错误。一瞬间,拼写检查将启动,然后拼写错误的文本将加下划线。但是你猜怎么着:富编辑控件实际上EN_CHANGE
只会为下划线事件发送一个通知(假设您已经通过 do 注册了通知SendMessage(hwnd, EM_SETEVENTMASK, 0, (LPARAM)ENM_CHANGE)
)。
有没有一种解决方法可以避免这种行为?我有一个带有一些启用拼写检查的富编辑控件的对话框。而且我还想知道编辑事件何时发生,所以我知道何时启用“保存”按钮。EN_CHANGE
因此,仅针对拼写检查下划线事件获取通知是一个问题。
我考虑过的一个选项是 EN_CHANGE
完全禁用通知,然后在子类富编辑控件中自行触发它们。例如,当有 a 时WM_CHAR
,它会显式发送 EN_CHANGE
通知等。但这似乎是个问题,因为有许多类型的事件应该触发更改,如删除、复制/粘贴等,我可能会没有正确捕获所有这些。
我考虑过的另一个选项是EN_CHANGE
动态启用和禁用通知。例如,仅在有焦点时启用它们,并在焦点被杀死时禁用它们。但这似乎也有问题,因为富编辑在设置其文本时可能已经具有焦点。然后会出现拼写检查下划线,并且EN_CHANGE
会发送不需要的通知。
我想也可以使用计时器,但我认为这很容易出错。
有人有其他想法吗?
这是一个可重现的示例。只需运行它,它就会说发生了一些变化:
#include <Windows.h>
#include <atlbase.h>
#include <atlwin.h>
#include <atltypes.h>
#include <Richedit.h>
class CMyWindow :
public CWindowImpl<CMyWindow, CWindow, CWinTraits<WS_VISIBLE>>
{
public:
CMyWindow()
{
}
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
COMMAND_CODE_HANDLER(EN_CHANGE, OnChange)
END_MSG_MAP()
private:
LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL& bHandled)
{
bHandled = FALSE;
LoadLibrary(L"Msftedit.dll");
CRect rc;
GetClientRect(&rc);
m_wndRichEdit.Create(MSFTEDIT_CLASS, m_hWnd, &rc,
NULL, WS_VISIBLE | WS_CHILD | WS_BORDER);
INT iLangOpts = m_wndRichEdit.SendMessage(EM_GETLANGOPTIONS, NULL, NULL);
iLangOpts |= IMF_SPELLCHECKING;
m_wndRichEdit.SendMessage(EM_SETLANGOPTIONS, NULL, (LPARAM)iLangOpts);
m_wndRichEdit.SetWindowText(L"sdflajlf adlfjldsfklj dfsl");
m_wndRichEdit.SendMessage(EM_SETEVENTMASK, 0, (LPARAM)ENM_CHANGE);
return 0;
}
LRESULT OnChange(WORD, WORD, HWND, BOOL&)
{
MessageBox(L"changed", NULL, NULL);
return 0;
}
private:
CWindow m_wndRichEdit;
};
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
CMyWindow wnd;
CRect rc(0, 0, 200, 200);
wnd.Create(NULL, &rc);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
此外,似乎使用EM_SETMODIFY
并EM_GETMODIFY
没有帮助。我猜拼写检查下划线会导致 a EM_SETMODIFY
,因此在处理程序中检查该标志是无用的。