更新:根据要求,我添加了用于创建Window及其RichEdit控件的所有代码。
我正在尝试处理用作另一个窗口的子项的RichEdit控件的Windows消息。
现在我确实使用了RichEdit控件,除了我自己的WndProc
。问题在于,当我设置wc.lpszClassName = MSFTEDIT_CLASS;
以使其与lpClassName
中使用的CreateWindowEx()
匹配时,RichEdit控件的内容不再显示为绘制(即文本等),但是,然后它的WndProc函数可以处理消息。
创建窗口:
首先是构造函数:
SubWindow::SubWindow(const wchar_t *szAppNameImport)
{
szAppName = szAppNameImport;
cfmt = CHARFORMATW();
hwnd = HWND();
windowRect = RECT();
editControlHwnd = HWND();
wc = WNDCLASSEX();
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_CLASSDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szAppName;
wc.hIconSm = LoadIcon(wc.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
}
然后是Create()
函数:
VOID SubWindow::Create(unsigned int window_startX, unsigned int window_startY, unsigned int windowWidthInput, unsigned int windowHeightInput, HWND parent)
{
windowRect.left = window_startX;
windowRect.top = window_startY;
windowRect.right = windowWidthInput;
windowRect.bottom = windowHeightInput;
if(!RegisterClassEx(&wc))
{
throw std::exception();
}
if((hwnd = CreateWindowEx
(
WS_EX_CLIENTEDGE,
szAppName,
TEXT("Our classy sub window!"),
WS_OVERLAPPEDWINDOW| WS_VISIBLE,
windowRect.left, windowRect.top,
windowRect.right, windowRect.bottom,
parent,
NULL,
wc.hInstance,
NULL))==NULL)
{
throw std::exception();
}
SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)this);
ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);
}
的WndProc:
LRESULT CALLBACK SubWindow::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SubWindow *childWindowPointer = (SubWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(childWindowPointer != NULL)
{
if(childWindowPointer->GetEditControl() == hwnd)
OutputDebugString(L"I SHOULD NOT BE CALLED");
return childWindowPointer->MsgProc(hwnd, uMsg, wParam, lParam);
}
else
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
MsgProc:
LRESULT SubWindow::MsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch(uMsg)
{
case WM_WINDOWPOSCHANGED:
{
GetClientRect(hwnd, &windowRect);
SetWindowPos(editControlHwnd, NULL, windowRect.left, windowRect.top, windowRect.right, windowRect.bottom, SWP_NOZORDER | SWP_NOACTIVATE);
return 0;
}
case WM_DESTROY:
{
OutputDebugString(TEXT("DESTROYING A SUB WINDOW!\n"));
return 0;
}
case WM_PAINT:
{
InvalidateRect (hwnd, NULL, FALSE);
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
}
case EM_EXSETSEL:
{
if(hwnd == editControlHwnd)
{
OutputDebugString(L"Text selection changed");
return 0;
}
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
RichEdit控件完美地绘制和运行,显然没有问题,除了它没有使用我定义的WndProc
。
我不确定我在这里做错了什么,或者我怎么能正确解决这个问题。
修改
基于答案和注释,我已经恢复了我的代码,只使用包含RichEdit控件的Window
类,因此创建:
void SubWindow::CreateEditControl()
{
std::wstring initialText = TEXT("TestWindow\r\n");
LoadLibrary(L"Msftedit.dll");
GetClientRect(hwnd, &windowRect);
editControlHwnd = CreateWindowEx(0, MSFTEDIT_CLASS, initialText.data(),
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_READONLY | WS_VSCROLL | ES_NOHIDESEL,
windowRect.left, windowRect.top,windowRect.right,windowRect.bottom,
hwnd,
NULL, NULL, NULL);
cfmt.cbSize = sizeof(CHARFORMAT);
cfmt.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE;
cfmt.dwEffects = 0;
cfmt.yHeight = 160;
cfmt.crTextColor = RGB(0,0,0);
wcscpy_s(cfmt.szFaceName, TEXT("Tahoma"));
SendMessage(editControlHwnd, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cfmt);
}
如何在Window的MsgProc中处理来自此控件的消息?
答案 0 :(得分:1)
使用默认类名(MSFTEDIT_CLASS
)创建富编辑控件窗口时,所有邮件都将发送到其父窗口。由于您不是父窗口,因此无法处理这些消息。
因此,您需要对控件进行子类化,替换将直接调用的自己的窗口过程,而不是允许将消息传递给父级。这很简单;我之前在this answer for a regular edit control讨论过它。更改后的示例代码如下所示:
// Stores the old original window procedure for the rich edit control.
WNDPROC wpOldRichEditProc;
// The new custom window procedure for the rich edit control.
LRESULT CALLBACK CustomRichEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
...
}
// Pass the messages you don't process on to the original window procedure.
CallWindowProc(wpOldRichEditProc, hWnd, msg, wParam, lParam);
}
当你创建控件时:
// Create the rich edit control
HWND hWnd = CreateWindowEx(...)
// Subclass it.
wpOldRichEditProc= (WNDPROC)SetWindowLongPtr(hWnd,
GWLP_WNDPROC,
(WNDPROC)CustomRichEditProc);
每当它被销毁时,你还需要确保 unubclass 控件。另一个示例演示了如何响应父窗口收到的消息,但这不适用于您的情况,因为您没有收到父窗口的消息。相反,您需要从控件中删除子类以响应其自己的WM_NCDESTROY
消息:
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)wpOldRichEditProc);
或者,公共控件库的第6版使用a set of utility functions引入了一种新的,不易出错的子类化方法。 (关键功能实际上存在于早期版本中,但它没有记录。)考虑到您无法控制实际拥有窗口的进程,这可以说是首选方法。
有两种方法here on MSDN的演示。
当然,您不必仅为单个控件创建子类。您还可以注册一个自定义窗口类,其行为与内置的富编辑控件相同,但仍然可以首先破解该类窗口收到的消息。我无法从这个问题来判断这是否必要; 听起来就好像你只有一个你关心的控件。
答案 1 :(得分:1)
您说最初的问题是您的父窗口没有从RichEdit控件获取通知消息。您是否向RichEdit控件发送了EM_SETEVENTMASK消息?如果不这样做,RichEdit控件将不会向其父窗口发送某些通知消息。请参阅EM_SETEVENTMASK message。
答案 2 :(得分:0)
您能否展示涉及wc
结构和窗口创建的代码?我很确定你不希望主窗口与富编辑控件具有相同的类 - 这就是我到目前为止所阅读的内容。
我甚至不知道为什么WNDCLASSEX
适用于丰富的编辑控件。
我的建议是,您可以使用SetWindowLong()
和GWL_WNDPROC
EditControl::WndProc
向您的{{1}}创建简化内容并“创建”丰富的编辑控件的子类。